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