1 /* Copyright (C) 1993-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Written by Ulrich Drepper <drepper@cygnus.com>.
4 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>.
20 As a special exception, if you link the code in this file with
21 files compiled with a GNU compiler to produce an executable,
22 that does not cause the resulting executable to be covered by
23 the GNU Lesser General Public License. This exception does not
24 however invalidate any other reasons why the executable file
25 might be covered by the GNU Lesser General Public License.
26 This exception applies to code released by its copyright holders
27 in files containing the exception. */
29 /* Generic or default I/O operations. */
38 # define __wmemcpy(dst, src, n) wmemcpy (dst, src, n)
42 static int save_for_wbackup (_IO_FILE
*fp
, wchar_t *end_p
) __THROW
48 /* Return minimum _pos markers
49 Assumes the current get area is the main get area. */
51 _IO_least_wmarker (fp
, end_p
)
55 _IO_ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
56 struct _IO_marker
*mark
;
57 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
58 if (mark
->_pos
< least_so_far
)
59 least_so_far
= mark
->_pos
;
62 libc_hidden_def (_IO_least_wmarker
)
64 /* Switch current get area from backup buffer to (start of) main get area. */
66 _IO_switch_to_main_wget_area (fp
)
70 fp
->_flags
&= ~_IO_IN_BACKUP
;
71 /* Swap _IO_read_end and _IO_save_end. */
72 tmp
= fp
->_wide_data
->_IO_read_end
;
73 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
74 fp
->_wide_data
->_IO_save_end
= tmp
;
75 /* Swap _IO_read_base and _IO_save_base. */
76 tmp
= fp
->_wide_data
->_IO_read_base
;
77 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
78 fp
->_wide_data
->_IO_save_base
= tmp
;
79 /* Set _IO_read_ptr. */
80 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
82 libc_hidden_def (_IO_switch_to_main_wget_area
)
85 /* Switch current get area from main get area to (end of) backup area. */
87 _IO_switch_to_wbackup_area (fp
)
91 fp
->_flags
|= _IO_IN_BACKUP
;
92 /* Swap _IO_read_end and _IO_save_end. */
93 tmp
= fp
->_wide_data
->_IO_read_end
;
94 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
95 fp
->_wide_data
->_IO_save_end
= tmp
;
96 /* Swap _IO_read_base and _IO_save_base. */
97 tmp
= fp
->_wide_data
->_IO_read_base
;
98 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
99 fp
->_wide_data
->_IO_save_base
= tmp
;
100 /* Set _IO_read_ptr. */
101 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
103 libc_hidden_def (_IO_switch_to_wbackup_area
)
107 _IO_wsetb (f
, b
, eb
, a
)
113 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags2
& _IO_FLAGS2_USER_WBUF
))
114 free (f
->_wide_data
->_IO_buf_base
);
115 f
->_wide_data
->_IO_buf_base
= b
;
116 f
->_wide_data
->_IO_buf_end
= eb
;
118 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
120 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
122 libc_hidden_def (_IO_wsetb
)
126 _IO_wdefault_pbackfail (fp
, c
)
130 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
131 && !_IO_in_backup (fp
)
132 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
136 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
137 if (!_IO_in_backup (fp
))
139 /* We need to keep the invariant that the main get area
140 logically follows the backup area. */
141 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
142 && _IO_have_wbackup (fp
))
144 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
147 else if (!_IO_have_wbackup (fp
))
149 /* No backup buffer: allocate one. */
150 /* Use nshort buffer, if unused? (probably not) FIXME */
151 int backup_size
= 128;
152 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
156 fp
->_wide_data
->_IO_save_base
= bbuf
;
157 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
159 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
161 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
162 _IO_switch_to_wbackup_area (fp
);
164 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
166 /* Increase size of existing backup buffer. */
168 _IO_size_t old_size
= (fp
->_wide_data
->_IO_read_end
169 - fp
->_wide_data
->_IO_read_base
);
171 new_size
= 2 * old_size
;
172 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
175 __wmemcpy (new_buf
+ (new_size
- old_size
),
176 fp
->_wide_data
->_IO_read_base
, old_size
);
177 free (fp
->_wide_data
->_IO_read_base
);
178 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
180 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
183 *--fp
->_wide_data
->_IO_read_ptr
= c
;
187 libc_hidden_def (_IO_wdefault_pbackfail
)
191 _IO_wdefault_finish (fp
, dummy
)
195 struct _IO_marker
*mark
;
196 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
198 free (fp
->_wide_data
->_IO_buf_base
);
199 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
202 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
205 if (fp
->_IO_save_base
)
207 free (fp
->_wide_data
->_IO_save_base
);
208 fp
->_IO_save_base
= NULL
;
212 if (fp
->_lock
!= NULL
)
213 _IO_lock_fini (*fp
->_lock
);
216 _IO_un_link ((struct _IO_FILE_plus
*) fp
);
218 libc_hidden_def (_IO_wdefault_finish
)
222 _IO_wdefault_uflow (fp
)
226 wch
= _IO_UNDERFLOW (fp
);
229 return *fp
->_wide_data
->_IO_read_ptr
++;
231 libc_hidden_def (_IO_wdefault_uflow
)
241 return _IO_OVERFLOW (f
, wch
);
243 libc_hidden_def (__woverflow
)
250 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
255 if (_IO_in_put_mode (fp
))
256 if (_IO_switch_to_wget_mode (fp
) == EOF
)
258 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
259 return *fp
->_wide_data
->_IO_read_ptr
++;
260 if (_IO_in_backup (fp
))
262 _IO_switch_to_main_wget_area (fp
);
263 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
264 return *fp
->_wide_data
->_IO_read_ptr
++;
266 if (_IO_have_markers (fp
))
268 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
271 else if (_IO_have_wbackup (fp
))
272 _IO_free_wbackup_area (fp
);
273 return _IO_UFLOW (fp
);
275 libc_hidden_def (__wuflow
)
281 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
286 if (_IO_in_put_mode (fp
))
287 if (_IO_switch_to_wget_mode (fp
) == EOF
)
289 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
290 return *fp
->_wide_data
->_IO_read_ptr
;
291 if (_IO_in_backup (fp
))
293 _IO_switch_to_main_wget_area (fp
);
294 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
295 return *fp
->_wide_data
->_IO_read_ptr
;
297 if (_IO_have_markers (fp
))
299 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
302 else if (_IO_have_backup (fp
))
303 _IO_free_wbackup_area (fp
);
304 return _IO_UNDERFLOW (fp
);
306 libc_hidden_def (__wunderflow
)
310 _IO_wdefault_xsputn (f
, data
, n
)
315 const wchar_t *s
= (const wchar_t *) data
;
321 /* Space available. */
322 _IO_ssize_t count
= (f
->_wide_data
->_IO_write_end
323 - f
->_wide_data
->_IO_write_ptr
);
326 if ((_IO_size_t
) count
> more
)
331 f
->_wide_data
->_IO_write_ptr
=
332 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
334 memcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
335 f
->_wide_data
->_IO_write_ptr
+= count
;
343 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
345 for (i
= count
; --i
>= 0; )
347 f
->_wide_data
->_IO_write_ptr
= p
;
351 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
357 libc_hidden_def (_IO_wdefault_xsputn
)
361 _IO_wdefault_xsgetn (fp
, data
, n
)
367 wchar_t *s
= (wchar_t*) data
;
370 /* Data available. */
371 _IO_ssize_t count
= (fp
->_wide_data
->_IO_read_end
372 - fp
->_wide_data
->_IO_read_ptr
);
375 if ((_IO_size_t
) count
> more
)
380 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
382 memcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
385 fp
->_wide_data
->_IO_read_ptr
+= count
;
391 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
395 fp
->_wide_data
->_IO_read_ptr
= p
;
399 if (more
== 0 || __wunderflow (fp
) == WEOF
)
404 libc_hidden_def (_IO_wdefault_xsgetn
)
411 if (fp
->_wide_data
->_IO_buf_base
)
413 if (!(fp
->_flags
& _IO_UNBUFFERED
))
414 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
416 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
,
417 fp
->_wide_data
->_shortbuf
+ 1, 0);
419 libc_hidden_def (_IO_wdoallocbuf
)
423 _IO_wdefault_doallocate (fp
)
428 buf
= malloc (_IO_BUFSIZ
);
429 if (__glibc_unlikely (buf
== NULL
))
431 _IO_wsetb (fp
, buf
, buf
+ _IO_BUFSIZ
, 1);
434 libc_hidden_def (_IO_wdefault_doallocate
)
438 _IO_switch_to_wget_mode (fp
)
441 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
442 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
444 if (_IO_in_backup (fp
))
445 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
448 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
449 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
450 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
452 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
454 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
455 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
457 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
460 libc_hidden_def (_IO_switch_to_wget_mode
)
463 _IO_free_wbackup_area (fp
)
466 if (_IO_in_backup (fp
))
467 _IO_switch_to_main_wget_area (fp
); /* Just in case. */
468 free (fp
->_wide_data
->_IO_save_base
);
469 fp
->_wide_data
->_IO_save_base
= NULL
;
470 fp
->_wide_data
->_IO_save_end
= NULL
;
471 fp
->_wide_data
->_IO_backup_base
= NULL
;
473 libc_hidden_def (_IO_free_wbackup_area
)
477 _IO_switch_to_wput_mode (fp
)
480 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_read_ptr
;
481 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_read_ptr
;
482 /* Following is wrong if line- or un-buffered? */
483 fp
->_wide_data
->_IO_write_end
= (fp
->_flags
& _IO_IN_BACKUP
484 ? fp
->_wide_data
->_IO_read_end
485 : fp
->_wide_data
->_IO_buf_end
);
487 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
488 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_end
;
490 fp
->_flags
|= _IO_CURRENTLY_PUTTING
;
500 save_for_wbackup (fp
, end_p
)
504 /* Append [_IO_read_base..end_p] to backup area. */
505 _IO_ssize_t least_mark
= _IO_least_wmarker (fp
, end_p
);
506 /* needed_size is how much space we need in the backup area. */
507 _IO_size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
509 /* FIXME: Dubious arithmetic if pointers are NULL */
510 _IO_size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
511 - fp
->_wide_data
->_IO_save_base
);
512 _IO_size_t avail
; /* Extra space available for future expansion. */
514 struct _IO_marker
*mark
;
515 if (needed_size
> current_Bsize
)
519 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
521 if (new_buffer
== NULL
)
522 return EOF
; /* FIXME */
526 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
527 fp
->_wide_data
->_IO_save_end
+ least_mark
,
529 fp
->_wide_data
->_IO_read_base
,
530 end_p
- fp
->_wide_data
->_IO_read_base
);
532 memcpy (new_buffer
+ avail
,
533 fp
->_wide_data
->_IO_save_end
+ least_mark
,
534 -least_mark
* sizeof (wchar_t));
535 memcpy (new_buffer
+ avail
- least_mark
,
536 fp
->_wide_data
->_IO_read_base
,
537 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
543 __wmemcpy (new_buffer
+ avail
,
544 fp
->_wide_data
->_IO_read_base
+ least_mark
,
547 memcpy (new_buffer
+ avail
,
548 fp
->_wide_data
->_IO_read_base
+ least_mark
,
549 needed_size
* sizeof (wchar_t));
552 free (fp
->_wide_data
->_IO_save_base
);
553 fp
->_wide_data
->_IO_save_base
= new_buffer
;
554 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
558 avail
= current_Bsize
- needed_size
;
562 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
563 fp
->_wide_data
->_IO_save_end
+ least_mark
,
565 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
566 fp
->_wide_data
->_IO_read_base
,
567 end_p
- fp
->_wide_data
->_IO_read_base
);
569 memmove (fp
->_wide_data
->_IO_save_base
+ avail
,
570 fp
->_wide_data
->_IO_save_end
+ least_mark
,
571 -least_mark
* sizeof (wchar_t));
572 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
573 fp
->_wide_data
->_IO_read_base
,
574 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
577 else if (needed_size
> 0)
579 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
580 fp
->_wide_data
->_IO_read_base
+ least_mark
,
583 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
584 fp
->_wide_data
->_IO_read_base
+ least_mark
,
585 needed_size
* sizeof (wchar_t));
588 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
589 /* Adjust all the streammarkers. */
590 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
591 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
597 _IO_sputbackwc (fp
, c
)
603 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
604 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
606 fp
->_wide_data
->_IO_read_ptr
--;
610 result
= _IO_PBACKFAIL (fp
, c
);
613 fp
->_flags
&= ~_IO_EOF_SEEN
;
617 libc_hidden_def (_IO_sputbackwc
)
625 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
627 fp
->_wide_data
->_IO_read_ptr
--;
628 result
= *fp
->_wide_data
->_IO_read_ptr
;
631 result
= _IO_PBACKFAIL (fp
, EOF
);
634 fp
->_flags
&= ~_IO_EOF_SEEN
;
641 _IO_adjust_wcolumn (start
, line
, count
)
646 const wchar_t *ptr
= line
+ count
;
649 return line
+ count
- ptr
- 1;
650 return start
+ count
;
654 _IO_init_wmarker (marker
, fp
)
655 struct _IO_marker
*marker
;
659 if (_IO_in_put_mode (fp
))
660 _IO_switch_to_wget_mode (fp
);
661 if (_IO_in_backup (fp
))
662 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
664 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
665 - fp
->_wide_data
->_IO_read_base
);
667 /* Should perhaps sort the chain? */
668 marker
->_next
= fp
->_markers
;
669 fp
->_markers
= marker
;
672 #define BAD_DELTA EOF
674 /* Return difference between MARK and current position of MARK's stream. */
676 _IO_wmarker_delta (mark
)
677 struct _IO_marker
*mark
;
680 if (mark
->_sbuf
== NULL
)
682 if (_IO_in_backup (mark
->_sbuf
))
683 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
684 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
686 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
687 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
688 return mark
->_pos
- cur_pos
;
692 _IO_seekwmark (fp
, mark
, delta
)
694 struct _IO_marker
*mark
;
697 if (mark
->_sbuf
!= fp
)
701 if (_IO_in_backup (fp
))
702 _IO_switch_to_main_wget_area (fp
);
703 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
708 if (!_IO_in_backup (fp
))
709 _IO_switch_to_wbackup_area (fp
);
710 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
716 _IO_unsave_wmarkers (fp
)
719 struct _IO_marker
*mark
= fp
->_markers
;
723 streampos offset
= seekoff (0, ios::cur
, ios::in
);
726 offset
+= eGptr () - Gbase ();
727 for ( ; mark
!= NULL
; mark
= mark
->_next
)
728 mark
->set_streampos (mark
->_pos
+ offset
);
732 for ( ; mark
!= NULL
; mark
= mark
->_next
)
733 mark
->set_streampos (EOF
);
739 if (_IO_have_backup (fp
))
740 _IO_free_wbackup_area (fp
);