1 /* Copyright (C) 1993-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>.
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
27 /* Generic or default I/O operations. */
35 static int save_for_wbackup (FILE *fp
, wchar_t *end_p
) __THROW
;
37 /* Return minimum _pos markers
38 Assumes the current get area is the main get area. */
40 _IO_least_wmarker (FILE *fp
, wchar_t *end_p
)
42 ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
43 struct _IO_marker
*mark
;
44 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
45 if (mark
->_pos
< least_so_far
)
46 least_so_far
= mark
->_pos
;
49 libc_hidden_def (_IO_least_wmarker
)
51 /* Switch current get area from backup buffer to (start of) main get area. */
53 _IO_switch_to_main_wget_area (FILE *fp
)
56 fp
->_flags
&= ~_IO_IN_BACKUP
;
57 /* Swap _IO_read_end and _IO_save_end. */
58 tmp
= fp
->_wide_data
->_IO_read_end
;
59 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
60 fp
->_wide_data
->_IO_save_end
= tmp
;
61 /* Swap _IO_read_base and _IO_save_base. */
62 tmp
= fp
->_wide_data
->_IO_read_base
;
63 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
64 fp
->_wide_data
->_IO_save_base
= tmp
;
65 /* Set _IO_read_ptr. */
66 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
68 libc_hidden_def (_IO_switch_to_main_wget_area
)
71 /* Switch current get area from main get area to (end of) backup area. */
73 _IO_switch_to_wbackup_area (FILE *fp
)
76 fp
->_flags
|= _IO_IN_BACKUP
;
77 /* Swap _IO_read_end and _IO_save_end. */
78 tmp
= fp
->_wide_data
->_IO_read_end
;
79 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
80 fp
->_wide_data
->_IO_save_end
= tmp
;
81 /* Swap _IO_read_base and _IO_save_base. */
82 tmp
= fp
->_wide_data
->_IO_read_base
;
83 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
84 fp
->_wide_data
->_IO_save_base
= tmp
;
85 /* Set _IO_read_ptr. */
86 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
88 libc_hidden_def (_IO_switch_to_wbackup_area
)
92 _IO_wsetb (FILE *f
, wchar_t *b
, wchar_t *eb
, int a
)
94 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags2
& _IO_FLAGS2_USER_WBUF
))
95 free (f
->_wide_data
->_IO_buf_base
);
96 f
->_wide_data
->_IO_buf_base
= b
;
97 f
->_wide_data
->_IO_buf_end
= eb
;
99 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
101 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
103 libc_hidden_def (_IO_wsetb
)
107 _IO_wdefault_pbackfail (FILE *fp
, wint_t c
)
109 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
110 && !_IO_in_backup (fp
)
111 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
115 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
116 if (!_IO_in_backup (fp
))
118 /* We need to keep the invariant that the main get area
119 logically follows the backup area. */
120 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
121 && _IO_have_wbackup (fp
))
123 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
126 else if (!_IO_have_wbackup (fp
))
128 /* No backup buffer: allocate one. */
129 /* Use nshort buffer, if unused? (probably not) FIXME */
130 int backup_size
= 128;
131 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
135 fp
->_wide_data
->_IO_save_base
= bbuf
;
136 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
138 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
140 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
141 _IO_switch_to_wbackup_area (fp
);
143 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
145 /* Increase size of existing backup buffer. */
147 size_t old_size
= (fp
->_wide_data
->_IO_read_end
148 - fp
->_wide_data
->_IO_read_base
);
150 new_size
= 2 * old_size
;
151 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
154 __wmemcpy (new_buf
+ (new_size
- old_size
),
155 fp
->_wide_data
->_IO_read_base
, old_size
);
156 free (fp
->_wide_data
->_IO_read_base
);
157 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
159 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
162 *--fp
->_wide_data
->_IO_read_ptr
= c
;
166 libc_hidden_def (_IO_wdefault_pbackfail
)
170 _IO_wdefault_finish (FILE *fp
, int dummy
)
172 struct _IO_marker
*mark
;
173 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
175 free (fp
->_wide_data
->_IO_buf_base
);
176 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
179 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
182 if (fp
->_IO_save_base
)
184 free (fp
->_wide_data
->_IO_save_base
);
185 fp
->_IO_save_base
= NULL
;
189 if (fp
->_lock
!= NULL
)
190 _IO_lock_fini (*fp
->_lock
);
193 _IO_un_link ((struct _IO_FILE_plus
*) fp
);
195 libc_hidden_def (_IO_wdefault_finish
)
199 _IO_wdefault_uflow (FILE *fp
)
202 wch
= _IO_UNDERFLOW (fp
);
205 return *fp
->_wide_data
->_IO_read_ptr
++;
207 libc_hidden_def (_IO_wdefault_uflow
)
211 __woverflow (FILE *f
, wint_t wch
)
215 return _IO_OVERFLOW (f
, wch
);
217 libc_hidden_def (__woverflow
)
223 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
228 if (_IO_in_put_mode (fp
))
229 if (_IO_switch_to_wget_mode (fp
) == EOF
)
231 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
232 return *fp
->_wide_data
->_IO_read_ptr
++;
233 if (_IO_in_backup (fp
))
235 _IO_switch_to_main_wget_area (fp
);
236 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
237 return *fp
->_wide_data
->_IO_read_ptr
++;
239 if (_IO_have_markers (fp
))
241 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
244 else if (_IO_have_wbackup (fp
))
245 _IO_free_wbackup_area (fp
);
246 return _IO_UFLOW (fp
);
248 libc_hidden_def (__wuflow
)
251 __wunderflow (FILE *fp
)
253 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
258 if (_IO_in_put_mode (fp
))
259 if (_IO_switch_to_wget_mode (fp
) == EOF
)
261 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
262 return *fp
->_wide_data
->_IO_read_ptr
;
263 if (_IO_in_backup (fp
))
265 _IO_switch_to_main_wget_area (fp
);
266 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
267 return *fp
->_wide_data
->_IO_read_ptr
;
269 if (_IO_have_markers (fp
))
271 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
274 else if (_IO_have_backup (fp
))
275 _IO_free_wbackup_area (fp
);
276 return _IO_UNDERFLOW (fp
);
278 libc_hidden_def (__wunderflow
)
282 _IO_wdefault_xsputn (FILE *f
, const void *data
, size_t n
)
284 const wchar_t *s
= (const wchar_t *) data
;
290 /* Space available. */
291 ssize_t count
= (f
->_wide_data
->_IO_write_end
292 - f
->_wide_data
->_IO_write_ptr
);
295 if ((size_t) count
> more
)
299 f
->_wide_data
->_IO_write_ptr
=
300 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
307 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
309 for (i
= count
; --i
>= 0; )
311 f
->_wide_data
->_IO_write_ptr
= p
;
315 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
321 libc_hidden_def (_IO_wdefault_xsputn
)
325 _IO_wdefault_xsgetn (FILE *fp
, void *data
, size_t n
)
328 wchar_t *s
= (wchar_t*) data
;
331 /* Data available. */
332 ssize_t count
= (fp
->_wide_data
->_IO_read_end
333 - fp
->_wide_data
->_IO_read_ptr
);
336 if ((size_t) count
> more
)
340 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
341 fp
->_wide_data
->_IO_read_ptr
+= count
;
347 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
351 fp
->_wide_data
->_IO_read_ptr
= p
;
355 if (more
== 0 || __wunderflow (fp
) == WEOF
)
360 libc_hidden_def (_IO_wdefault_xsgetn
)
364 _IO_wdoallocbuf (FILE *fp
)
366 if (fp
->_wide_data
->_IO_buf_base
)
368 if (!(fp
->_flags
& _IO_UNBUFFERED
))
369 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
371 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
,
372 fp
->_wide_data
->_shortbuf
+ 1, 0);
374 libc_hidden_def (_IO_wdoallocbuf
)
378 _IO_wdefault_doallocate (FILE *fp
)
380 wchar_t *buf
= (wchar_t *)malloc (BUFSIZ
);
381 if (__glibc_unlikely (buf
== NULL
))
384 _IO_wsetb (fp
, buf
, buf
+ BUFSIZ
/ sizeof *buf
, 1);
387 libc_hidden_def (_IO_wdefault_doallocate
)
391 _IO_switch_to_wget_mode (FILE *fp
)
393 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
394 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
396 if (_IO_in_backup (fp
))
397 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
400 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
401 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
402 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
404 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
406 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
407 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
409 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
412 libc_hidden_def (_IO_switch_to_wget_mode
)
415 _IO_free_wbackup_area (FILE *fp
)
417 if (_IO_in_backup (fp
))
418 _IO_switch_to_main_wget_area (fp
); /* Just in case. */
419 free (fp
->_wide_data
->_IO_save_base
);
420 fp
->_wide_data
->_IO_save_base
= NULL
;
421 fp
->_wide_data
->_IO_save_end
= NULL
;
422 fp
->_wide_data
->_IO_backup_base
= NULL
;
424 libc_hidden_def (_IO_free_wbackup_area
)
427 save_for_wbackup (FILE *fp
, wchar_t *end_p
)
429 /* Append [_IO_read_base..end_p] to backup area. */
430 ssize_t least_mark
= _IO_least_wmarker (fp
, end_p
);
431 /* needed_size is how much space we need in the backup area. */
432 size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
434 /* FIXME: Dubious arithmetic if pointers are NULL */
435 size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
436 - fp
->_wide_data
->_IO_save_base
);
437 size_t avail
; /* Extra space available for future expansion. */
439 struct _IO_marker
*mark
;
440 if (needed_size
> current_Bsize
)
444 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
446 if (new_buffer
== NULL
)
447 return EOF
; /* FIXME */
450 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
451 fp
->_wide_data
->_IO_save_end
+ least_mark
,
453 fp
->_wide_data
->_IO_read_base
,
454 end_p
- fp
->_wide_data
->_IO_read_base
);
458 __wmemcpy (new_buffer
+ avail
,
459 fp
->_wide_data
->_IO_read_base
+ least_mark
,
462 free (fp
->_wide_data
->_IO_save_base
);
463 fp
->_wide_data
->_IO_save_base
= new_buffer
;
464 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
468 avail
= current_Bsize
- needed_size
;
471 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
472 fp
->_wide_data
->_IO_save_end
+ least_mark
,
474 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
475 fp
->_wide_data
->_IO_read_base
,
476 end_p
- fp
->_wide_data
->_IO_read_base
);
478 else if (needed_size
> 0)
479 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
480 fp
->_wide_data
->_IO_read_base
+ least_mark
,
483 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
484 /* Adjust all the streammarkers. */
485 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
486 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
492 _IO_sputbackwc (FILE *fp
, wint_t c
)
496 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
497 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
499 fp
->_wide_data
->_IO_read_ptr
--;
503 result
= _IO_PBACKFAIL (fp
, c
);
506 fp
->_flags
&= ~_IO_EOF_SEEN
;
510 libc_hidden_def (_IO_sputbackwc
)
513 _IO_sungetwc (FILE *fp
)
517 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
519 fp
->_wide_data
->_IO_read_ptr
--;
520 result
= *fp
->_wide_data
->_IO_read_ptr
;
523 result
= _IO_PBACKFAIL (fp
, EOF
);
526 fp
->_flags
&= ~_IO_EOF_SEEN
;
533 _IO_adjust_wcolumn (unsigned start
, const wchar_t *line
, int count
)
535 const wchar_t *ptr
= line
+ count
;
538 return line
+ count
- ptr
- 1;
539 return start
+ count
;
543 _IO_init_wmarker (struct _IO_marker
*marker
, FILE *fp
)
546 if (_IO_in_put_mode (fp
))
547 _IO_switch_to_wget_mode (fp
);
548 if (_IO_in_backup (fp
))
549 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
551 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
552 - fp
->_wide_data
->_IO_read_base
);
554 /* Should perhaps sort the chain? */
555 marker
->_next
= fp
->_markers
;
556 fp
->_markers
= marker
;
559 #define BAD_DELTA EOF
561 /* Return difference between MARK and current position of MARK's stream. */
563 _IO_wmarker_delta (struct _IO_marker
*mark
)
566 if (mark
->_sbuf
== NULL
)
568 if (_IO_in_backup (mark
->_sbuf
))
569 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
570 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
572 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
573 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
574 return mark
->_pos
- cur_pos
;
578 _IO_seekwmark (FILE *fp
, struct _IO_marker
*mark
, int delta
)
580 if (mark
->_sbuf
!= fp
)
584 if (_IO_in_backup (fp
))
585 _IO_switch_to_main_wget_area (fp
);
586 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
591 if (!_IO_in_backup (fp
))
592 _IO_switch_to_wbackup_area (fp
);
593 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
599 _IO_unsave_wmarkers (FILE *fp
)
601 struct _IO_marker
*mark
= fp
->_markers
;
607 if (_IO_have_backup (fp
))
608 _IO_free_wbackup_area (fp
);