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 (_IO_FILE
*fp
, wchar_t *end_p
)
53 _IO_ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
54 struct _IO_marker
*mark
;
55 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
56 if (mark
->_pos
< least_so_far
)
57 least_so_far
= mark
->_pos
;
60 libc_hidden_def (_IO_least_wmarker
)
62 /* Switch current get area from backup buffer to (start of) main get area. */
64 _IO_switch_to_main_wget_area (_IO_FILE
*fp
)
67 fp
->_flags
&= ~_IO_IN_BACKUP
;
68 /* Swap _IO_read_end and _IO_save_end. */
69 tmp
= fp
->_wide_data
->_IO_read_end
;
70 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
71 fp
->_wide_data
->_IO_save_end
= tmp
;
72 /* Swap _IO_read_base and _IO_save_base. */
73 tmp
= fp
->_wide_data
->_IO_read_base
;
74 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
75 fp
->_wide_data
->_IO_save_base
= tmp
;
76 /* Set _IO_read_ptr. */
77 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
79 libc_hidden_def (_IO_switch_to_main_wget_area
)
82 /* Switch current get area from main get area to (end of) backup area. */
84 _IO_switch_to_wbackup_area (_IO_FILE
*fp
)
87 fp
->_flags
|= _IO_IN_BACKUP
;
88 /* Swap _IO_read_end and _IO_save_end. */
89 tmp
= fp
->_wide_data
->_IO_read_end
;
90 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
91 fp
->_wide_data
->_IO_save_end
= tmp
;
92 /* Swap _IO_read_base and _IO_save_base. */
93 tmp
= fp
->_wide_data
->_IO_read_base
;
94 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
95 fp
->_wide_data
->_IO_save_base
= tmp
;
96 /* Set _IO_read_ptr. */
97 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
99 libc_hidden_def (_IO_switch_to_wbackup_area
)
103 _IO_wsetb (_IO_FILE
*f
, wchar_t *b
, wchar_t *eb
, int a
)
105 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags2
& _IO_FLAGS2_USER_WBUF
))
106 free (f
->_wide_data
->_IO_buf_base
);
107 f
->_wide_data
->_IO_buf_base
= b
;
108 f
->_wide_data
->_IO_buf_end
= eb
;
110 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
112 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
114 libc_hidden_def (_IO_wsetb
)
118 _IO_wdefault_pbackfail (_IO_FILE
*fp
, wint_t c
)
120 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
121 && !_IO_in_backup (fp
)
122 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
126 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
127 if (!_IO_in_backup (fp
))
129 /* We need to keep the invariant that the main get area
130 logically follows the backup area. */
131 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
132 && _IO_have_wbackup (fp
))
134 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
137 else if (!_IO_have_wbackup (fp
))
139 /* No backup buffer: allocate one. */
140 /* Use nshort buffer, if unused? (probably not) FIXME */
141 int backup_size
= 128;
142 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
146 fp
->_wide_data
->_IO_save_base
= bbuf
;
147 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
149 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
151 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
152 _IO_switch_to_wbackup_area (fp
);
154 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
156 /* Increase size of existing backup buffer. */
158 _IO_size_t old_size
= (fp
->_wide_data
->_IO_read_end
159 - fp
->_wide_data
->_IO_read_base
);
161 new_size
= 2 * old_size
;
162 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
165 __wmemcpy (new_buf
+ (new_size
- old_size
),
166 fp
->_wide_data
->_IO_read_base
, old_size
);
167 free (fp
->_wide_data
->_IO_read_base
);
168 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
170 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
173 *--fp
->_wide_data
->_IO_read_ptr
= c
;
177 libc_hidden_def (_IO_wdefault_pbackfail
)
181 _IO_wdefault_finish (_IO_FILE
*fp
, int dummy
)
183 struct _IO_marker
*mark
;
184 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
186 free (fp
->_wide_data
->_IO_buf_base
);
187 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
190 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
193 if (fp
->_IO_save_base
)
195 free (fp
->_wide_data
->_IO_save_base
);
196 fp
->_IO_save_base
= NULL
;
200 if (fp
->_lock
!= NULL
)
201 _IO_lock_fini (*fp
->_lock
);
204 _IO_un_link ((struct _IO_FILE_plus
*) fp
);
206 libc_hidden_def (_IO_wdefault_finish
)
210 _IO_wdefault_uflow (_IO_FILE
*fp
)
213 wch
= _IO_UNDERFLOW (fp
);
216 return *fp
->_wide_data
->_IO_read_ptr
++;
218 libc_hidden_def (_IO_wdefault_uflow
)
222 __woverflow (_IO_FILE
*f
, wint_t wch
)
226 return _IO_OVERFLOW (f
, wch
);
228 libc_hidden_def (__woverflow
)
232 __wuflow (_IO_FILE
*fp
)
234 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
239 if (_IO_in_put_mode (fp
))
240 if (_IO_switch_to_wget_mode (fp
) == EOF
)
242 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
243 return *fp
->_wide_data
->_IO_read_ptr
++;
244 if (_IO_in_backup (fp
))
246 _IO_switch_to_main_wget_area (fp
);
247 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
248 return *fp
->_wide_data
->_IO_read_ptr
++;
250 if (_IO_have_markers (fp
))
252 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
255 else if (_IO_have_wbackup (fp
))
256 _IO_free_wbackup_area (fp
);
257 return _IO_UFLOW (fp
);
259 libc_hidden_def (__wuflow
)
262 __wunderflow (_IO_FILE
*fp
)
264 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
269 if (_IO_in_put_mode (fp
))
270 if (_IO_switch_to_wget_mode (fp
) == EOF
)
272 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
273 return *fp
->_wide_data
->_IO_read_ptr
;
274 if (_IO_in_backup (fp
))
276 _IO_switch_to_main_wget_area (fp
);
277 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
278 return *fp
->_wide_data
->_IO_read_ptr
;
280 if (_IO_have_markers (fp
))
282 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
285 else if (_IO_have_backup (fp
))
286 _IO_free_wbackup_area (fp
);
287 return _IO_UNDERFLOW (fp
);
289 libc_hidden_def (__wunderflow
)
293 _IO_wdefault_xsputn (_IO_FILE
*f
, const void *data
, _IO_size_t n
)
295 const wchar_t *s
= (const wchar_t *) data
;
301 /* Space available. */
302 _IO_ssize_t count
= (f
->_wide_data
->_IO_write_end
303 - f
->_wide_data
->_IO_write_ptr
);
306 if ((_IO_size_t
) count
> more
)
311 f
->_wide_data
->_IO_write_ptr
=
312 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
314 memcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
315 f
->_wide_data
->_IO_write_ptr
+= count
;
323 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
325 for (i
= count
; --i
>= 0; )
327 f
->_wide_data
->_IO_write_ptr
= p
;
331 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
337 libc_hidden_def (_IO_wdefault_xsputn
)
341 _IO_wdefault_xsgetn (_IO_FILE
*fp
, void *data
, _IO_size_t n
)
344 wchar_t *s
= (wchar_t*) data
;
347 /* Data available. */
348 _IO_ssize_t count
= (fp
->_wide_data
->_IO_read_end
349 - fp
->_wide_data
->_IO_read_ptr
);
352 if ((_IO_size_t
) count
> more
)
357 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
359 memcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
362 fp
->_wide_data
->_IO_read_ptr
+= count
;
368 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
372 fp
->_wide_data
->_IO_read_ptr
= p
;
376 if (more
== 0 || __wunderflow (fp
) == WEOF
)
381 libc_hidden_def (_IO_wdefault_xsgetn
)
385 _IO_wdoallocbuf (_IO_FILE
*fp
)
387 if (fp
->_wide_data
->_IO_buf_base
)
389 if (!(fp
->_flags
& _IO_UNBUFFERED
))
390 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
392 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
,
393 fp
->_wide_data
->_shortbuf
+ 1, 0);
395 libc_hidden_def (_IO_wdoallocbuf
)
399 _IO_wdefault_doallocate (_IO_FILE
*fp
)
403 buf
= malloc (_IO_BUFSIZ
);
404 if (__glibc_unlikely (buf
== NULL
))
406 _IO_wsetb (fp
, buf
, buf
+ _IO_BUFSIZ
, 1);
409 libc_hidden_def (_IO_wdefault_doallocate
)
413 _IO_switch_to_wget_mode (_IO_FILE
*fp
)
415 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
416 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
418 if (_IO_in_backup (fp
))
419 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
422 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
423 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
424 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
426 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
428 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
429 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
431 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
434 libc_hidden_def (_IO_switch_to_wget_mode
)
437 _IO_free_wbackup_area (_IO_FILE
*fp
)
439 if (_IO_in_backup (fp
))
440 _IO_switch_to_main_wget_area (fp
); /* Just in case. */
441 free (fp
->_wide_data
->_IO_save_base
);
442 fp
->_wide_data
->_IO_save_base
= NULL
;
443 fp
->_wide_data
->_IO_save_end
= NULL
;
444 fp
->_wide_data
->_IO_backup_base
= NULL
;
446 libc_hidden_def (_IO_free_wbackup_area
)
450 _IO_switch_to_wput_mode (_IO_FILE
*fp
)
452 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_read_ptr
;
453 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_read_ptr
;
454 /* Following is wrong if line- or un-buffered? */
455 fp
->_wide_data
->_IO_write_end
= (fp
->_flags
& _IO_IN_BACKUP
456 ? fp
->_wide_data
->_IO_read_end
457 : fp
->_wide_data
->_IO_buf_end
);
459 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
460 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_end
;
462 fp
->_flags
|= _IO_CURRENTLY_PUTTING
;
472 save_for_wbackup (fp
, end_p
)
476 /* Append [_IO_read_base..end_p] to backup area. */
477 _IO_ssize_t least_mark
= _IO_least_wmarker (fp
, end_p
);
478 /* needed_size is how much space we need in the backup area. */
479 _IO_size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
481 /* FIXME: Dubious arithmetic if pointers are NULL */
482 _IO_size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
483 - fp
->_wide_data
->_IO_save_base
);
484 _IO_size_t avail
; /* Extra space available for future expansion. */
486 struct _IO_marker
*mark
;
487 if (needed_size
> current_Bsize
)
491 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
493 if (new_buffer
== NULL
)
494 return EOF
; /* FIXME */
498 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
499 fp
->_wide_data
->_IO_save_end
+ least_mark
,
501 fp
->_wide_data
->_IO_read_base
,
502 end_p
- fp
->_wide_data
->_IO_read_base
);
504 memcpy (new_buffer
+ avail
,
505 fp
->_wide_data
->_IO_save_end
+ least_mark
,
506 -least_mark
* sizeof (wchar_t));
507 memcpy (new_buffer
+ avail
- least_mark
,
508 fp
->_wide_data
->_IO_read_base
,
509 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
515 __wmemcpy (new_buffer
+ avail
,
516 fp
->_wide_data
->_IO_read_base
+ least_mark
,
519 memcpy (new_buffer
+ avail
,
520 fp
->_wide_data
->_IO_read_base
+ least_mark
,
521 needed_size
* sizeof (wchar_t));
524 free (fp
->_wide_data
->_IO_save_base
);
525 fp
->_wide_data
->_IO_save_base
= new_buffer
;
526 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
530 avail
= current_Bsize
- needed_size
;
534 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
535 fp
->_wide_data
->_IO_save_end
+ least_mark
,
537 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
538 fp
->_wide_data
->_IO_read_base
,
539 end_p
- fp
->_wide_data
->_IO_read_base
);
541 memmove (fp
->_wide_data
->_IO_save_base
+ avail
,
542 fp
->_wide_data
->_IO_save_end
+ least_mark
,
543 -least_mark
* sizeof (wchar_t));
544 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
545 fp
->_wide_data
->_IO_read_base
,
546 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
549 else if (needed_size
> 0)
551 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
552 fp
->_wide_data
->_IO_read_base
+ least_mark
,
555 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
556 fp
->_wide_data
->_IO_read_base
+ least_mark
,
557 needed_size
* sizeof (wchar_t));
560 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
561 /* Adjust all the streammarkers. */
562 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
563 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
569 _IO_sputbackwc (_IO_FILE
*fp
, wint_t c
)
573 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
574 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
576 fp
->_wide_data
->_IO_read_ptr
--;
580 result
= _IO_PBACKFAIL (fp
, c
);
583 fp
->_flags
&= ~_IO_EOF_SEEN
;
587 libc_hidden_def (_IO_sputbackwc
)
590 _IO_sungetwc (_IO_FILE
*fp
)
594 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
596 fp
->_wide_data
->_IO_read_ptr
--;
597 result
= *fp
->_wide_data
->_IO_read_ptr
;
600 result
= _IO_PBACKFAIL (fp
, EOF
);
603 fp
->_flags
&= ~_IO_EOF_SEEN
;
610 _IO_adjust_wcolumn (unsigned start
, const wchar_t *line
, int count
)
612 const wchar_t *ptr
= line
+ count
;
615 return line
+ count
- ptr
- 1;
616 return start
+ count
;
620 _IO_init_wmarker (struct _IO_marker
*marker
, _IO_FILE
*fp
)
623 if (_IO_in_put_mode (fp
))
624 _IO_switch_to_wget_mode (fp
);
625 if (_IO_in_backup (fp
))
626 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
628 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
629 - fp
->_wide_data
->_IO_read_base
);
631 /* Should perhaps sort the chain? */
632 marker
->_next
= fp
->_markers
;
633 fp
->_markers
= marker
;
636 #define BAD_DELTA EOF
638 /* Return difference between MARK and current position of MARK's stream. */
640 _IO_wmarker_delta (struct _IO_marker
*mark
)
643 if (mark
->_sbuf
== NULL
)
645 if (_IO_in_backup (mark
->_sbuf
))
646 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
647 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
649 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
650 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
651 return mark
->_pos
- cur_pos
;
655 _IO_seekwmark (_IO_FILE
*fp
, struct _IO_marker
*mark
, int delta
)
657 if (mark
->_sbuf
!= fp
)
661 if (_IO_in_backup (fp
))
662 _IO_switch_to_main_wget_area (fp
);
663 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
668 if (!_IO_in_backup (fp
))
669 _IO_switch_to_wbackup_area (fp
);
670 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
676 _IO_unsave_wmarkers (_IO_FILE
*fp
)
678 struct _IO_marker
*mark
= fp
->_markers
;
682 streampos offset
= seekoff (0, ios::cur
, ios::in
);
685 offset
+= eGptr () - Gbase ();
686 for ( ; mark
!= NULL
; mark
= mark
->_next
)
687 mark
->set_streampos (mark
->_pos
+ offset
);
691 for ( ; mark
!= NULL
; mark
= mark
->_next
)
692 mark
->set_streampos (EOF
);
698 if (_IO_have_backup (fp
))
699 _IO_free_wbackup_area (fp
);