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