gmon: Remove internal_function attribute
[glibc.git] / libio / wfileops.c
blob8756b6fe1aa46f311ee8cc58c6edbf28a16049ce
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>
36 /* Convert TO_DO wide character from DATA to FP.
37 Then mark FP as having empty buffers. */
38 int
39 _IO_wdo_write (_IO_FILE *fp, const wchar_t *data, _IO_size_t to_do)
41 struct _IO_codecvt *cc = fp->_codecvt;
43 if (to_do > 0)
45 if (fp->_IO_write_end == fp->_IO_write_ptr
46 && fp->_IO_write_end != fp->_IO_write_base)
48 if (_IO_new_do_write (fp, fp->_IO_write_base,
49 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
50 return WEOF;
55 enum __codecvt_result result;
56 const wchar_t *new_data;
57 char mb_buf[MB_LEN_MAX];
58 char *write_base, *write_ptr, *buf_end;
60 if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf))
62 /* Make sure we have room for at least one multibyte
63 character. */
64 write_ptr = write_base = mb_buf;
65 buf_end = mb_buf + sizeof (mb_buf);
67 else
69 write_ptr = fp->_IO_write_ptr;
70 write_base = fp->_IO_write_base;
71 buf_end = fp->_IO_buf_end;
74 /* Now convert from the internal format into the external buffer. */
75 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
76 data, data + to_do, &new_data,
77 write_ptr,
78 buf_end,
79 &write_ptr);
81 /* Write out what we produced so far. */
82 if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
83 /* Something went wrong. */
84 return WEOF;
86 to_do -= new_data - data;
88 /* Next see whether we had problems during the conversion. If yes,
89 we cannot go on. */
90 if (result != __codecvt_ok
91 && (result != __codecvt_partial || new_data - data == 0))
92 break;
94 data = new_data;
96 while (to_do > 0);
99 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
100 fp->_wide_data->_IO_buf_base);
101 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
102 = fp->_wide_data->_IO_buf_base;
103 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
104 ? fp->_wide_data->_IO_buf_base
105 : fp->_wide_data->_IO_buf_end);
107 return to_do == 0 ? 0 : WEOF;
109 libc_hidden_def (_IO_wdo_write)
112 wint_t
113 _IO_wfile_underflow (_IO_FILE *fp)
115 struct _IO_codecvt *cd;
116 enum __codecvt_result status;
117 _IO_ssize_t count;
119 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
121 fp->_flags |= _IO_ERR_SEEN;
122 __set_errno (EBADF);
123 return WEOF;
125 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
126 return *fp->_wide_data->_IO_read_ptr;
128 cd = fp->_codecvt;
130 /* Maybe there is something left in the external buffer. */
131 if (fp->_IO_read_ptr < fp->_IO_read_end)
133 /* There is more in the external. Convert it. */
134 const char *read_stop = (const char *) fp->_IO_read_ptr;
136 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
137 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
138 fp->_wide_data->_IO_buf_base;
139 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
140 fp->_IO_read_ptr, fp->_IO_read_end,
141 &read_stop,
142 fp->_wide_data->_IO_read_ptr,
143 fp->_wide_data->_IO_buf_end,
144 &fp->_wide_data->_IO_read_end);
146 fp->_IO_read_base = fp->_IO_read_ptr;
147 fp->_IO_read_ptr = (char *) read_stop;
149 /* If we managed to generate some text return the next character. */
150 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
151 return *fp->_wide_data->_IO_read_ptr;
153 if (status == __codecvt_error)
155 __set_errno (EILSEQ);
156 fp->_flags |= _IO_ERR_SEEN;
157 return WEOF;
160 /* Move the remaining content of the read buffer to the beginning. */
161 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
162 fp->_IO_read_end - fp->_IO_read_ptr);
163 fp->_IO_read_end = (fp->_IO_buf_base
164 + (fp->_IO_read_end - fp->_IO_read_ptr));
165 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
167 else
168 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
169 fp->_IO_buf_base;
171 if (fp->_IO_buf_base == NULL)
173 /* Maybe we already have a push back pointer. */
174 if (fp->_IO_save_base != NULL)
176 free (fp->_IO_save_base);
177 fp->_flags &= ~_IO_IN_BACKUP;
179 _IO_doallocbuf (fp);
181 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
182 fp->_IO_buf_base;
185 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
186 fp->_IO_buf_base;
188 if (fp->_wide_data->_IO_buf_base == NULL)
190 /* Maybe we already have a push back pointer. */
191 if (fp->_wide_data->_IO_save_base != NULL)
193 free (fp->_wide_data->_IO_save_base);
194 fp->_flags &= ~_IO_IN_BACKUP;
196 _IO_wdoallocbuf (fp);
199 /* Flush all line buffered files before reading. */
200 /* FIXME This can/should be moved to genops ?? */
201 if (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
203 #if 0
204 _IO_flush_all_linebuffered ();
205 #else
206 /* We used to flush all line-buffered stream. This really isn't
207 required by any standard. My recollection is that
208 traditional Unix systems did this for stdout. stderr better
209 not be line buffered. So we do just that here
210 explicitly. --drepper */
211 _IO_acquire_lock (_IO_stdout);
213 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
214 == (_IO_LINKED | _IO_LINE_BUF))
215 _IO_OVERFLOW (_IO_stdout, EOF);
217 _IO_release_lock (_IO_stdout);
218 #endif
221 _IO_switch_to_get_mode (fp);
223 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
224 fp->_wide_data->_IO_buf_base;
225 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
226 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
227 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
229 const char *read_ptr_copy;
230 char accbuf[MB_LEN_MAX];
231 size_t naccbuf = 0;
232 again:
233 count = _IO_SYSREAD (fp, fp->_IO_read_end,
234 fp->_IO_buf_end - fp->_IO_read_end);
235 if (count <= 0)
237 if (count == 0 && naccbuf == 0)
239 fp->_flags |= _IO_EOF_SEEN;
240 fp->_offset = _IO_pos_BAD;
242 else
243 fp->_flags |= _IO_ERR_SEEN, count = 0;
245 fp->_IO_read_end += count;
246 if (count == 0)
248 if (naccbuf != 0)
249 /* There are some bytes in the external buffer but they don't
250 convert to anything. */
251 __set_errno (EILSEQ);
252 return WEOF;
254 if (fp->_offset != _IO_pos_BAD)
255 _IO_pos_adjust (fp->_offset, count);
257 /* Now convert the read input. */
258 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
259 fp->_IO_read_base = fp->_IO_read_ptr;
260 const char *from = fp->_IO_read_ptr;
261 const char *to = fp->_IO_read_end;
262 size_t to_copy = count;
263 if (__glibc_unlikely (naccbuf != 0))
265 to_copy = MIN (sizeof (accbuf) - naccbuf, count);
266 to = __mempcpy (&accbuf[naccbuf], from, to_copy);
267 naccbuf += to_copy;
268 from = accbuf;
270 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
271 from, to, &read_ptr_copy,
272 fp->_wide_data->_IO_read_end,
273 fp->_wide_data->_IO_buf_end,
274 &fp->_wide_data->_IO_read_end);
276 if (__glibc_unlikely (naccbuf != 0))
277 fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
278 else
279 fp->_IO_read_ptr = (char *) read_ptr_copy;
280 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
282 if (status == __codecvt_error)
284 out_eilseq:
285 __set_errno (EILSEQ);
286 fp->_flags |= _IO_ERR_SEEN;
287 return WEOF;
290 /* The read bytes make no complete character. Try reading again. */
291 assert (status == __codecvt_partial);
293 if (naccbuf == 0)
295 if (fp->_IO_read_base < fp->_IO_read_ptr)
297 /* Partially used the buffer for some input data that
298 produces no output. */
299 size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
300 memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
301 fp->_IO_read_ptr = fp->_IO_read_base;
302 fp->_IO_read_end -= avail;
303 goto again;
305 naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
306 if (naccbuf >= sizeof (accbuf))
307 goto out_eilseq;
309 memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
311 else
313 size_t used = read_ptr_copy - accbuf;
314 if (used > 0)
316 memmove (accbuf, read_ptr_copy, naccbuf - used);
317 naccbuf -= used;
320 if (naccbuf == sizeof (accbuf))
321 goto out_eilseq;
324 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
326 goto again;
329 return *fp->_wide_data->_IO_read_ptr;
331 libc_hidden_def (_IO_wfile_underflow)
334 static wint_t
335 _IO_wfile_underflow_mmap (_IO_FILE *fp)
337 struct _IO_codecvt *cd;
338 const char *read_stop;
340 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
342 fp->_flags |= _IO_ERR_SEEN;
343 __set_errno (EBADF);
344 return WEOF;
346 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
347 return *fp->_wide_data->_IO_read_ptr;
349 cd = fp->_codecvt;
351 /* Maybe there is something left in the external buffer. */
352 if (fp->_IO_read_ptr >= fp->_IO_read_end
353 /* No. But maybe the read buffer is not fully set up. */
354 && _IO_file_underflow_mmap (fp) == EOF)
355 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
356 flags as appropriate. */
357 return WEOF;
359 /* There is more in the external. Convert it. */
360 read_stop = (const char *) fp->_IO_read_ptr;
362 if (fp->_wide_data->_IO_buf_base == NULL)
364 /* Maybe we already have a push back pointer. */
365 if (fp->_wide_data->_IO_save_base != NULL)
367 free (fp->_wide_data->_IO_save_base);
368 fp->_flags &= ~_IO_IN_BACKUP;
370 _IO_wdoallocbuf (fp);
373 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
374 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
375 fp->_wide_data->_IO_buf_base;
376 (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
377 fp->_IO_read_ptr, fp->_IO_read_end,
378 &read_stop,
379 fp->_wide_data->_IO_read_ptr,
380 fp->_wide_data->_IO_buf_end,
381 &fp->_wide_data->_IO_read_end);
383 fp->_IO_read_ptr = (char *) read_stop;
385 /* If we managed to generate some text return the next character. */
386 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
387 return *fp->_wide_data->_IO_read_ptr;
389 /* There is some garbage at the end of the file. */
390 __set_errno (EILSEQ);
391 fp->_flags |= _IO_ERR_SEEN;
392 return WEOF;
395 static wint_t
396 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
398 /* This is the first read attempt. Doing the underflow will choose mmap
399 or vanilla operations and then punt to the chosen underflow routine.
400 Then we can punt to ours. */
401 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
402 return WEOF;
404 return _IO_WUNDERFLOW (fp);
408 wint_t
409 _IO_wfile_overflow (_IO_FILE *f, wint_t wch)
411 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
413 f->_flags |= _IO_ERR_SEEN;
414 __set_errno (EBADF);
415 return WEOF;
417 /* If currently reading or no buffer allocated. */
418 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
420 /* Allocate a buffer if needed. */
421 if (f->_wide_data->_IO_write_base == 0)
423 _IO_wdoallocbuf (f);
424 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
425 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
427 if (f->_IO_write_base == NULL)
429 _IO_doallocbuf (f);
430 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
433 else
435 /* Otherwise must be currently reading. If _IO_read_ptr
436 (and hence also _IO_read_end) is at the buffer end,
437 logically slide the buffer forwards one block (by setting
438 the read pointers to all point at the beginning of the
439 block). This makes room for subsequent output.
440 Otherwise, set the read pointers to _IO_read_end (leaving
441 that alone, so it can continue to correspond to the
442 external position). */
443 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
445 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
446 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
447 f->_wide_data->_IO_buf_base;
450 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
451 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
452 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
453 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
454 f->_wide_data->_IO_read_end;
456 f->_IO_write_ptr = f->_IO_read_ptr;
457 f->_IO_write_base = f->_IO_write_ptr;
458 f->_IO_write_end = f->_IO_buf_end;
459 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
461 f->_flags |= _IO_CURRENTLY_PUTTING;
462 if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
463 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
465 if (wch == WEOF)
466 return _IO_do_flush (f);
467 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
468 /* Buffer is really full */
469 if (_IO_do_flush (f) == EOF)
470 return WEOF;
471 *f->_wide_data->_IO_write_ptr++ = wch;
472 if ((f->_flags & _IO_UNBUFFERED)
473 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
474 if (_IO_do_flush (f) == EOF)
475 return WEOF;
476 return wch;
478 libc_hidden_def (_IO_wfile_overflow)
480 wint_t
481 _IO_wfile_sync (_IO_FILE *fp)
483 _IO_ssize_t delta;
484 wint_t retval = 0;
486 /* char* ptr = cur_ptr(); */
487 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
488 if (_IO_do_flush (fp))
489 return WEOF;
490 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
491 if (delta != 0)
493 /* We have to find out how many bytes we have to go back in the
494 external buffer. */
495 struct _IO_codecvt *cv = fp->_codecvt;
496 _IO_off64_t new_pos;
498 int clen = (*cv->__codecvt_do_encoding) (cv);
500 if (clen > 0)
501 /* It is easy, a fixed number of input bytes are used for each
502 wide character. */
503 delta *= clen;
504 else
506 /* We have to find out the hard way how much to back off.
507 To do this we determine how much input we needed to
508 generate the wide characters up to the current reading
509 position. */
510 int nread;
512 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
513 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
514 fp->_IO_read_base,
515 fp->_IO_read_end, delta);
516 fp->_IO_read_ptr = fp->_IO_read_base + nread;
517 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
520 new_pos = _IO_SYSSEEK (fp, delta, 1);
521 if (new_pos != (_IO_off64_t) EOF)
523 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
524 fp->_IO_read_end = fp->_IO_read_ptr;
526 else if (errno == ESPIPE)
527 ; /* Ignore error from unseekable devices. */
528 else
529 retval = WEOF;
531 if (retval != WEOF)
532 fp->_offset = _IO_pos_BAD;
533 /* FIXME: Cleanup - can this be shared? */
534 /* setg(base(), ptr, ptr); */
535 return retval;
537 libc_hidden_def (_IO_wfile_sync)
539 /* Adjust the internal buffer pointers to reflect the state in the external
540 buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
541 assumed to be converted and available in the range
542 fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
544 Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set. */
545 static int
546 adjust_wide_data (_IO_FILE *fp, bool do_convert)
548 struct _IO_codecvt *cv = fp->_codecvt;
550 int clen = (*cv->__codecvt_do_encoding) (cv);
552 /* Take the easy way out for constant length encodings if we don't need to
553 convert. */
554 if (!do_convert && clen > 0)
556 fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
557 / clen);
558 goto done;
561 enum __codecvt_result status;
562 const char *read_stop = (const char *) fp->_IO_read_base;
566 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
567 status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
568 fp->_IO_read_base, fp->_IO_read_ptr,
569 &read_stop,
570 fp->_wide_data->_IO_read_base,
571 fp->_wide_data->_IO_buf_end,
572 &fp->_wide_data->_IO_read_end);
574 /* Should we return EILSEQ? */
575 if (__glibc_unlikely (status == __codecvt_error))
577 fp->_flags |= _IO_ERR_SEEN;
578 return -1;
581 while (__builtin_expect (status == __codecvt_partial, 0));
583 done:
584 /* Now seek to _IO_read_end to behave as if we have read it all in. */
585 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
587 return 0;
590 /* ftell{,o} implementation for wide mode. Don't modify any state of the file
591 pointer while we try to get the current state of the stream except in one
592 case, which is when we have unflushed writes in append mode. */
593 static _IO_off64_t
594 do_ftell_wide (_IO_FILE *fp)
596 _IO_off64_t result, offset = 0;
598 /* No point looking for offsets in the buffer if it hasn't even been
599 allocated. */
600 if (fp->_wide_data->_IO_buf_base != NULL)
602 const wchar_t *wide_read_base;
603 const wchar_t *wide_read_ptr;
604 const wchar_t *wide_read_end;
605 bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
606 > fp->_wide_data->_IO_write_base);
608 bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
610 /* When we have unflushed writes in append mode, seek to the end of the
611 file and record that offset. This is the only time we change the file
612 stream state and it is safe since the file handle is active. */
613 if (unflushed_writes && append_mode)
615 result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
616 if (result == _IO_pos_BAD)
617 return EOF;
618 else
619 fp->_offset = result;
622 /* XXX For wide stream with backup store it is not very
623 reasonable to determine the offset. The pushed-back
624 character might require a state change and we need not be
625 able to compute the initial state by reverse transformation
626 since there is no guarantee of symmetry. So we don't even
627 try and return an error. */
628 if (_IO_in_backup (fp))
630 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
632 __set_errno (EINVAL);
633 return -1;
636 /* Nothing in the backup store, so note the backed up pointers
637 without changing the state. */
638 wide_read_base = fp->_wide_data->_IO_save_base;
639 wide_read_ptr = wide_read_base;
640 wide_read_end = fp->_wide_data->_IO_save_end;
642 else
644 wide_read_base = fp->_wide_data->_IO_read_base;
645 wide_read_ptr = fp->_wide_data->_IO_read_ptr;
646 wide_read_end = fp->_wide_data->_IO_read_end;
649 struct _IO_codecvt *cv = fp->_codecvt;
650 int clen = (*cv->__codecvt_do_encoding) (cv);
652 if (!unflushed_writes)
654 if (clen > 0)
656 offset -= (wide_read_end - wide_read_ptr) * clen;
657 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
659 else
661 int nread;
663 size_t delta = wide_read_ptr - wide_read_base;
664 __mbstate_t state = fp->_wide_data->_IO_last_state;
665 nread = (*cv->__codecvt_do_length) (cv, &state,
666 fp->_IO_read_base,
667 fp->_IO_read_end, delta);
668 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
671 else
673 if (clen > 0)
674 offset += (fp->_wide_data->_IO_write_ptr
675 - fp->_wide_data->_IO_write_base) * clen;
676 else
678 size_t delta = (fp->_wide_data->_IO_write_ptr
679 - fp->_wide_data->_IO_write_base);
681 /* Allocate enough space for the conversion. */
682 size_t outsize = delta * sizeof (wchar_t);
683 char *out = malloc (outsize);
684 char *outstop = out;
685 const wchar_t *in = fp->_wide_data->_IO_write_base;
687 enum __codecvt_result status;
689 __mbstate_t state = fp->_wide_data->_IO_last_state;
690 status = (*cv->__codecvt_do_out) (cv, &state,
691 in, in + delta, &in,
692 out, out + outsize, &outstop);
694 /* We don't check for __codecvt_partial because it can be
695 returned on one of two conditions: either the output
696 buffer is full or the input sequence is incomplete. We
697 take care to allocate enough buffer and our input
698 sequences must be complete since they are accepted as
699 wchar_t; if not, then that is an error. */
700 if (__glibc_unlikely (status != __codecvt_ok))
702 free (out);
703 return WEOF;
706 offset += outstop - out;
707 free (out);
710 /* We don't trust _IO_read_end to represent the current file offset
711 when writing in append mode because the value would have to be
712 shifted to the end of the file during a flush. Use the write base
713 instead, along with the new offset we got above when we did a seek
714 to the end of the file. */
715 if (append_mode)
716 offset += fp->_IO_write_ptr - fp->_IO_write_base;
717 /* For all other modes, _IO_read_end represents the file offset. */
718 else
719 offset += fp->_IO_write_ptr - fp->_IO_read_end;
723 if (fp->_offset != _IO_pos_BAD)
724 result = fp->_offset;
725 else
726 result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
728 if (result == EOF)
729 return result;
731 result += offset;
733 if (result < 0)
735 __set_errno (EINVAL);
736 return EOF;
739 return result;
742 _IO_off64_t
743 _IO_wfile_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
745 _IO_off64_t result;
746 _IO_off64_t delta, new_offset;
747 long int count;
749 /* Short-circuit into a separate function. We don't want to mix any
750 functionality and we don't want to touch anything inside the FILE
751 object. */
752 if (mode == 0)
753 return do_ftell_wide (fp);
755 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
756 offset of the underlying file must be exact. */
757 int must_be_exact = ((fp->_wide_data->_IO_read_base
758 == fp->_wide_data->_IO_read_end)
759 && (fp->_wide_data->_IO_write_base
760 == fp->_wide_data->_IO_write_ptr));
762 bool was_writing = ((fp->_wide_data->_IO_write_ptr
763 > fp->_wide_data->_IO_write_base)
764 || _IO_in_put_mode (fp));
766 /* Flush unwritten characters.
767 (This may do an unneeded write if we seek within the buffer.
768 But to be able to switch to reading, we would need to set
769 egptr to pptr. That can't be done in the current design,
770 which assumes file_ptr() is eGptr. Anyway, since we probably
771 end up flushing when we close(), it doesn't make much difference.)
772 FIXME: simulate mem-mapped files. */
773 if (was_writing && _IO_switch_to_wget_mode (fp))
774 return WEOF;
776 if (fp->_wide_data->_IO_buf_base == NULL)
778 /* It could be that we already have a pushback buffer. */
779 if (fp->_wide_data->_IO_read_base != NULL)
781 free (fp->_wide_data->_IO_read_base);
782 fp->_flags &= ~_IO_IN_BACKUP;
784 _IO_doallocbuf (fp);
785 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
786 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
787 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
788 fp->_wide_data->_IO_buf_base);
789 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
790 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
793 switch (dir)
795 struct _IO_codecvt *cv;
796 int clen;
798 case _IO_seek_cur:
799 /* Adjust for read-ahead (bytes is buffer). To do this we must
800 find out which position in the external buffer corresponds to
801 the current position in the internal buffer. */
802 cv = fp->_codecvt;
803 clen = (*cv->__codecvt_do_encoding) (cv);
805 if (mode != 0 || !was_writing)
807 if (clen > 0)
809 offset -= (fp->_wide_data->_IO_read_end
810 - fp->_wide_data->_IO_read_ptr) * clen;
811 /* Adjust by readahead in external buffer. */
812 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
814 else
816 int nread;
818 delta = (fp->_wide_data->_IO_read_ptr
819 - fp->_wide_data->_IO_read_base);
820 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
821 nread = (*cv->__codecvt_do_length) (cv,
822 &fp->_wide_data->_IO_state,
823 fp->_IO_read_base,
824 fp->_IO_read_end, delta);
825 fp->_IO_read_ptr = fp->_IO_read_base + nread;
826 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
827 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
831 if (fp->_offset == _IO_pos_BAD)
832 goto dumb;
834 /* Make offset absolute, assuming current pointer is file_ptr(). */
835 offset += fp->_offset;
837 dir = _IO_seek_set;
838 break;
839 case _IO_seek_set:
840 break;
841 case _IO_seek_end:
843 struct stat64 st;
844 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
846 offset += st.st_size;
847 dir = _IO_seek_set;
849 else
850 goto dumb;
853 /* At this point, dir==_IO_seek_set. */
855 /* If destination is within current buffer, optimize: */
856 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
857 && !_IO_in_backup (fp))
859 _IO_off64_t start_offset = (fp->_offset
860 - (fp->_IO_read_end - fp->_IO_buf_base));
861 if (offset >= start_offset && offset < fp->_offset)
863 _IO_setg (fp, fp->_IO_buf_base,
864 fp->_IO_buf_base + (offset - start_offset),
865 fp->_IO_read_end);
866 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
867 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
868 fp->_wide_data->_IO_buf_base,
869 fp->_wide_data->_IO_buf_base);
870 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
871 fp->_wide_data->_IO_buf_base);
873 if (adjust_wide_data (fp, false))
874 goto dumb;
876 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
877 goto resync;
881 if (fp->_flags & _IO_NO_READS)
882 goto dumb;
884 /* Try to seek to a block boundary, to improve kernel page management. */
885 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
886 delta = offset - new_offset;
887 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
889 new_offset = offset;
890 delta = 0;
892 result = _IO_SYSSEEK (fp, new_offset, 0);
893 if (result < 0)
894 return EOF;
895 if (delta == 0)
896 count = 0;
897 else
899 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
900 (must_be_exact
901 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
902 if (count < delta)
904 /* We weren't allowed to read, but try to seek the remainder. */
905 offset = count == EOF ? delta : delta-count;
906 dir = _IO_seek_cur;
907 goto dumb;
910 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
911 fp->_IO_buf_base + count);
912 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
913 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
914 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
915 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
917 if (adjust_wide_data (fp, true))
918 goto dumb;
920 fp->_offset = result + count;
921 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
922 return offset;
923 dumb:
925 _IO_unsave_markers (fp);
926 result = _IO_SYSSEEK (fp, offset, dir);
927 if (result != EOF)
929 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
930 fp->_offset = result;
931 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
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,
936 fp->_wide_data->_IO_buf_base);
938 return result;
940 resync:
941 /* We need to do it since it is possible that the file offset in
942 the kernel may be changed behind our back. It may happen when
943 we fopen a file and then do a fork. One process may access the
944 file and the kernel file offset will be changed. */
945 if (fp->_offset >= 0)
946 _IO_SYSSEEK (fp, fp->_offset, 0);
948 return offset;
950 libc_hidden_def (_IO_wfile_seekoff)
953 _IO_size_t
954 _IO_wfile_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
956 const wchar_t *s = (const wchar_t *) data;
957 _IO_size_t to_do = n;
958 int must_flush = 0;
959 _IO_size_t count;
961 if (n <= 0)
962 return 0;
963 /* This is an optimized implementation.
964 If the amount to be written straddles a block boundary
965 (or the filebuf is unbuffered), use sys_write directly. */
967 /* First figure out how much space is available in the buffer. */
968 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
969 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
971 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
972 if (count >= n)
974 const wchar_t *p;
975 for (p = s + n; p > s; )
977 if (*--p == L'\n')
979 count = p - s + 1;
980 must_flush = 1;
981 break;
986 /* Then fill the buffer. */
987 if (count > 0)
989 if (count > to_do)
990 count = to_do;
991 if (count > 20)
993 f->_wide_data->_IO_write_ptr =
994 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
995 s += count;
997 else
999 wchar_t *p = f->_wide_data->_IO_write_ptr;
1000 int i = (int) count;
1001 while (--i >= 0)
1002 *p++ = *s++;
1003 f->_wide_data->_IO_write_ptr = p;
1005 to_do -= count;
1007 if (to_do > 0)
1008 to_do -= _IO_wdefault_xsputn (f, s, to_do);
1009 if (must_flush
1010 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1011 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1012 f->_wide_data->_IO_write_ptr
1013 - f->_wide_data->_IO_write_base);
1015 return n - to_do;
1017 libc_hidden_def (_IO_wfile_xsputn)
1020 const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1022 JUMP_INIT_DUMMY,
1023 JUMP_INIT(finish, _IO_new_file_finish),
1024 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1025 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1026 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1027 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1028 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1029 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1030 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1031 JUMP_INIT(seekpos, _IO_default_seekpos),
1032 JUMP_INIT(setbuf, _IO_new_file_setbuf),
1033 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1034 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1035 JUMP_INIT(read, _IO_file_read),
1036 JUMP_INIT(write, _IO_new_file_write),
1037 JUMP_INIT(seek, _IO_file_seek),
1038 JUMP_INIT(close, _IO_file_close),
1039 JUMP_INIT(stat, _IO_file_stat),
1040 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1041 JUMP_INIT(imbue, _IO_default_imbue)
1043 libc_hidden_data_def (_IO_wfile_jumps)
1046 const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
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_mmap),
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_file_setbuf_mmap),
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_mmap),
1065 JUMP_INIT(stat, _IO_file_stat),
1066 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1067 JUMP_INIT(imbue, _IO_default_imbue)
1070 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1072 JUMP_INIT_DUMMY,
1073 JUMP_INIT(finish, _IO_new_file_finish),
1074 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1075 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1076 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1077 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1078 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1079 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1080 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1081 JUMP_INIT(seekpos, _IO_default_seekpos),
1082 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1083 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1084 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1085 JUMP_INIT(read, _IO_file_read),
1086 JUMP_INIT(write, _IO_new_file_write),
1087 JUMP_INIT(seek, _IO_file_seek),
1088 JUMP_INIT(close, _IO_file_close),
1089 JUMP_INIT(stat, _IO_file_stat),
1090 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1091 JUMP_INIT(imbue, _IO_default_imbue)