1/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Written by Ulrich Drepper <drepper@cygnus.com>.
4 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>.
19
20 As a special exception, if you link the code in this file with
21 files compiled with a GNU compiler to produce an executable,
22 that does not cause the resulting executable to be covered by
23 the GNU Lesser General Public License. This exception does not
24 however invalidate any other reasons why the executable file
25 might be covered by the GNU Lesser General Public License.
26 This exception applies to code released by its copyright holders
27 in files containing the exception. */
28
29#include <assert.h>
30#include <libioP.h>
31#include <wchar.h>
32#include <gconv.h>
33#include <stdlib.h>
34#include <string.h>
35
36
37#ifndef _LIBC
38# define _IO_new_do_write _IO_do_write
39# define _IO_new_file_attach _IO_file_attach
40# define _IO_new_file_close_it _IO_file_close_it
41# define _IO_new_file_finish _IO_file_finish
42# define _IO_new_file_fopen _IO_file_fopen
43# define _IO_new_file_init _IO_file_init
44# define _IO_new_file_setbuf _IO_file_setbuf
45# define _IO_new_file_sync _IO_file_sync
46# define _IO_new_file_overflow _IO_file_overflow
47# define _IO_new_file_seekoff _IO_file_seekoff
48# define _IO_new_file_underflow _IO_file_underflow
49# define _IO_new_file_write _IO_file_write
50# define _IO_new_file_xsputn _IO_file_xsputn
51#endif
52
53
54/* Convert TO_DO wide character from DATA to FP.
55 Then mark FP as having empty buffers. */
56int
57_IO_wdo_write (_IO_FILE *fp, const wchar_t *data, _IO_size_t to_do)
58{
59 struct _IO_codecvt *cc = fp->_codecvt;
60
61 if (to_do > 0)
62 {
63 if (fp->_IO_write_end == fp->_IO_write_ptr
64 && fp->_IO_write_end != fp->_IO_write_base)
65 {
66 if (_IO_new_do_write (fp, fp->_IO_write_base,
67 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
68 return WEOF;
69 }
70
71 do
72 {
73 enum __codecvt_result result;
74 const wchar_t *new_data;
75 char mb_buf[MB_LEN_MAX];
76 char *write_base, *write_ptr, *buf_end;
77
78 if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf))
79 {
80 /* Make sure we have room for at least one multibyte
81 character. */
82 write_ptr = write_base = mb_buf;
83 buf_end = mb_buf + sizeof (mb_buf);
84 }
85 else
86 {
87 write_ptr = fp->_IO_write_ptr;
88 write_base = fp->_IO_write_base;
89 buf_end = fp->_IO_buf_end;
90 }
91
92 /* Now convert from the internal format into the external buffer. */
93 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
94 data, data + to_do, &new_data,
95 write_ptr,
96 buf_end,
97 &write_ptr);
98
99 /* Write out what we produced so far. */
100 if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
101 /* Something went wrong. */
102 return WEOF;
103
104 to_do -= new_data - data;
105
106 /* Next see whether we had problems during the conversion. If yes,
107 we cannot go on. */
108 if (result != __codecvt_ok
109 && (result != __codecvt_partial || new_data - data == 0))
110 break;
111
112 data = new_data;
113 }
114 while (to_do > 0);
115 }
116
117 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
118 fp->_wide_data->_IO_buf_base);
119 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
120 = fp->_wide_data->_IO_buf_base;
121 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
122 ? fp->_wide_data->_IO_buf_base
123 : fp->_wide_data->_IO_buf_end);
124
125 return to_do == 0 ? 0 : WEOF;
126}
127libc_hidden_def (_IO_wdo_write)
128
129
130wint_t
131_IO_wfile_underflow (_IO_FILE *fp)
132{
133 struct _IO_codecvt *cd;
134 enum __codecvt_result status;
135 _IO_ssize_t count;
136
137 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
138 {
139 fp->_flags |= _IO_ERR_SEEN;
140 __set_errno (EBADF);
141 return WEOF;
142 }
143 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
144 return *fp->_wide_data->_IO_read_ptr;
145
146 cd = fp->_codecvt;
147
148 /* Maybe there is something left in the external buffer. */
149 if (fp->_IO_read_ptr < fp->_IO_read_end)
150 {
151 /* There is more in the external. Convert it. */
152 const char *read_stop = (const char *) fp->_IO_read_ptr;
153
154 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
155 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
156 fp->_wide_data->_IO_buf_base;
157 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
158 fp->_IO_read_ptr, fp->_IO_read_end,
159 &read_stop,
160 fp->_wide_data->_IO_read_ptr,
161 fp->_wide_data->_IO_buf_end,
162 &fp->_wide_data->_IO_read_end);
163
164 fp->_IO_read_base = fp->_IO_read_ptr;
165 fp->_IO_read_ptr = (char *) read_stop;
166
167 /* If we managed to generate some text return the next character. */
168 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
169 return *fp->_wide_data->_IO_read_ptr;
170
171 if (status == __codecvt_error)
172 {
173 __set_errno (EILSEQ);
174 fp->_flags |= _IO_ERR_SEEN;
175 return WEOF;
176 }
177
178 /* Move the remaining content of the read buffer to the beginning. */
179 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
180 fp->_IO_read_end - fp->_IO_read_ptr);
181 fp->_IO_read_end = (fp->_IO_buf_base
182 + (fp->_IO_read_end - fp->_IO_read_ptr));
183 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
184 }
185 else
186 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
187 fp->_IO_buf_base;
188
189 if (fp->_IO_buf_base == NULL)
190 {
191 /* Maybe we already have a push back pointer. */
192 if (fp->_IO_save_base != NULL)
193 {
194 free (fp->_IO_save_base);
195 fp->_flags &= ~_IO_IN_BACKUP;
196 }
197 _IO_doallocbuf (fp);
198
199 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
200 fp->_IO_buf_base;
201 }
202
203 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
204 fp->_IO_buf_base;
205
206 if (fp->_wide_data->_IO_buf_base == NULL)
207 {
208 /* Maybe we already have a push back pointer. */
209 if (fp->_wide_data->_IO_save_base != NULL)
210 {
211 free (fp->_wide_data->_IO_save_base);
212 fp->_flags &= ~_IO_IN_BACKUP;
213 }
214 _IO_wdoallocbuf (fp);
215 }
216
217 /* Flush all line buffered files before reading. */
218 /* FIXME This can/should be moved to genops ?? */
219 if (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
220 {
221#if 0
222 _IO_flush_all_linebuffered ();
223#else
224 /* We used to flush all line-buffered stream. This really isn't
225 required by any standard. My recollection is that
226 traditional Unix systems did this for stdout. stderr better
227 not be line buffered. So we do just that here
228 explicitly. --drepper */
229 _IO_acquire_lock (_IO_stdout);
230
231 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
232 == (_IO_LINKED | _IO_LINE_BUF))
233 _IO_OVERFLOW (_IO_stdout, EOF);
234
235 _IO_release_lock (_IO_stdout);
236#endif
237 }
238
239 _IO_switch_to_get_mode (fp);
240
241 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
242 fp->_wide_data->_IO_buf_base;
243 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
244 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
245 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
246
247 const char *read_ptr_copy;
248 char accbuf[MB_LEN_MAX];
249 size_t naccbuf = 0;
250 again:
251 count = _IO_SYSREAD (fp, fp->_IO_read_end,
252 fp->_IO_buf_end - fp->_IO_read_end);
253 if (count <= 0)
254 {
255 if (count == 0 && naccbuf == 0)
256 {
257 fp->_flags |= _IO_EOF_SEEN;
258 fp->_offset = _IO_pos_BAD;
259 }
260 else
261 fp->_flags |= _IO_ERR_SEEN, count = 0;
262 }
263 fp->_IO_read_end += count;
264 if (count == 0)
265 {
266 if (naccbuf != 0)
267 /* There are some bytes in the external buffer but they don't
268 convert to anything. */
269 __set_errno (EILSEQ);
270 return WEOF;
271 }
272 if (fp->_offset != _IO_pos_BAD)
273 _IO_pos_adjust (fp->_offset, count);
274
275 /* Now convert the read input. */
276 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
277 fp->_IO_read_base = fp->_IO_read_ptr;
278 const char *from = fp->_IO_read_ptr;
279 const char *to = fp->_IO_read_end;
280 size_t to_copy = count;
281 if (__glibc_unlikely (naccbuf != 0))
282 {
283 to_copy = MIN (sizeof (accbuf) - naccbuf, count);
284 to = __mempcpy (&accbuf[naccbuf], from, to_copy);
285 naccbuf += to_copy;
286 from = accbuf;
287 }
288 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
289 from, to, &read_ptr_copy,
290 fp->_wide_data->_IO_read_end,
291 fp->_wide_data->_IO_buf_end,
292 &fp->_wide_data->_IO_read_end);
293
294 if (__glibc_unlikely (naccbuf != 0))
295 fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
296 else
297 fp->_IO_read_ptr = (char *) read_ptr_copy;
298 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
299 {
300 if (status == __codecvt_error)
301 {
302 out_eilseq:
303 __set_errno (EILSEQ);
304 fp->_flags |= _IO_ERR_SEEN;
305 return WEOF;
306 }
307
308 /* The read bytes make no complete character. Try reading again. */
309 assert (status == __codecvt_partial);
310
311 if (naccbuf == 0)
312 {
313 if (fp->_IO_read_base < fp->_IO_read_ptr)
314 {
315 /* Partially used the buffer for some input data that
316 produces no output. */
317 size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
318 memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
319 fp->_IO_read_ptr = fp->_IO_read_base;
320 fp->_IO_read_end -= avail;
321 goto again;
322 }
323 naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
324 if (naccbuf >= sizeof (accbuf))
325 goto out_eilseq;
326
327 memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
328 }
329 else
330 {
331 size_t used = read_ptr_copy - accbuf;
332 if (used > 0)
333 {
334 memmove (accbuf, read_ptr_copy, naccbuf - used);
335 naccbuf -= used;
336 }
337
338 if (naccbuf == sizeof (accbuf))
339 goto out_eilseq;
340 }
341
342 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
343
344 goto again;
345 }
346
347 return *fp->_wide_data->_IO_read_ptr;
348}
349libc_hidden_def (_IO_wfile_underflow)
350
351
352static wint_t
353_IO_wfile_underflow_mmap (_IO_FILE *fp)
354{
355 struct _IO_codecvt *cd;
356 const char *read_stop;
357
358 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
359 {
360 fp->_flags |= _IO_ERR_SEEN;
361 __set_errno (EBADF);
362 return WEOF;
363 }
364 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
365 return *fp->_wide_data->_IO_read_ptr;
366
367 cd = fp->_codecvt;
368
369 /* Maybe there is something left in the external buffer. */
370 if (fp->_IO_read_ptr >= fp->_IO_read_end
371 /* No. But maybe the read buffer is not fully set up. */
372 && _IO_file_underflow_mmap (fp) == EOF)
373 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
374 flags as appropriate. */
375 return WEOF;
376
377 /* There is more in the external. Convert it. */
378 read_stop = (const char *) fp->_IO_read_ptr;
379
380 if (fp->_wide_data->_IO_buf_base == NULL)
381 {
382 /* Maybe we already have a push back pointer. */
383 if (fp->_wide_data->_IO_save_base != NULL)
384 {
385 free (fp->_wide_data->_IO_save_base);
386 fp->_flags &= ~_IO_IN_BACKUP;
387 }
388 _IO_wdoallocbuf (fp);
389 }
390
391 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
392 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
393 fp->_wide_data->_IO_buf_base;
394 (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
395 fp->_IO_read_ptr, fp->_IO_read_end,
396 &read_stop,
397 fp->_wide_data->_IO_read_ptr,
398 fp->_wide_data->_IO_buf_end,
399 &fp->_wide_data->_IO_read_end);
400
401 fp->_IO_read_ptr = (char *) read_stop;
402
403 /* If we managed to generate some text return the next character. */
404 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
405 return *fp->_wide_data->_IO_read_ptr;
406
407 /* There is some garbage at the end of the file. */
408 __set_errno (EILSEQ);
409 fp->_flags |= _IO_ERR_SEEN;
410 return WEOF;
411}
412
413static wint_t
414_IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
415{
416 /* This is the first read attempt. Doing the underflow will choose mmap
417 or vanilla operations and then punt to the chosen underflow routine.
418 Then we can punt to ours. */
419 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
420 return WEOF;
421
422 return _IO_WUNDERFLOW (fp);
423}
424
425
426wint_t
427_IO_wfile_overflow (_IO_FILE *f, wint_t wch)
428{
429 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
430 {
431 f->_flags |= _IO_ERR_SEEN;
432 __set_errno (EBADF);
433 return WEOF;
434 }
435 /* If currently reading or no buffer allocated. */
436 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
437 {
438 /* Allocate a buffer if needed. */
439 if (f->_wide_data->_IO_write_base == 0)
440 {
441 _IO_wdoallocbuf (f);
442 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
443 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
444
445 if (f->_IO_write_base == NULL)
446 {
447 _IO_doallocbuf (f);
448 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
449 }
450 }
451 else
452 {
453 /* Otherwise must be currently reading. If _IO_read_ptr
454 (and hence also _IO_read_end) is at the buffer end,
455 logically slide the buffer forwards one block (by setting
456 the read pointers to all point at the beginning of the
457 block). This makes room for subsequent output.
458 Otherwise, set the read pointers to _IO_read_end (leaving
459 that alone, so it can continue to correspond to the
460 external position). */
461 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
462 {
463 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
464 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
465 f->_wide_data->_IO_buf_base;
466 }
467 }
468 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
469 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
470 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
471 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
472 f->_wide_data->_IO_read_end;
473
474 f->_IO_write_ptr = f->_IO_read_ptr;
475 f->_IO_write_base = f->_IO_write_ptr;
476 f->_IO_write_end = f->_IO_buf_end;
477 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
478
479 f->_flags |= _IO_CURRENTLY_PUTTING;
480 if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
481 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
482 }
483 if (wch == WEOF)
484 return _IO_do_flush (f);
485 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
486 /* Buffer is really full */
487 if (_IO_do_flush (f) == EOF)
488 return WEOF;
489 *f->_wide_data->_IO_write_ptr++ = wch;
490 if ((f->_flags & _IO_UNBUFFERED)
491 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
492 if (_IO_do_flush (f) == EOF)
493 return WEOF;
494 return wch;
495}
496libc_hidden_def (_IO_wfile_overflow)
497
498wint_t
499_IO_wfile_sync (_IO_FILE *fp)
500{
501 _IO_ssize_t delta;
502 wint_t retval = 0;
503
504 /* char* ptr = cur_ptr(); */
505 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
506 if (_IO_do_flush (fp))
507 return WEOF;
508 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
509 if (delta != 0)
510 {
511 /* We have to find out how many bytes we have to go back in the
512 external buffer. */
513 struct _IO_codecvt *cv = fp->_codecvt;
514 _IO_off64_t new_pos;
515
516 int clen = (*cv->__codecvt_do_encoding) (cv);
517
518 if (clen > 0)
519 /* It is easy, a fixed number of input bytes are used for each
520 wide character. */
521 delta *= clen;
522 else
523 {
524 /* We have to find out the hard way how much to back off.
525 To do this we determine how much input we needed to
526 generate the wide characters up to the current reading
527 position. */
528 int nread;
529 size_t wnread = (fp->_wide_data->_IO_read_ptr
530 - fp->_wide_data->_IO_read_base);
531 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
532 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
533 fp->_IO_read_base,
534 fp->_IO_read_end, wnread);
535 fp->_IO_read_ptr = fp->_IO_read_base + nread;
536 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
537 }
538
539 new_pos = _IO_SYSSEEK (fp, delta, 1);
540 if (new_pos != (_IO_off64_t) EOF)
541 {
542 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
543 fp->_IO_read_end = fp->_IO_read_ptr;
544 }
545#ifdef ESPIPE
546 else if (errno == ESPIPE)
547 ; /* Ignore error from unseekable devices. */
548#endif
549 else
550 retval = WEOF;
551 }
552 if (retval != WEOF)
553 fp->_offset = _IO_pos_BAD;
554 /* FIXME: Cleanup - can this be shared? */
555 /* setg(base(), ptr, ptr); */
556 return retval;
557}
558libc_hidden_def (_IO_wfile_sync)
559
560/* Adjust the internal buffer pointers to reflect the state in the external
561 buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
562 assumed to be converted and available in the range
563 fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
564
565 Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set. */
566static int
567adjust_wide_data (_IO_FILE *fp, bool do_convert)
568{
569 struct _IO_codecvt *cv = fp->_codecvt;
570
571 int clen = (*cv->__codecvt_do_encoding) (cv);
572
573 /* Take the easy way out for constant length encodings if we don't need to
574 convert. */
575 if (!do_convert && clen > 0)
576 {
577 fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
578 / clen);
579 goto done;
580 }
581
582 enum __codecvt_result status;
583 const char *read_stop = (const char *) fp->_IO_read_base;
584 do
585 {
586
587 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
588 status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
589 fp->_IO_read_base, fp->_IO_read_ptr,
590 &read_stop,
591 fp->_wide_data->_IO_read_base,
592 fp->_wide_data->_IO_buf_end,
593 &fp->_wide_data->_IO_read_end);
594
595 /* Should we return EILSEQ? */
596 if (__glibc_unlikely (status == __codecvt_error))
597 {
598 fp->_flags |= _IO_ERR_SEEN;
599 return -1;
600 }
601 }
602 while (__builtin_expect (status == __codecvt_partial, 0));
603
604done:
605 /* Now seek to _IO_read_end to behave as if we have read it all in. */
606 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
607
608 return 0;
609}
610
611/* ftell{,o} implementation for wide mode. Don't modify any state of the file
612 pointer while we try to get the current state of the stream except in one
613 case, which is when we have unflushed writes in append mode. */
614static _IO_off64_t
615do_ftell_wide (_IO_FILE *fp)
616{
617 _IO_off64_t result, offset = 0;
618
619 /* No point looking for offsets in the buffer if it hasn't even been
620 allocated. */
621 if (fp->_wide_data->_IO_buf_base != NULL)
622 {
623 const wchar_t *wide_read_base;
624 const wchar_t *wide_read_ptr;
625 const wchar_t *wide_read_end;
626 bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
627 > fp->_wide_data->_IO_write_base);
628
629 bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
630
631 /* When we have unflushed writes in append mode, seek to the end of the
632 file and record that offset. This is the only time we change the file
633 stream state and it is safe since the file handle is active. */
634 if (unflushed_writes && append_mode)
635 {
636 result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
637 if (result == _IO_pos_BAD)
638 return EOF;
639 else
640 fp->_offset = result;
641 }
642
643 /* XXX For wide stream with backup store it is not very
644 reasonable to determine the offset. The pushed-back
645 character might require a state change and we need not be
646 able to compute the initial state by reverse transformation
647 since there is no guarantee of symmetry. So we don't even
648 try and return an error. */
649 if (_IO_in_backup (fp))
650 {
651 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
652 {
653 __set_errno (EINVAL);
654 return -1;
655 }
656
657 /* Nothing in the backup store, so note the backed up pointers
658 without changing the state. */
659 wide_read_base = fp->_wide_data->_IO_save_base;
660 wide_read_ptr = wide_read_base;
661 wide_read_end = fp->_wide_data->_IO_save_end;
662 }
663 else
664 {
665 wide_read_base = fp->_wide_data->_IO_read_base;
666 wide_read_ptr = fp->_wide_data->_IO_read_ptr;
667 wide_read_end = fp->_wide_data->_IO_read_end;
668 }
669
670 struct _IO_codecvt *cv = fp->_codecvt;
671 int clen = (*cv->__codecvt_do_encoding) (cv);
672
673 if (!unflushed_writes)
674 {
675 if (clen > 0)
676 {
677 offset -= (wide_read_end - wide_read_ptr) * clen;
678 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
679 }
680 else
681 {
682 int nread;
683
684 size_t delta = wide_read_ptr - wide_read_base;
685 __mbstate_t state = fp->_wide_data->_IO_last_state;
686 nread = (*cv->__codecvt_do_length) (cv, &state,
687 fp->_IO_read_base,
688 fp->_IO_read_end, delta);
689 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
690 }
691 }
692 else
693 {
694 if (clen > 0)
695 offset += (fp->_wide_data->_IO_write_ptr
696 - fp->_wide_data->_IO_write_base) * clen;
697 else
698 {
699 size_t delta = (fp->_wide_data->_IO_write_ptr
700 - fp->_wide_data->_IO_write_base);
701
702 /* Allocate enough space for the conversion. */
703 size_t outsize = delta * sizeof (wchar_t);
704 char *out = malloc (outsize);
705 char *outstop = out;
706 const wchar_t *in = fp->_wide_data->_IO_write_base;
707
708 enum __codecvt_result status;
709
710 __mbstate_t state = fp->_wide_data->_IO_last_state;
711 status = (*cv->__codecvt_do_out) (cv, &state,
712 in, in + delta, &in,
713 out, out + outsize, &outstop);
714
715 /* We don't check for __codecvt_partial because it can be
716 returned on one of two conditions: either the output
717 buffer is full or the input sequence is incomplete. We
718 take care to allocate enough buffer and our input
719 sequences must be complete since they are accepted as
720 wchar_t; if not, then that is an error. */
721 if (__glibc_unlikely (status != __codecvt_ok))
722 {
723 free (out);
724 return WEOF;
725 }
726
727 offset += outstop - out;
728 free (out);
729 }
730
731 /* We don't trust _IO_read_end to represent the current file offset
732 when writing in append mode because the value would have to be
733 shifted to the end of the file during a flush. Use the write base
734 instead, along with the new offset we got above when we did a seek
735 to the end of the file. */
736 if (append_mode)
737 offset += fp->_IO_write_ptr - fp->_IO_write_base;
738 /* For all other modes, _IO_read_end represents the file offset. */
739 else
740 offset += fp->_IO_write_ptr - fp->_IO_read_end;
741 }
742 }
743
744 if (fp->_offset != _IO_pos_BAD)
745 result = fp->_offset;
746 else
747 result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
748
749 if (result == EOF)
750 return result;
751
752 result += offset;
753
754 if (result < 0)
755 {
756 __set_errno (EINVAL);
757 return EOF;
758 }
759
760 return result;
761}
762
763_IO_off64_t
764_IO_wfile_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
765{
766 _IO_off64_t result;
767 _IO_off64_t delta, new_offset;
768 long int count;
769
770 /* Short-circuit into a separate function. We don't want to mix any
771 functionality and we don't want to touch anything inside the FILE
772 object. */
773 if (mode == 0)
774 return do_ftell_wide (fp);
775
776 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
777 offset of the underlying file must be exact. */
778 int must_be_exact = ((fp->_wide_data->_IO_read_base
779 == fp->_wide_data->_IO_read_end)
780 && (fp->_wide_data->_IO_write_base
781 == fp->_wide_data->_IO_write_ptr));
782
783 bool was_writing = ((fp->_wide_data->_IO_write_ptr
784 > fp->_wide_data->_IO_write_base)
785 || _IO_in_put_mode (fp));
786
787 /* Flush unwritten characters.
788 (This may do an unneeded write if we seek within the buffer.
789 But to be able to switch to reading, we would need to set
790 egptr to pptr. That can't be done in the current design,
791 which assumes file_ptr() is eGptr. Anyway, since we probably
792 end up flushing when we close(), it doesn't make much difference.)
793 FIXME: simulate mem-mapped files. */
794 if (was_writing && _IO_switch_to_wget_mode (fp))
795 return WEOF;
796
797 if (fp->_wide_data->_IO_buf_base == NULL)
798 {
799 /* It could be that we already have a pushback buffer. */
800 if (fp->_wide_data->_IO_read_base != NULL)
801 {
802 free (fp->_wide_data->_IO_read_base);
803 fp->_flags &= ~_IO_IN_BACKUP;
804 }
805 _IO_doallocbuf (fp);
806 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
807 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
808 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
809 fp->_wide_data->_IO_buf_base);
810 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
811 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
812 }
813
814 switch (dir)
815 {
816 struct _IO_codecvt *cv;
817 int clen;
818
819 case _IO_seek_cur:
820 /* Adjust for read-ahead (bytes is buffer). To do this we must
821 find out which position in the external buffer corresponds to
822 the current position in the internal buffer. */
823 cv = fp->_codecvt;
824 clen = (*cv->__codecvt_do_encoding) (cv);
825
826 if (mode != 0 || !was_writing)
827 {
828 if (clen > 0)
829 {
830 offset -= (fp->_wide_data->_IO_read_end
831 - fp->_wide_data->_IO_read_ptr) * clen;
832 /* Adjust by readahead in external buffer. */
833 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
834 }
835 else
836 {
837 int nread;
838
839 delta = (fp->_wide_data->_IO_read_ptr
840 - fp->_wide_data->_IO_read_base);
841 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
842 nread = (*cv->__codecvt_do_length) (cv,
843 &fp->_wide_data->_IO_state,
844 fp->_IO_read_base,
845 fp->_IO_read_end, delta);
846 fp->_IO_read_ptr = fp->_IO_read_base + nread;
847 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
848 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
849 }
850 }
851
852 if (fp->_offset == _IO_pos_BAD)
853 goto dumb;
854
855 /* Make offset absolute, assuming current pointer is file_ptr(). */
856 offset += fp->_offset;
857
858 dir = _IO_seek_set;
859 break;
860 case _IO_seek_set:
861 break;
862 case _IO_seek_end:
863 {
864 struct stat64 st;
865 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
866 {
867 offset += st.st_size;
868 dir = _IO_seek_set;
869 }
870 else
871 goto dumb;
872 }
873 }
874 /* At this point, dir==_IO_seek_set. */
875
876 /* If destination is within current buffer, optimize: */
877 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
878 && !_IO_in_backup (fp))
879 {
880 _IO_off64_t start_offset = (fp->_offset
881 - (fp->_IO_read_end - fp->_IO_buf_base));
882 if (offset >= start_offset && offset < fp->_offset)
883 {
884 _IO_setg (fp, fp->_IO_buf_base,
885 fp->_IO_buf_base + (offset - start_offset),
886 fp->_IO_read_end);
887 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
888 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
889 fp->_wide_data->_IO_buf_base,
890 fp->_wide_data->_IO_buf_base);
891 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
892 fp->_wide_data->_IO_buf_base);
893
894 if (adjust_wide_data (fp, false))
895 goto dumb;
896
897 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
898 goto resync;
899 }
900 }
901
902 if (fp->_flags & _IO_NO_READS)
903 goto dumb;
904
905 /* Try to seek to a block boundary, to improve kernel page management. */
906 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
907 delta = offset - new_offset;
908 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
909 {
910 new_offset = offset;
911 delta = 0;
912 }
913 result = _IO_SYSSEEK (fp, new_offset, 0);
914 if (result < 0)
915 return EOF;
916 if (delta == 0)
917 count = 0;
918 else
919 {
920 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
921 (must_be_exact
922 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
923 if (count < delta)
924 {
925 /* We weren't allowed to read, but try to seek the remainder. */
926 offset = count == EOF ? delta : delta-count;
927 dir = _IO_seek_cur;
928 goto dumb;
929 }
930 }
931 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
932 fp->_IO_buf_base + count);
933 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
934 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
935 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
936 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
937
938 if (adjust_wide_data (fp, true))
939 goto dumb;
940
941 fp->_offset = result + count;
942 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
943 return offset;
944 dumb:
945
946 _IO_unsave_markers (fp);
947 result = _IO_SYSSEEK (fp, offset, dir);
948 if (result != EOF)
949 {
950 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
951 fp->_offset = result;
952 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
953 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
954 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
955 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
956 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
957 fp->_wide_data->_IO_buf_base);
958 }
959 return result;
960
961resync:
962 /* We need to do it since it is possible that the file offset in
963 the kernel may be changed behind our back. It may happen when
964 we fopen a file and then do a fork. One process may access the
965 file and the kernel file offset will be changed. */
966 if (fp->_offset >= 0)
967 _IO_SYSSEEK (fp, fp->_offset, 0);
968
969 return offset;
970}
971libc_hidden_def (_IO_wfile_seekoff)
972
973
974_IO_size_t
975_IO_wfile_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
976{
977 const wchar_t *s = (const wchar_t *) data;
978 _IO_size_t to_do = n;
979 int must_flush = 0;
980 _IO_size_t count;
981
982 if (n <= 0)
983 return 0;
984 /* This is an optimized implementation.
985 If the amount to be written straddles a block boundary
986 (or the filebuf is unbuffered), use sys_write directly. */
987
988 /* First figure out how much space is available in the buffer. */
989 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
990 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
991 {
992 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
993 if (count >= n)
994 {
995 const wchar_t *p;
996 for (p = s + n; p > s; )
997 {
998 if (*--p == L'\n')
999 {
1000 count = p - s + 1;
1001 must_flush = 1;
1002 break;
1003 }
1004 }
1005 }
1006 }
1007 /* Then fill the buffer. */
1008 if (count > 0)
1009 {
1010 if (count > to_do)
1011 count = to_do;
1012 if (count > 20)
1013 {
1014#ifdef _LIBC
1015 f->_wide_data->_IO_write_ptr =
1016 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
1017#else
1018 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
1019 f->_wide_data->_IO_write_ptr += count;
1020#endif
1021 s += count;
1022 }
1023 else
1024 {
1025 wchar_t *p = f->_wide_data->_IO_write_ptr;
1026 int i = (int) count;
1027 while (--i >= 0)
1028 *p++ = *s++;
1029 f->_wide_data->_IO_write_ptr = p;
1030 }
1031 to_do -= count;
1032 }
1033 if (to_do > 0)
1034 to_do -= _IO_wdefault_xsputn (f, s, to_do);
1035 if (must_flush
1036 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1037 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1038 f->_wide_data->_IO_write_ptr
1039 - f->_wide_data->_IO_write_base);
1040
1041 return n - to_do;
1042}
1043libc_hidden_def (_IO_wfile_xsputn)
1044
1045
1046const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1047{
1048 JUMP_INIT_DUMMY,
1049 JUMP_INIT(finish, _IO_new_file_finish),
1050 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1051 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1052 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1053 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1054 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1055 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1056 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1057 JUMP_INIT(seekpos, _IO_default_seekpos),
1058 JUMP_INIT(setbuf, _IO_new_file_setbuf),
1059 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1060 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1061 JUMP_INIT(read, _IO_file_read),
1062 JUMP_INIT(write, _IO_new_file_write),
1063 JUMP_INIT(seek, _IO_file_seek),
1064 JUMP_INIT(close, _IO_file_close),
1065 JUMP_INIT(stat, _IO_file_stat),
1066 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1067 JUMP_INIT(imbue, _IO_default_imbue)
1068};
1069libc_hidden_data_def (_IO_wfile_jumps)
1070
1071
1072const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
1073{
1074 JUMP_INIT_DUMMY,
1075 JUMP_INIT(finish, _IO_new_file_finish),
1076 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1077 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
1078 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1079 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1080 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1081 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1082 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1083 JUMP_INIT(seekpos, _IO_default_seekpos),
1084 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1085 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1086 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1087 JUMP_INIT(read, _IO_file_read),
1088 JUMP_INIT(write, _IO_new_file_write),
1089 JUMP_INIT(seek, _IO_file_seek),
1090 JUMP_INIT(close, _IO_file_close_mmap),
1091 JUMP_INIT(stat, _IO_file_stat),
1092 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1093 JUMP_INIT(imbue, _IO_default_imbue)
1094};
1095
1096const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1097{
1098 JUMP_INIT_DUMMY,
1099 JUMP_INIT(finish, _IO_new_file_finish),
1100 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1101 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1102 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1103 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1104 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1105 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1106 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1107 JUMP_INIT(seekpos, _IO_default_seekpos),
1108 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1109 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1110 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1111 JUMP_INIT(read, _IO_file_read),
1112 JUMP_INIT(write, _IO_new_file_write),
1113 JUMP_INIT(seek, _IO_file_seek),
1114 JUMP_INIT(close, _IO_file_close),
1115 JUMP_INIT(stat, _IO_file_stat),
1116 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1117 JUMP_INIT(imbue, _IO_default_imbue)
1118};
1119