Update old tunables framework document/script.
[glibc.git] / libio / wfileops.c
blobfb94f45040f57f36c3fc6c98b699ef6f7f2b4c01
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>.
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.
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.
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/>.
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. */
29 #include <assert.h>
30 #include <libioP.h>
31 #include <wchar.h>
32 #include <gconv.h>
33 #include <stdlib.h>
34 #include <string.h>
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
54 /* Convert TO_DO wide character from DATA to FP.
55 Then mark FP as having empty buffers. */
56 int
57 _IO_wdo_write (_IO_FILE *fp, const wchar_t *data, _IO_size_t to_do)
59 struct _IO_codecvt *cc = fp->_codecvt;
61 if (to_do > 0)
63 if (fp->_IO_write_end == fp->_IO_write_ptr
64 && fp->_IO_write_end != fp->_IO_write_base)
66 if (_IO_new_do_write (fp, fp->_IO_write_base,
67 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
68 return WEOF;
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;
78 if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf))
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);
85 else
87 write_ptr = fp->_IO_write_ptr;
88 write_base = fp->_IO_write_base;
89 buf_end = fp->_IO_buf_end;
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);
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;
104 to_do -= new_data - data;
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;
112 data = new_data;
114 while (to_do > 0);
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);
125 return to_do == 0 ? 0 : WEOF;
127 libc_hidden_def (_IO_wdo_write)
130 wint_t
131 _IO_wfile_underflow (_IO_FILE *fp)
133 struct _IO_codecvt *cd;
134 enum __codecvt_result status;
135 _IO_ssize_t count;
137 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
139 fp->_flags |= _IO_ERR_SEEN;
140 __set_errno (EBADF);
141 return WEOF;
143 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
144 return *fp->_wide_data->_IO_read_ptr;
146 cd = fp->_codecvt;
148 /* Maybe there is something left in the external buffer. */
149 if (fp->_IO_read_ptr < fp->_IO_read_end)
151 /* There is more in the external. Convert it. */
152 const char *read_stop = (const char *) fp->_IO_read_ptr;
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);
164 fp->_IO_read_base = fp->_IO_read_ptr;
165 fp->_IO_read_ptr = (char *) read_stop;
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;
171 if (status == __codecvt_error)
173 __set_errno (EILSEQ);
174 fp->_flags |= _IO_ERR_SEEN;
175 return WEOF;
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;
185 else
186 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
187 fp->_IO_buf_base;
189 if (fp->_IO_buf_base == NULL)
191 /* Maybe we already have a push back pointer. */
192 if (fp->_IO_save_base != NULL)
194 free (fp->_IO_save_base);
195 fp->_flags &= ~_IO_IN_BACKUP;
197 _IO_doallocbuf (fp);
199 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
200 fp->_IO_buf_base;
203 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
204 fp->_IO_buf_base;
206 if (fp->_wide_data->_IO_buf_base == NULL)
208 /* Maybe we already have a push back pointer. */
209 if (fp->_wide_data->_IO_save_base != NULL)
211 free (fp->_wide_data->_IO_save_base);
212 fp->_flags &= ~_IO_IN_BACKUP;
214 _IO_wdoallocbuf (fp);
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))
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);
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);
235 _IO_release_lock (_IO_stdout);
236 #endif
239 _IO_switch_to_get_mode (fp);
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;
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)
255 if (count == 0 && naccbuf == 0)
257 fp->_flags |= _IO_EOF_SEEN;
258 fp->_offset = _IO_pos_BAD;
260 else
261 fp->_flags |= _IO_ERR_SEEN, count = 0;
263 fp->_IO_read_end += count;
264 if (count == 0)
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;
272 if (fp->_offset != _IO_pos_BAD)
273 _IO_pos_adjust (fp->_offset, count);
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))
283 to_copy = MIN (sizeof (accbuf) - naccbuf, count);
284 to = __mempcpy (&accbuf[naccbuf], from, to_copy);
285 naccbuf += to_copy;
286 from = accbuf;
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);
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)
300 if (status == __codecvt_error)
302 out_eilseq:
303 __set_errno (EILSEQ);
304 fp->_flags |= _IO_ERR_SEEN;
305 return WEOF;
308 /* The read bytes make no complete character. Try reading again. */
309 assert (status == __codecvt_partial);
311 if (naccbuf == 0)
313 if (fp->_IO_read_base < fp->_IO_read_ptr)
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;
323 naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
324 if (naccbuf >= sizeof (accbuf))
325 goto out_eilseq;
327 memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
329 else
331 size_t used = read_ptr_copy - accbuf;
332 if (used > 0)
334 memmove (accbuf, read_ptr_copy, naccbuf - used);
335 naccbuf -= used;
338 if (naccbuf == sizeof (accbuf))
339 goto out_eilseq;
342 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
344 goto again;
347 return *fp->_wide_data->_IO_read_ptr;
349 libc_hidden_def (_IO_wfile_underflow)
352 static wint_t
353 _IO_wfile_underflow_mmap (_IO_FILE *fp)
355 struct _IO_codecvt *cd;
356 const char *read_stop;
358 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
360 fp->_flags |= _IO_ERR_SEEN;
361 __set_errno (EBADF);
362 return WEOF;
364 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
365 return *fp->_wide_data->_IO_read_ptr;
367 cd = fp->_codecvt;
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;
377 /* There is more in the external. Convert it. */
378 read_stop = (const char *) fp->_IO_read_ptr;
380 if (fp->_wide_data->_IO_buf_base == NULL)
382 /* Maybe we already have a push back pointer. */
383 if (fp->_wide_data->_IO_save_base != NULL)
385 free (fp->_wide_data->_IO_save_base);
386 fp->_flags &= ~_IO_IN_BACKUP;
388 _IO_wdoallocbuf (fp);
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);
401 fp->_IO_read_ptr = (char *) read_stop;
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;
407 /* There is some garbage at the end of the file. */
408 __set_errno (EILSEQ);
409 fp->_flags |= _IO_ERR_SEEN;
410 return WEOF;
413 static wint_t
414 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
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;
422 return _IO_WUNDERFLOW (fp);
426 wint_t
427 _IO_wfile_overflow (_IO_FILE *f, wint_t wch)
429 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
431 f->_flags |= _IO_ERR_SEEN;
432 __set_errno (EBADF);
433 return WEOF;
435 /* If currently reading or no buffer allocated. */
436 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
438 /* Allocate a buffer if needed. */
439 if (f->_wide_data->_IO_write_base == 0)
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);
445 if (f->_IO_write_base == NULL)
447 _IO_doallocbuf (f);
448 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
451 else
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)
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;
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;
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;
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;
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;
496 libc_hidden_def (_IO_wfile_overflow)
498 wint_t
499 _IO_wfile_sync (_IO_FILE *fp)
501 _IO_ssize_t delta;
502 wint_t retval = 0;
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)
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;
516 int clen = (*cv->__codecvt_do_encoding) (cv);
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
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;
530 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
531 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
532 fp->_IO_read_base,
533 fp->_IO_read_end, delta);
534 fp->_IO_read_ptr = fp->_IO_read_base + nread;
535 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
538 new_pos = _IO_SYSSEEK (fp, delta, 1);
539 if (new_pos != (_IO_off64_t) EOF)
541 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
542 fp->_IO_read_end = fp->_IO_read_ptr;
544 #ifdef ESPIPE
545 else if (errno == ESPIPE)
546 ; /* Ignore error from unseekable devices. */
547 #endif
548 else
549 retval = WEOF;
551 if (retval != WEOF)
552 fp->_offset = _IO_pos_BAD;
553 /* FIXME: Cleanup - can this be shared? */
554 /* setg(base(), ptr, ptr); */
555 return retval;
557 libc_hidden_def (_IO_wfile_sync)
559 /* Adjust the internal buffer pointers to reflect the state in the external
560 buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
561 assumed to be converted and available in the range
562 fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
564 Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set. */
565 static int
566 adjust_wide_data (_IO_FILE *fp, bool do_convert)
568 struct _IO_codecvt *cv = fp->_codecvt;
570 int clen = (*cv->__codecvt_do_encoding) (cv);
572 /* Take the easy way out for constant length encodings if we don't need to
573 convert. */
574 if (!do_convert && clen > 0)
576 fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
577 / clen);
578 goto done;
581 enum __codecvt_result status;
582 const char *read_stop = (const char *) fp->_IO_read_base;
586 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
587 status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
588 fp->_IO_read_base, fp->_IO_read_ptr,
589 &read_stop,
590 fp->_wide_data->_IO_read_base,
591 fp->_wide_data->_IO_buf_end,
592 &fp->_wide_data->_IO_read_end);
594 /* Should we return EILSEQ? */
595 if (__glibc_unlikely (status == __codecvt_error))
597 fp->_flags |= _IO_ERR_SEEN;
598 return -1;
601 while (__builtin_expect (status == __codecvt_partial, 0));
603 done:
604 /* Now seek to _IO_read_end to behave as if we have read it all in. */
605 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
607 return 0;
610 /* ftell{,o} implementation for wide mode. Don't modify any state of the file
611 pointer while we try to get the current state of the stream except in one
612 case, which is when we have unflushed writes in append mode. */
613 static _IO_off64_t
614 do_ftell_wide (_IO_FILE *fp)
616 _IO_off64_t result, offset = 0;
618 /* No point looking for offsets in the buffer if it hasn't even been
619 allocated. */
620 if (fp->_wide_data->_IO_buf_base != NULL)
622 const wchar_t *wide_read_base;
623 const wchar_t *wide_read_ptr;
624 const wchar_t *wide_read_end;
625 bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
626 > fp->_wide_data->_IO_write_base);
628 bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
630 /* When we have unflushed writes in append mode, seek to the end of the
631 file and record that offset. This is the only time we change the file
632 stream state and it is safe since the file handle is active. */
633 if (unflushed_writes && append_mode)
635 result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
636 if (result == _IO_pos_BAD)
637 return EOF;
638 else
639 fp->_offset = result;
642 /* XXX For wide stream with backup store it is not very
643 reasonable to determine the offset. The pushed-back
644 character might require a state change and we need not be
645 able to compute the initial state by reverse transformation
646 since there is no guarantee of symmetry. So we don't even
647 try and return an error. */
648 if (_IO_in_backup (fp))
650 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
652 __set_errno (EINVAL);
653 return -1;
656 /* Nothing in the backup store, so note the backed up pointers
657 without changing the state. */
658 wide_read_base = fp->_wide_data->_IO_save_base;
659 wide_read_ptr = wide_read_base;
660 wide_read_end = fp->_wide_data->_IO_save_end;
662 else
664 wide_read_base = fp->_wide_data->_IO_read_base;
665 wide_read_ptr = fp->_wide_data->_IO_read_ptr;
666 wide_read_end = fp->_wide_data->_IO_read_end;
669 struct _IO_codecvt *cv = fp->_codecvt;
670 int clen = (*cv->__codecvt_do_encoding) (cv);
672 if (!unflushed_writes)
674 if (clen > 0)
676 offset -= (wide_read_end - wide_read_ptr) * clen;
677 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
679 else
681 int nread;
683 size_t delta = wide_read_ptr - wide_read_base;
684 __mbstate_t state = fp->_wide_data->_IO_last_state;
685 nread = (*cv->__codecvt_do_length) (cv, &state,
686 fp->_IO_read_base,
687 fp->_IO_read_end, delta);
688 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
691 else
693 if (clen > 0)
694 offset += (fp->_wide_data->_IO_write_ptr
695 - fp->_wide_data->_IO_write_base) * clen;
696 else
698 size_t delta = (fp->_wide_data->_IO_write_ptr
699 - fp->_wide_data->_IO_write_base);
701 /* Allocate enough space for the conversion. */
702 size_t outsize = delta * sizeof (wchar_t);
703 char *out = malloc (outsize);
704 char *outstop = out;
705 const wchar_t *in = fp->_wide_data->_IO_write_base;
707 enum __codecvt_result status;
709 __mbstate_t state = fp->_wide_data->_IO_last_state;
710 status = (*cv->__codecvt_do_out) (cv, &state,
711 in, in + delta, &in,
712 out, out + outsize, &outstop);
714 /* We don't check for __codecvt_partial because it can be
715 returned on one of two conditions: either the output
716 buffer is full or the input sequence is incomplete. We
717 take care to allocate enough buffer and our input
718 sequences must be complete since they are accepted as
719 wchar_t; if not, then that is an error. */
720 if (__glibc_unlikely (status != __codecvt_ok))
722 free (out);
723 return WEOF;
726 offset += outstop - out;
727 free (out);
730 /* We don't trust _IO_read_end to represent the current file offset
731 when writing in append mode because the value would have to be
732 shifted to the end of the file during a flush. Use the write base
733 instead, along with the new offset we got above when we did a seek
734 to the end of the file. */
735 if (append_mode)
736 offset += fp->_IO_write_ptr - fp->_IO_write_base;
737 /* For all other modes, _IO_read_end represents the file offset. */
738 else
739 offset += fp->_IO_write_ptr - fp->_IO_read_end;
743 if (fp->_offset != _IO_pos_BAD)
744 result = fp->_offset;
745 else
746 result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
748 if (result == EOF)
749 return result;
751 result += offset;
753 if (result < 0)
755 __set_errno (EINVAL);
756 return EOF;
759 return result;
762 _IO_off64_t
763 _IO_wfile_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
765 _IO_off64_t result;
766 _IO_off64_t delta, new_offset;
767 long int count;
769 /* Short-circuit into a separate function. We don't want to mix any
770 functionality and we don't want to touch anything inside the FILE
771 object. */
772 if (mode == 0)
773 return do_ftell_wide (fp);
775 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
776 offset of the underlying file must be exact. */
777 int must_be_exact = ((fp->_wide_data->_IO_read_base
778 == fp->_wide_data->_IO_read_end)
779 && (fp->_wide_data->_IO_write_base
780 == fp->_wide_data->_IO_write_ptr));
782 bool was_writing = ((fp->_wide_data->_IO_write_ptr
783 > fp->_wide_data->_IO_write_base)
784 || _IO_in_put_mode (fp));
786 /* Flush unwritten characters.
787 (This may do an unneeded write if we seek within the buffer.
788 But to be able to switch to reading, we would need to set
789 egptr to pptr. That can't be done in the current design,
790 which assumes file_ptr() is eGptr. Anyway, since we probably
791 end up flushing when we close(), it doesn't make much difference.)
792 FIXME: simulate mem-mapped files. */
793 if (was_writing && _IO_switch_to_wget_mode (fp))
794 return WEOF;
796 if (fp->_wide_data->_IO_buf_base == NULL)
798 /* It could be that we already have a pushback buffer. */
799 if (fp->_wide_data->_IO_read_base != NULL)
801 free (fp->_wide_data->_IO_read_base);
802 fp->_flags &= ~_IO_IN_BACKUP;
804 _IO_doallocbuf (fp);
805 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
806 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
807 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
808 fp->_wide_data->_IO_buf_base);
809 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
810 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
813 switch (dir)
815 struct _IO_codecvt *cv;
816 int clen;
818 case _IO_seek_cur:
819 /* Adjust for read-ahead (bytes is buffer). To do this we must
820 find out which position in the external buffer corresponds to
821 the current position in the internal buffer. */
822 cv = fp->_codecvt;
823 clen = (*cv->__codecvt_do_encoding) (cv);
825 if (mode != 0 || !was_writing)
827 if (clen > 0)
829 offset -= (fp->_wide_data->_IO_read_end
830 - fp->_wide_data->_IO_read_ptr) * clen;
831 /* Adjust by readahead in external buffer. */
832 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
834 else
836 int nread;
838 delta = (fp->_wide_data->_IO_read_ptr
839 - fp->_wide_data->_IO_read_base);
840 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
841 nread = (*cv->__codecvt_do_length) (cv,
842 &fp->_wide_data->_IO_state,
843 fp->_IO_read_base,
844 fp->_IO_read_end, delta);
845 fp->_IO_read_ptr = fp->_IO_read_base + nread;
846 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
847 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
851 if (fp->_offset == _IO_pos_BAD)
852 goto dumb;
854 /* Make offset absolute, assuming current pointer is file_ptr(). */
855 offset += fp->_offset;
857 dir = _IO_seek_set;
858 break;
859 case _IO_seek_set:
860 break;
861 case _IO_seek_end:
863 struct stat64 st;
864 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
866 offset += st.st_size;
867 dir = _IO_seek_set;
869 else
870 goto dumb;
873 /* At this point, dir==_IO_seek_set. */
875 /* If destination is within current buffer, optimize: */
876 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
877 && !_IO_in_backup (fp))
879 _IO_off64_t start_offset = (fp->_offset
880 - (fp->_IO_read_end - fp->_IO_buf_base));
881 if (offset >= start_offset && offset < fp->_offset)
883 _IO_setg (fp, fp->_IO_buf_base,
884 fp->_IO_buf_base + (offset - start_offset),
885 fp->_IO_read_end);
886 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
887 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
888 fp->_wide_data->_IO_buf_base,
889 fp->_wide_data->_IO_buf_base);
890 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
891 fp->_wide_data->_IO_buf_base);
893 if (adjust_wide_data (fp, false))
894 goto dumb;
896 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
897 goto resync;
901 if (fp->_flags & _IO_NO_READS)
902 goto dumb;
904 /* Try to seek to a block boundary, to improve kernel page management. */
905 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
906 delta = offset - new_offset;
907 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
909 new_offset = offset;
910 delta = 0;
912 result = _IO_SYSSEEK (fp, new_offset, 0);
913 if (result < 0)
914 return EOF;
915 if (delta == 0)
916 count = 0;
917 else
919 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
920 (must_be_exact
921 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
922 if (count < delta)
924 /* We weren't allowed to read, but try to seek the remainder. */
925 offset = count == EOF ? delta : delta-count;
926 dir = _IO_seek_cur;
927 goto dumb;
930 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
931 fp->_IO_buf_base + count);
932 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
933 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
934 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
935 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
937 if (adjust_wide_data (fp, true))
938 goto dumb;
940 fp->_offset = result + count;
941 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
942 return offset;
943 dumb:
945 _IO_unsave_markers (fp);
946 result = _IO_SYSSEEK (fp, offset, dir);
947 if (result != EOF)
949 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
950 fp->_offset = result;
951 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
952 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
953 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
954 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
955 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
956 fp->_wide_data->_IO_buf_base);
958 return result;
960 resync:
961 /* We need to do it since it is possible that the file offset in
962 the kernel may be changed behind our back. It may happen when
963 we fopen a file and then do a fork. One process may access the
964 file and the kernel file offset will be changed. */
965 if (fp->_offset >= 0)
966 _IO_SYSSEEK (fp, fp->_offset, 0);
968 return offset;
970 libc_hidden_def (_IO_wfile_seekoff)
973 _IO_size_t
974 _IO_wfile_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
976 const wchar_t *s = (const wchar_t *) data;
977 _IO_size_t to_do = n;
978 int must_flush = 0;
979 _IO_size_t count;
981 if (n <= 0)
982 return 0;
983 /* This is an optimized implementation.
984 If the amount to be written straddles a block boundary
985 (or the filebuf is unbuffered), use sys_write directly. */
987 /* First figure out how much space is available in the buffer. */
988 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
989 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
991 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
992 if (count >= n)
994 const wchar_t *p;
995 for (p = s + n; p > s; )
997 if (*--p == L'\n')
999 count = p - s + 1;
1000 must_flush = 1;
1001 break;
1006 /* Then fill the buffer. */
1007 if (count > 0)
1009 if (count > to_do)
1010 count = to_do;
1011 if (count > 20)
1013 #ifdef _LIBC
1014 f->_wide_data->_IO_write_ptr =
1015 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
1016 #else
1017 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
1018 f->_wide_data->_IO_write_ptr += count;
1019 #endif
1020 s += count;
1022 else
1024 wchar_t *p = f->_wide_data->_IO_write_ptr;
1025 int i = (int) count;
1026 while (--i >= 0)
1027 *p++ = *s++;
1028 f->_wide_data->_IO_write_ptr = p;
1030 to_do -= count;
1032 if (to_do > 0)
1033 to_do -= _IO_wdefault_xsputn (f, s, to_do);
1034 if (must_flush
1035 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1036 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1037 f->_wide_data->_IO_write_ptr
1038 - f->_wide_data->_IO_write_base);
1040 return n - to_do;
1042 libc_hidden_def (_IO_wfile_xsputn)
1045 const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1047 JUMP_INIT_DUMMY,
1048 JUMP_INIT(finish, _IO_new_file_finish),
1049 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1050 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1051 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1052 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1053 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1054 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1055 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1056 JUMP_INIT(seekpos, _IO_default_seekpos),
1057 JUMP_INIT(setbuf, _IO_new_file_setbuf),
1058 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1059 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1060 JUMP_INIT(read, _IO_file_read),
1061 JUMP_INIT(write, _IO_new_file_write),
1062 JUMP_INIT(seek, _IO_file_seek),
1063 JUMP_INIT(close, _IO_file_close),
1064 JUMP_INIT(stat, _IO_file_stat),
1065 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1066 JUMP_INIT(imbue, _IO_default_imbue)
1068 libc_hidden_data_def (_IO_wfile_jumps)
1071 const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
1073 JUMP_INIT_DUMMY,
1074 JUMP_INIT(finish, _IO_new_file_finish),
1075 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1076 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
1077 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1078 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1079 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1080 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1081 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1082 JUMP_INIT(seekpos, _IO_default_seekpos),
1083 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1084 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1085 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1086 JUMP_INIT(read, _IO_file_read),
1087 JUMP_INIT(write, _IO_new_file_write),
1088 JUMP_INIT(seek, _IO_file_seek),
1089 JUMP_INIT(close, _IO_file_close_mmap),
1090 JUMP_INIT(stat, _IO_file_stat),
1091 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1092 JUMP_INIT(imbue, _IO_default_imbue)
1095 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1097 JUMP_INIT_DUMMY,
1098 JUMP_INIT(finish, _IO_new_file_finish),
1099 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1100 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1101 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1102 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1103 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1104 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1105 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1106 JUMP_INIT(seekpos, _IO_default_seekpos),
1107 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1108 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1109 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1110 JUMP_INIT(read, _IO_file_read),
1111 JUMP_INIT(write, _IO_new_file_write),
1112 JUMP_INIT(seek, _IO_file_seek),
1113 JUMP_INIT(close, _IO_file_close),
1114 JUMP_INIT(stat, _IO_file_stat),
1115 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1116 JUMP_INIT(imbue, _IO_default_imbue)