* sysdeps/m68k/fpu/libm-test-ulps: Update.
[glibc.git] / libio / wfileops.c
blobf12cb22a7dfecf2229d96d435b17486659a817a5
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 #include <wchar.h>
31 #include <gconv.h>
32 #include <stdlib.h>
33 #include <string.h>
36 #ifndef _LIBC
37 # define _IO_new_do_write _IO_do_write
38 # define _IO_new_file_attach _IO_file_attach
39 # define _IO_new_file_close_it _IO_file_close_it
40 # define _IO_new_file_finish _IO_file_finish
41 # define _IO_new_file_fopen _IO_file_fopen
42 # define _IO_new_file_init _IO_file_init
43 # define _IO_new_file_setbuf _IO_file_setbuf
44 # define _IO_new_file_sync _IO_file_sync
45 # define _IO_new_file_overflow _IO_file_overflow
46 # define _IO_new_file_seekoff _IO_file_seekoff
47 # define _IO_new_file_underflow _IO_file_underflow
48 # define _IO_new_file_write _IO_file_write
49 # define _IO_new_file_xsputn _IO_file_xsputn
50 #endif
53 _IO_FILE *
54 _IO_wfile_setbuf (fp, p, len)
55 _IO_FILE *fp;
56 wchar_t *p;
57 _IO_ssize_t len;
59 if (_IO_wdefault_setbuf (fp, p, len) == NULL)
60 return NULL;
62 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
63 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
64 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
65 fp->_wide_data->_IO_buf_base);
67 return fp;
71 /* Convert TO_DO wide character from DATA to FP.
72 Then mark FP as having empty buffers. */
73 int
74 _IO_wdo_write (fp, data, to_do)
75 _IO_FILE *fp;
76 const wchar_t *data;
77 _IO_size_t to_do;
79 struct _IO_codecvt *cc = fp->_codecvt;
81 if (to_do > 0)
83 if (fp->_IO_write_end == fp->_IO_write_ptr
84 && fp->_IO_write_end != fp->_IO_write_base)
86 if (_IO_new_do_write (fp, fp->_IO_write_base,
87 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
88 return EOF;
93 enum __codecvt_result result;
94 const wchar_t *new_data;
96 /* Now convert from the internal format into the external buffer. */
97 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
98 data, data + to_do, &new_data,
99 fp->_IO_write_ptr,
100 fp->_IO_buf_end,
101 &fp->_IO_write_ptr);
103 /* Write out what we produced so far. */
104 if (_IO_new_do_write (fp, fp->_IO_write_base,
105 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
106 /* Something went wrong. */
107 return EOF;
109 to_do -= new_data - data;
111 /* Next see whether we had problems during the conversion. If yes,
112 we cannot go on. */
113 if (result != __codecvt_ok
114 && (result != __codecvt_partial || new_data - data == 0))
115 break;
117 data = new_data;
119 while (to_do > 0);
122 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
123 fp->_wide_data->_IO_buf_base);
124 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
125 = fp->_wide_data->_IO_buf_base;
126 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
127 ? fp->_wide_data->_IO_buf_base
128 : fp->_wide_data->_IO_buf_end);
130 return to_do == 0 ? 0 : WEOF;
134 wint_t
135 _IO_wfile_underflow (fp)
136 _IO_FILE *fp;
138 struct _IO_codecvt *cd;
139 enum __codecvt_result status;
140 _IO_ssize_t count;
141 int tries;
142 const char *read_ptr_copy;
144 if (fp->_flags & _IO_NO_READS)
146 fp->_flags |= _IO_ERR_SEEN;
147 __set_errno (EBADF);
148 return WEOF;
150 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
151 return *fp->_wide_data->_IO_read_ptr;
153 cd = fp->_codecvt;
155 /* Maybe there is something left in the external buffer. */
156 if (fp->_IO_read_ptr < fp->_IO_read_end)
158 /* Convert it. */
159 size_t avail_bytes = fp->_IO_read_end - fp->_IO_read_ptr;
161 if (avail_bytes >= (*cd->__codecvt_do_max_length) (cd))
163 /* There is more in the external. */
164 const char *read_stop = (const char *) fp->_IO_read_ptr;
166 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
167 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
168 fp->_IO_read_ptr, fp->_IO_read_end,
169 &read_stop,
170 fp->_wide_data->_IO_read_end,
171 fp->_wide_data->_IO_buf_end,
172 &fp->_wide_data->_IO_read_end);
174 fp->_IO_read_ptr = (char *) read_stop;
176 /* If we managed to generate some text return the next character. */
177 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
178 return *fp->_wide_data->_IO_read_ptr;
180 if (status == __codecvt_error)
182 __set_errno (EILSEQ);
183 fp->_flags |= _IO_ERR_SEEN;
184 return WEOF;
188 /* Move the remaining content of the read buffer to the beginning. */
189 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
190 fp->_IO_read_end - fp->_IO_read_ptr);
191 fp->_IO_read_end = (fp->_IO_buf_base
192 + (fp->_IO_read_end - fp->_IO_read_ptr));
193 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
195 else
196 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
197 fp->_IO_buf_base;
199 if (fp->_IO_buf_base == NULL)
201 /* Maybe we already have a push back pointer. */
202 if (fp->_IO_save_base != NULL)
204 free (fp->_IO_save_base);
205 fp->_flags &= ~_IO_IN_BACKUP;
207 _IO_doallocbuf (fp);
209 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
210 fp->_IO_buf_base;
213 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
214 fp->_IO_buf_base;
216 if (fp->_wide_data->_IO_buf_base == NULL)
218 /* Maybe we already have a push back pointer. */
219 if (fp->_wide_data->_IO_save_base != NULL)
221 free (fp->_wide_data->_IO_save_base);
222 fp->_flags &= ~_IO_IN_BACKUP;
224 _IO_wdoallocbuf (fp);
227 /* Flush all line buffered files before reading. */
228 /* FIXME This can/should be moved to genops ?? */
229 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
230 _IO_flush_all_linebuffered ();
232 _IO_switch_to_get_mode (fp);
234 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
235 fp->_wide_data->_IO_buf_base;
236 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
237 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
238 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
240 tries = 0;
241 again:
242 count = _IO_SYSREAD (fp, fp->_IO_read_end,
243 fp->_IO_buf_end - fp->_IO_read_end);
244 if (count <= 0)
246 if (count == 0 && tries == 0)
247 fp->_flags |= _IO_EOF_SEEN;
248 else
249 fp->_flags |= _IO_ERR_SEEN, count = 0;
251 fp->_IO_read_end += count;
252 if (count == 0)
254 if (tries != 0)
255 /* There are some bytes in the external buffer but they don't
256 convert to anything. */
257 __set_errno (EILSEQ);
258 return WEOF;
260 if (fp->_offset != _IO_pos_BAD)
261 _IO_pos_adjust (fp->_offset, count);
263 /* Now convert the read input. */
264 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
265 fp->_IO_read_base = fp->_IO_read_ptr;
266 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
267 fp->_IO_read_ptr, fp->_IO_read_end,
268 &read_ptr_copy,
269 fp->_wide_data->_IO_read_end,
270 fp->_wide_data->_IO_buf_end,
271 &fp->_wide_data->_IO_read_end);
273 fp->_IO_read_ptr = (char *) read_ptr_copy;
274 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
276 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
278 __set_errno (EILSEQ);
279 fp->_flags |= _IO_ERR_SEEN;
280 return WEOF;
283 /* The read bytes make no complete character. Try reading again. */
284 assert (status == __codecvt_partial);
285 ++tries;
286 goto again;
289 return *fp->_wide_data->_IO_read_ptr;
293 wint_t
294 _IO_wfile_overflow (f, wch)
295 _IO_FILE *f;
296 wint_t wch;
298 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
300 f->_flags |= _IO_ERR_SEEN;
301 __set_errno (EBADF);
302 return WEOF;
304 /* If currently reading or no buffer allocated. */
305 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
307 /* Allocate a buffer if needed. */
308 if (f->_wide_data->_IO_write_base == 0)
310 _IO_wdoallocbuf (f);
311 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
312 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
314 if (f->_IO_write_base == NULL)
316 _IO_doallocbuf (f);
317 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
320 else
322 /* Otherwise must be currently reading. If _IO_read_ptr
323 (and hence also _IO_read_end) is at the buffer end,
324 logically slide the buffer forwards one block (by setting
325 the read pointers to all point at the beginning of the
326 block). This makes room for subsequent output.
327 Otherwise, set the read pointers to _IO_read_end (leaving
328 that alone, so it can continue to correspond to the
329 external position). */
330 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
332 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
333 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
334 f->_wide_data->_IO_buf_base;
337 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
338 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
339 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
340 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
341 f->_wide_data->_IO_read_end;
343 f->_IO_write_ptr = f->_IO_read_ptr;
344 f->_IO_write_base = f->_IO_write_ptr;
345 f->_IO_write_end = f->_IO_buf_end;
346 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
348 f->_flags |= _IO_CURRENTLY_PUTTING;
349 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
350 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
352 if (wch == WEOF)
353 return _IO_do_flush (f);
354 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
355 /* Buffer is really full */
356 if (_IO_do_flush (f) == WEOF)
357 return WEOF;
358 *f->_wide_data->_IO_write_ptr++ = wch;
359 if ((f->_flags & _IO_UNBUFFERED)
360 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
361 if (_IO_do_flush (f) == WEOF)
362 return WEOF;
363 return wch;
366 wint_t
367 _IO_wfile_sync (fp)
368 _IO_FILE *fp;
370 _IO_ssize_t delta;
371 wint_t retval = 0;
373 /* char* ptr = cur_ptr(); */
374 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
375 if (_IO_do_flush (fp))
376 return WEOF;
377 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
378 if (delta != 0)
380 /* We have to find out how many bytes we have to go back in the
381 external buffer. */
382 struct _IO_codecvt *cv = fp->_codecvt;
383 _IO_off64_t new_pos;
385 int clen = (*cv->__codecvt_do_encoding) (cv);
387 if (clen > 0)
388 /* It is easy, a fixed number of input bytes are used for each
389 wide character. */
390 delta *= clen;
391 else
393 /* We have to find out the hard way how much to back off.
394 To do this we determine how much input we needed to
395 generate the wide characters up to the current reading
396 position. */
397 int nread;
399 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
400 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
401 fp->_IO_read_base,
402 fp->_IO_read_end, delta);
403 fp->_IO_read_ptr = fp->_IO_read_base + nread;
404 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
407 new_pos = _IO_SYSSEEK (fp, delta, 1);
408 if (new_pos != (_IO_off64_t) EOF)
410 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
411 fp->_IO_read_end = fp->_IO_read_ptr;
413 #ifdef ESPIPE
414 else if (errno == ESPIPE)
415 ; /* Ignore error from unseekable devices. */
416 #endif
417 else
418 retval = WEOF;
420 if (retval != WEOF)
421 fp->_offset = _IO_pos_BAD;
422 /* FIXME: Cleanup - can this be shared? */
423 /* setg(base(), ptr, ptr); */
424 return retval;
427 _IO_off64_t
428 _IO_wfile_seekoff (fp, offset, dir, mode)
429 _IO_FILE *fp;
430 _IO_off64_t offset;
431 int dir;
432 int mode;
434 _IO_off64_t result;
435 _IO_off64_t delta, new_offset;
436 long int count;
437 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
438 offset of the underlying file must be exact. */
439 int must_be_exact = ((fp->_wide_data->_IO_read_base
440 == fp->_wide_data->_IO_read_end)
441 && (fp->_wide_data->_IO_write_base
442 == fp->_wide_data->_IO_write_ptr));
444 if (mode == 0)
445 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
447 /* Flush unwritten characters.
448 (This may do an unneeded write if we seek within the buffer.
449 But to be able to switch to reading, we would need to set
450 egptr to ptr. That can't be done in the current design,
451 which assumes file_ptr() is eGptr. Anyway, since we probably
452 end up flushing when we close(), it doesn't make much difference.)
453 FIXME: simulate mem-papped files. */
455 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
456 || _IO_in_put_mode (fp))
457 if (_IO_switch_to_wget_mode (fp))
458 return WEOF;
460 if (fp->_wide_data->_IO_buf_base == NULL)
462 /* It could be that we already have a pushback buffer. */
463 if (fp->_wide_data->_IO_read_base != NULL)
465 free (fp->_wide_data->_IO_read_base);
466 fp->_flags &= ~_IO_IN_BACKUP;
468 _IO_doallocbuf (fp);
469 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
470 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
471 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
472 fp->_wide_data->_IO_buf_base);
473 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
474 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
477 switch (dir)
479 struct _IO_codecvt *cv;
480 int clen;
482 case _IO_seek_cur:
483 /* Adjust for read-ahead (bytes is buffer). To do this we must
484 find out which position in the external buffer corresponds to
485 the current position in the internal buffer. */
486 cv = fp->_codecvt;
487 clen = (*cv->__codecvt_do_encoding) (cv);
489 if (clen > 0)
490 offset -= (fp->_wide_data->_IO_read_end
491 - fp->_wide_data->_IO_read_ptr) * clen;
492 else
494 int nread;
496 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
497 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
498 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
499 fp->_IO_read_base,
500 fp->_IO_read_end, delta);
501 fp->_IO_read_ptr = fp->_IO_read_base + nread;
502 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
505 if (fp->_offset == _IO_pos_BAD)
506 goto dumb;
507 /* Make offset absolute, assuming current pointer is file_ptr(). */
508 offset += fp->_offset;
510 dir = _IO_seek_set;
511 break;
512 case _IO_seek_set:
513 break;
514 case _IO_seek_end:
516 struct _G_stat64 st;
517 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
519 offset += st.st_size;
520 dir = _IO_seek_set;
522 else
523 goto dumb;
526 /* At this point, dir==_IO_seek_set. */
528 /* If we are only interested in the current position we've found it now. */
529 if (mode == 0)
530 return offset;
532 /* If destination is within current buffer, optimize: */
533 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
534 && !_IO_in_backup (fp))
536 /* Offset relative to start of main get area. */
537 _IO_off64_t rel_offset = (offset - fp->_offset
538 + (fp->_IO_read_end - fp->_IO_read_base));
539 if (rel_offset >= 0)
541 #if 0
542 if (_IO_in_backup (fp))
543 _IO_switch_to_main_get_area (fp);
544 #endif
545 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
547 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
548 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
550 /* Now set the pointer for the internal buffer. This
551 might be an iterative process. Though the read
552 pointer is somewhere in the current external buffer
553 this does not mean we can convert this whole buffer
554 at once fitting in the internal buffer. */
559 while (0);
561 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
562 goto resync;
564 #ifdef TODO
565 /* If we have streammarkers, seek forward by reading ahead. */
566 if (_IO_have_markers (fp))
568 int to_skip = rel_offset
569 - (fp->_IO_read_ptr - fp->_IO_read_base);
570 if (ignore (to_skip) != to_skip)
571 goto dumb;
572 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
573 goto resync;
575 #endif
577 #ifdef TODO
578 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
580 if (!_IO_in_backup (fp))
581 _IO_switch_to_backup_area (fp);
582 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
583 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
584 goto resync;
586 #endif
589 #ifdef TODO
590 _IO_unsave_markers (fp);
591 #endif
593 if (fp->_flags & _IO_NO_READS)
594 goto dumb;
596 /* Try to seek to a block boundary, to improve kernel page management. */
597 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
598 delta = offset - new_offset;
599 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
601 new_offset = offset;
602 delta = 0;
604 result = _IO_SYSSEEK (fp, new_offset, 0);
605 if (result < 0)
606 return EOF;
607 if (delta == 0)
608 count = 0;
609 else
611 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
612 (must_be_exact
613 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
614 if (count < delta)
616 /* We weren't allowed to read, but try to seek the remainder. */
617 offset = count == EOF ? delta : delta-count;
618 dir = _IO_seek_cur;
619 goto dumb;
622 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
623 fp->_IO_buf_base + count);
624 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
625 fp->_offset = result + count;
626 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
627 return offset;
628 dumb:
630 _IO_unsave_markers (fp);
631 result = _IO_SYSSEEK (fp, offset, dir);
632 if (result != EOF)
634 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
635 fp->_offset = result;
636 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
637 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
639 return result;
641 resync:
642 /* We need to do it since it is possible that the file offset in
643 the kernel may be changed behind our back. It may happen when
644 we fopen a file and then do a fork. One process may access the
645 the file and the kernel file offset will be changed. */
646 if (fp->_offset >= 0)
647 _IO_SYSSEEK (fp, fp->_offset, 0);
649 return offset;
653 _IO_size_t
654 _IO_wfile_xsputn (f, data, n)
655 _IO_FILE *f;
656 const void *data;
657 _IO_size_t n;
659 register const wchar_t *s = (const wchar_t *) data;
660 _IO_size_t to_do = n;
661 int must_flush = 0;
662 _IO_size_t count;
664 if (n <= 0)
665 return 0;
666 /* This is an optimized implementation.
667 If the amount to be written straddles a block boundary
668 (or the filebuf is unbuffered), use sys_write directly. */
670 /* First figure out how much space is available in the buffer. */
671 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
672 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
674 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
675 if (count >= n)
677 register const wchar_t *p;
678 for (p = s + n; p > s; )
680 if (*--p == L'\n')
682 count = p - s + 1;
683 must_flush = 1;
684 break;
689 /* Then fill the buffer. */
690 if (count > 0)
692 if (count > to_do)
693 count = to_do;
694 if (count > 20)
696 #ifdef _LIBC
697 f->_wide_data->_IO_write_ptr =
698 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
699 #else
700 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
701 f->_wide_data->_IO_write_ptr += count;
702 #endif
703 s += count;
705 else
707 register wchar_t *p = f->_wide_data->_IO_write_ptr;
708 register int i = (int) count;
709 while (--i >= 0)
710 *p++ = *s++;
711 f->_wide_data->_IO_write_ptr = p;
713 to_do -= count;
715 if (to_do > 0)
716 to_do -= _IO_wdefault_xsputn (f, s, to_do);
717 if (must_flush
718 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
719 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
720 f->_wide_data->_IO_write_ptr
721 - f->_wide_data->_IO_write_base);
723 return n - to_do;
727 struct _IO_jump_t _IO_wfile_jumps =
729 JUMP_INIT_DUMMY,
730 JUMP_INIT(finish, _IO_new_file_finish),
731 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
732 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
733 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
734 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
735 JUMP_INIT(xsputn, _IO_wfile_xsputn),
736 JUMP_INIT(xsgetn, _IO_file_xsgetn),
737 JUMP_INIT(seekoff, _IO_wfile_seekoff),
738 JUMP_INIT(seekpos, _IO_default_seekpos),
739 JUMP_INIT(setbuf, _IO_new_file_setbuf),
740 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
741 JUMP_INIT(doallocate, _IO_wfile_doallocate),
742 JUMP_INIT(read, _IO_file_read),
743 JUMP_INIT(write, _IO_new_file_write),
744 JUMP_INIT(seek, _IO_file_seek),
745 JUMP_INIT(close, _IO_file_close),
746 JUMP_INIT(stat, _IO_file_stat),
747 JUMP_INIT(showmanyc, _IO_default_showmanyc),
748 JUMP_INIT(imbue, _IO_default_imbue)