Use 'a' operand code for prefetch instruction.
[official-gcc.git] / libstdc++-v3 / libio / wfileops.c
blob1dd524a3ffb25d3c0aa438ed6b779743cbb17f2b
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>.
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.
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.
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.
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. */
28 #include <assert.h>
29 #include <libioP.h>
30 #ifdef _GLIBCPP_USE_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>
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
56 _IO_FILE *
57 _IO_wfile_setbuf (fp, p, len)
58 _IO_FILE *fp;
59 wchar_t *p;
60 _IO_ssize_t len;
62 if (_IO_wdefault_setbuf (fp, p, len) == NULL)
63 return NULL;
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);
70 return fp;
74 /* Convert TO_DO wide character from DATA to FP.
75 Then mark FP as having empty buffers. */
76 int
77 _IO_wdo_write (fp, data, to_do)
78 _IO_FILE *fp;
79 const wchar_t *data;
80 _IO_size_t to_do;
82 struct _IO_codecvt *cc = fp->_codecvt;
84 if (to_do > 0)
86 if (fp->_IO_write_end == fp->_IO_write_ptr
87 && fp->_IO_write_end != fp->_IO_write_base)
89 if (_IO_new_do_write (fp, fp->_IO_write_base,
90 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
91 return EOF;
96 enum __codecvt_result result;
97 const wchar_t *new_data;
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);
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;
112 to_do -= new_data - data;
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;
120 data = new_data;
122 while (to_do > 0);
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);
133 return to_do == 0 ? 0 : WEOF;
137 wint_t
138 _IO_wfile_underflow (fp)
139 _IO_FILE *fp;
141 struct _IO_codecvt *cd;
142 enum __codecvt_result status;
143 _IO_ssize_t count;
144 int tries;
145 const char *read_ptr_copy;
147 if (fp->_flags & _IO_NO_READS)
149 fp->_flags |= _IO_ERR_SEEN;
150 __set_errno (EBADF);
151 return WEOF;
153 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
154 return *fp->_wide_data->_IO_read_ptr;
156 cd = fp->_codecvt;
158 /* Maybe there is something left in the external buffer. */
159 if (fp->_IO_read_ptr < fp->_IO_read_end)
161 /* Convert it. */
162 size_t avail_bytes = fp->_IO_read_end - fp->_IO_read_ptr;
164 if (avail_bytes >= (*cd->__codecvt_do_max_length) (cd))
166 /* There is more in the external. */
167 const char *read_stop = (const char *) fp->_IO_read_ptr;
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);
177 fp->_IO_read_ptr = (char *) read_stop;
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;
183 if (status == __codecvt_error)
185 __set_errno (EILSEQ);
186 fp->_flags |= _IO_ERR_SEEN;
187 return WEOF;
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;
198 else
199 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
200 fp->_IO_buf_base;
202 if (fp->_IO_buf_base == NULL)
204 /* Maybe we already have a push back pointer. */
205 if (fp->_IO_save_base != NULL)
207 free (fp->_IO_save_base);
208 fp->_flags &= ~_IO_IN_BACKUP;
210 _IO_doallocbuf (fp);
212 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
213 fp->_IO_buf_base;
216 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
217 fp->_IO_buf_base;
219 if (fp->_wide_data->_IO_buf_base == NULL)
221 /* Maybe we already have a push back pointer. */
222 if (fp->_wide_data->_IO_save_base != NULL)
224 free (fp->_wide_data->_IO_save_base);
225 fp->_flags &= ~_IO_IN_BACKUP;
227 _IO_wdoallocbuf (fp);
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 ();
235 _IO_switch_to_get_mode (fp);
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;
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)
249 if (count == 0 && tries == 0)
250 fp->_flags |= _IO_EOF_SEEN;
251 else
252 fp->_flags |= _IO_ERR_SEEN, count = 0;
254 fp->_IO_read_end += count;
255 if (count == 0)
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;
263 if (fp->_offset != _IO_pos_BAD)
264 _IO_pos_adjust (fp->_offset, count);
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);
276 fp->_IO_read_ptr = (char *) read_ptr_copy;
277 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
279 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
281 __set_errno (EILSEQ);
282 fp->_flags |= _IO_ERR_SEEN;
283 return WEOF;
286 /* The read bytes make no complete character. Try reading again. */
287 assert (status == __codecvt_partial);
288 ++tries;
289 goto again;
292 return *fp->_wide_data->_IO_read_ptr;
296 wint_t
297 _IO_wfile_overflow (f, wch)
298 _IO_FILE *f;
299 wint_t wch;
301 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
303 f->_flags |= _IO_ERR_SEEN;
304 __set_errno (EBADF);
305 return WEOF;
307 /* If currently reading or no buffer allocated. */
308 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
310 /* Allocate a buffer if needed. */
311 if (f->_wide_data->_IO_write_base == 0)
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);
317 if (f->_IO_write_base == NULL)
319 _IO_doallocbuf (f);
320 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
323 else
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)
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;
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;
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;
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;
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;
369 wint_t
370 _IO_wfile_sync (fp)
371 _IO_FILE *fp;
373 _IO_ssize_t delta;
374 wint_t retval = 0;
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)
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;
388 int clen = (*cv->__codecvt_do_encoding) (cv);
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
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;
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);
410 new_pos = _IO_SYSSEEK (fp, delta, 1);
411 if (new_pos != (_IO_off64_t) EOF)
413 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
414 fp->_IO_read_end = fp->_IO_read_ptr;
416 #ifdef ESPIPE
417 else if (errno == ESPIPE)
418 ; /* Ignore error from unseekable devices. */
419 #endif
420 else
421 retval = WEOF;
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;
430 _IO_off64_t
431 _IO_wfile_seekoff (fp, offset, dir, mode)
432 _IO_FILE *fp;
433 _IO_off64_t offset;
434 int dir;
435 int mode;
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));
447 if (mode == 0)
448 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
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. */
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;
463 if (fp->_wide_data->_IO_buf_base == NULL)
465 /* It could be that we already have a pushback buffer. */
466 if (fp->_wide_data->_IO_read_base != NULL)
468 free (fp->_wide_data->_IO_read_base);
469 fp->_flags &= ~_IO_IN_BACKUP;
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);
480 switch (dir)
482 struct _IO_codecvt *cv;
483 int clen;
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);
492 if (clen > 0)
493 offset -= (fp->_wide_data->_IO_read_end
494 - fp->_wide_data->_IO_read_ptr) * clen;
495 else
497 int nread;
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;
508 if (fp->_offset == _IO_pos_BAD)
509 goto dumb;
510 /* Make offset absolute, assuming current pointer is file_ptr(). */
511 offset += fp->_offset;
513 dir = _IO_seek_set;
514 break;
515 case _IO_seek_set:
516 break;
517 case _IO_seek_end:
519 struct _G_stat64 st;
520 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
522 offset += st.st_size;
523 dir = _IO_seek_set;
525 else
526 goto dumb;
529 /* At this point, dir==_IO_seek_set. */
531 /* If we are only interested in the current position we've found it now. */
532 if (mode == 0)
533 return offset;
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))
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)
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)
550 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
551 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
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. */
562 while (0);
564 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
565 goto resync;
567 #ifdef TODO
568 /* If we have streammarkers, seek forward by reading ahead. */
569 if (_IO_have_markers (fp))
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;
578 #endif
580 #ifdef TODO
581 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
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;
589 #endif
592 #ifdef TODO
593 _IO_unsave_markers (fp);
594 #endif
596 if (fp->_flags & _IO_NO_READS)
597 goto dumb;
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)
604 new_offset = offset;
605 delta = 0;
607 result = _IO_SYSSEEK (fp, new_offset, 0);
608 if (result < 0)
609 return EOF;
610 if (delta == 0)
611 count = 0;
612 else
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)
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;
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:
633 _IO_unsave_markers (fp);
634 result = _IO_SYSSEEK (fp, offset, dir);
635 if (result != EOF)
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);
642 return result;
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);
652 return offset;
656 _IO_size_t
657 _IO_wfile_xsputn (f, data, n)
658 _IO_FILE *f;
659 const void *data;
660 _IO_size_t n;
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;
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. */
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))
677 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
678 if (count >= n)
680 register const wchar_t *p;
681 for (p = s + n; p > s; )
683 if (*--p == L'\n')
685 count = p - s + 1;
686 must_flush = 1;
687 break;
692 /* Then fill the buffer. */
693 if (count > 0)
695 if (count > to_do)
696 count = to_do;
697 if (count > 20)
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;
708 else
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;
716 to_do -= count;
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);
726 return n - to_do;
730 struct _IO_jump_t _IO_wfile_jumps =
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)
754 #endif /* _GLIBCPP_USE_WCHAR_T */