1 /* Copyright (C) 1993-2021 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 <https://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. */
37 static int save_for_wbackup (FILE *fp
, wchar_t *end_p
) __THROW
;
39 /* Return minimum _pos markers
40 Assumes the current get area is the main get area. */
42 _IO_least_wmarker (FILE *fp
, wchar_t *end_p
)
44 ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
45 struct _IO_marker
*mark
;
46 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
47 if (mark
->_pos
< least_so_far
)
48 least_so_far
= mark
->_pos
;
51 libc_hidden_def (_IO_least_wmarker
)
53 /* Switch current get area from backup buffer to (start of) main get area. */
55 _IO_switch_to_main_wget_area (FILE *fp
)
58 fp
->_flags
&= ~_IO_IN_BACKUP
;
59 /* Swap _IO_read_end and _IO_save_end. */
60 tmp
= fp
->_wide_data
->_IO_read_end
;
61 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
62 fp
->_wide_data
->_IO_save_end
= tmp
;
63 /* Swap _IO_read_base and _IO_save_base. */
64 tmp
= fp
->_wide_data
->_IO_read_base
;
65 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
66 fp
->_wide_data
->_IO_save_base
= tmp
;
67 /* Set _IO_read_ptr. */
68 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
70 libc_hidden_def (_IO_switch_to_main_wget_area
)
73 /* Switch current get area from main get area to (end of) backup area. */
75 _IO_switch_to_wbackup_area (FILE *fp
)
78 fp
->_flags
|= _IO_IN_BACKUP
;
79 /* Swap _IO_read_end and _IO_save_end. */
80 tmp
= fp
->_wide_data
->_IO_read_end
;
81 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
82 fp
->_wide_data
->_IO_save_end
= tmp
;
83 /* Swap _IO_read_base and _IO_save_base. */
84 tmp
= fp
->_wide_data
->_IO_read_base
;
85 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
86 fp
->_wide_data
->_IO_save_base
= tmp
;
87 /* Set _IO_read_ptr. */
88 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
90 libc_hidden_def (_IO_switch_to_wbackup_area
)
94 _IO_wsetb (FILE *f
, wchar_t *b
, wchar_t *eb
, int a
)
96 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags2
& _IO_FLAGS2_USER_WBUF
))
97 free (f
->_wide_data
->_IO_buf_base
);
98 f
->_wide_data
->_IO_buf_base
= b
;
99 f
->_wide_data
->_IO_buf_end
= eb
;
101 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
103 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
105 libc_hidden_def (_IO_wsetb
)
109 _IO_wdefault_pbackfail (FILE *fp
, wint_t c
)
111 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
112 && !_IO_in_backup (fp
)
113 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
117 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
118 if (!_IO_in_backup (fp
))
120 /* We need to keep the invariant that the main get area
121 logically follows the backup area. */
122 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
123 && _IO_have_wbackup (fp
))
125 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
128 else if (!_IO_have_wbackup (fp
))
130 /* No backup buffer: allocate one. */
131 /* Use nshort buffer, if unused? (probably not) FIXME */
132 int backup_size
= 128;
133 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
137 fp
->_wide_data
->_IO_save_base
= bbuf
;
138 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
140 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
142 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
143 _IO_switch_to_wbackup_area (fp
);
145 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
147 /* Increase size of existing backup buffer. */
149 size_t old_size
= (fp
->_wide_data
->_IO_read_end
150 - fp
->_wide_data
->_IO_read_base
);
152 new_size
= 2 * old_size
;
153 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
156 __wmemcpy (new_buf
+ (new_size
- old_size
),
157 fp
->_wide_data
->_IO_read_base
, old_size
);
158 free (fp
->_wide_data
->_IO_read_base
);
159 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
161 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
164 *--fp
->_wide_data
->_IO_read_ptr
= c
;
168 libc_hidden_def (_IO_wdefault_pbackfail
)
172 _IO_wdefault_finish (FILE *fp
, int dummy
)
174 struct _IO_marker
*mark
;
175 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
177 free (fp
->_wide_data
->_IO_buf_base
);
178 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
181 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
184 if (fp
->_IO_save_base
)
186 free (fp
->_wide_data
->_IO_save_base
);
187 fp
->_IO_save_base
= NULL
;
191 if (fp
->_lock
!= NULL
)
192 _IO_lock_fini (*fp
->_lock
);
195 _IO_un_link ((struct _IO_FILE_plus
*) fp
);
197 libc_hidden_def (_IO_wdefault_finish
)
201 _IO_wdefault_uflow (FILE *fp
)
204 wch
= _IO_UNDERFLOW (fp
);
207 return *fp
->_wide_data
->_IO_read_ptr
++;
209 libc_hidden_def (_IO_wdefault_uflow
)
213 __woverflow (FILE *f
, wint_t wch
)
217 return _IO_OVERFLOW (f
, wch
);
219 libc_hidden_def (__woverflow
)
225 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
230 if (_IO_in_put_mode (fp
))
231 if (_IO_switch_to_wget_mode (fp
) == EOF
)
233 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
234 return *fp
->_wide_data
->_IO_read_ptr
++;
235 if (_IO_in_backup (fp
))
237 _IO_switch_to_main_wget_area (fp
);
238 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
239 return *fp
->_wide_data
->_IO_read_ptr
++;
241 if (_IO_have_markers (fp
))
243 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
246 else if (_IO_have_wbackup (fp
))
247 _IO_free_wbackup_area (fp
);
248 return _IO_UFLOW (fp
);
250 libc_hidden_def (__wuflow
)
253 __wunderflow (FILE *fp
)
255 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
260 if (_IO_in_put_mode (fp
))
261 if (_IO_switch_to_wget_mode (fp
) == EOF
)
263 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
264 return *fp
->_wide_data
->_IO_read_ptr
;
265 if (_IO_in_backup (fp
))
267 _IO_switch_to_main_wget_area (fp
);
268 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
269 return *fp
->_wide_data
->_IO_read_ptr
;
271 if (_IO_have_markers (fp
))
273 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
276 else if (_IO_have_backup (fp
))
277 _IO_free_wbackup_area (fp
);
278 return _IO_UNDERFLOW (fp
);
280 libc_hidden_def (__wunderflow
)
284 _IO_wdefault_xsputn (FILE *f
, const void *data
, size_t n
)
286 const wchar_t *s
= (const wchar_t *) data
;
292 /* Space available. */
293 ssize_t count
= (f
->_wide_data
->_IO_write_end
294 - f
->_wide_data
->_IO_write_ptr
);
297 if ((size_t) count
> more
)
301 f
->_wide_data
->_IO_write_ptr
=
302 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
309 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
311 for (i
= count
; --i
>= 0; )
313 f
->_wide_data
->_IO_write_ptr
= p
;
317 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
323 libc_hidden_def (_IO_wdefault_xsputn
)
327 _IO_wdefault_xsgetn (FILE *fp
, void *data
, size_t n
)
330 wchar_t *s
= (wchar_t*) data
;
333 /* Data available. */
334 ssize_t count
= (fp
->_wide_data
->_IO_read_end
335 - fp
->_wide_data
->_IO_read_ptr
);
338 if ((size_t) count
> more
)
342 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
343 fp
->_wide_data
->_IO_read_ptr
+= count
;
349 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
353 fp
->_wide_data
->_IO_read_ptr
= p
;
357 if (more
== 0 || __wunderflow (fp
) == WEOF
)
362 libc_hidden_def (_IO_wdefault_xsgetn
)
366 _IO_wdoallocbuf (FILE *fp
)
368 if (fp
->_wide_data
->_IO_buf_base
)
370 if (!(fp
->_flags
& _IO_UNBUFFERED
))
371 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
373 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
,
374 fp
->_wide_data
->_shortbuf
+ 1, 0);
376 libc_hidden_def (_IO_wdoallocbuf
)
380 _IO_wdefault_doallocate (FILE *fp
)
382 wchar_t *buf
= (wchar_t *)malloc (BUFSIZ
);
383 if (__glibc_unlikely (buf
== NULL
))
386 _IO_wsetb (fp
, buf
, buf
+ BUFSIZ
/ sizeof *buf
, 1);
389 libc_hidden_def (_IO_wdefault_doallocate
)
393 _IO_switch_to_wget_mode (FILE *fp
)
395 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
396 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
398 if (_IO_in_backup (fp
))
399 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
402 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
403 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
404 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
406 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
408 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
409 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
411 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
414 libc_hidden_def (_IO_switch_to_wget_mode
)
417 _IO_free_wbackup_area (FILE *fp
)
419 if (_IO_in_backup (fp
))
420 _IO_switch_to_main_wget_area (fp
); /* Just in case. */
421 free (fp
->_wide_data
->_IO_save_base
);
422 fp
->_wide_data
->_IO_save_base
= NULL
;
423 fp
->_wide_data
->_IO_save_end
= NULL
;
424 fp
->_wide_data
->_IO_backup_base
= NULL
;
426 libc_hidden_def (_IO_free_wbackup_area
)
429 save_for_wbackup (FILE *fp
, wchar_t *end_p
)
431 /* Append [_IO_read_base..end_p] to backup area. */
432 ssize_t least_mark
= _IO_least_wmarker (fp
, end_p
);
433 /* needed_size is how much space we need in the backup area. */
434 size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
436 /* FIXME: Dubious arithmetic if pointers are NULL */
437 size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
438 - fp
->_wide_data
->_IO_save_base
);
439 size_t avail
; /* Extra space available for future expansion. */
441 struct _IO_marker
*mark
;
442 if (needed_size
> current_Bsize
)
446 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
448 if (new_buffer
== NULL
)
449 return EOF
; /* FIXME */
452 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
453 fp
->_wide_data
->_IO_save_end
+ least_mark
,
455 fp
->_wide_data
->_IO_read_base
,
456 end_p
- fp
->_wide_data
->_IO_read_base
);
460 __wmemcpy (new_buffer
+ avail
,
461 fp
->_wide_data
->_IO_read_base
+ least_mark
,
464 free (fp
->_wide_data
->_IO_save_base
);
465 fp
->_wide_data
->_IO_save_base
= new_buffer
;
466 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
470 avail
= current_Bsize
- needed_size
;
473 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
474 fp
->_wide_data
->_IO_save_end
+ least_mark
,
476 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
477 fp
->_wide_data
->_IO_read_base
,
478 end_p
- fp
->_wide_data
->_IO_read_base
);
480 else if (needed_size
> 0)
481 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
482 fp
->_wide_data
->_IO_read_base
+ least_mark
,
485 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
486 /* Adjust all the streammarkers. */
487 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
488 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
494 _IO_sputbackwc (FILE *fp
, wint_t c
)
498 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
499 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
501 fp
->_wide_data
->_IO_read_ptr
--;
505 result
= _IO_PBACKFAIL (fp
, c
);
508 fp
->_flags
&= ~_IO_EOF_SEEN
;
512 libc_hidden_def (_IO_sputbackwc
)
515 _IO_sungetwc (FILE *fp
)
519 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
521 fp
->_wide_data
->_IO_read_ptr
--;
522 result
= *fp
->_wide_data
->_IO_read_ptr
;
525 result
= _IO_PBACKFAIL (fp
, EOF
);
528 fp
->_flags
&= ~_IO_EOF_SEEN
;
535 _IO_adjust_wcolumn (unsigned start
, const wchar_t *line
, int count
)
537 const wchar_t *ptr
= line
+ count
;
540 return line
+ count
- ptr
- 1;
541 return start
+ count
;
545 _IO_init_wmarker (struct _IO_marker
*marker
, FILE *fp
)
548 if (_IO_in_put_mode (fp
))
549 _IO_switch_to_wget_mode (fp
);
550 if (_IO_in_backup (fp
))
551 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
553 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
554 - fp
->_wide_data
->_IO_read_base
);
556 /* Should perhaps sort the chain? */
557 marker
->_next
= fp
->_markers
;
558 fp
->_markers
= marker
;
561 #define BAD_DELTA EOF
563 /* Return difference between MARK and current position of MARK's stream. */
565 _IO_wmarker_delta (struct _IO_marker
*mark
)
568 if (mark
->_sbuf
== NULL
)
570 if (_IO_in_backup (mark
->_sbuf
))
571 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
572 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
574 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
575 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
576 return mark
->_pos
- cur_pos
;
580 _IO_seekwmark (FILE *fp
, struct _IO_marker
*mark
, int delta
)
582 if (mark
->_sbuf
!= fp
)
586 if (_IO_in_backup (fp
))
587 _IO_switch_to_main_wget_area (fp
);
588 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
593 if (!_IO_in_backup (fp
))
594 _IO_switch_to_wbackup_area (fp
);
595 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
601 _IO_unsave_wmarkers (FILE *fp
)
603 struct _IO_marker
*mark
= fp
->_markers
;
609 if (_IO_have_backup (fp
))
610 _IO_free_wbackup_area (fp
);