1 /* Copyright (C) 1993,1995,1997-2002,2004,2006,2012
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Written by Ulrich Drepper <drepper@cygnus.com>.
5 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>.
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. */
30 /* Generic or default I/O operations. */
39 # define __wmemcpy(dst, src, n) wmemcpy (dst, src, n)
43 static int save_for_wbackup (_IO_FILE
*fp
, wchar_t *end_p
) __THROW
49 /* Return minimum _pos markers
50 Assumes the current get area is the main get area. */
51 _IO_ssize_t
_IO_least_wmarker (_IO_FILE
*fp
, wchar_t *end_p
) __THROW
;
54 _IO_least_wmarker (fp
, end_p
)
58 _IO_ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
59 struct _IO_marker
*mark
;
60 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
61 if (mark
->_pos
< least_so_far
)
62 least_so_far
= mark
->_pos
;
65 INTDEF(_IO_least_wmarker
)
67 /* Switch current get area from backup buffer to (start of) main get area. */
69 _IO_switch_to_main_wget_area (fp
)
73 fp
->_flags
&= ~_IO_IN_BACKUP
;
74 /* Swap _IO_read_end and _IO_save_end. */
75 tmp
= fp
->_wide_data
->_IO_read_end
;
76 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
77 fp
->_wide_data
->_IO_save_end
= tmp
;
78 /* Swap _IO_read_base and _IO_save_base. */
79 tmp
= fp
->_wide_data
->_IO_read_base
;
80 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
81 fp
->_wide_data
->_IO_save_base
= tmp
;
82 /* Set _IO_read_ptr. */
83 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
85 INTDEF(_IO_switch_to_main_wget_area
)
88 /* Switch current get area from main get area to (end of) backup area. */
90 _IO_switch_to_wbackup_area (fp
)
94 fp
->_flags
|= _IO_IN_BACKUP
;
95 /* Swap _IO_read_end and _IO_save_end. */
96 tmp
= fp
->_wide_data
->_IO_read_end
;
97 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
98 fp
->_wide_data
->_IO_save_end
= tmp
;
99 /* Swap _IO_read_base and _IO_save_base. */
100 tmp
= fp
->_wide_data
->_IO_read_base
;
101 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
102 fp
->_wide_data
->_IO_save_base
= tmp
;
103 /* Set _IO_read_ptr. */
104 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
106 INTDEF(_IO_switch_to_wbackup_area
)
110 _IO_wsetb (f
, b
, eb
, a
)
116 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags2
& _IO_FLAGS2_USER_WBUF
))
117 FREE_BUF (f
->_wide_data
->_IO_buf_base
, _IO_wblen (f
) * sizeof (wchar_t));
118 f
->_wide_data
->_IO_buf_base
= b
;
119 f
->_wide_data
->_IO_buf_end
= eb
;
121 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
123 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
129 _IO_wdefault_pbackfail (fp
, c
)
133 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
134 && !_IO_in_backup (fp
)
135 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
139 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
140 if (!_IO_in_backup (fp
))
142 /* We need to keep the invariant that the main get area
143 logically follows the backup area. */
144 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
145 && _IO_have_wbackup (fp
))
147 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
150 else if (!_IO_have_wbackup (fp
))
152 /* No backup buffer: allocate one. */
153 /* Use nshort buffer, if unused? (probably not) FIXME */
154 int backup_size
= 128;
155 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
159 fp
->_wide_data
->_IO_save_base
= bbuf
;
160 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
162 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
164 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
165 INTUSE(_IO_switch_to_wbackup_area
) (fp
);
167 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
169 /* Increase size of existing backup buffer. */
171 _IO_size_t old_size
= (fp
->_wide_data
->_IO_read_end
172 - fp
->_wide_data
->_IO_read_base
);
174 new_size
= 2 * old_size
;
175 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
178 __wmemcpy (new_buf
+ (new_size
- old_size
),
179 fp
->_wide_data
->_IO_read_base
, old_size
);
180 free (fp
->_wide_data
->_IO_read_base
);
181 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
183 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
186 *--fp
->_wide_data
->_IO_read_ptr
= c
;
190 INTDEF(_IO_wdefault_pbackfail
)
194 _IO_wdefault_finish (fp
, dummy
)
198 struct _IO_marker
*mark
;
199 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
201 FREE_BUF (fp
->_wide_data
->_IO_buf_base
,
202 _IO_wblen (fp
) * sizeof (wchar_t));
203 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
206 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
209 if (fp
->_IO_save_base
)
211 free (fp
->_wide_data
->_IO_save_base
);
212 fp
->_IO_save_base
= NULL
;
216 if (fp
->_lock
!= NULL
)
217 _IO_lock_fini (*fp
->_lock
);
220 INTUSE(_IO_un_link
) ((struct _IO_FILE_plus
*) fp
);
222 INTDEF(_IO_wdefault_finish
)
226 _IO_wdefault_uflow (fp
)
230 wch
= _IO_UNDERFLOW (fp
);
233 return *fp
->_wide_data
->_IO_read_ptr
++;
235 INTDEF(_IO_wdefault_uflow
)
245 return _IO_OVERFLOW (f
, wch
);
247 libc_hidden_def (__woverflow
)
254 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
259 if (_IO_in_put_mode (fp
))
260 if (INTUSE(_IO_switch_to_wget_mode
) (fp
) == EOF
)
262 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
263 return *fp
->_wide_data
->_IO_read_ptr
++;
264 if (_IO_in_backup (fp
))
266 INTUSE(_IO_switch_to_main_wget_area
) (fp
);
267 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
268 return *fp
->_wide_data
->_IO_read_ptr
++;
270 if (_IO_have_markers (fp
))
272 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
275 else if (_IO_have_wbackup (fp
))
276 INTUSE(_IO_free_wbackup_area
) (fp
);
277 return _IO_UFLOW (fp
);
279 libc_hidden_def (__wuflow
)
285 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
290 if (_IO_in_put_mode (fp
))
291 if (INTUSE(_IO_switch_to_wget_mode
) (fp
) == EOF
)
293 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
294 return *fp
->_wide_data
->_IO_read_ptr
;
295 if (_IO_in_backup (fp
))
297 INTUSE(_IO_switch_to_main_wget_area
) (fp
);
298 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
299 return *fp
->_wide_data
->_IO_read_ptr
;
301 if (_IO_have_markers (fp
))
303 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
306 else if (_IO_have_backup (fp
))
307 INTUSE(_IO_free_wbackup_area
) (fp
);
308 return _IO_UNDERFLOW (fp
);
310 libc_hidden_def (__wunderflow
)
314 _IO_wdefault_xsputn (f
, data
, n
)
319 const wchar_t *s
= (const wchar_t *) data
;
325 /* Space available. */
326 _IO_ssize_t count
= (f
->_wide_data
->_IO_write_end
327 - f
->_wide_data
->_IO_write_ptr
);
330 if ((_IO_size_t
) count
> more
)
335 f
->_wide_data
->_IO_write_ptr
=
336 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
338 memcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
339 f
->_wide_data
->_IO_write_ptr
+= count
;
347 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
349 for (i
= count
; --i
>= 0; )
351 f
->_wide_data
->_IO_write_ptr
= p
;
355 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
361 INTDEF(_IO_wdefault_xsputn
)
365 _IO_wdefault_xsgetn (fp
, data
, n
)
371 wchar_t *s
= (wchar_t*) data
;
374 /* Data available. */
375 _IO_ssize_t count
= (fp
->_wide_data
->_IO_read_end
376 - fp
->_wide_data
->_IO_read_ptr
);
379 if ((_IO_size_t
) count
> more
)
384 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
386 memcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
389 fp
->_wide_data
->_IO_read_ptr
+= count
;
395 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
399 fp
->_wide_data
->_IO_read_ptr
= p
;
403 if (more
== 0 || __wunderflow (fp
) == WEOF
)
408 INTDEF(_IO_wdefault_xsgetn
)
415 if (fp
->_wide_data
->_IO_buf_base
)
417 if (!(fp
->_flags
& _IO_UNBUFFERED
))
418 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
420 INTUSE(_IO_wsetb
) (fp
, fp
->_wide_data
->_shortbuf
,
421 fp
->_wide_data
->_shortbuf
+ 1, 0);
423 INTDEF(_IO_wdoallocbuf
)
427 _IO_wdefault_doallocate (fp
)
432 ALLOC_WBUF (buf
, _IO_BUFSIZ
, EOF
);
433 INTUSE(_IO_wsetb
) (fp
, buf
, buf
+ _IO_BUFSIZ
, 1);
436 INTDEF(_IO_wdefault_doallocate
)
440 _IO_switch_to_wget_mode (fp
)
443 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
444 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
446 if (_IO_in_backup (fp
))
447 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
450 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
451 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
452 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
454 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
456 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
457 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
459 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
462 INTDEF(_IO_switch_to_wget_mode
)
465 _IO_free_wbackup_area (fp
)
468 if (_IO_in_backup (fp
))
469 INTUSE(_IO_switch_to_main_wget_area
) (fp
); /* Just in case. */
470 free (fp
->_wide_data
->_IO_save_base
);
471 fp
->_wide_data
->_IO_save_base
= NULL
;
472 fp
->_wide_data
->_IO_save_end
= NULL
;
473 fp
->_wide_data
->_IO_backup_base
= NULL
;
475 INTDEF(_IO_free_wbackup_area
)
479 _IO_switch_to_wput_mode (fp
)
482 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_read_ptr
;
483 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_read_ptr
;
484 /* Following is wrong if line- or un-buffered? */
485 fp
->_wide_data
->_IO_write_end
= (fp
->_flags
& _IO_IN_BACKUP
486 ? fp
->_wide_data
->_IO_read_end
487 : fp
->_wide_data
->_IO_buf_end
);
489 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
490 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_end
;
492 fp
->_flags
|= _IO_CURRENTLY_PUTTING
;
502 save_for_wbackup (fp
, end_p
)
506 /* Append [_IO_read_base..end_p] to backup area. */
507 _IO_ssize_t least_mark
= INTUSE(_IO_least_wmarker
) (fp
, end_p
);
508 /* needed_size is how much space we need in the backup area. */
509 _IO_size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
511 /* FIXME: Dubious arithmetic if pointers are NULL */
512 _IO_size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
513 - fp
->_wide_data
->_IO_save_base
);
514 _IO_size_t avail
; /* Extra space available for future expansion. */
516 struct _IO_marker
*mark
;
517 if (needed_size
> current_Bsize
)
521 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
523 if (new_buffer
== NULL
)
524 return EOF
; /* FIXME */
528 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
529 fp
->_wide_data
->_IO_save_end
+ least_mark
,
531 fp
->_wide_data
->_IO_read_base
,
532 end_p
- fp
->_wide_data
->_IO_read_base
);
534 memcpy (new_buffer
+ avail
,
535 fp
->_wide_data
->_IO_save_end
+ least_mark
,
536 -least_mark
* sizeof (wchar_t));
537 memcpy (new_buffer
+ avail
- least_mark
,
538 fp
->_wide_data
->_IO_read_base
,
539 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
545 __wmemcpy (new_buffer
+ avail
,
546 fp
->_wide_data
->_IO_read_base
+ least_mark
,
549 memcpy (new_buffer
+ avail
,
550 fp
->_wide_data
->_IO_read_base
+ least_mark
,
551 needed_size
* sizeof (wchar_t));
554 free (fp
->_wide_data
->_IO_save_base
);
555 fp
->_wide_data
->_IO_save_base
= new_buffer
;
556 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
560 avail
= current_Bsize
- needed_size
;
564 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
565 fp
->_wide_data
->_IO_save_end
+ least_mark
,
567 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
568 fp
->_wide_data
->_IO_read_base
,
569 end_p
- fp
->_wide_data
->_IO_read_base
);
571 memmove (fp
->_wide_data
->_IO_save_base
+ avail
,
572 fp
->_wide_data
->_IO_save_end
+ least_mark
,
573 -least_mark
* sizeof (wchar_t));
574 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
575 fp
->_wide_data
->_IO_read_base
,
576 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
579 else if (needed_size
> 0)
581 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
582 fp
->_wide_data
->_IO_read_base
+ least_mark
,
585 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
586 fp
->_wide_data
->_IO_read_base
+ least_mark
,
587 needed_size
* sizeof (wchar_t));
590 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
591 /* Adjust all the streammarkers. */
592 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
593 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
599 _IO_sputbackwc (fp
, c
)
605 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
606 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
608 fp
->_wide_data
->_IO_read_ptr
--;
612 result
= _IO_PBACKFAIL (fp
, c
);
615 fp
->_flags
&= ~_IO_EOF_SEEN
;
619 INTDEF(_IO_sputbackwc
)
627 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
629 fp
->_wide_data
->_IO_read_ptr
--;
630 result
= *fp
->_wide_data
->_IO_read_ptr
;
633 result
= _IO_PBACKFAIL (fp
, EOF
);
636 fp
->_flags
&= ~_IO_EOF_SEEN
;
643 _IO_adjust_wcolumn (start
, line
, count
)
648 const wchar_t *ptr
= line
+ count
;
651 return line
+ count
- ptr
- 1;
652 return start
+ count
;
656 _IO_init_wmarker (marker
, fp
)
657 struct _IO_marker
*marker
;
661 if (_IO_in_put_mode (fp
))
662 INTUSE(_IO_switch_to_wget_mode
) (fp
);
663 if (_IO_in_backup (fp
))
664 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
666 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
667 - fp
->_wide_data
->_IO_read_base
);
669 /* Should perhaps sort the chain? */
670 marker
->_next
= fp
->_markers
;
671 fp
->_markers
= marker
;
674 #define BAD_DELTA EOF
676 /* Return difference between MARK and current position of MARK's stream. */
678 _IO_wmarker_delta (mark
)
679 struct _IO_marker
*mark
;
682 if (mark
->_sbuf
== NULL
)
684 if (_IO_in_backup (mark
->_sbuf
))
685 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
686 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
688 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
689 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
690 return mark
->_pos
- cur_pos
;
694 _IO_seekwmark (fp
, mark
, delta
)
696 struct _IO_marker
*mark
;
699 if (mark
->_sbuf
!= fp
)
703 if (_IO_in_backup (fp
))
704 INTUSE(_IO_switch_to_main_wget_area
) (fp
);
705 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
710 if (!_IO_in_backup (fp
))
711 INTUSE(_IO_switch_to_wbackup_area
) (fp
);
712 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
718 _IO_unsave_wmarkers (fp
)
721 struct _IO_marker
*mark
= fp
->_markers
;
725 streampos offset
= seekoff (0, ios::cur
, ios::in
);
728 offset
+= eGptr () - Gbase ();
729 for ( ; mark
!= NULL
; mark
= mark
->_next
)
730 mark
->set_streampos (mark
->_pos
+ offset
);
734 for ( ; mark
!= NULL
; mark
= mark
->_next
)
735 mark
->set_streampos (EOF
);
741 if (_IO_have_backup (fp
))
742 INTUSE(_IO_free_wbackup_area
) (fp
);