Fix typos.
[platform/upstream/glibc.git] / libio / wfileops.c
1 /* Copyright (C) 1993-2013 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, see
18    <http://www.gnu.org/licenses/>.
19
20    As a special exception, if you link the code in this file with
21    files compiled with a GNU compiler to produce an executable,
22    that does not cause the resulting executable to be covered by
23    the GNU Lesser General Public License.  This exception does not
24    however invalidate any other reasons why the executable file
25    might be covered by the GNU Lesser General Public License.
26    This exception applies to code released by its copyright holders
27    in files containing the exception.  */
28
29 #include <assert.h>
30 #include <libioP.h>
31 #include <wchar.h>
32 #include <gconv.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36
37 #ifndef _LIBC
38 # define _IO_new_do_write _IO_do_write
39 # define _IO_new_file_attach _IO_file_attach
40 # define _IO_new_file_close_it _IO_file_close_it
41 # define _IO_new_file_finish _IO_file_finish
42 # define _IO_new_file_fopen _IO_file_fopen
43 # define _IO_new_file_init _IO_file_init
44 # define _IO_new_file_setbuf _IO_file_setbuf
45 # define _IO_new_file_sync _IO_file_sync
46 # define _IO_new_file_overflow _IO_file_overflow
47 # define _IO_new_file_seekoff _IO_file_seekoff
48 # define _IO_new_file_underflow _IO_file_underflow
49 # define _IO_new_file_write _IO_file_write
50 # define _IO_new_file_xsputn _IO_file_xsputn
51 #endif
52
53
54 /* Convert TO_DO wide character from DATA to FP.
55    Then mark FP as having empty buffers. */
56 int
57 _IO_wdo_write (fp, data, to_do)
58      _IO_FILE *fp;
59      const wchar_t *data;
60      _IO_size_t to_do;
61 {
62   struct _IO_codecvt *cc = fp->_codecvt;
63
64   if (to_do > 0)
65     {
66       if (fp->_IO_write_end == fp->_IO_write_ptr
67           && fp->_IO_write_end != fp->_IO_write_base)
68         {
69           if (_IO_new_do_write (fp, fp->_IO_write_base,
70                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
71             return WEOF;
72         }
73
74       do
75         {
76           enum __codecvt_result result;
77           const wchar_t *new_data;
78
79           /* Now convert from the internal format into the external buffer.  */
80           result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
81                                             data, data + to_do, &new_data,
82                                             fp->_IO_write_ptr,
83                                             fp->_IO_buf_end,
84                                             &fp->_IO_write_ptr);
85
86           /* Write out what we produced so far.  */
87           if (_IO_new_do_write (fp, fp->_IO_write_base,
88                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
89             /* Something went wrong.  */
90             return WEOF;
91
92           to_do -= new_data - data;
93
94           /* Next see whether we had problems during the conversion.  If yes,
95              we cannot go on.  */
96           if (result != __codecvt_ok
97               && (result != __codecvt_partial || new_data - data == 0))
98             break;
99
100           data = new_data;
101         }
102       while (to_do > 0);
103     }
104
105   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
106              fp->_wide_data->_IO_buf_base);
107   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
108     = fp->_wide_data->_IO_buf_base;
109   fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
110                                    ? fp->_wide_data->_IO_buf_base
111                                    : fp->_wide_data->_IO_buf_end);
112
113   return to_do == 0 ? 0 : WEOF;
114 }
115 libc_hidden_def (_IO_wdo_write)
116
117
118 wint_t
119 _IO_wfile_underflow (fp)
120      _IO_FILE *fp;
121 {
122   struct _IO_codecvt *cd;
123   enum __codecvt_result status;
124   _IO_ssize_t count;
125
126   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
127     {
128       fp->_flags |= _IO_ERR_SEEN;
129       __set_errno (EBADF);
130       return WEOF;
131     }
132   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
133     return *fp->_wide_data->_IO_read_ptr;
134
135   cd = fp->_codecvt;
136
137   /* Maybe there is something left in the external buffer.  */
138   if (fp->_IO_read_ptr < fp->_IO_read_end)
139     {
140       /* There is more in the external.  Convert it.  */
141       const char *read_stop = (const char *) fp->_IO_read_ptr;
142
143       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
144       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
145         fp->_wide_data->_IO_buf_base;
146       status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
147                                        fp->_IO_read_ptr, fp->_IO_read_end,
148                                        &read_stop,
149                                        fp->_wide_data->_IO_read_ptr,
150                                        fp->_wide_data->_IO_buf_end,
151                                        &fp->_wide_data->_IO_read_end);
152
153       fp->_IO_read_base = fp->_IO_read_ptr;
154       fp->_IO_read_ptr = (char *) read_stop;
155
156       /* If we managed to generate some text return the next character.  */
157       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
158         return *fp->_wide_data->_IO_read_ptr;
159
160       if (status == __codecvt_error)
161         {
162           __set_errno (EILSEQ);
163           fp->_flags |= _IO_ERR_SEEN;
164           return WEOF;
165         }
166
167       /* Move the remaining content of the read buffer to the beginning.  */
168       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
169                fp->_IO_read_end - fp->_IO_read_ptr);
170       fp->_IO_read_end = (fp->_IO_buf_base
171                           + (fp->_IO_read_end - fp->_IO_read_ptr));
172       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
173     }
174   else
175     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
176       fp->_IO_buf_base;
177
178   if (fp->_IO_buf_base == NULL)
179     {
180       /* Maybe we already have a push back pointer.  */
181       if (fp->_IO_save_base != NULL)
182         {
183           free (fp->_IO_save_base);
184           fp->_flags &= ~_IO_IN_BACKUP;
185         }
186       _IO_doallocbuf (fp);
187
188       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
189         fp->_IO_buf_base;
190     }
191
192   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
193     fp->_IO_buf_base;
194
195   if (fp->_wide_data->_IO_buf_base == NULL)
196     {
197       /* Maybe we already have a push back pointer.  */
198       if (fp->_wide_data->_IO_save_base != NULL)
199         {
200           free (fp->_wide_data->_IO_save_base);
201           fp->_flags &= ~_IO_IN_BACKUP;
202         }
203       _IO_wdoallocbuf (fp);
204     }
205
206   /* Flush all line buffered files before reading. */
207   /* FIXME This can/should be moved to genops ?? */
208   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
209     {
210 #if 0
211       _IO_flush_all_linebuffered ();
212 #else
213       /* We used to flush all line-buffered stream.  This really isn't
214          required by any standard.  My recollection is that
215          traditional Unix systems did this for stdout.  stderr better
216          not be line buffered.  So we do just that here
217          explicitly.  --drepper */
218       _IO_acquire_lock (_IO_stdout);
219
220       if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
221           == (_IO_LINKED | _IO_LINE_BUF))
222         _IO_OVERFLOW (_IO_stdout, EOF);
223
224       _IO_release_lock (_IO_stdout);
225 #endif
226     }
227
228   _IO_switch_to_get_mode (fp);
229
230   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
231     fp->_wide_data->_IO_buf_base;
232   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
233   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
234     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
235
236   const char *read_ptr_copy;
237   char accbuf[MB_LEN_MAX];
238   size_t naccbuf = 0;
239  again:
240   count = _IO_SYSREAD (fp, fp->_IO_read_end,
241                        fp->_IO_buf_end - fp->_IO_read_end);
242   if (count <= 0)
243     {
244       if (count == 0 && naccbuf == 0)
245         fp->_flags |= _IO_EOF_SEEN;
246       else
247         fp->_flags |= _IO_ERR_SEEN, count = 0;
248     }
249   fp->_IO_read_end += count;
250   if (count == 0)
251     {
252       if (naccbuf != 0)
253         /* There are some bytes in the external buffer but they don't
254            convert to anything.  */
255         __set_errno (EILSEQ);
256       return WEOF;
257     }
258   if (fp->_offset != _IO_pos_BAD)
259     _IO_pos_adjust (fp->_offset, count);
260
261   /* Now convert the read input.  */
262   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
263   fp->_IO_read_base = fp->_IO_read_ptr;
264   const char *from = fp->_IO_read_ptr;
265   const char *to = fp->_IO_read_end;
266   size_t to_copy = count;
267   if (__builtin_expect (naccbuf != 0, 0))
268     {
269       to_copy = MIN (sizeof (accbuf) - naccbuf, count);
270       to = __mempcpy (&accbuf[naccbuf], from, to_copy);
271       naccbuf += to_copy;
272       from = accbuf;
273     }
274   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
275                                    from, to, &read_ptr_copy,
276                                    fp->_wide_data->_IO_read_end,
277                                    fp->_wide_data->_IO_buf_end,
278                                    &fp->_wide_data->_IO_read_end);
279
280   if (__builtin_expect (naccbuf != 0, 0))
281     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
282   else
283     fp->_IO_read_ptr = (char *) read_ptr_copy;
284   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
285     {
286       if (status == __codecvt_error)
287         {
288         out_eilseq:
289           __set_errno (EILSEQ);
290           fp->_flags |= _IO_ERR_SEEN;
291           return WEOF;
292         }
293
294       /* The read bytes make no complete character.  Try reading again.  */
295       assert (status == __codecvt_partial);
296
297       if (naccbuf == 0)
298         {
299           if (fp->_IO_read_base < fp->_IO_read_ptr)
300             {
301               /* Partially used the buffer for some input data that
302                  produces no output.  */
303               size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
304               memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
305               fp->_IO_read_ptr = fp->_IO_read_base;
306               fp->_IO_read_end -= avail;
307               goto again;
308             }
309           naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
310           if (naccbuf >= sizeof (accbuf))
311             goto out_eilseq;
312
313           memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
314         }
315       else
316         {
317           size_t used = read_ptr_copy - accbuf;
318           if (used > 0)
319             {
320               memmove (accbuf, read_ptr_copy, naccbuf - used);
321               naccbuf -= used;
322             }
323
324           if (naccbuf == sizeof (accbuf))
325             goto out_eilseq;
326         }
327
328       fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
329
330       goto again;
331     }
332
333   return *fp->_wide_data->_IO_read_ptr;
334 }
335 libc_hidden_def (_IO_wfile_underflow)
336
337
338 static wint_t
339 _IO_wfile_underflow_mmap (_IO_FILE *fp)
340 {
341   struct _IO_codecvt *cd;
342   const char *read_stop;
343
344   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
345     {
346       fp->_flags |= _IO_ERR_SEEN;
347       __set_errno (EBADF);
348       return WEOF;
349     }
350   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
351     return *fp->_wide_data->_IO_read_ptr;
352
353   cd = fp->_codecvt;
354
355   /* Maybe there is something left in the external buffer.  */
356   if (fp->_IO_read_ptr >= fp->_IO_read_end
357       /* No.  But maybe the read buffer is not fully set up.  */
358       && _IO_file_underflow_mmap (fp) == EOF)
359     /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
360        flags as appropriate.  */
361     return WEOF;
362
363   /* There is more in the external.  Convert it.  */
364   read_stop = (const char *) fp->_IO_read_ptr;
365
366   if (fp->_wide_data->_IO_buf_base == NULL)
367     {
368       /* Maybe we already have a push back pointer.  */
369       if (fp->_wide_data->_IO_save_base != NULL)
370         {
371           free (fp->_wide_data->_IO_save_base);
372           fp->_flags &= ~_IO_IN_BACKUP;
373         }
374       _IO_wdoallocbuf (fp);
375     }
376
377   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
378   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
379     fp->_wide_data->_IO_buf_base;
380   (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
381                           fp->_IO_read_ptr, fp->_IO_read_end,
382                           &read_stop,
383                           fp->_wide_data->_IO_read_ptr,
384                           fp->_wide_data->_IO_buf_end,
385                           &fp->_wide_data->_IO_read_end);
386
387   fp->_IO_read_ptr = (char *) read_stop;
388
389   /* If we managed to generate some text return the next character.  */
390   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
391     return *fp->_wide_data->_IO_read_ptr;
392
393   /* There is some garbage at the end of the file.  */
394   __set_errno (EILSEQ);
395   fp->_flags |= _IO_ERR_SEEN;
396   return WEOF;
397 }
398
399 static wint_t
400 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
401 {
402   /* This is the first read attempt.  Doing the underflow will choose mmap
403      or vanilla operations and then punt to the chosen underflow routine.
404      Then we can punt to ours.  */
405   if (_IO_file_underflow_maybe_mmap (fp) == EOF)
406     return WEOF;
407
408   return _IO_WUNDERFLOW (fp);
409 }
410
411
412 wint_t
413 _IO_wfile_overflow (f, wch)
414      _IO_FILE *f;
415      wint_t wch;
416 {
417   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
418     {
419       f->_flags |= _IO_ERR_SEEN;
420       __set_errno (EBADF);
421       return WEOF;
422     }
423   /* If currently reading or no buffer allocated. */
424   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
425     {
426       /* Allocate a buffer if needed. */
427       if (f->_wide_data->_IO_write_base == 0)
428         {
429           _IO_wdoallocbuf (f);
430           _IO_wsetg (f, f->_wide_data->_IO_buf_base,
431                      f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
432
433           if (f->_IO_write_base == NULL)
434             {
435               _IO_doallocbuf (f);
436               _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
437             }
438         }
439       else
440         {
441           /* Otherwise must be currently reading.  If _IO_read_ptr
442              (and hence also _IO_read_end) is at the buffer end,
443              logically slide the buffer forwards one block (by setting
444              the read pointers to all point at the beginning of the
445              block).  This makes room for subsequent output.
446              Otherwise, set the read pointers to _IO_read_end (leaving
447              that alone, so it can continue to correspond to the
448              external position). */
449           if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
450             {
451               f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
452               f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
453                 f->_wide_data->_IO_buf_base;
454             }
455         }
456       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
457       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
458       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
459       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
460         f->_wide_data->_IO_read_end;
461
462       f->_IO_write_ptr = f->_IO_read_ptr;
463       f->_IO_write_base = f->_IO_write_ptr;
464       f->_IO_write_end = f->_IO_buf_end;
465       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
466
467       f->_flags |= _IO_CURRENTLY_PUTTING;
468       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
469         f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
470     }
471   if (wch == WEOF)
472     return _IO_do_flush (f);
473   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
474     /* Buffer is really full */
475     if (_IO_do_flush (f) == EOF)
476       return WEOF;
477   *f->_wide_data->_IO_write_ptr++ = wch;
478   if ((f->_flags & _IO_UNBUFFERED)
479       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
480     if (_IO_do_flush (f) == EOF)
481       return WEOF;
482   return wch;
483 }
484 libc_hidden_def (_IO_wfile_overflow)
485
486 wint_t
487 _IO_wfile_sync (fp)
488      _IO_FILE *fp;
489 {
490   _IO_ssize_t delta;
491   wint_t retval = 0;
492
493   /*    char* ptr = cur_ptr(); */
494   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
495     if (_IO_do_flush (fp))
496       return WEOF;
497   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
498   if (delta != 0)
499     {
500       /* We have to find out how many bytes we have to go back in the
501          external buffer.  */
502       struct _IO_codecvt *cv = fp->_codecvt;
503       _IO_off64_t new_pos;
504
505       int clen = (*cv->__codecvt_do_encoding) (cv);
506
507       if (clen > 0)
508         /* It is easy, a fixed number of input bytes are used for each
509            wide character.  */
510         delta *= clen;
511       else
512         {
513           /* We have to find out the hard way how much to back off.
514              To do this we determine how much input we needed to
515              generate the wide characters up to the current reading
516              position.  */
517           int nread;
518
519           fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
520           nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
521                                               fp->_IO_read_base,
522                                               fp->_IO_read_end, delta);
523           fp->_IO_read_ptr = fp->_IO_read_base + nread;
524           delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
525         }
526
527       new_pos = _IO_SYSSEEK (fp, delta, 1);
528       if (new_pos != (_IO_off64_t) EOF)
529         {
530           fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
531           fp->_IO_read_end = fp->_IO_read_ptr;
532         }
533 #ifdef ESPIPE
534       else if (errno == ESPIPE)
535         ; /* Ignore error from unseekable devices. */
536 #endif
537       else
538         retval = WEOF;
539     }
540   if (retval != WEOF)
541     fp->_offset = _IO_pos_BAD;
542   /* FIXME: Cleanup - can this be shared? */
543   /*    setg(base(), ptr, ptr); */
544   return retval;
545 }
546 libc_hidden_def (_IO_wfile_sync)
547
548 /* Adjust the internal buffer pointers to reflect the state in the external
549    buffer.  The content between fp->_IO_read_base and fp->_IO_read_ptr is
550    assumed to be converted and available in the range
551    fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
552
553    Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set.  */
554 static int
555 adjust_wide_data (_IO_FILE *fp, bool do_convert)
556 {
557   struct _IO_codecvt *cv = fp->_codecvt;
558
559   int clen = (*cv->__codecvt_do_encoding) (cv);
560
561   /* Take the easy way out for constant length encodings if we don't need to
562      convert.  */
563   if (!do_convert && clen > 0)
564     {
565       fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
566                                        / clen);
567       goto done;
568     }
569
570   enum __codecvt_result status;
571   const char *read_stop = (const char *) fp->_IO_read_base;
572   do
573     {
574
575       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
576       status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
577                                        fp->_IO_read_base, fp->_IO_read_ptr,
578                                        &read_stop,
579                                        fp->_wide_data->_IO_read_base,
580                                        fp->_wide_data->_IO_buf_end,
581                                        &fp->_wide_data->_IO_read_end);
582
583       /* Should we return EILSEQ?  */
584       if (__builtin_expect (status == __codecvt_error, 0))
585         {
586           fp->_flags |= _IO_ERR_SEEN;
587           return -1;
588         }
589     }
590   while (__builtin_expect (status == __codecvt_partial, 0));
591
592 done:
593   /* Now seek to _IO_read_end to behave as if we have read it all in.  */
594   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
595
596   return 0;
597 }
598
599 _IO_off64_t
600 _IO_wfile_seekoff (fp, offset, dir, mode)
601      _IO_FILE *fp;
602      _IO_off64_t offset;
603      int dir;
604      int mode;
605 {
606   _IO_off64_t result;
607   _IO_off64_t delta, new_offset;
608   long int count;
609   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
610      offset of the underlying file must be exact.  */
611   int must_be_exact = ((fp->_wide_data->_IO_read_base
612                         == fp->_wide_data->_IO_read_end)
613                        && (fp->_wide_data->_IO_write_base
614                            == fp->_wide_data->_IO_write_ptr));
615
616   bool was_writing = ((fp->_wide_data->_IO_write_ptr
617                        > fp->_wide_data->_IO_write_base)
618                       || _IO_in_put_mode (fp));
619
620   if (mode == 0)
621     {
622       /* XXX For wide stream with backup store it is not very
623          reasonable to determine the offset.  The pushed-back
624          character might require a state change and we need not be
625          able to compute the initial state by reverse transformation
626          since there is no guarantee of symmetry.  So we don't even
627          try and return an error.  */
628       if (_IO_in_backup (fp))
629         {
630           if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
631             {
632               __set_errno (EINVAL);
633               return -1;
634             }
635
636           /* There is no more data in the backup buffer.  We can
637              switch back.  */
638           _IO_switch_to_main_wget_area (fp);
639         }
640
641       dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
642     }
643
644   /* Flush unwritten characters.
645      (This may do an unneeded write if we seek within the buffer.
646      But to be able to switch to reading, we would need to set
647      egptr to pptr.  That can't be done in the current design,
648      which assumes file_ptr() is eGptr.  Anyway, since we probably
649      end up flushing when we close(), it doesn't make much difference.)
650      FIXME: simulate mem-mapped files. */
651   else if (was_writing && _IO_switch_to_wget_mode (fp))
652     return WEOF;
653
654   if (fp->_wide_data->_IO_buf_base == NULL)
655     {
656       /* It could be that we already have a pushback buffer.  */
657       if (fp->_wide_data->_IO_read_base != NULL)
658         {
659           free (fp->_wide_data->_IO_read_base);
660           fp->_flags &= ~_IO_IN_BACKUP;
661         }
662       _IO_doallocbuf (fp);
663       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
664       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
665       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
666                  fp->_wide_data->_IO_buf_base);
667       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
668                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
669     }
670
671   switch (dir)
672     {
673       struct _IO_codecvt *cv;
674       int clen;
675
676     case _IO_seek_cur:
677       /* Adjust for read-ahead (bytes is buffer).  To do this we must
678          find out which position in the external buffer corresponds to
679          the current position in the internal buffer.  */
680       cv = fp->_codecvt;
681       clen = (*cv->__codecvt_do_encoding) (cv);
682
683       if (mode != 0 || !was_writing)
684         {
685           if (clen > 0)
686             {
687               offset -= (fp->_wide_data->_IO_read_end
688                          - fp->_wide_data->_IO_read_ptr) * clen;
689               /* Adjust by readahead in external buffer.  */
690               offset -= fp->_IO_read_end - fp->_IO_read_ptr;
691             }
692           else
693             {
694               int nread;
695
696             flushed:
697               delta = (fp->_wide_data->_IO_read_ptr
698                        - fp->_wide_data->_IO_read_base);
699               fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
700               nread = (*cv->__codecvt_do_length) (cv,
701                                                   &fp->_wide_data->_IO_state,
702                                                   fp->_IO_read_base,
703                                                   fp->_IO_read_end, delta);
704               fp->_IO_read_ptr = fp->_IO_read_base + nread;
705               fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
706               offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
707             }
708         }
709       else
710         {
711           char *new_write_ptr = fp->_IO_write_ptr;
712
713           if (clen > 0)
714             offset += (fp->_wide_data->_IO_write_ptr
715                        - fp->_wide_data->_IO_write_base) / clen;
716           else
717             {
718               enum __codecvt_result status;
719               delta = (fp->_wide_data->_IO_write_ptr
720                        - fp->_wide_data->_IO_write_base);
721               const wchar_t *write_base = fp->_wide_data->_IO_write_base;
722
723               /* FIXME: This actually ends up in two iterations of conversion,
724                  one here and the next when the buffer actually gets flushed.
725                  It may be possible to optimize this in future so that
726                  wdo_write identifies already converted content and does not
727                  redo it.  In any case, this is much better than having to
728                  flush buffers for every ftell.  */
729               do
730                 {
731                   /* Ugh, no point trying to avoid the flush.  Just do it
732                      and go back to how it was with the read mode.  */
733                   if (delta > 0 && new_write_ptr == fp->_IO_buf_end)
734                     {
735                       if (_IO_switch_to_wget_mode (fp))
736                         return WEOF;
737                       goto flushed;
738                     }
739
740                   const wchar_t *new_wbase = fp->_wide_data->_IO_write_base;
741                   fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
742                   status = (*cv->__codecvt_do_out) (cv,
743                                                     &fp->_wide_data->_IO_state,
744                                                     write_base,
745                                                     write_base + delta,
746                                                     &new_wbase,
747                                                     new_write_ptr,
748                                                     fp->_IO_buf_end,
749                                                     &new_write_ptr);
750
751                   delta -= new_wbase - write_base;
752
753                   /* If there was an error, then return WEOF.
754                      TODO: set buffer state.  */
755                   if (__builtin_expect (status == __codecvt_error, 0))
756                       return WEOF;
757                 }
758               while (delta > 0);
759             }
760
761           /* _IO_read_end coincides with fp._offset, so the actual file position
762              is fp._offset - (_IO_read_end - new_write_ptr).  This is fine
763              even if fp._offset is not set, since fp->_IO_read_end is then at
764              _IO_buf_base and this adjustment is for unbuffered output.  */
765           offset -= fp->_IO_read_end - new_write_ptr;
766         }
767
768       if (fp->_offset == _IO_pos_BAD)
769         {
770           if (mode != 0)
771             goto dumb;
772           else
773             {
774               result = _IO_SYSSEEK (fp, 0, dir);
775               if (result == EOF)
776                 return result;
777               fp->_offset = result;
778             }
779         }
780
781       /* Make offset absolute, assuming current pointer is file_ptr(). */
782       offset += fp->_offset;
783
784       dir = _IO_seek_set;
785       break;
786     case _IO_seek_set:
787       break;
788     case _IO_seek_end:
789       {
790         struct stat64 st;
791         if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
792           {
793             offset += st.st_size;
794             dir = _IO_seek_set;
795           }
796         else
797           goto dumb;
798       }
799     }
800   /* At this point, dir==_IO_seek_set. */
801
802   /* If we are only interested in the current position we've found it now.  */
803   if (mode == 0)
804     return offset;
805
806   /* If destination is within current buffer, optimize: */
807   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
808       && !_IO_in_backup (fp))
809     {
810       _IO_off64_t start_offset = (fp->_offset
811                                   - (fp->_IO_read_end - fp->_IO_buf_base));
812       if (offset >= start_offset && offset < fp->_offset)
813         {
814           _IO_setg (fp, fp->_IO_buf_base,
815                     fp->_IO_buf_base + (offset - start_offset),
816                     fp->_IO_read_end);
817           _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
818           _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
819                      fp->_wide_data->_IO_buf_base,
820                      fp->_wide_data->_IO_buf_base);
821           _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
822                      fp->_wide_data->_IO_buf_base);
823
824           if (adjust_wide_data (fp, false))
825             goto dumb;
826
827           _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
828           goto resync;
829         }
830     }
831
832   if (fp->_flags & _IO_NO_READS)
833     goto dumb;
834
835   /* Try to seek to a block boundary, to improve kernel page management. */
836   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
837   delta = offset - new_offset;
838   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
839     {
840       new_offset = offset;
841       delta = 0;
842     }
843   result = _IO_SYSSEEK (fp, new_offset, 0);
844   if (result < 0)
845     return EOF;
846   if (delta == 0)
847     count = 0;
848   else
849     {
850       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
851                            (must_be_exact
852                             ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
853       if (count < delta)
854         {
855           /* We weren't allowed to read, but try to seek the remainder. */
856           offset = count == EOF ? delta : delta-count;
857           dir = _IO_seek_cur;
858           goto dumb;
859         }
860     }
861   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
862             fp->_IO_buf_base + count);
863   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
864   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
865              fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
866   _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
867
868   if (adjust_wide_data (fp, true))
869     goto dumb;
870
871   fp->_offset = result + count;
872   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
873   return offset;
874  dumb:
875
876   _IO_unsave_markers (fp);
877   result = _IO_SYSSEEK (fp, offset, dir);
878   if (result != EOF)
879     {
880       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
881       fp->_offset = result;
882       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
883       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
884       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
885                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
886       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
887                  fp->_wide_data->_IO_buf_base);
888     }
889   return result;
890
891 resync:
892   /* We need to do it since it is possible that the file offset in
893      the kernel may be changed behind our back. It may happen when
894      we fopen a file and then do a fork. One process may access the
895      file and the kernel file offset will be changed. */
896   if (fp->_offset >= 0)
897     _IO_SYSSEEK (fp, fp->_offset, 0);
898
899   return offset;
900 }
901 libc_hidden_def (_IO_wfile_seekoff)
902
903
904 _IO_size_t
905 _IO_wfile_xsputn (f, data, n)
906      _IO_FILE *f;
907      const void *data;
908      _IO_size_t n;
909 {
910   const wchar_t *s = (const wchar_t *) data;
911   _IO_size_t to_do = n;
912   int must_flush = 0;
913   _IO_size_t count;
914
915   if (n <= 0)
916     return 0;
917   /* This is an optimized implementation.
918      If the amount to be written straddles a block boundary
919      (or the filebuf is unbuffered), use sys_write directly. */
920
921   /* First figure out how much space is available in the buffer. */
922   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
923   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
924     {
925       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
926       if (count >= n)
927         {
928           const wchar_t *p;
929           for (p = s + n; p > s; )
930             {
931               if (*--p == L'\n')
932                 {
933                   count = p - s + 1;
934                   must_flush = 1;
935                   break;
936                 }
937             }
938         }
939     }
940   /* Then fill the buffer. */
941   if (count > 0)
942     {
943       if (count > to_do)
944         count = to_do;
945       if (count > 20)
946         {
947 #ifdef _LIBC
948           f->_wide_data->_IO_write_ptr =
949             __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
950 #else
951           wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
952           f->_wide_data->_IO_write_ptr += count;
953 #endif
954           s += count;
955         }
956       else
957         {
958           wchar_t *p = f->_wide_data->_IO_write_ptr;
959           int i = (int) count;
960           while (--i >= 0)
961             *p++ = *s++;
962           f->_wide_data->_IO_write_ptr = p;
963         }
964       to_do -= count;
965     }
966   if (to_do > 0)
967     to_do -= _IO_wdefault_xsputn (f, s, to_do);
968   if (must_flush
969       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
970     _IO_wdo_write (f, f->_wide_data->_IO_write_base,
971                    f->_wide_data->_IO_write_ptr
972                    - f->_wide_data->_IO_write_base);
973
974   return n - to_do;
975 }
976 libc_hidden_def (_IO_wfile_xsputn)
977
978
979 const struct _IO_jump_t _IO_wfile_jumps =
980 {
981   JUMP_INIT_DUMMY,
982   JUMP_INIT(finish, _IO_new_file_finish),
983   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
984   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
985   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
986   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
987   JUMP_INIT(xsputn, _IO_wfile_xsputn),
988   JUMP_INIT(xsgetn, _IO_file_xsgetn),
989   JUMP_INIT(seekoff, _IO_wfile_seekoff),
990   JUMP_INIT(seekpos, _IO_default_seekpos),
991   JUMP_INIT(setbuf, _IO_new_file_setbuf),
992   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
993   JUMP_INIT(doallocate, _IO_wfile_doallocate),
994   JUMP_INIT(read, _IO_file_read),
995   JUMP_INIT(write, _IO_new_file_write),
996   JUMP_INIT(seek, _IO_file_seek),
997   JUMP_INIT(close, _IO_file_close),
998   JUMP_INIT(stat, _IO_file_stat),
999   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1000   JUMP_INIT(imbue, _IO_default_imbue)
1001 };
1002 libc_hidden_data_def (_IO_wfile_jumps)
1003
1004
1005 const struct _IO_jump_t _IO_wfile_jumps_mmap =
1006 {
1007   JUMP_INIT_DUMMY,
1008   JUMP_INIT(finish, _IO_new_file_finish),
1009   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1010   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
1011   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1012   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1013   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1014   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1015   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1016   JUMP_INIT(seekpos, _IO_default_seekpos),
1017   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1018   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1019   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1020   JUMP_INIT(read, _IO_file_read),
1021   JUMP_INIT(write, _IO_new_file_write),
1022   JUMP_INIT(seek, _IO_file_seek),
1023   JUMP_INIT(close, _IO_file_close_mmap),
1024   JUMP_INIT(stat, _IO_file_stat),
1025   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1026   JUMP_INIT(imbue, _IO_default_imbue)
1027 };
1028
1029 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
1030 {
1031   JUMP_INIT_DUMMY,
1032   JUMP_INIT(finish, _IO_new_file_finish),
1033   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1034   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1035   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1036   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1037   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1038   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1039   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1040   JUMP_INIT(seekpos, _IO_default_seekpos),
1041   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1042   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1043   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1044   JUMP_INIT(read, _IO_file_read),
1045   JUMP_INIT(write, _IO_new_file_write),
1046   JUMP_INIT(seek, _IO_file_seek),
1047   JUMP_INIT(close, _IO_file_close),
1048   JUMP_INIT(stat, _IO_file_stat),
1049   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1050   JUMP_INIT(imbue, _IO_default_imbue)
1051 };