Update.
[platform/upstream/glibc.git] / libio / wfileops.c
1 /* Copyright (C) 1993,95,97,98,99,2000,2001,2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Written by Ulrich Drepper <drepper@cygnus.com>.
4    Based on the single byte version by Per Bothner <bothner@cygnus.com>.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.
20
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.  */
29
30 #include <assert.h>
31 #include <libioP.h>
32 #include <wchar.h>
33 #include <gconv.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37
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
53
54
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;
62 {
63   struct _IO_codecvt *cc = fp->_codecvt;
64
65   if (to_do > 0)
66     {
67       if (fp->_IO_write_end == fp->_IO_write_ptr
68           && fp->_IO_write_end != fp->_IO_write_base)
69         {
70           if (_IO_new_do_write (fp, fp->_IO_write_base,
71                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
72             return EOF;
73         }
74
75       do
76         {
77           enum __codecvt_result result;
78           const wchar_t *new_data;
79
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);
86
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;
92
93           to_do -= new_data - data;
94
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;
100
101           data = new_data;
102         }
103       while (to_do > 0);
104     }
105
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);
113
114   return to_do == 0 ? 0 : WEOF;
115 }
116 INTDEF(_IO_wdo_write)
117
118
119 wint_t
120 _IO_wfile_underflow (fp)
121      _IO_FILE *fp;
122 {
123   struct _IO_codecvt *cd;
124   enum __codecvt_result status;
125   _IO_ssize_t count;
126   int tries;
127   const char *read_ptr_copy;
128
129   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
130     {
131       fp->_flags |= _IO_ERR_SEEN;
132       __set_errno (EBADF);
133       return WEOF;
134     }
135   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
136     return *fp->_wide_data->_IO_read_ptr;
137
138   cd = fp->_codecvt;
139
140   /* Maybe there is something left in the external buffer.  */
141   if (fp->_IO_read_ptr < fp->_IO_read_end)
142     {
143       /* There is more in the external.  Convert it.  */
144       const char *read_stop = (const char *) fp->_IO_read_ptr;
145
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);
155
156       fp->_IO_read_ptr = (char *) read_stop;
157
158       /* If we managed to generate some text return the next character.  */
159       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
160         return *fp->_wide_data->_IO_read_ptr;
161
162       if (status == __codecvt_error)
163         {
164           __set_errno (EILSEQ);
165           fp->_flags |= _IO_ERR_SEEN;
166           return WEOF;
167         }
168
169       /* Move the remaining content of the read buffer to the beginning.  */
170       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
171                fp->_IO_read_end - fp->_IO_read_ptr);
172       fp->_IO_read_end = (fp->_IO_buf_base
173                           + (fp->_IO_read_end - fp->_IO_read_ptr));
174       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
175     }
176   else
177     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
178       fp->_IO_buf_base;
179
180   if (fp->_IO_buf_base == NULL)
181     {
182       /* Maybe we already have a push back pointer.  */
183       if (fp->_IO_save_base != NULL)
184         {
185           free (fp->_IO_save_base);
186           fp->_flags &= ~_IO_IN_BACKUP;
187         }
188       INTUSE(_IO_doallocbuf) (fp);
189
190       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
191         fp->_IO_buf_base;
192     }
193
194   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
195     fp->_IO_buf_base;
196
197   if (fp->_wide_data->_IO_buf_base == NULL)
198     {
199       /* Maybe we already have a push back pointer.  */
200       if (fp->_wide_data->_IO_save_base != NULL)
201         {
202           free (fp->_wide_data->_IO_save_base);
203           fp->_flags &= ~_IO_IN_BACKUP;
204         }
205       INTUSE(_IO_wdoallocbuf) (fp);
206     }
207
208   /* Flush all line buffered files before reading. */
209   /* FIXME This can/should be moved to genops ?? */
210   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
211     {
212 #if 0
213       INTUSE(_IO_flush_all_linebuffered) ();
214 #else
215       /* We used to flush all line-buffered stream.  This really isn't
216          required by any standard.  My recollection is that
217          traditional Unix systems did this for stdout.  stderr better
218          not be line buffered.  So we do just that here
219          explicitly.  --drepper */
220       _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile,
221                                 _IO_stdout);
222       _IO_flockfile (_IO_stdout);
223
224       if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
225           == (_IO_LINKED | _IO_LINE_BUF))
226         _IO_OVERFLOW (_IO_stdout, EOF);
227
228       _IO_funlockfile (_IO_stdout);
229       _IO_cleanup_region_end (0);
230 #endif
231     }
232
233   INTUSE(_IO_switch_to_get_mode) (fp);
234
235   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
236     fp->_wide_data->_IO_buf_base;
237   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
238   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
239     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
240
241   tries = 0;
242  again:
243   count = _IO_SYSREAD (fp, fp->_IO_read_end,
244                        fp->_IO_buf_end - fp->_IO_read_end);
245   if (count <= 0)
246     {
247       if (count == 0 && tries == 0)
248         fp->_flags |= _IO_EOF_SEEN;
249       else
250         fp->_flags |= _IO_ERR_SEEN, count = 0;
251     }
252   fp->_IO_read_end += count;
253   if (count == 0)
254     {
255       if (tries != 0)
256         /* There are some bytes in the external buffer but they don't
257            convert to anything.  */
258         __set_errno (EILSEQ);
259       return WEOF;
260     }
261   if (fp->_offset != _IO_pos_BAD)
262     _IO_pos_adjust (fp->_offset, count);
263
264   /* Now convert the read input.  */
265   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
266   fp->_IO_read_base = fp->_IO_read_ptr;
267   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
268                                    fp->_IO_read_ptr, fp->_IO_read_end,
269                                    &read_ptr_copy,
270                                    fp->_wide_data->_IO_read_end,
271                                    fp->_wide_data->_IO_buf_end,
272                                    &fp->_wide_data->_IO_read_end);
273
274   fp->_IO_read_ptr = (char *) read_ptr_copy;
275   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
276     {
277       if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
278         {
279           __set_errno (EILSEQ);
280           fp->_flags |= _IO_ERR_SEEN;
281           return WEOF;
282         }
283
284       /* The read bytes make no complete character.  Try reading again.  */
285       assert (status == __codecvt_partial);
286       ++tries;
287       goto again;
288     }
289
290   return *fp->_wide_data->_IO_read_ptr;
291 }
292 INTDEF(_IO_wfile_underflow)
293
294
295 static wint_t
296 _IO_wfile_underflow_mmap (_IO_FILE *fp)
297 {
298   struct _IO_codecvt *cd;
299   enum __codecvt_result status;
300   const char *read_stop;
301
302   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
303     {
304       fp->_flags |= _IO_ERR_SEEN;
305       __set_errno (EBADF);
306       return WEOF;
307     }
308   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
309     return *fp->_wide_data->_IO_read_ptr;
310
311   cd = fp->_codecvt;
312
313   /* Maybe there is something left in the external buffer.  */
314   if (fp->_IO_read_ptr >= fp->_IO_read_end
315       /* No.  But maybe the read buffer is not fully set up.  */
316       && _IO_file_underflow_mmap (fp) == EOF)
317     /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
318        flags as appropriate.  */
319     return WEOF;
320
321   /* There is more in the external.  Convert it.  */
322   read_stop = (const char *) fp->_IO_read_ptr;
323
324   if (fp->_wide_data->_IO_buf_base == NULL)
325     {
326       /* Maybe we already have a push back pointer.  */
327       if (fp->_wide_data->_IO_save_base != NULL)
328         {
329           free (fp->_wide_data->_IO_save_base);
330           fp->_flags &= ~_IO_IN_BACKUP;
331         }
332       INTUSE(_IO_wdoallocbuf) (fp);
333     }
334
335   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
336   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
337     fp->_wide_data->_IO_buf_base;
338   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
339                                    fp->_IO_read_ptr, fp->_IO_read_end,
340                                    &read_stop,
341                                    fp->_wide_data->_IO_read_ptr,
342                                    fp->_wide_data->_IO_buf_end,
343                                    &fp->_wide_data->_IO_read_end);
344
345   fp->_IO_read_ptr = (char *) read_stop;
346
347   /* If we managed to generate some text return the next character.  */
348   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
349     return *fp->_wide_data->_IO_read_ptr;
350
351   /* There is some garbage at the end of the file.  */
352   __set_errno (EILSEQ);
353   fp->_flags |= _IO_ERR_SEEN;
354   return WEOF;
355 }
356
357 static wint_t
358 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
359 {
360   /* This is the first read attempt.  Doing the underflow will choose mmap
361      or vanilla operations and then punt to the chosen underflow routine.
362      Then we can punt to ours.  */
363   if (_IO_file_underflow_maybe_mmap (fp) == EOF)
364     return WEOF;
365
366   return _IO_WUNDERFLOW (fp);
367 }
368
369
370 wint_t
371 _IO_wfile_overflow (f, wch)
372      _IO_FILE *f;
373      wint_t wch;
374 {
375   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
376     {
377       f->_flags |= _IO_ERR_SEEN;
378       __set_errno (EBADF);
379       return WEOF;
380     }
381   /* If currently reading or no buffer allocated. */
382   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
383     {
384       /* Allocate a buffer if needed. */
385       if (f->_wide_data->_IO_write_base == 0)
386         {
387           INTUSE(_IO_wdoallocbuf) (f);
388           _IO_wsetg (f, f->_wide_data->_IO_buf_base,
389                      f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
390
391           if (f->_IO_write_base == NULL)
392             {
393               INTUSE(_IO_doallocbuf) (f);
394               _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
395             }
396         }
397       else
398         {
399           /* Otherwise must be currently reading.  If _IO_read_ptr
400              (and hence also _IO_read_end) is at the buffer end,
401              logically slide the buffer forwards one block (by setting
402              the read pointers to all point at the beginning of the
403              block).  This makes room for subsequent output.
404              Otherwise, set the read pointers to _IO_read_end (leaving
405              that alone, so it can continue to correspond to the
406              external position). */
407           if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
408             {
409               f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
410               f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
411                 f->_wide_data->_IO_buf_base;
412             }
413         }
414       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
415       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
416       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
417       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
418         f->_wide_data->_IO_read_end;
419
420       f->_IO_write_ptr = f->_IO_read_ptr;
421       f->_IO_write_base = f->_IO_write_ptr;
422       f->_IO_write_end = f->_IO_buf_end;
423       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
424
425       f->_flags |= _IO_CURRENTLY_PUTTING;
426       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
427         f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
428     }
429   if (wch == WEOF)
430     return _IO_do_flush (f);
431   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
432     /* Buffer is really full */
433     if (_IO_do_flush (f) == EOF)
434       return WEOF;
435   *f->_wide_data->_IO_write_ptr++ = wch;
436   if ((f->_flags & _IO_UNBUFFERED)
437       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
438     if (_IO_do_flush (f) == EOF)
439       return WEOF;
440   return wch;
441 }
442 INTDEF(_IO_wfile_overflow)
443
444 wint_t
445 _IO_wfile_sync (fp)
446      _IO_FILE *fp;
447 {
448   _IO_ssize_t delta;
449   wint_t retval = 0;
450
451   /*    char* ptr = cur_ptr(); */
452   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
453     if (_IO_do_flush (fp))
454       return WEOF;
455   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
456   if (delta != 0)
457     {
458       /* We have to find out how many bytes we have to go back in the
459          external buffer.  */
460       struct _IO_codecvt *cv = fp->_codecvt;
461       _IO_off64_t new_pos;
462
463       int clen = (*cv->__codecvt_do_encoding) (cv);
464
465       if (clen > 0)
466         /* It is easy, a fixed number of input bytes are used for each
467            wide character.  */
468         delta *= clen;
469       else
470         {
471           /* We have to find out the hard way how much to back off.
472              To do this we determine how much input we needed to
473              generate the wide characters up to the current reading
474              position.  */
475           int nread;
476
477           fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
478           nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
479                                               fp->_IO_read_base,
480                                               fp->_IO_read_end, delta);
481           fp->_IO_read_ptr = fp->_IO_read_base + nread;
482           delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
483         }
484
485       new_pos = _IO_SYSSEEK (fp, delta, 1);
486       if (new_pos != (_IO_off64_t) EOF)
487         {
488           fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
489           fp->_IO_read_end = fp->_IO_read_ptr;
490         }
491 #ifdef ESPIPE
492       else if (errno == ESPIPE)
493         ; /* Ignore error from unseekable devices. */
494 #endif
495       else
496         retval = WEOF;
497     }
498   if (retval != WEOF)
499     fp->_offset = _IO_pos_BAD;
500   /* FIXME: Cleanup - can this be shared? */
501   /*    setg(base(), ptr, ptr); */
502   return retval;
503 }
504 INTDEF(_IO_wfile_sync)
505
506 _IO_off64_t
507 _IO_wfile_seekoff (fp, offset, dir, mode)
508      _IO_FILE *fp;
509      _IO_off64_t offset;
510      int dir;
511      int mode;
512 {
513   _IO_off64_t result;
514   _IO_off64_t delta, new_offset;
515   long int count;
516   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
517      offset of the underlying file must be exact.  */
518   int must_be_exact = ((fp->_wide_data->_IO_read_base
519                         == fp->_wide_data->_IO_read_end)
520                        && (fp->_wide_data->_IO_write_base
521                            == fp->_wide_data->_IO_write_ptr));
522
523   if (mode == 0)
524     {
525       /* XXX For wide stream with backup store it is not very
526          reasonable to determine the offset.  The pushed-back
527          character might require a state change and we need not be
528          able to compute the initial state by reverse transformation
529          since there is no guarantee of symmetry.  So we don't even
530          try and return an error.  */
531       if (_IO_in_backup (fp))
532         {
533           if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
534             {
535               __set_errno (EINVAL);
536               return -1;
537             }
538
539           /* There is no more data in the backup buffer.  We can
540              switch back.  */
541           INTUSE(_IO_switch_to_main_wget_area) (fp);
542         }
543
544       dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
545     }
546
547   /* Flush unwritten characters.
548      (This may do an unneeded write if we seek within the buffer.
549      But to be able to switch to reading, we would need to set
550      egptr to ptr.  That can't be done in the current design,
551      which assumes file_ptr() is eGptr.  Anyway, since we probably
552      end up flushing when we close(), it doesn't make much difference.)
553      FIXME: simulate mem-mapped files. */
554
555   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
556       || _IO_in_put_mode (fp))
557     if (INTUSE(_IO_switch_to_wget_mode) (fp))
558       return WEOF;
559
560   if (fp->_wide_data->_IO_buf_base == NULL)
561     {
562       /* It could be that we already have a pushback buffer.  */
563       if (fp->_wide_data->_IO_read_base != NULL)
564         {
565           free (fp->_wide_data->_IO_read_base);
566           fp->_flags &= ~_IO_IN_BACKUP;
567         }
568       INTUSE(_IO_doallocbuf) (fp);
569       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
570       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
571       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
572                  fp->_wide_data->_IO_buf_base);
573       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
574                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
575     }
576
577   switch (dir)
578     {
579       struct _IO_codecvt *cv;
580       int clen;
581
582     case _IO_seek_cur:
583       /* Adjust for read-ahead (bytes is buffer).  To do this we must
584          find out which position in the external buffer corresponds to
585          the current position in the internal buffer.  */
586       cv = fp->_codecvt;
587       clen = (*cv->__codecvt_do_encoding) (cv);
588
589       if (clen > 0)
590         offset -= (fp->_wide_data->_IO_read_end
591                    - fp->_wide_data->_IO_read_ptr) * clen;
592       else
593         {
594           int nread;
595
596           delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
597           fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
598           nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
599                                               fp->_IO_read_base,
600                                               fp->_IO_read_end, delta);
601           fp->_IO_read_ptr = fp->_IO_read_base + nread;
602           fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
603           offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
604         }
605
606       if (fp->_offset == _IO_pos_BAD)
607         goto dumb;
608       /* Make offset absolute, assuming current pointer is file_ptr(). */
609       offset += fp->_offset;
610
611       dir = _IO_seek_set;
612       break;
613     case _IO_seek_set:
614       break;
615     case _IO_seek_end:
616       {
617         struct _G_stat64 st;
618         if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
619           {
620             offset += st.st_size;
621             dir = _IO_seek_set;
622           }
623         else
624           goto dumb;
625       }
626     }
627   /* At this point, dir==_IO_seek_set. */
628
629   /* If we are only interested in the current position we've found it now.  */
630   if (mode == 0)
631     return offset;
632
633   /* If destination is within current buffer, optimize: */
634   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
635       && !_IO_in_backup (fp))
636     {
637       /* Offset relative to start of main get area. */
638       _IO_off64_t rel_offset = (offset - fp->_offset
639                                 + (fp->_IO_read_end - fp->_IO_read_base));
640       if (rel_offset >= 0)
641         {
642 #if 0
643           if (_IO_in_backup (fp))
644             _IO_switch_to_main_get_area (fp);
645 #endif
646           if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
647             {
648               enum __codecvt_result status;
649               struct _IO_codecvt *cd = fp->_codecvt;
650               const char *read_ptr_copy;
651
652               fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
653               _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
654
655               /* Now set the pointer for the internal buffer.  This
656                  might be an iterative process.  Though the read
657                  pointer is somewhere in the current external buffer
658                  this does not mean we can convert this whole buffer
659                  at once fitting in the internal buffer.  */
660               fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
661               read_ptr_copy = fp->_IO_read_base;
662               fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
663               do
664                 {
665                   wchar_t buffer[1024];
666                   wchar_t *ignore;
667                   status = (*cd->__codecvt_do_in) (cd,
668                                                    &fp->_wide_data->_IO_state,
669                                                    read_ptr_copy,
670                                                    fp->_IO_read_ptr,
671                                                    &read_ptr_copy,
672                                                    buffer,
673                                                    buffer
674                                                    + (sizeof (buffer)
675                                                       / sizeof (buffer[0])),
676                                                    &ignore);
677                   if (status != __codecvt_ok && status != __codecvt_partial)
678                     {
679                       fp->_flags |= _IO_ERR_SEEN;
680                       goto dumb;
681                     }
682                 }
683               while (read_ptr_copy != fp->_IO_read_ptr);
684
685               fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
686
687               _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
688               goto resync;
689             }
690 #ifdef TODO
691             /* If we have streammarkers, seek forward by reading ahead. */
692             if (_IO_have_markers (fp))
693               {
694                 int to_skip = rel_offset
695                   - (fp->_IO_read_ptr - fp->_IO_read_base);
696                 if (ignore (to_skip) != to_skip)
697                   goto dumb;
698                 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
699                 goto resync;
700               }
701 #endif
702         }
703 #ifdef TODO
704       if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
705         {
706           if (!_IO_in_backup (fp))
707             _IO_switch_to_backup_area (fp);
708           gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
709           _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
710           goto resync;
711         }
712 #endif
713     }
714
715 #ifdef TODO
716   INTUSE(_IO_unsave_markers) (fp);
717 #endif
718
719   if (fp->_flags & _IO_NO_READS)
720     goto dumb;
721
722   /* Try to seek to a block boundary, to improve kernel page management. */
723   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
724   delta = offset - new_offset;
725   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
726     {
727       new_offset = offset;
728       delta = 0;
729     }
730   result = _IO_SYSSEEK (fp, new_offset, 0);
731   if (result < 0)
732     return EOF;
733   if (delta == 0)
734     count = 0;
735   else
736     {
737       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
738                            (must_be_exact
739                             ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
740       if (count < delta)
741         {
742           /* We weren't allowed to read, but try to seek the remainder. */
743           offset = count == EOF ? delta : delta-count;
744           dir = _IO_seek_cur;
745           goto dumb;
746         }
747     }
748   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
749             fp->_IO_buf_base + count);
750   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
751   fp->_offset = result + count;
752   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
753   return offset;
754  dumb:
755
756   INTUSE(_IO_unsave_markers) (fp);
757   result = _IO_SYSSEEK (fp, offset, dir);
758   if (result != EOF)
759     {
760       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
761       fp->_offset = result;
762       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
763       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
764       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
765                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
766       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
767                  fp->_wide_data->_IO_buf_base);
768     }
769   return result;
770
771 resync:
772   /* We need to do it since it is possible that the file offset in
773      the kernel may be changed behind our back. It may happen when
774      we fopen a file and then do a fork. One process may access the
775      the file and the kernel file offset will be changed. */
776   if (fp->_offset >= 0)
777     _IO_SYSSEEK (fp, fp->_offset, 0);
778
779   return offset;
780 }
781 INTDEF(_IO_wfile_seekoff)
782
783
784 _IO_size_t
785 _IO_wfile_xsputn (f, data, n)
786      _IO_FILE *f;
787      const void *data;
788      _IO_size_t n;
789 {
790   register const wchar_t *s = (const wchar_t *) data;
791   _IO_size_t to_do = n;
792   int must_flush = 0;
793   _IO_size_t count;
794
795   if (n <= 0)
796     return 0;
797   /* This is an optimized implementation.
798      If the amount to be written straddles a block boundary
799      (or the filebuf is unbuffered), use sys_write directly. */
800
801   /* First figure out how much space is available in the buffer. */
802   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
803   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
804     {
805       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
806       if (count >= n)
807         {
808           register const wchar_t *p;
809           for (p = s + n; p > s; )
810             {
811               if (*--p == L'\n')
812                 {
813                   count = p - s + 1;
814                   must_flush = 1;
815                   break;
816                 }
817             }
818         }
819     }
820   /* Then fill the buffer. */
821   if (count > 0)
822     {
823       if (count > to_do)
824         count = to_do;
825       if (count > 20)
826         {
827 #ifdef _LIBC
828           f->_wide_data->_IO_write_ptr =
829             __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
830 #else
831           wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
832           f->_wide_data->_IO_write_ptr += count;
833 #endif
834           s += count;
835         }
836       else
837         {
838           register wchar_t *p = f->_wide_data->_IO_write_ptr;
839           register int i = (int) count;
840           while (--i >= 0)
841             *p++ = *s++;
842           f->_wide_data->_IO_write_ptr = p;
843         }
844       to_do -= count;
845     }
846   if (to_do > 0)
847     to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);
848   if (must_flush
849       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
850     INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base,
851                            f->_wide_data->_IO_write_ptr
852                            - f->_wide_data->_IO_write_base);
853
854   return n - to_do;
855 }
856 INTDEF(_IO_wfile_xsputn)
857
858
859 struct _IO_jump_t _IO_wfile_jumps =
860 {
861   JUMP_INIT_DUMMY,
862   JUMP_INIT(finish, _IO_new_file_finish),
863   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
864   JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)),
865   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
866   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
867   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
868   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
869   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
870   JUMP_INIT(seekpos, _IO_default_seekpos),
871   JUMP_INIT(setbuf, _IO_new_file_setbuf),
872   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
873   JUMP_INIT(doallocate, _IO_wfile_doallocate),
874   JUMP_INIT(read, INTUSE(_IO_file_read)),
875   JUMP_INIT(write, _IO_new_file_write),
876   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
877   JUMP_INIT(close, INTUSE(_IO_file_close)),
878   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
879   JUMP_INIT(showmanyc, _IO_default_showmanyc),
880   JUMP_INIT(imbue, _IO_default_imbue)
881 };
882 libc_hidden_data_def (_IO_wfile_jumps)
883
884
885 struct _IO_jump_t _IO_wfile_jumps_mmap =
886 {
887   JUMP_INIT_DUMMY,
888   JUMP_INIT(finish, _IO_new_file_finish),
889   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
890   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
891   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
892   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
893   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
894   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
895   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
896   JUMP_INIT(seekpos, _IO_default_seekpos),
897   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
898   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
899   JUMP_INIT(doallocate, _IO_wfile_doallocate),
900   JUMP_INIT(read, INTUSE(_IO_file_read)),
901   JUMP_INIT(write, _IO_new_file_write),
902   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
903   JUMP_INIT(close, _IO_file_close_mmap),
904   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
905   JUMP_INIT(showmanyc, _IO_default_showmanyc),
906   JUMP_INIT(imbue, _IO_default_imbue)
907 };
908
909 struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
910 {
911   JUMP_INIT_DUMMY,
912   JUMP_INIT(finish, _IO_new_file_finish),
913   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
914   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
915   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
916   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
917   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
918   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
919   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
920   JUMP_INIT(seekpos, _IO_default_seekpos),
921   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
922   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
923   JUMP_INIT(doallocate, _IO_wfile_doallocate),
924   JUMP_INIT(read, INTUSE(_IO_file_read)),
925   JUMP_INIT(write, _IO_new_file_write),
926   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
927   JUMP_INIT(close, INTUSE(_IO_file_close)),
928   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
929   JUMP_INIT(showmanyc, _IO_default_showmanyc),
930   JUMP_INIT(imbue, _IO_default_imbue)
931 };