Collation order of @-. and space has changed in new iso14651_t1_common file, adapt...
[glibc.git] / libio / wfileops.c
blob1dbf72f7971c9625e37aee6908cea6455aab39a4
1 /* Copyright (C) 1993-2018 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 (FILE *fp, const wchar_t *data, 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 (FILE *fp)
115 struct _IO_codecvt *cd;
116 enum __codecvt_result status;
117 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 /* FIXME This can/should be moved to genops ?? */
200 if (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
202 /* We used to flush all line-buffered stream. This really isn't
203 required by any standard. My recollection is that
204 traditional Unix systems did this for stdout. stderr better
205 not be line buffered. So we do just that here
206 explicitly. --drepper */
207 _IO_acquire_lock (_IO_stdout);
209 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
210 == (_IO_LINKED | _IO_LINE_BUF))
211 _IO_OVERFLOW (_IO_stdout, EOF);
213 _IO_release_lock (_IO_stdout);
216 _IO_switch_to_get_mode (fp);
218 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
219 fp->_wide_data->_IO_buf_base;
220 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
221 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
222 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
224 const char *read_ptr_copy;
225 char accbuf[MB_LEN_MAX];
226 size_t naccbuf = 0;
227 again:
228 count = _IO_SYSREAD (fp, fp->_IO_read_end,
229 fp->_IO_buf_end - fp->_IO_read_end);
230 if (count <= 0)
232 if (count == 0 && naccbuf == 0)
234 fp->_flags |= _IO_EOF_SEEN;
235 fp->_offset = _IO_pos_BAD;
237 else
238 fp->_flags |= _IO_ERR_SEEN, count = 0;
240 fp->_IO_read_end += count;
241 if (count == 0)
243 if (naccbuf != 0)
244 /* There are some bytes in the external buffer but they don't
245 convert to anything. */
246 __set_errno (EILSEQ);
247 return WEOF;
249 if (fp->_offset != _IO_pos_BAD)
250 _IO_pos_adjust (fp->_offset, count);
252 /* Now convert the read input. */
253 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
254 fp->_IO_read_base = fp->_IO_read_ptr;
255 const char *from = fp->_IO_read_ptr;
256 const char *to = fp->_IO_read_end;
257 size_t to_copy = count;
258 if (__glibc_unlikely (naccbuf != 0))
260 to_copy = MIN (sizeof (accbuf) - naccbuf, count);
261 to = __mempcpy (&accbuf[naccbuf], from, to_copy);
262 naccbuf += to_copy;
263 from = accbuf;
265 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
266 from, to, &read_ptr_copy,
267 fp->_wide_data->_IO_read_end,
268 fp->_wide_data->_IO_buf_end,
269 &fp->_wide_data->_IO_read_end);
271 if (__glibc_unlikely (naccbuf != 0))
272 fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
273 else
274 fp->_IO_read_ptr = (char *) read_ptr_copy;
275 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
277 if (status == __codecvt_error)
279 out_eilseq:
280 __set_errno (EILSEQ);
281 fp->_flags |= _IO_ERR_SEEN;
282 return WEOF;
285 /* The read bytes make no complete character. Try reading again. */
286 assert (status == __codecvt_partial);
288 if (naccbuf == 0)
290 if (fp->_IO_read_base < fp->_IO_read_ptr)
292 /* Partially used the buffer for some input data that
293 produces no output. */
294 size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
295 memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
296 fp->_IO_read_ptr = fp->_IO_read_base;
297 fp->_IO_read_end -= avail;
298 goto again;
300 naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
301 if (naccbuf >= sizeof (accbuf))
302 goto out_eilseq;
304 memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
306 else
308 size_t used = read_ptr_copy - accbuf;
309 if (used > 0)
311 memmove (accbuf, read_ptr_copy, naccbuf - used);
312 naccbuf -= used;
315 if (naccbuf == sizeof (accbuf))
316 goto out_eilseq;
319 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
321 goto again;
324 return *fp->_wide_data->_IO_read_ptr;
326 libc_hidden_def (_IO_wfile_underflow)
329 static wint_t
330 _IO_wfile_underflow_mmap (FILE *fp)
332 struct _IO_codecvt *cd;
333 const char *read_stop;
335 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
337 fp->_flags |= _IO_ERR_SEEN;
338 __set_errno (EBADF);
339 return WEOF;
341 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
342 return *fp->_wide_data->_IO_read_ptr;
344 cd = fp->_codecvt;
346 /* Maybe there is something left in the external buffer. */
347 if (fp->_IO_read_ptr >= fp->_IO_read_end
348 /* No. But maybe the read buffer is not fully set up. */
349 && _IO_file_underflow_mmap (fp) == EOF)
350 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
351 flags as appropriate. */
352 return WEOF;
354 /* There is more in the external. Convert it. */
355 read_stop = (const char *) fp->_IO_read_ptr;
357 if (fp->_wide_data->_IO_buf_base == NULL)
359 /* Maybe we already have a push back pointer. */
360 if (fp->_wide_data->_IO_save_base != NULL)
362 free (fp->_wide_data->_IO_save_base);
363 fp->_flags &= ~_IO_IN_BACKUP;
365 _IO_wdoallocbuf (fp);
368 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
369 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
370 fp->_wide_data->_IO_buf_base;
371 (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
372 fp->_IO_read_ptr, fp->_IO_read_end,
373 &read_stop,
374 fp->_wide_data->_IO_read_ptr,
375 fp->_wide_data->_IO_buf_end,
376 &fp->_wide_data->_IO_read_end);
378 fp->_IO_read_ptr = (char *) read_stop;
380 /* If we managed to generate some text return the next character. */
381 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
382 return *fp->_wide_data->_IO_read_ptr;
384 /* There is some garbage at the end of the file. */
385 __set_errno (EILSEQ);
386 fp->_flags |= _IO_ERR_SEEN;
387 return WEOF;
390 static wint_t
391 _IO_wfile_underflow_maybe_mmap (FILE *fp)
393 /* This is the first read attempt. Doing the underflow will choose mmap
394 or vanilla operations and then punt to the chosen underflow routine.
395 Then we can punt to ours. */
396 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
397 return WEOF;
399 return _IO_WUNDERFLOW (fp);
403 wint_t
404 _IO_wfile_overflow (FILE *f, wint_t wch)
406 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
408 f->_flags |= _IO_ERR_SEEN;
409 __set_errno (EBADF);
410 return WEOF;
412 /* If currently reading or no buffer allocated. */
413 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
415 /* Allocate a buffer if needed. */
416 if (f->_wide_data->_IO_write_base == 0)
418 _IO_wdoallocbuf (f);
419 _IO_free_wbackup_area (f);
420 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
421 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
423 if (f->_IO_write_base == NULL)
425 _IO_doallocbuf (f);
426 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
429 else
431 /* Otherwise must be currently reading. If _IO_read_ptr
432 (and hence also _IO_read_end) is at the buffer end,
433 logically slide the buffer forwards one block (by setting
434 the read pointers to all point at the beginning of the
435 block). This makes room for subsequent output.
436 Otherwise, set the read pointers to _IO_read_end (leaving
437 that alone, so it can continue to correspond to the
438 external position). */
439 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
441 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
442 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
443 f->_wide_data->_IO_buf_base;
446 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
447 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
448 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
449 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
450 f->_wide_data->_IO_read_end;
452 f->_IO_write_ptr = f->_IO_read_ptr;
453 f->_IO_write_base = f->_IO_write_ptr;
454 f->_IO_write_end = f->_IO_buf_end;
455 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
457 f->_flags |= _IO_CURRENTLY_PUTTING;
458 if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
459 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
461 if (wch == WEOF)
462 return _IO_do_flush (f);
463 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
464 /* Buffer is really full */
465 if (_IO_do_flush (f) == EOF)
466 return WEOF;
467 *f->_wide_data->_IO_write_ptr++ = wch;
468 if ((f->_flags & _IO_UNBUFFERED)
469 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
470 if (_IO_do_flush (f) == EOF)
471 return WEOF;
472 return wch;
474 libc_hidden_def (_IO_wfile_overflow)
476 wint_t
477 _IO_wfile_sync (FILE *fp)
479 ssize_t delta;
480 wint_t retval = 0;
482 /* char* ptr = cur_ptr(); */
483 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
484 if (_IO_do_flush (fp))
485 return WEOF;
486 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
487 if (delta != 0)
489 /* We have to find out how many bytes we have to go back in the
490 external buffer. */
491 struct _IO_codecvt *cv = fp->_codecvt;
492 off64_t new_pos;
494 int clen = (*cv->__codecvt_do_encoding) (cv);
496 if (clen > 0)
497 /* It is easy, a fixed number of input bytes are used for each
498 wide character. */
499 delta *= clen;
500 else
502 /* We have to find out the hard way how much to back off.
503 To do this we determine how much input we needed to
504 generate the wide characters up to the current reading
505 position. */
506 int nread;
508 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
509 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
510 fp->_IO_read_base,
511 fp->_IO_read_end, delta);
512 fp->_IO_read_ptr = fp->_IO_read_base + nread;
513 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
516 new_pos = _IO_SYSSEEK (fp, delta, 1);
517 if (new_pos != (off64_t) EOF)
519 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
520 fp->_IO_read_end = fp->_IO_read_ptr;
522 else if (errno == ESPIPE)
523 ; /* Ignore error from unseekable devices. */
524 else
525 retval = WEOF;
527 if (retval != WEOF)
528 fp->_offset = _IO_pos_BAD;
529 /* FIXME: Cleanup - can this be shared? */
530 /* setg(base(), ptr, ptr); */
531 return retval;
533 libc_hidden_def (_IO_wfile_sync)
535 /* Adjust the internal buffer pointers to reflect the state in the external
536 buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
537 assumed to be converted and available in the range
538 fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
540 Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set. */
541 static int
542 adjust_wide_data (FILE *fp, bool do_convert)
544 struct _IO_codecvt *cv = fp->_codecvt;
546 int clen = (*cv->__codecvt_do_encoding) (cv);
548 /* Take the easy way out for constant length encodings if we don't need to
549 convert. */
550 if (!do_convert && clen > 0)
552 fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
553 / clen);
554 goto done;
557 enum __codecvt_result status;
558 const char *read_stop = (const char *) fp->_IO_read_base;
562 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
563 status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
564 fp->_IO_read_base, fp->_IO_read_ptr,
565 &read_stop,
566 fp->_wide_data->_IO_read_base,
567 fp->_wide_data->_IO_buf_end,
568 &fp->_wide_data->_IO_read_end);
570 /* Should we return EILSEQ? */
571 if (__glibc_unlikely (status == __codecvt_error))
573 fp->_flags |= _IO_ERR_SEEN;
574 return -1;
577 while (__builtin_expect (status == __codecvt_partial, 0));
579 done:
580 /* Now seek to _IO_read_end to behave as if we have read it all in. */
581 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
583 return 0;
586 /* ftell{,o} implementation for wide mode. Don't modify any state of the file
587 pointer while we try to get the current state of the stream except in one
588 case, which is when we have unflushed writes in append mode. */
589 static off64_t
590 do_ftell_wide (FILE *fp)
592 off64_t result, offset = 0;
594 /* No point looking for offsets in the buffer if it hasn't even been
595 allocated. */
596 if (fp->_wide_data->_IO_buf_base != NULL)
598 const wchar_t *wide_read_base;
599 const wchar_t *wide_read_ptr;
600 const wchar_t *wide_read_end;
601 bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
602 > fp->_wide_data->_IO_write_base);
604 bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
606 /* When we have unflushed writes in append mode, seek to the end of the
607 file and record that offset. This is the only time we change the file
608 stream state and it is safe since the file handle is active. */
609 if (unflushed_writes && append_mode)
611 result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
612 if (result == _IO_pos_BAD)
613 return EOF;
614 else
615 fp->_offset = result;
618 /* XXX For wide stream with backup store it is not very
619 reasonable to determine the offset. The pushed-back
620 character might require a state change and we need not be
621 able to compute the initial state by reverse transformation
622 since there is no guarantee of symmetry. So we don't even
623 try and return an error. */
624 if (_IO_in_backup (fp))
626 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
628 __set_errno (EINVAL);
629 return -1;
632 /* Nothing in the backup store, so note the backed up pointers
633 without changing the state. */
634 wide_read_base = fp->_wide_data->_IO_save_base;
635 wide_read_ptr = wide_read_base;
636 wide_read_end = fp->_wide_data->_IO_save_end;
638 else
640 wide_read_base = fp->_wide_data->_IO_read_base;
641 wide_read_ptr = fp->_wide_data->_IO_read_ptr;
642 wide_read_end = fp->_wide_data->_IO_read_end;
645 struct _IO_codecvt *cv = fp->_codecvt;
646 int clen = (*cv->__codecvt_do_encoding) (cv);
648 if (!unflushed_writes)
650 if (clen > 0)
652 offset -= (wide_read_end - wide_read_ptr) * clen;
653 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
655 else
657 int nread;
659 size_t delta = wide_read_ptr - wide_read_base;
660 __mbstate_t state = fp->_wide_data->_IO_last_state;
661 nread = (*cv->__codecvt_do_length) (cv, &state,
662 fp->_IO_read_base,
663 fp->_IO_read_end, delta);
664 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
667 else
669 if (clen > 0)
670 offset += (fp->_wide_data->_IO_write_ptr
671 - fp->_wide_data->_IO_write_base) * clen;
672 else
674 size_t delta = (fp->_wide_data->_IO_write_ptr
675 - fp->_wide_data->_IO_write_base);
677 /* Allocate enough space for the conversion. */
678 size_t outsize = delta * sizeof (wchar_t);
679 char *out = malloc (outsize);
680 char *outstop = out;
681 const wchar_t *in = fp->_wide_data->_IO_write_base;
683 enum __codecvt_result status;
685 __mbstate_t state = fp->_wide_data->_IO_last_state;
686 status = (*cv->__codecvt_do_out) (cv, &state,
687 in, in + delta, &in,
688 out, out + outsize, &outstop);
690 /* We don't check for __codecvt_partial because it can be
691 returned on one of two conditions: either the output
692 buffer is full or the input sequence is incomplete. We
693 take care to allocate enough buffer and our input
694 sequences must be complete since they are accepted as
695 wchar_t; if not, then that is an error. */
696 if (__glibc_unlikely (status != __codecvt_ok))
698 free (out);
699 return WEOF;
702 offset += outstop - out;
703 free (out);
706 /* We don't trust _IO_read_end to represent the current file offset
707 when writing in append mode because the value would have to be
708 shifted to the end of the file during a flush. Use the write base
709 instead, along with the new offset we got above when we did a seek
710 to the end of the file. */
711 if (append_mode)
712 offset += fp->_IO_write_ptr - fp->_IO_write_base;
713 /* For all other modes, _IO_read_end represents the file offset. */
714 else
715 offset += fp->_IO_write_ptr - fp->_IO_read_end;
719 if (fp->_offset != _IO_pos_BAD)
720 result = fp->_offset;
721 else
722 result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
724 if (result == EOF)
725 return result;
727 result += offset;
729 if (result < 0)
731 __set_errno (EINVAL);
732 return EOF;
735 return result;
738 off64_t
739 _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
741 off64_t result;
742 off64_t delta, new_offset;
743 long int count;
745 /* Short-circuit into a separate function. We don't want to mix any
746 functionality and we don't want to touch anything inside the FILE
747 object. */
748 if (mode == 0)
749 return do_ftell_wide (fp);
751 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
752 offset of the underlying file must be exact. */
753 int must_be_exact = ((fp->_wide_data->_IO_read_base
754 == fp->_wide_data->_IO_read_end)
755 && (fp->_wide_data->_IO_write_base
756 == fp->_wide_data->_IO_write_ptr));
758 bool was_writing = ((fp->_wide_data->_IO_write_ptr
759 > fp->_wide_data->_IO_write_base)
760 || _IO_in_put_mode (fp));
762 /* Flush unwritten characters.
763 (This may do an unneeded write if we seek within the buffer.
764 But to be able to switch to reading, we would need to set
765 egptr to pptr. That can't be done in the current design,
766 which assumes file_ptr() is eGptr. Anyway, since we probably
767 end up flushing when we close(), it doesn't make much difference.)
768 FIXME: simulate mem-mapped files. */
769 if (was_writing && _IO_switch_to_wget_mode (fp))
770 return WEOF;
772 if (fp->_wide_data->_IO_buf_base == NULL)
774 /* It could be that we already have a pushback buffer. */
775 if (fp->_wide_data->_IO_read_base != NULL)
777 free (fp->_wide_data->_IO_read_base);
778 fp->_flags &= ~_IO_IN_BACKUP;
780 _IO_doallocbuf (fp);
781 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
782 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
783 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
784 fp->_wide_data->_IO_buf_base);
785 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
786 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
789 switch (dir)
791 struct _IO_codecvt *cv;
792 int clen;
794 case _IO_seek_cur:
795 /* Adjust for read-ahead (bytes is buffer). To do this we must
796 find out which position in the external buffer corresponds to
797 the current position in the internal buffer. */
798 cv = fp->_codecvt;
799 clen = (*cv->__codecvt_do_encoding) (cv);
801 if (mode != 0 || !was_writing)
803 if (clen > 0)
805 offset -= (fp->_wide_data->_IO_read_end
806 - fp->_wide_data->_IO_read_ptr) * clen;
807 /* Adjust by readahead in external buffer. */
808 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
810 else
812 int nread;
814 delta = (fp->_wide_data->_IO_read_ptr
815 - fp->_wide_data->_IO_read_base);
816 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
817 nread = (*cv->__codecvt_do_length) (cv,
818 &fp->_wide_data->_IO_state,
819 fp->_IO_read_base,
820 fp->_IO_read_end, delta);
821 fp->_IO_read_ptr = fp->_IO_read_base + nread;
822 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
823 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
827 if (fp->_offset == _IO_pos_BAD)
828 goto dumb;
830 /* Make offset absolute, assuming current pointer is file_ptr(). */
831 offset += fp->_offset;
833 dir = _IO_seek_set;
834 break;
835 case _IO_seek_set:
836 break;
837 case _IO_seek_end:
839 struct stat64 st;
840 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
842 offset += st.st_size;
843 dir = _IO_seek_set;
845 else
846 goto dumb;
850 _IO_free_wbackup_area (fp);
852 /* At this point, dir==_IO_seek_set. */
854 /* If destination is within current buffer, optimize: */
855 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
856 && !_IO_in_backup (fp))
858 off64_t start_offset = (fp->_offset
859 - (fp->_IO_read_end - fp->_IO_buf_base));
860 if (offset >= start_offset && offset < fp->_offset)
862 _IO_setg (fp, fp->_IO_buf_base,
863 fp->_IO_buf_base + (offset - start_offset),
864 fp->_IO_read_end);
865 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
866 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
867 fp->_wide_data->_IO_buf_base,
868 fp->_wide_data->_IO_buf_base);
869 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
870 fp->_wide_data->_IO_buf_base);
872 if (adjust_wide_data (fp, false))
873 goto dumb;
875 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
876 goto resync;
880 if (fp->_flags & _IO_NO_READS)
881 goto dumb;
883 /* Try to seek to a block boundary, to improve kernel page management. */
884 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
885 delta = offset - new_offset;
886 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
888 new_offset = offset;
889 delta = 0;
891 result = _IO_SYSSEEK (fp, new_offset, 0);
892 if (result < 0)
893 return EOF;
894 if (delta == 0)
895 count = 0;
896 else
898 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
899 (must_be_exact
900 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
901 if (count < delta)
903 /* We weren't allowed to read, but try to seek the remainder. */
904 offset = count == EOF ? delta : delta-count;
905 dir = _IO_seek_cur;
906 goto dumb;
909 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
910 fp->_IO_buf_base + count);
911 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
912 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
913 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
914 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
916 if (adjust_wide_data (fp, true))
917 goto dumb;
919 fp->_offset = result + count;
920 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
921 return offset;
922 dumb:
924 _IO_unsave_markers (fp);
925 result = _IO_SYSSEEK (fp, offset, dir);
926 if (result != EOF)
928 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
929 fp->_offset = result;
930 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
931 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
932 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
933 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
934 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
935 fp->_wide_data->_IO_buf_base);
937 return result;
939 resync:
940 /* We need to do it since it is possible that the file offset in
941 the kernel may be changed behind our back. It may happen when
942 we fopen a file and then do a fork. One process may access the
943 file and the kernel file offset will be changed. */
944 if (fp->_offset >= 0)
945 _IO_SYSSEEK (fp, fp->_offset, 0);
947 return offset;
949 libc_hidden_def (_IO_wfile_seekoff)
952 size_t
953 _IO_wfile_xsputn (FILE *f, const void *data, size_t n)
955 const wchar_t *s = (const wchar_t *) data;
956 size_t to_do = n;
957 int must_flush = 0;
958 size_t count;
960 if (n <= 0)
961 return 0;
962 /* This is an optimized implementation.
963 If the amount to be written straddles a block boundary
964 (or the filebuf is unbuffered), use sys_write directly. */
966 /* First figure out how much space is available in the buffer. */
967 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
968 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
970 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
971 if (count >= n)
973 const wchar_t *p;
974 for (p = s + n; p > s; )
976 if (*--p == L'\n')
978 count = p - s + 1;
979 must_flush = 1;
980 break;
985 /* Then fill the buffer. */
986 if (count > 0)
988 if (count > to_do)
989 count = to_do;
990 if (count > 20)
992 f->_wide_data->_IO_write_ptr =
993 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
994 s += count;
996 else
998 wchar_t *p = f->_wide_data->_IO_write_ptr;
999 int i = (int) count;
1000 while (--i >= 0)
1001 *p++ = *s++;
1002 f->_wide_data->_IO_write_ptr = p;
1004 to_do -= count;
1006 if (to_do > 0)
1007 to_do -= _IO_wdefault_xsputn (f, s, to_do);
1008 if (must_flush
1009 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1010 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1011 f->_wide_data->_IO_write_ptr
1012 - f->_wide_data->_IO_write_base);
1014 return n - to_do;
1016 libc_hidden_def (_IO_wfile_xsputn)
1019 const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1021 JUMP_INIT_DUMMY,
1022 JUMP_INIT(finish, _IO_new_file_finish),
1023 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1024 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1025 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1026 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1027 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1028 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1029 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1030 JUMP_INIT(seekpos, _IO_default_seekpos),
1031 JUMP_INIT(setbuf, _IO_new_file_setbuf),
1032 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1033 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1034 JUMP_INIT(read, _IO_file_read),
1035 JUMP_INIT(write, _IO_new_file_write),
1036 JUMP_INIT(seek, _IO_file_seek),
1037 JUMP_INIT(close, _IO_file_close),
1038 JUMP_INIT(stat, _IO_file_stat),
1039 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1040 JUMP_INIT(imbue, _IO_default_imbue)
1042 libc_hidden_data_def (_IO_wfile_jumps)
1045 const struct _IO_jump_t _IO_wfile_jumps_mmap 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_mmap),
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_file_setbuf_mmap),
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_mmap),
1064 JUMP_INIT(stat, _IO_file_stat),
1065 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1066 JUMP_INIT(imbue, _IO_default_imbue)
1069 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1071 JUMP_INIT_DUMMY,
1072 JUMP_INIT(finish, _IO_new_file_finish),
1073 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1074 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1075 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1076 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1077 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1078 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1079 JUMP_INIT(seekoff, _IO_wfile_seekoff),
1080 JUMP_INIT(seekpos, _IO_default_seekpos),
1081 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1082 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1083 JUMP_INIT(doallocate, _IO_wfile_doallocate),
1084 JUMP_INIT(read, _IO_file_read),
1085 JUMP_INIT(write, _IO_new_file_write),
1086 JUMP_INIT(seek, _IO_file_seek),
1087 JUMP_INIT(close, _IO_file_close),
1088 JUMP_INIT(stat, _IO_file_stat),
1089 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1090 JUMP_INIT(imbue, _IO_default_imbue)