2.9
[glibc/nacl-glibc.git] / libio / wfileops.c
blobb930aad067523df6e0bc21b922970a615a9499a7
1 /* Copyright (C) 1993,1995,1997-2003,2004, 2006 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, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 As a special exception, if you link the code in this file with
22 files compiled with a GNU compiler to produce an executable,
23 that does not cause the resulting executable to be covered by
24 the GNU Lesser General Public License. This exception does not
25 however invalidate any other reasons why the executable file
26 might be covered by the GNU Lesser General Public License.
27 This exception applies to code released by its copyright holders
28 in files containing the exception. */
30 #include <assert.h>
31 #include <libioP.h>
32 #include <wchar.h>
33 #include <gconv.h>
34 #include <stdlib.h>
35 #include <string.h>
38 #ifndef _LIBC
39 # define _IO_new_do_write _IO_do_write
40 # define _IO_new_file_attach _IO_file_attach
41 # define _IO_new_file_close_it _IO_file_close_it
42 # define _IO_new_file_finish _IO_file_finish
43 # define _IO_new_file_fopen _IO_file_fopen
44 # define _IO_new_file_init _IO_file_init
45 # define _IO_new_file_setbuf _IO_file_setbuf
46 # define _IO_new_file_sync _IO_file_sync
47 # define _IO_new_file_overflow _IO_file_overflow
48 # define _IO_new_file_seekoff _IO_file_seekoff
49 # define _IO_new_file_underflow _IO_file_underflow
50 # define _IO_new_file_write _IO_file_write
51 # define _IO_new_file_xsputn _IO_file_xsputn
52 #endif
55 /* Convert TO_DO wide character from DATA to FP.
56 Then mark FP as having empty buffers. */
57 int
58 _IO_wdo_write (fp, data, to_do)
59 _IO_FILE *fp;
60 const wchar_t *data;
61 _IO_size_t to_do;
63 struct _IO_codecvt *cc = fp->_codecvt;
65 if (to_do > 0)
67 if (fp->_IO_write_end == fp->_IO_write_ptr
68 && fp->_IO_write_end != fp->_IO_write_base)
70 if (_IO_new_do_write (fp, fp->_IO_write_base,
71 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
72 return WEOF;
77 enum __codecvt_result result;
78 const wchar_t *new_data;
80 /* Now convert from the internal format into the external buffer. */
81 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
82 data, data + to_do, &new_data,
83 fp->_IO_write_ptr,
84 fp->_IO_buf_end,
85 &fp->_IO_write_ptr);
87 /* Write out what we produced so far. */
88 if (_IO_new_do_write (fp, fp->_IO_write_base,
89 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
90 /* Something went wrong. */
91 return WEOF;
93 to_do -= new_data - data;
95 /* Next see whether we had problems during the conversion. If yes,
96 we cannot go on. */
97 if (result != __codecvt_ok
98 && (result != __codecvt_partial || new_data - data == 0))
99 break;
101 data = new_data;
103 while (to_do > 0);
106 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
107 fp->_wide_data->_IO_buf_base);
108 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
109 = fp->_wide_data->_IO_buf_base;
110 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
111 ? fp->_wide_data->_IO_buf_base
112 : fp->_wide_data->_IO_buf_end);
114 return to_do == 0 ? 0 : WEOF;
116 INTDEF(_IO_wdo_write)
119 wint_t
120 _IO_wfile_underflow (fp)
121 _IO_FILE *fp;
123 struct _IO_codecvt *cd;
124 enum __codecvt_result status;
125 _IO_ssize_t count;
126 int tries;
127 const char *read_ptr_copy;
129 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
131 fp->_flags |= _IO_ERR_SEEN;
132 __set_errno (EBADF);
133 return WEOF;
135 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
136 return *fp->_wide_data->_IO_read_ptr;
138 cd = fp->_codecvt;
140 /* Maybe there is something left in the external buffer. */
141 if (fp->_IO_read_ptr < fp->_IO_read_end)
143 /* There is more in the external. Convert it. */
144 const char *read_stop = (const char *) fp->_IO_read_ptr;
146 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
147 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
148 fp->_wide_data->_IO_buf_base;
149 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
150 fp->_IO_read_ptr, fp->_IO_read_end,
151 &read_stop,
152 fp->_wide_data->_IO_read_ptr,
153 fp->_wide_data->_IO_buf_end,
154 &fp->_wide_data->_IO_read_end);
156 fp->_IO_read_base = fp->_IO_read_ptr;
157 fp->_IO_read_ptr = (char *) read_stop;
159 /* If we managed to generate some text return the next character. */
160 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
161 return *fp->_wide_data->_IO_read_ptr;
163 if (status == __codecvt_error)
165 __set_errno (EILSEQ);
166 fp->_flags |= _IO_ERR_SEEN;
167 return WEOF;
170 /* Move the remaining content of the read buffer to the beginning. */
171 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
172 fp->_IO_read_end - fp->_IO_read_ptr);
173 fp->_IO_read_end = (fp->_IO_buf_base
174 + (fp->_IO_read_end - fp->_IO_read_ptr));
175 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
177 else
178 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
179 fp->_IO_buf_base;
181 if (fp->_IO_buf_base == NULL)
183 /* Maybe we already have a push back pointer. */
184 if (fp->_IO_save_base != NULL)
186 free (fp->_IO_save_base);
187 fp->_flags &= ~_IO_IN_BACKUP;
189 INTUSE(_IO_doallocbuf) (fp);
191 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
192 fp->_IO_buf_base;
195 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
196 fp->_IO_buf_base;
198 if (fp->_wide_data->_IO_buf_base == NULL)
200 /* Maybe we already have a push back pointer. */
201 if (fp->_wide_data->_IO_save_base != NULL)
203 free (fp->_wide_data->_IO_save_base);
204 fp->_flags &= ~_IO_IN_BACKUP;
206 INTUSE(_IO_wdoallocbuf) (fp);
209 /* Flush all line buffered files before reading. */
210 /* FIXME This can/should be moved to genops ?? */
211 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
213 #if 0
214 INTUSE(_IO_flush_all_linebuffered) ();
215 #else
216 /* We used to flush all line-buffered stream. This really isn't
217 required by any standard. My recollection is that
218 traditional Unix systems did this for stdout. stderr better
219 not be line buffered. So we do just that here
220 explicitly. --drepper */
221 _IO_acquire_lock (_IO_stdout);
223 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
224 == (_IO_LINKED | _IO_LINE_BUF))
225 _IO_OVERFLOW (_IO_stdout, EOF);
227 _IO_release_lock (_IO_stdout);
228 #endif
231 INTUSE(_IO_switch_to_get_mode) (fp);
233 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
234 fp->_wide_data->_IO_buf_base;
235 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
236 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
237 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
239 tries = 0;
240 again:
241 count = _IO_SYSREAD (fp, fp->_IO_read_end,
242 fp->_IO_buf_end - fp->_IO_read_end);
243 if (count <= 0)
245 if (count == 0 && tries == 0)
246 fp->_flags |= _IO_EOF_SEEN;
247 else
248 fp->_flags |= _IO_ERR_SEEN, count = 0;
250 fp->_IO_read_end += count;
251 if (count == 0)
253 if (tries != 0)
254 /* There are some bytes in the external buffer but they don't
255 convert to anything. */
256 __set_errno (EILSEQ);
257 return WEOF;
259 if (fp->_offset != _IO_pos_BAD)
260 _IO_pos_adjust (fp->_offset, count);
262 /* Now convert the read input. */
263 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
264 fp->_IO_read_base = fp->_IO_read_ptr;
265 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
266 fp->_IO_read_ptr, fp->_IO_read_end,
267 &read_ptr_copy,
268 fp->_wide_data->_IO_read_end,
269 fp->_wide_data->_IO_buf_end,
270 &fp->_wide_data->_IO_read_end);
272 fp->_IO_read_ptr = (char *) read_ptr_copy;
273 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
275 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
277 __set_errno (EILSEQ);
278 fp->_flags |= _IO_ERR_SEEN;
279 return WEOF;
282 /* The read bytes make no complete character. Try reading again. */
283 assert (status == __codecvt_partial);
284 ++tries;
285 goto again;
288 return *fp->_wide_data->_IO_read_ptr;
290 INTDEF(_IO_wfile_underflow)
293 static wint_t
294 _IO_wfile_underflow_mmap (_IO_FILE *fp)
296 struct _IO_codecvt *cd;
297 enum __codecvt_result status;
298 const char *read_stop;
300 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
302 fp->_flags |= _IO_ERR_SEEN;
303 __set_errno (EBADF);
304 return WEOF;
306 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
307 return *fp->_wide_data->_IO_read_ptr;
309 cd = fp->_codecvt;
311 /* Maybe there is something left in the external buffer. */
312 if (fp->_IO_read_ptr >= fp->_IO_read_end
313 /* No. But maybe the read buffer is not fully set up. */
314 && _IO_file_underflow_mmap (fp) == EOF)
315 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
316 flags as appropriate. */
317 return WEOF;
319 /* There is more in the external. Convert it. */
320 read_stop = (const char *) fp->_IO_read_ptr;
322 if (fp->_wide_data->_IO_buf_base == NULL)
324 /* Maybe we already have a push back pointer. */
325 if (fp->_wide_data->_IO_save_base != NULL)
327 free (fp->_wide_data->_IO_save_base);
328 fp->_flags &= ~_IO_IN_BACKUP;
330 INTUSE(_IO_wdoallocbuf) (fp);
333 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
334 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
335 fp->_wide_data->_IO_buf_base;
336 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
337 fp->_IO_read_ptr, fp->_IO_read_end,
338 &read_stop,
339 fp->_wide_data->_IO_read_ptr,
340 fp->_wide_data->_IO_buf_end,
341 &fp->_wide_data->_IO_read_end);
343 fp->_IO_read_ptr = (char *) read_stop;
345 /* If we managed to generate some text return the next character. */
346 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
347 return *fp->_wide_data->_IO_read_ptr;
349 /* There is some garbage at the end of the file. */
350 __set_errno (EILSEQ);
351 fp->_flags |= _IO_ERR_SEEN;
352 return WEOF;
355 static wint_t
356 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
358 /* This is the first read attempt. Doing the underflow will choose mmap
359 or vanilla operations and then punt to the chosen underflow routine.
360 Then we can punt to ours. */
361 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
362 return WEOF;
364 return _IO_WUNDERFLOW (fp);
368 wint_t
369 _IO_wfile_overflow (f, wch)
370 _IO_FILE *f;
371 wint_t wch;
373 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
375 f->_flags |= _IO_ERR_SEEN;
376 __set_errno (EBADF);
377 return WEOF;
379 /* If currently reading or no buffer allocated. */
380 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
382 /* Allocate a buffer if needed. */
383 if (f->_wide_data->_IO_write_base == 0)
385 INTUSE(_IO_wdoallocbuf) (f);
386 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
387 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
389 if (f->_IO_write_base == NULL)
391 INTUSE(_IO_doallocbuf) (f);
392 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
395 else
397 /* Otherwise must be currently reading. If _IO_read_ptr
398 (and hence also _IO_read_end) is at the buffer end,
399 logically slide the buffer forwards one block (by setting
400 the read pointers to all point at the beginning of the
401 block). This makes room for subsequent output.
402 Otherwise, set the read pointers to _IO_read_end (leaving
403 that alone, so it can continue to correspond to the
404 external position). */
405 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
407 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
408 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
409 f->_wide_data->_IO_buf_base;
412 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
413 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
414 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
415 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
416 f->_wide_data->_IO_read_end;
418 f->_IO_write_ptr = f->_IO_read_ptr;
419 f->_IO_write_base = f->_IO_write_ptr;
420 f->_IO_write_end = f->_IO_buf_end;
421 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
423 f->_flags |= _IO_CURRENTLY_PUTTING;
424 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
425 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
427 if (wch == WEOF)
428 return _IO_do_flush (f);
429 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
430 /* Buffer is really full */
431 if (_IO_do_flush (f) == EOF)
432 return WEOF;
433 *f->_wide_data->_IO_write_ptr++ = wch;
434 if ((f->_flags & _IO_UNBUFFERED)
435 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
436 if (_IO_do_flush (f) == EOF)
437 return WEOF;
438 return wch;
440 INTDEF(_IO_wfile_overflow)
442 wint_t
443 _IO_wfile_sync (fp)
444 _IO_FILE *fp;
446 _IO_ssize_t delta;
447 wint_t retval = 0;
449 /* char* ptr = cur_ptr(); */
450 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
451 if (_IO_do_flush (fp))
452 return WEOF;
453 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
454 if (delta != 0)
456 /* We have to find out how many bytes we have to go back in the
457 external buffer. */
458 struct _IO_codecvt *cv = fp->_codecvt;
459 _IO_off64_t new_pos;
461 int clen = (*cv->__codecvt_do_encoding) (cv);
463 if (clen > 0)
464 /* It is easy, a fixed number of input bytes are used for each
465 wide character. */
466 delta *= clen;
467 else
469 /* We have to find out the hard way how much to back off.
470 To do this we determine how much input we needed to
471 generate the wide characters up to the current reading
472 position. */
473 int nread;
475 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
476 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
477 fp->_IO_read_base,
478 fp->_IO_read_end, delta);
479 fp->_IO_read_ptr = fp->_IO_read_base + nread;
480 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
483 new_pos = _IO_SYSSEEK (fp, delta, 1);
484 if (new_pos != (_IO_off64_t) EOF)
486 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
487 fp->_IO_read_end = fp->_IO_read_ptr;
489 #ifdef ESPIPE
490 else if (errno == ESPIPE)
491 ; /* Ignore error from unseekable devices. */
492 #endif
493 else
494 retval = WEOF;
496 if (retval != WEOF)
497 fp->_offset = _IO_pos_BAD;
498 /* FIXME: Cleanup - can this be shared? */
499 /* setg(base(), ptr, ptr); */
500 return retval;
502 INTDEF(_IO_wfile_sync)
504 _IO_off64_t
505 _IO_wfile_seekoff (fp, offset, dir, mode)
506 _IO_FILE *fp;
507 _IO_off64_t offset;
508 int dir;
509 int mode;
511 _IO_off64_t result;
512 _IO_off64_t delta, new_offset;
513 long int count;
514 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
515 offset of the underlying file must be exact. */
516 int must_be_exact = ((fp->_wide_data->_IO_read_base
517 == fp->_wide_data->_IO_read_end)
518 && (fp->_wide_data->_IO_write_base
519 == fp->_wide_data->_IO_write_ptr));
521 if (mode == 0)
523 /* XXX For wide stream with backup store it is not very
524 reasonable to determine the offset. The pushed-back
525 character might require a state change and we need not be
526 able to compute the initial state by reverse transformation
527 since there is no guarantee of symmetry. So we don't even
528 try and return an error. */
529 if (_IO_in_backup (fp))
531 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
533 __set_errno (EINVAL);
534 return -1;
537 /* There is no more data in the backup buffer. We can
538 switch back. */
539 INTUSE(_IO_switch_to_main_wget_area) (fp);
542 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
545 /* Flush unwritten characters.
546 (This may do an unneeded write if we seek within the buffer.
547 But to be able to switch to reading, we would need to set
548 egptr to ptr. That can't be done in the current design,
549 which assumes file_ptr() is eGptr. Anyway, since we probably
550 end up flushing when we close(), it doesn't make much difference.)
551 FIXME: simulate mem-mapped files. */
553 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
554 || _IO_in_put_mode (fp))
555 if (INTUSE(_IO_switch_to_wget_mode) (fp))
556 return WEOF;
558 if (fp->_wide_data->_IO_buf_base == NULL)
560 /* It could be that we already have a pushback buffer. */
561 if (fp->_wide_data->_IO_read_base != NULL)
563 free (fp->_wide_data->_IO_read_base);
564 fp->_flags &= ~_IO_IN_BACKUP;
566 INTUSE(_IO_doallocbuf) (fp);
567 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
568 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
569 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
570 fp->_wide_data->_IO_buf_base);
571 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
572 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
575 switch (dir)
577 struct _IO_codecvt *cv;
578 int clen;
580 case _IO_seek_cur:
581 /* Adjust for read-ahead (bytes is buffer). To do this we must
582 find out which position in the external buffer corresponds to
583 the current position in the internal buffer. */
584 cv = fp->_codecvt;
585 clen = (*cv->__codecvt_do_encoding) (cv);
587 if (clen > 0)
588 offset -= (fp->_wide_data->_IO_read_end
589 - fp->_wide_data->_IO_read_ptr) * clen;
590 else
592 int nread;
594 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
595 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
596 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
597 fp->_IO_read_base,
598 fp->_IO_read_end, delta);
599 fp->_IO_read_ptr = fp->_IO_read_base + nread;
600 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
601 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
604 if (fp->_offset == _IO_pos_BAD)
605 goto dumb;
606 /* Make offset absolute, assuming current pointer is file_ptr(). */
607 offset += fp->_offset;
609 dir = _IO_seek_set;
610 break;
611 case _IO_seek_set:
612 break;
613 case _IO_seek_end:
615 struct _G_stat64 st;
616 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
618 offset += st.st_size;
619 dir = _IO_seek_set;
621 else
622 goto dumb;
625 /* At this point, dir==_IO_seek_set. */
627 /* If we are only interested in the current position we've found it now. */
628 if (mode == 0)
629 return offset;
631 /* If destination is within current buffer, optimize: */
632 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
633 && !_IO_in_backup (fp))
635 /* Offset relative to start of main get area. */
636 _IO_off64_t rel_offset = (offset - fp->_offset
637 + (fp->_IO_read_end - fp->_IO_read_base));
638 if (rel_offset >= 0)
640 #if 0
641 if (_IO_in_backup (fp))
642 _IO_switch_to_main_get_area (fp);
643 #endif
644 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
646 enum __codecvt_result status;
647 struct _IO_codecvt *cd = fp->_codecvt;
648 const char *read_ptr_copy;
650 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
651 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
653 /* Now set the pointer for the internal buffer. This
654 might be an iterative process. Though the read
655 pointer is somewhere in the current external buffer
656 this does not mean we can convert this whole buffer
657 at once fitting in the internal buffer. */
658 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
659 read_ptr_copy = fp->_IO_read_base;
660 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
663 wchar_t buffer[1024];
664 wchar_t *ignore;
665 status = (*cd->__codecvt_do_in) (cd,
666 &fp->_wide_data->_IO_state,
667 read_ptr_copy,
668 fp->_IO_read_ptr,
669 &read_ptr_copy,
670 buffer,
671 buffer
672 + (sizeof (buffer)
673 / sizeof (buffer[0])),
674 &ignore);
675 if (status != __codecvt_ok && status != __codecvt_partial)
677 fp->_flags |= _IO_ERR_SEEN;
678 goto dumb;
681 while (read_ptr_copy != fp->_IO_read_ptr);
683 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
685 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
686 goto resync;
688 #ifdef TODO
689 /* If we have streammarkers, seek forward by reading ahead. */
690 if (_IO_have_markers (fp))
692 int to_skip = rel_offset
693 - (fp->_IO_read_ptr - fp->_IO_read_base);
694 if (ignore (to_skip) != to_skip)
695 goto dumb;
696 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
697 goto resync;
699 #endif
701 #ifdef TODO
702 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
704 if (!_IO_in_backup (fp))
705 _IO_switch_to_backup_area (fp);
706 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
707 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
708 goto resync;
710 #endif
713 #ifdef TODO
714 INTUSE(_IO_unsave_markers) (fp);
715 #endif
717 if (fp->_flags & _IO_NO_READS)
718 goto dumb;
720 /* Try to seek to a block boundary, to improve kernel page management. */
721 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
722 delta = offset - new_offset;
723 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
725 new_offset = offset;
726 delta = 0;
728 result = _IO_SYSSEEK (fp, new_offset, 0);
729 if (result < 0)
730 return EOF;
731 if (delta == 0)
732 count = 0;
733 else
735 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
736 (must_be_exact
737 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
738 if (count < delta)
740 /* We weren't allowed to read, but try to seek the remainder. */
741 offset = count == EOF ? delta : delta-count;
742 dir = _IO_seek_cur;
743 goto dumb;
746 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
747 fp->_IO_buf_base + count);
748 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
749 fp->_offset = result + count;
750 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
751 return offset;
752 dumb:
754 INTUSE(_IO_unsave_markers) (fp);
755 result = _IO_SYSSEEK (fp, offset, dir);
756 if (result != EOF)
758 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
759 fp->_offset = result;
760 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
761 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
762 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
763 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
764 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
765 fp->_wide_data->_IO_buf_base);
767 return result;
769 resync:
770 /* We need to do it since it is possible that the file offset in
771 the kernel may be changed behind our back. It may happen when
772 we fopen a file and then do a fork. One process may access the
773 the file and the kernel file offset will be changed. */
774 if (fp->_offset >= 0)
775 _IO_SYSSEEK (fp, fp->_offset, 0);
777 return offset;
779 INTDEF(_IO_wfile_seekoff)
782 _IO_size_t
783 _IO_wfile_xsputn (f, data, n)
784 _IO_FILE *f;
785 const void *data;
786 _IO_size_t n;
788 register const wchar_t *s = (const wchar_t *) data;
789 _IO_size_t to_do = n;
790 int must_flush = 0;
791 _IO_size_t count;
793 if (n <= 0)
794 return 0;
795 /* This is an optimized implementation.
796 If the amount to be written straddles a block boundary
797 (or the filebuf is unbuffered), use sys_write directly. */
799 /* First figure out how much space is available in the buffer. */
800 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
801 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
803 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
804 if (count >= n)
806 register const wchar_t *p;
807 for (p = s + n; p > s; )
809 if (*--p == L'\n')
811 count = p - s + 1;
812 must_flush = 1;
813 break;
818 /* Then fill the buffer. */
819 if (count > 0)
821 if (count > to_do)
822 count = to_do;
823 if (count > 20)
825 #ifdef _LIBC
826 f->_wide_data->_IO_write_ptr =
827 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
828 #else
829 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
830 f->_wide_data->_IO_write_ptr += count;
831 #endif
832 s += count;
834 else
836 register wchar_t *p = f->_wide_data->_IO_write_ptr;
837 register int i = (int) count;
838 while (--i >= 0)
839 *p++ = *s++;
840 f->_wide_data->_IO_write_ptr = p;
842 to_do -= count;
844 if (to_do > 0)
845 to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);
846 if (must_flush
847 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
848 INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base,
849 f->_wide_data->_IO_write_ptr
850 - f->_wide_data->_IO_write_base);
852 return n - to_do;
854 INTDEF(_IO_wfile_xsputn)
857 const struct _IO_jump_t _IO_wfile_jumps =
859 JUMP_INIT_DUMMY,
860 JUMP_INIT(finish, _IO_new_file_finish),
861 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
862 JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)),
863 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
864 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
865 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
866 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
867 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
868 JUMP_INIT(seekpos, _IO_default_seekpos),
869 JUMP_INIT(setbuf, _IO_new_file_setbuf),
870 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
871 JUMP_INIT(doallocate, _IO_wfile_doallocate),
872 JUMP_INIT(read, INTUSE(_IO_file_read)),
873 JUMP_INIT(write, _IO_new_file_write),
874 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
875 JUMP_INIT(close, INTUSE(_IO_file_close)),
876 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
877 JUMP_INIT(showmanyc, _IO_default_showmanyc),
878 JUMP_INIT(imbue, _IO_default_imbue)
880 libc_hidden_data_def (_IO_wfile_jumps)
883 const struct _IO_jump_t _IO_wfile_jumps_mmap =
885 JUMP_INIT_DUMMY,
886 JUMP_INIT(finish, _IO_new_file_finish),
887 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
888 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
889 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
890 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
891 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
892 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
893 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
894 JUMP_INIT(seekpos, _IO_default_seekpos),
895 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
896 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
897 JUMP_INIT(doallocate, _IO_wfile_doallocate),
898 JUMP_INIT(read, INTUSE(_IO_file_read)),
899 JUMP_INIT(write, _IO_new_file_write),
900 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
901 JUMP_INIT(close, _IO_file_close_mmap),
902 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
903 JUMP_INIT(showmanyc, _IO_default_showmanyc),
904 JUMP_INIT(imbue, _IO_default_imbue)
907 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
909 JUMP_INIT_DUMMY,
910 JUMP_INIT(finish, _IO_new_file_finish),
911 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
912 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
913 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
914 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
915 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
916 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
917 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
918 JUMP_INIT(seekpos, _IO_default_seekpos),
919 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
920 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
921 JUMP_INIT(doallocate, _IO_wfile_doallocate),
922 JUMP_INIT(read, INTUSE(_IO_file_read)),
923 JUMP_INIT(write, _IO_new_file_write),
924 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
925 JUMP_INIT(close, INTUSE(_IO_file_close)),
926 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
927 JUMP_INIT(showmanyc, _IO_default_showmanyc),
928 JUMP_INIT(imbue, _IO_default_imbue)