1 /* Copyright (C) 1993, 95, 97, 98, 99, 2000 Free Software Foundation, Inc.
2    This file is part of the GNU IO Library.
3    Written by Ulrich Drepper <drepper@cygnus.com>.
4    Based on the single byte version by Per Bothner <bothner@cygnus.com>.
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License as
8    published by the Free Software Foundation; either version 2, or (at
9    your option) any later version.
10 
11    This library is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this library; see the file COPYING.  If not, write to
18    the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19    MA 02111-1307, USA.
20 
21    As a special exception, if you link this library with files
22    compiled with a GNU compiler to produce an executable, this does
23    not cause the resulting executable to be covered by the GNU General
24    Public License.  This exception does not however invalidate any
25    other reasons why the executable file might be covered by the GNU
26    General Public License.  */
27 
28 #include <assert.h>
29 #include <libioP.h>
30 #if defined(_GLIBCPP_USE_WCHAR_T) || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
31 #include <wchar.h>
32 #ifdef HAVE_GCONV_H
33 #  include <gconv.h>
34 #endif
35 #include <stdlib.h>
36 #include <string.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 _IO_FILE *
_IO_wfile_setbuf(fp,p,len)57 _IO_wfile_setbuf (fp, p, len)
58      _IO_FILE *fp;
59      wchar_t *p;
60      _IO_ssize_t len;
61 {
62   if (_IO_wdefault_setbuf (fp, p, len) == NULL)
63     return NULL;
64 
65   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
66     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
67   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
68 	     fp->_wide_data->_IO_buf_base);
69 
70   return fp;
71 }
72 
73 
74 /* Convert TO_DO wide character from DATA to FP.
75    Then mark FP as having empty buffers. */
76 int
_IO_wdo_write(fp,data,to_do)77 _IO_wdo_write (fp, data, to_do)
78      _IO_FILE *fp;
79      const wchar_t *data;
80      _IO_size_t to_do;
81 {
82   struct _IO_codecvt *cc = fp->_codecvt;
83 
84   if (to_do > 0)
85     {
86       if (fp->_IO_write_end == fp->_IO_write_ptr
87 	  && fp->_IO_write_end != fp->_IO_write_base)
88 	{
89 	  if (_IO_new_do_write (fp, fp->_IO_write_base,
90 				fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
91 	    return EOF;
92 	}
93 
94       do
95 	{
96 	  enum __codecvt_result result;
97 	  const wchar_t *new_data;
98 
99 	  /* Now convert from the internal format into the external buffer.  */
100 	  result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
101 					    data, data + to_do, &new_data,
102 					    fp->_IO_write_ptr,
103 					    fp->_IO_buf_end,
104 					    &fp->_IO_write_ptr);
105 
106 	  /* Write out what we produced so far.  */
107 	  if (_IO_new_do_write (fp, fp->_IO_write_base,
108 				fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
109 	    /* Something went wrong.  */
110 	    return EOF;
111 
112 	  to_do -= new_data - data;
113 
114 	  /* Next see whether we had problems during the conversion.  If yes,
115 	     we cannot go on.  */
116 	  if (result != __codecvt_ok
117 	      && (result != __codecvt_partial || new_data - data == 0))
118 	    break;
119 
120 	  data = new_data;
121 	}
122       while (to_do > 0);
123     }
124 
125   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
126 	     fp->_wide_data->_IO_buf_base);
127   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
128     = fp->_wide_data->_IO_buf_base;
129   fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
130 				   ? fp->_wide_data->_IO_buf_base
131 				   : fp->_wide_data->_IO_buf_end);
132 
133   return to_do == 0 ? 0 : WEOF;
134 }
135 
136 
137 wint_t
_IO_wfile_underflow(fp)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 (fp->_flags & _IO_NO_READS)
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       /* Convert it.  */
162       size_t avail_bytes = fp->_IO_read_end - fp->_IO_read_ptr;
163 
164       if (avail_bytes >= (*cd->__codecvt_do_max_length) (cd))
165 	{
166 	  /* There is more in the external.  */
167 	  const char *read_stop = (const char *) fp->_IO_read_ptr;
168 
169 	  fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
170 	  status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
171 					   fp->_IO_read_ptr, fp->_IO_read_end,
172 					   &read_stop,
173 					   fp->_wide_data->_IO_read_end,
174 					   fp->_wide_data->_IO_buf_end,
175 					   &fp->_wide_data->_IO_read_end);
176 
177 	  fp->_IO_read_ptr = (char *) read_stop;
178 
179 	  /* If we managed to generate some text return the next character.  */
180 	  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
181 	    return *fp->_wide_data->_IO_read_ptr;
182 
183 	  if (status == __codecvt_error)
184 	    {
185 	      __set_errno (EILSEQ);
186 	      fp->_flags |= _IO_ERR_SEEN;
187 	      return WEOF;
188 	    }
189 	}
190 
191       /* Move the remaining content of the read buffer to the beginning.  */
192       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
193 	       fp->_IO_read_end - fp->_IO_read_ptr);
194       fp->_IO_read_end = (fp->_IO_buf_base
195 			  + (fp->_IO_read_end - fp->_IO_read_ptr));
196       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
197     }
198   else
199     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
200       fp->_IO_buf_base;
201 
202   if (fp->_IO_buf_base == NULL)
203     {
204       /* Maybe we already have a push back pointer.  */
205       if (fp->_IO_save_base != NULL)
206 	{
207 	  free (fp->_IO_save_base);
208 	  fp->_flags &= ~_IO_IN_BACKUP;
209 	}
210       _IO_doallocbuf (fp);
211 
212       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
213 	fp->_IO_buf_base;
214     }
215 
216   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
217     fp->_IO_buf_base;
218 
219   if (fp->_wide_data->_IO_buf_base == NULL)
220     {
221       /* Maybe we already have a push back pointer.  */
222       if (fp->_wide_data->_IO_save_base != NULL)
223 	{
224 	  free (fp->_wide_data->_IO_save_base);
225 	  fp->_flags &= ~_IO_IN_BACKUP;
226 	}
227       _IO_wdoallocbuf (fp);
228     }
229 
230   /* Flush all line buffered files before reading. */
231   /* FIXME This can/should be moved to genops ?? */
232   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
233     _IO_flush_all_linebuffered ();
234 
235   _IO_switch_to_get_mode (fp);
236 
237   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
238     fp->_wide_data->_IO_buf_base;
239   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
240   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
241     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
242 
243   tries = 0;
244  again:
245   count = _IO_SYSREAD (fp, fp->_IO_read_end,
246 		       fp->_IO_buf_end - fp->_IO_read_end);
247   if (count <= 0)
248     {
249       if (count == 0 && tries == 0)
250 	fp->_flags |= _IO_EOF_SEEN;
251       else
252 	fp->_flags |= _IO_ERR_SEEN, count = 0;
253     }
254   fp->_IO_read_end += count;
255   if (count == 0)
256     {
257       if (tries != 0)
258 	/* There are some bytes in the external buffer but they don't
259            convert to anything.  */
260 	__set_errno (EILSEQ);
261       return WEOF;
262     }
263   if (fp->_offset != _IO_pos_BAD)
264     _IO_pos_adjust (fp->_offset, count);
265 
266   /* Now convert the read input.  */
267   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
268   fp->_IO_read_base = fp->_IO_read_ptr;
269   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
270 				   fp->_IO_read_ptr, fp->_IO_read_end,
271 				   &read_ptr_copy,
272 				   fp->_wide_data->_IO_read_end,
273 				   fp->_wide_data->_IO_buf_end,
274 				   &fp->_wide_data->_IO_read_end);
275 
276   fp->_IO_read_ptr = (char *) read_ptr_copy;
277   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
278     {
279       if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
280 	{
281 	  __set_errno (EILSEQ);
282 	  fp->_flags |= _IO_ERR_SEEN;
283 	  return WEOF;
284 	}
285 
286       /* The read bytes make no complete character.  Try reading again.  */
287       assert (status == __codecvt_partial);
288       ++tries;
289       goto again;
290     }
291 
292   return *fp->_wide_data->_IO_read_ptr;
293 }
294 
295 
296 wint_t
_IO_wfile_overflow(f,wch)297 _IO_wfile_overflow (f, wch)
298      _IO_FILE *f;
299      wint_t wch;
300 {
301   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
302     {
303       f->_flags |= _IO_ERR_SEEN;
304       __set_errno (EBADF);
305       return WEOF;
306     }
307   /* If currently reading or no buffer allocated. */
308   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
309     {
310       /* Allocate a buffer if needed. */
311       if (f->_wide_data->_IO_write_base == 0)
312 	{
313 	  _IO_wdoallocbuf (f);
314 	  _IO_wsetg (f, f->_wide_data->_IO_buf_base,
315 		     f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
316 
317 	  if (f->_IO_write_base == NULL)
318 	    {
319 	      _IO_doallocbuf (f);
320 	      _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
321 	    }
322 	}
323       else
324 	{
325 	  /* Otherwise must be currently reading.  If _IO_read_ptr
326 	     (and hence also _IO_read_end) is at the buffer end,
327 	     logically slide the buffer forwards one block (by setting
328 	     the read pointers to all point at the beginning of the
329 	     block).  This makes room for subsequent output.
330 	     Otherwise, set the read pointers to _IO_read_end (leaving
331 	     that alone, so it can continue to correspond to the
332 	     external position). */
333 	  if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
334 	    {
335 	      f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
336 	      f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
337 		f->_wide_data->_IO_buf_base;
338 	    }
339 	}
340       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
341       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
342       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
343       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
344 	f->_wide_data->_IO_read_end;
345 
346       f->_IO_write_ptr = f->_IO_read_ptr;
347       f->_IO_write_base = f->_IO_write_ptr;
348       f->_IO_write_end = f->_IO_buf_end;
349       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
350 
351       f->_flags |= _IO_CURRENTLY_PUTTING;
352       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
353 	f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
354     }
355   if (wch == WEOF)
356     return _IO_do_flush (f);
357   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
358     /* Buffer is really full */
359     if (_IO_do_flush (f) == WEOF)
360       return WEOF;
361   *f->_wide_data->_IO_write_ptr++ = wch;
362   if ((f->_flags & _IO_UNBUFFERED)
363       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
364     if (_IO_do_flush (f) == WEOF)
365       return WEOF;
366   return wch;
367 }
368 
369 wint_t
_IO_wfile_sync(fp)370 _IO_wfile_sync (fp)
371      _IO_FILE *fp;
372 {
373   _IO_ssize_t delta;
374   wint_t retval = 0;
375 
376   /*    char* ptr = cur_ptr(); */
377   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
378     if (_IO_do_flush (fp))
379       return WEOF;
380   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
381   if (delta != 0)
382     {
383       /* We have to find out how many bytes we have to go back in the
384 	 external buffer.  */
385       struct _IO_codecvt *cv = fp->_codecvt;
386       _IO_off64_t new_pos;
387 
388       int clen = (*cv->__codecvt_do_encoding) (cv);
389 
390       if (clen > 0)
391 	/* It is easy, a fixed number of input bytes are used for each
392 	   wide character.  */
393 	delta *= clen;
394       else
395 	{
396 	  /* We have to find out the hard way how much to back off.
397              To do this we determine how much input we needed to
398              generate the wide characters up to the current reading
399              position.  */
400 	  int nread;
401 
402 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
403 	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
404 					      fp->_IO_read_base,
405 					      fp->_IO_read_end, delta);
406 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
407 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
408 	}
409 
410       new_pos = _IO_SYSSEEK (fp, delta, 1);
411       if (new_pos != (_IO_off64_t) EOF)
412 	{
413 	  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
414 	  fp->_IO_read_end = fp->_IO_read_ptr;
415 	}
416 #ifdef ESPIPE
417       else if (errno == ESPIPE)
418 	; /* Ignore error from unseekable devices. */
419 #endif
420       else
421 	retval = WEOF;
422     }
423   if (retval != WEOF)
424     fp->_offset = _IO_pos_BAD;
425   /* FIXME: Cleanup - can this be shared? */
426   /*    setg(base(), ptr, ptr); */
427   return retval;
428 }
429 
430 _IO_off64_t
_IO_wfile_seekoff(fp,offset,dir,mode)431 _IO_wfile_seekoff (fp, offset, dir, mode)
432      _IO_FILE *fp;
433      _IO_off64_t offset;
434      int dir;
435      int mode;
436 {
437   _IO_off64_t result;
438   _IO_off64_t delta, new_offset;
439   long int count;
440   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
441      offset of the underlying file must be exact.  */
442   int must_be_exact = ((fp->_wide_data->_IO_read_base
443 			== fp->_wide_data->_IO_read_end)
444 		       && (fp->_wide_data->_IO_write_base
445 			   == fp->_wide_data->_IO_write_ptr));
446 
447   if (mode == 0)
448     dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
449 
450   /* Flush unwritten characters.
451      (This may do an unneeded write if we seek within the buffer.
452      But to be able to switch to reading, we would need to set
453      egptr to ptr.  That can't be done in the current design,
454      which assumes file_ptr() is eGptr.  Anyway, since we probably
455      end up flushing when we close(), it doesn't make much difference.)
456      FIXME: simulate mem-papped files. */
457 
458   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
459       || _IO_in_put_mode (fp))
460     if (_IO_switch_to_wget_mode (fp))
461       return WEOF;
462 
463   if (fp->_wide_data->_IO_buf_base == NULL)
464     {
465       /* It could be that we already have a pushback buffer.  */
466       if (fp->_wide_data->_IO_read_base != NULL)
467 	{
468 	  free (fp->_wide_data->_IO_read_base);
469 	  fp->_flags &= ~_IO_IN_BACKUP;
470 	}
471       _IO_doallocbuf (fp);
472       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
473       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
474       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
475 		 fp->_wide_data->_IO_buf_base);
476       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
477 		 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
478     }
479 
480   switch (dir)
481     {
482       struct _IO_codecvt *cv;
483       int clen;
484 
485     case _IO_seek_cur:
486       /* Adjust for read-ahead (bytes is buffer).  To do this we must
487          find out which position in the external buffer corresponds to
488          the current position in the internal buffer.  */
489       cv = fp->_codecvt;
490       clen = (*cv->__codecvt_do_encoding) (cv);
491 
492       if (clen > 0)
493 	offset -= (fp->_wide_data->_IO_read_end
494 		   - fp->_wide_data->_IO_read_ptr) * clen;
495       else
496 	{
497 	  int nread;
498 
499 	  delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
500 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
501 	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
502 					      fp->_IO_read_base,
503 					      fp->_IO_read_end, delta);
504 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
505 	  offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
506 	}
507 
508       if (fp->_offset == _IO_pos_BAD)
509 	goto dumb;
510       /* Make offset absolute, assuming current pointer is file_ptr(). */
511       offset += fp->_offset;
512 
513       dir = _IO_seek_set;
514       break;
515     case _IO_seek_set:
516       break;
517     case _IO_seek_end:
518       {
519 	struct _G_stat64 st;
520 	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
521 	  {
522 	    offset += st.st_size;
523 	    dir = _IO_seek_set;
524 	  }
525 	else
526 	  goto dumb;
527       }
528     }
529   /* At this point, dir==_IO_seek_set. */
530 
531   /* If we are only interested in the current position we've found it now.  */
532   if (mode == 0)
533     return offset;
534 
535   /* If destination is within current buffer, optimize: */
536   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
537       && !_IO_in_backup (fp))
538     {
539       /* Offset relative to start of main get area. */
540       _IO_off64_t rel_offset = (offset - fp->_offset
541 				+ (fp->_IO_read_end - fp->_IO_read_base));
542       if (rel_offset >= 0)
543 	{
544 #if 0
545 	  if (_IO_in_backup (fp))
546 	    _IO_switch_to_main_get_area (fp);
547 #endif
548 	  if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
549 	    {
550 	      fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
551 	      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
552 
553 	      /* Now set the pointer for the internal buffer.  This
554                  might be an iterative process.  Though the read
555                  pointer is somewhere in the current external buffer
556                  this does not mean we can convert this whole buffer
557                  at once fitting in the internal buffer.  */
558 	      do
559 		{
560 
561 		}
562 	      while (0);
563 
564 	      _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
565 	      goto resync;
566 	    }
567 #ifdef TODO
568 	    /* If we have streammarkers, seek forward by reading ahead. */
569 	    if (_IO_have_markers (fp))
570 	      {
571 		int to_skip = rel_offset
572 		  - (fp->_IO_read_ptr - fp->_IO_read_base);
573 		if (ignore (to_skip) != to_skip)
574 		  goto dumb;
575 		_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
576 		goto resync;
577 	      }
578 #endif
579 	}
580 #ifdef TODO
581       if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
582 	{
583 	  if (!_IO_in_backup (fp))
584 	    _IO_switch_to_backup_area (fp);
585 	  gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
586 	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
587 	  goto resync;
588 	}
589 #endif
590     }
591 
592 #ifdef TODO
593   _IO_unsave_markers (fp);
594 #endif
595 
596   if (fp->_flags & _IO_NO_READS)
597     goto dumb;
598 
599   /* Try to seek to a block boundary, to improve kernel page management. */
600   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
601   delta = offset - new_offset;
602   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
603     {
604       new_offset = offset;
605       delta = 0;
606     }
607   result = _IO_SYSSEEK (fp, new_offset, 0);
608   if (result < 0)
609     return EOF;
610   if (delta == 0)
611     count = 0;
612   else
613     {
614       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
615 			   (must_be_exact
616 			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
617       if (count < delta)
618 	{
619 	  /* We weren't allowed to read, but try to seek the remainder. */
620 	  offset = count == EOF ? delta : delta-count;
621 	  dir = _IO_seek_cur;
622 	  goto dumb;
623 	}
624     }
625   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
626 	    fp->_IO_buf_base + count);
627   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
628   fp->_offset = result + count;
629   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
630   return offset;
631  dumb:
632 
633   _IO_unsave_markers (fp);
634   result = _IO_SYSSEEK (fp, offset, dir);
635   if (result != EOF)
636     {
637       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
638       fp->_offset = result;
639       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
640       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
641     }
642   return result;
643 
644 resync:
645   /* We need to do it since it is possible that the file offset in
646      the kernel may be changed behind our back. It may happen when
647      we fopen a file and then do a fork. One process may access the
648      the file and the kernel file offset will be changed. */
649   if (fp->_offset >= 0)
650     _IO_SYSSEEK (fp, fp->_offset, 0);
651 
652   return offset;
653 }
654 
655 
656 _IO_size_t
_IO_wfile_xsputn(f,data,n)657 _IO_wfile_xsputn (f, data, n)
658      _IO_FILE *f;
659      const void *data;
660      _IO_size_t n;
661 {
662   register const wchar_t *s = (const wchar_t *) data;
663   _IO_size_t to_do = n;
664   int must_flush = 0;
665   _IO_size_t count;
666 
667   if (n <= 0)
668     return 0;
669   /* This is an optimized implementation.
670      If the amount to be written straddles a block boundary
671      (or the filebuf is unbuffered), use sys_write directly. */
672 
673   /* First figure out how much space is available in the buffer. */
674   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
675   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
676     {
677       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
678       if (count >= n)
679 	{
680 	  register const wchar_t *p;
681 	  for (p = s + n; p > s; )
682 	    {
683 	      if (*--p == L'\n')
684 		{
685 		  count = p - s + 1;
686 		  must_flush = 1;
687 		  break;
688 		}
689 	    }
690 	}
691     }
692   /* Then fill the buffer. */
693   if (count > 0)
694     {
695       if (count > to_do)
696 	count = to_do;
697       if (count > 20)
698 	{
699 #ifdef _LIBC
700 	  f->_wide_data->_IO_write_ptr =
701 	    __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
702 #else
703 	  wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
704 	  f->_wide_data->_IO_write_ptr += count;
705 #endif
706 	  s += count;
707 	}
708       else
709 	{
710 	  register wchar_t *p = f->_wide_data->_IO_write_ptr;
711 	  register int i = (int) count;
712 	  while (--i >= 0)
713 	    *p++ = *s++;
714 	  f->_wide_data->_IO_write_ptr = p;
715 	}
716       to_do -= count;
717     }
718   if (to_do > 0)
719     to_do -= _IO_wdefault_xsputn (f, s, to_do);
720   if (must_flush
721       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
722     _IO_wdo_write (f, f->_wide_data->_IO_write_base,
723 		   f->_wide_data->_IO_write_ptr
724 		   - f->_wide_data->_IO_write_base);
725 
726   return n - to_do;
727 }
728 
729 
730 struct _IO_jump_t _IO_wfile_jumps =
731 {
732   JUMP_INIT_DUMMY,
733   JUMP_INIT(finish, _IO_new_file_finish),
734   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
735   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
736   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
737   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
738   JUMP_INIT(xsputn, _IO_wfile_xsputn),
739   JUMP_INIT(xsgetn, _IO_file_xsgetn),
740   JUMP_INIT(seekoff, _IO_wfile_seekoff),
741   JUMP_INIT(seekpos, _IO_default_seekpos),
742   JUMP_INIT(setbuf, _IO_new_file_setbuf),
743   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
744   JUMP_INIT(doallocate, _IO_wfile_doallocate),
745   JUMP_INIT(read, _IO_file_read),
746   JUMP_INIT(write, _IO_new_file_write),
747   JUMP_INIT(seek, _IO_file_seek),
748   JUMP_INIT(close, _IO_file_close),
749   JUMP_INIT(stat, _IO_file_stat),
750   JUMP_INIT(showmanyc, _IO_default_showmanyc),
751   JUMP_INIT(imbue, _IO_default_imbue)
752 };
753 
754 #endif /* _GLIBCPP_USE_WCHAR_T */
755