Update.
[glibc.git] / libio / wfileops.c
blob45c9120f3426ca17c1a2136a2b3349fe70af9e09
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 _IO_FILE *
37 _IO_wfile_setbuf (fp, p, len)
38 _IO_FILE *fp;
39 wchar_t *p;
40 _IO_ssize_t len;
42 if (_IO_wdefault_setbuf (fp, p, len) == NULL)
43 return NULL;
45 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
46 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
47 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
48 fp->_wide_data->_IO_buf_base);
50 return fp;
54 /* Convert TO_DO wide character from DATA to FP.
55 Then mark FP as having empty buffers. */
56 int
57 _IO_wdo_write (fp, data, to_do)
58 _IO_FILE *fp;
59 const wchar_t *data;
60 _IO_size_t to_do;
62 struct _IO_codecvt *cc = &fp->_wide_data->_codecvt;
64 if (to_do > 0)
66 if (fp->_IO_write_end == fp->_IO_write_ptr
67 && fp->_IO_write_end != fp->_IO_write_base)
69 if (_IO_new_do_write (fp, fp->_IO_write_base,
70 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
71 return EOF;
76 enum __codecvt_result result;
77 const wchar_t *new_data;
79 /* Now convert from the internal format into the external buffer. */
80 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
81 data, data + to_do, &new_data,
82 fp->_IO_write_ptr,
83 fp->_IO_buf_end,
84 &fp->_IO_write_ptr);
86 /* Write out what we produced so far. */
87 if (_IO_new_do_write (fp, fp->_IO_write_base,
88 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
89 /* Something went wrong. */
90 return EOF;
92 to_do -= new_data - data;
94 /* Next see whether we had problems during the conversion. If yes,
95 we cannot go on. */
96 if (result != __codecvt_ok
97 && (result != __codecvt_partial || new_data - data == 0))
98 break;
100 data = new_data;
102 while (to_do > 0);
105 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
106 fp->_wide_data->_IO_buf_base);
107 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
108 = fp->_wide_data->_IO_buf_base;
109 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
110 ? fp->_wide_data->_IO_buf_base
111 : fp->_wide_data->_IO_buf_end);
113 return to_do == 0 ? 0 : WEOF;
117 wint_t
118 _IO_wfile_underflow (fp)
119 _IO_FILE *fp;
121 struct _IO_codecvt *cd;
122 enum __codecvt_result status;
123 _IO_ssize_t count;
124 int tries;
125 const char *read_ptr_copy;
127 if (fp->_flags & _IO_NO_READS)
129 fp->_flags |= _IO_ERR_SEEN;
130 __set_errno (EBADF);
131 return WEOF;
133 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
134 return *fp->_wide_data->_IO_read_ptr;
136 cd = &fp->_wide_data->_codecvt;
138 /* Maybe there is something left in the external buffer. */
139 if (fp->_IO_read_ptr < fp->_IO_read_end)
141 /* Convert it. */
142 size_t avail_bytes = fp->_IO_read_end - fp->_IO_read_ptr;
144 if (avail_bytes >= (*cd->__codecvt_do_max_length) (cd))
146 /* There is more in the external. */
147 const char *read_stop = (const char *) fp->_IO_read_ptr;
149 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
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_end,
154 fp->_wide_data->_IO_buf_end,
155 &fp->_wide_data->_IO_read_end);
157 fp->_IO_read_ptr = (char *) read_stop;
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;
163 if (status == __codecvt_error)
165 __set_errno (EILSEQ);
166 fp->_flags |= _IO_ERR_SEEN;
167 return WEOF;
171 /* Move the remaining content of the read buffer to the beginning. */
172 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
173 fp->_IO_read_end - fp->_IO_read_ptr);
174 fp->_IO_read_end = (fp->_IO_buf_base
175 + (fp->_IO_read_end - fp->_IO_read_ptr));
176 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
178 else
179 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
180 fp->_IO_buf_base;
182 if (fp->_IO_buf_base == NULL)
184 /* Maybe we already have a push back pointer. */
185 if (fp->_IO_save_base != NULL)
187 free (fp->_IO_save_base);
188 fp->_flags &= ~_IO_IN_BACKUP;
190 _IO_doallocbuf (fp);
192 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
193 fp->_IO_buf_base;
196 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
197 fp->_IO_buf_base;
199 if (fp->_wide_data->_IO_buf_base == NULL)
201 /* Maybe we already have a push back pointer. */
202 if (fp->_wide_data->_IO_save_base != NULL)
204 free (fp->_wide_data->_IO_save_base);
205 fp->_flags &= ~_IO_IN_BACKUP;
207 _IO_wdoallocbuf (fp);
210 /* Flush all line buffered files before reading. */
211 /* FIXME This can/should be moved to genops ?? */
212 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
213 _IO_flush_all_linebuffered ();
215 _IO_switch_to_get_mode (fp);
217 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
218 fp->_wide_data->_IO_buf_base;
219 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
220 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
221 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
223 tries = 0;
224 again:
225 count = _IO_SYSREAD (fp, fp->_IO_read_end,
226 fp->_IO_buf_end - fp->_IO_read_end);
227 if (count <= 0)
229 if (count == 0 && tries == 0)
230 fp->_flags |= _IO_EOF_SEEN;
231 else
232 fp->_flags |= _IO_ERR_SEEN, count = 0;
234 fp->_IO_read_end += count;
235 if (count == 0)
237 if (tries != 0)
238 /* There are some bytes in the external buffer but they don't
239 convert to anything. */
240 __set_errno (EILSEQ);
241 return WEOF;
243 if (fp->_offset != _IO_pos_BAD)
244 _IO_pos_adjust (fp->_offset, count);
246 /* Now convert the read input. */
247 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
248 fp->_IO_read_base = fp->_IO_read_ptr;
249 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
250 fp->_IO_read_ptr, fp->_IO_read_end,
251 &read_ptr_copy,
252 fp->_wide_data->_IO_read_end,
253 fp->_wide_data->_IO_buf_end,
254 &fp->_wide_data->_IO_read_end);
256 fp->_IO_read_ptr = (char *) read_ptr_copy;
257 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
259 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
261 __set_errno (EILSEQ);
262 fp->_flags |= _IO_ERR_SEEN;
263 return WEOF;
266 /* The read bytes make no complete character. Try reading again. */
267 assert (status == __codecvt_partial);
268 ++tries;
269 goto again;
272 return *fp->_wide_data->_IO_read_ptr;
276 wint_t
277 _IO_wfile_overflow (f, wch)
278 _IO_FILE *f;
279 wint_t wch;
281 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
283 f->_flags |= _IO_ERR_SEEN;
284 __set_errno (EBADF);
285 return WEOF;
287 /* If currently reading or no buffer allocated. */
288 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
290 /* Allocate a buffer if needed. */
291 if (f->_wide_data->_IO_write_base == 0)
293 _IO_wdoallocbuf (f);
294 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
295 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
297 if (f->_IO_write_base == NULL)
299 _IO_doallocbuf (f);
300 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
303 else
305 /* Otherwise must be currently reading. If _IO_read_ptr
306 (and hence also _IO_read_end) is at the buffer end,
307 logically slide the buffer forwards one block (by setting
308 the read pointers to all point at the beginning of the
309 block). This makes room for subsequent output.
310 Otherwise, set the read pointers to _IO_read_end (leaving
311 that alone, so it can continue to correspond to the
312 external position). */
313 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
315 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
316 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
317 f->_wide_data->_IO_buf_base;
320 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
321 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
322 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
323 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
324 f->_wide_data->_IO_read_end;
326 f->_IO_write_ptr = f->_IO_read_ptr;
327 f->_IO_write_base = f->_IO_write_ptr;
328 f->_IO_write_end = f->_IO_buf_end;
329 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
331 f->_flags |= _IO_CURRENTLY_PUTTING;
332 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
333 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
335 if (wch == WEOF)
336 return _IO_do_flush (f);
337 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
338 /* Buffer is really full */
339 if (_IO_do_flush (f) == WEOF)
340 return WEOF;
341 *f->_wide_data->_IO_write_ptr++ = wch;
342 if ((f->_flags & _IO_UNBUFFERED)
343 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
344 if (_IO_do_flush (f) == WEOF)
345 return WEOF;
346 return wch;
349 wint_t
350 _IO_wfile_sync (fp)
351 _IO_FILE *fp;
353 _IO_ssize_t delta;
354 wint_t retval = 0;
356 /* char* ptr = cur_ptr(); */
357 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
358 if (_IO_do_flush (fp))
359 return WEOF;
360 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
361 if (delta != 0)
363 /* We have to find out how many bytes we have to go back in the
364 external buffer. */
365 struct _IO_codecvt *cv = &fp->_wide_data->_codecvt;
366 _IO_off64_t new_pos;
368 int clen = (*cv->__codecvt_do_encoding) (cv);
370 if (clen > 0)
371 /* It is easy, a fixed number of input bytes are used for each
372 wide character. */
373 delta *= clen;
374 else
376 /* We have to find out the hard way how much to back off.
377 To do this we determine how much input we needed to
378 generate the wide characters up to the current reading
379 position. */
380 int nread;
382 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
383 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
384 fp->_IO_read_base,
385 fp->_IO_read_end, delta);
386 fp->_IO_read_ptr = fp->_IO_read_base + nread;
387 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
390 new_pos = _IO_SYSSEEK (fp, delta, 1);
391 if (new_pos != (_IO_off64_t) EOF)
393 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
394 fp->_IO_read_end = fp->_IO_read_ptr;
396 #ifdef ESPIPE
397 else if (errno == ESPIPE)
398 ; /* Ignore error from unseekable devices. */
399 #endif
400 else
401 retval = WEOF;
403 if (retval != WEOF)
404 fp->_offset = _IO_pos_BAD;
405 /* FIXME: Cleanup - can this be shared? */
406 /* setg(base(), ptr, ptr); */
407 return retval;
410 _IO_off64_t
411 _IO_wfile_seekoff (fp, offset, dir, mode)
412 _IO_FILE *fp;
413 _IO_off64_t offset;
414 int dir;
415 int mode;
417 _IO_off64_t result;
418 _IO_off64_t delta, new_offset;
419 long int count;
420 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
421 offset of the underlying file must be exact. */
422 int must_be_exact = ((fp->_wide_data->_IO_read_base
423 == fp->_wide_data->_IO_read_end)
424 && (fp->_wide_data->_IO_write_base
425 == fp->_wide_data->_IO_write_ptr));
427 if (mode == 0)
428 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
430 /* Flush unwritten characters.
431 (This may do an unneeded write if we seek within the buffer.
432 But to be able to switch to reading, we would need to set
433 egptr to ptr. That can't be done in the current design,
434 which assumes file_ptr() is eGptr. Anyway, since we probably
435 end up flushing when we close(), it doesn't make much difference.)
436 FIXME: simulate mem-papped files. */
438 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
439 || _IO_in_put_mode (fp))
440 if (_IO_switch_to_wget_mode (fp))
441 return WEOF;
443 if (fp->_wide_data->_IO_buf_base == NULL)
445 /* It could be that we already have a pushback buffer. */
446 if (fp->_wide_data->_IO_read_base != NULL)
448 free (fp->_wide_data->_IO_read_base);
449 fp->_flags &= ~_IO_IN_BACKUP;
451 _IO_doallocbuf (fp);
452 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
453 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
454 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
455 fp->_wide_data->_IO_buf_base);
456 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
457 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
460 switch (dir)
462 struct _IO_codecvt *cv;
463 int clen;
465 case _IO_seek_cur:
466 /* Adjust for read-ahead (bytes is buffer). To do this we must
467 find out which position in the external buffer corresponds to
468 the current position in the internal buffer. */
469 cv = &fp->_wide_data->_codecvt;
470 clen = (*cv->__codecvt_do_encoding) (cv);
472 if (clen > 0)
473 offset -= (fp->_wide_data->_IO_read_end
474 - fp->_wide_data->_IO_read_ptr) * clen;
475 else
477 int nread;
479 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
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 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
488 if (fp->_offset == _IO_pos_BAD)
489 goto dumb;
490 /* Make offset absolute, assuming current pointer is file_ptr(). */
491 offset += fp->_offset;
493 dir = _IO_seek_set;
494 break;
495 case _IO_seek_set:
496 break;
497 case _IO_seek_end:
499 struct _G_stat64 st;
500 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
502 offset += st.st_size;
503 dir = _IO_seek_set;
505 else
506 goto dumb;
509 /* At this point, dir==_IO_seek_set. */
511 /* If we are only interested in the current position we've found it now. */
512 if (mode == 0)
513 return offset;
515 /* If destination is within current buffer, optimize: */
516 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
517 && !_IO_in_backup (fp))
519 /* Offset relative to start of main get area. */
520 _IO_off64_t rel_offset = (offset - fp->_offset
521 + (fp->_IO_read_end - fp->_IO_read_base));
522 if (rel_offset >= 0)
524 #if 0
525 if (_IO_in_backup (fp))
526 _IO_switch_to_main_get_area (fp);
527 #endif
528 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
530 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
531 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
533 /* Now set the pointer for the internal buffer. This
534 might be an iterative process. Though the read
535 pointer is somewhere in the current external buffer
536 this does not mean we can convert this whole buffer
537 at once fitting in the internal buffer. */
542 while (0);
544 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
545 goto resync;
547 #ifdef TODO
548 /* If we have streammarkers, seek forward by reading ahead. */
549 if (_IO_have_markers (fp))
551 int to_skip = rel_offset
552 - (fp->_IO_read_ptr - fp->_IO_read_base);
553 if (ignore (to_skip) != to_skip)
554 goto dumb;
555 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
556 goto resync;
558 #endif
560 #ifdef TODO
561 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
563 if (!_IO_in_backup (fp))
564 _IO_switch_to_backup_area (fp);
565 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
566 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
567 goto resync;
569 #endif
572 #ifdef TODO
573 _IO_unsave_markers (fp);
574 #endif
576 if (fp->_flags & _IO_NO_READS)
577 goto dumb;
579 /* Try to seek to a block boundary, to improve kernel page management. */
580 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
581 delta = offset - new_offset;
582 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
584 new_offset = offset;
585 delta = 0;
587 result = _IO_SYSSEEK (fp, new_offset, 0);
588 if (result < 0)
589 return EOF;
590 if (delta == 0)
591 count = 0;
592 else
594 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
595 (must_be_exact
596 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
597 if (count < delta)
599 /* We weren't allowed to read, but try to seek the remainder. */
600 offset = count == EOF ? delta : delta-count;
601 dir = _IO_seek_cur;
602 goto dumb;
605 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
606 fp->_IO_buf_base + count);
607 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
608 fp->_offset = result + count;
609 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
610 return offset;
611 dumb:
613 _IO_unsave_markers (fp);
614 result = _IO_SYSSEEK (fp, offset, dir);
615 if (result != EOF)
617 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
618 fp->_offset = result;
619 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
620 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
622 return result;
624 resync:
625 /* We need to do it since it is possible that the file offset in
626 the kernel may be changed behind our back. It may happen when
627 we fopen a file and then do a fork. One process may access the
628 the file and the kernel file offset will be changed. */
629 if (fp->_offset >= 0)
630 _IO_SYSSEEK (fp, fp->_offset, 0);
632 return offset;
636 _IO_size_t
637 _IO_wfile_xsputn (f, data, n)
638 _IO_FILE *f;
639 const void *data;
640 _IO_size_t n;
642 register const wchar_t *s = (const wchar_t *) data;
643 _IO_size_t to_do = n;
644 int must_flush = 0;
645 _IO_size_t count;
647 if (n <= 0)
648 return 0;
649 /* This is an optimized implementation.
650 If the amount to be written straddles a block boundary
651 (or the filebuf is unbuffered), use sys_write directly. */
653 /* First figure out how much space is available in the buffer. */
654 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
655 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
657 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
658 if (count >= n)
660 register const wchar_t *p;
661 for (p = s + n; p > s; )
663 if (*--p == L'\n')
665 count = p - s + 1;
666 must_flush = 1;
667 break;
672 /* Then fill the buffer. */
673 if (count > 0)
675 if (count > to_do)
676 count = to_do;
677 if (count > 20)
679 #ifdef _LIBC
680 f->_wide_data->_IO_write_ptr =
681 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
682 #else
683 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
684 f->_wide_data->_IO_write_ptr += count;
685 #endif
686 s += count;
688 else
690 register wchar_t *p = f->_wide_data->_IO_write_ptr;
691 register int i = (int) count;
692 while (--i >= 0)
693 *p++ = *s++;
694 f->_wide_data->_IO_write_ptr = p;
696 to_do -= count;
698 if (to_do > 0)
699 to_do -= _IO_wdefault_xsputn (f, s, to_do);
700 if (must_flush
701 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
702 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
703 f->_wide_data->_IO_write_ptr
704 - f->_wide_data->_IO_write_base);
706 return n - to_do;
710 struct _IO_jump_t _IO_wfile_jumps =
712 JUMP_INIT_DUMMY,
713 JUMP_INIT(finish, _IO_new_file_finish),
714 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
715 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
716 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
717 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
718 JUMP_INIT(xsputn, _IO_wfile_xsputn),
719 JUMP_INIT(xsgetn, _IO_file_xsgetn),
720 JUMP_INIT(seekoff, _IO_wfile_seekoff),
721 JUMP_INIT(seekpos, _IO_default_seekpos),
722 JUMP_INIT(setbuf, _IO_new_file_setbuf),
723 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
724 JUMP_INIT(doallocate, _IO_wfile_doallocate),
725 JUMP_INIT(read, _IO_file_read),
726 JUMP_INIT(write, _IO_new_file_write),
727 JUMP_INIT(seek, _IO_file_seek),
728 JUMP_INIT(close, _IO_file_close),
729 JUMP_INIT(stat, _IO_file_stat),
730 JUMP_INIT(showmanyc, _IO_default_showmanyc),
731 JUMP_INIT(imbue, _IO_default_imbue)