1 /* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
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.
8
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.
13
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/>.
17
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. */
26
27 /* Generic or default I/O operations. */
28
29 #include "libioP.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wchar.h>
33
34
35 static int save_for_wbackup (FILE *fp, wchar_t *end_p) __THROW;
36
37 /* Return minimum _pos markers
38 Assumes the current get area is the main get area. */
39 ssize_t
_IO_least_wmarker(FILE * fp,wchar_t * end_p)40 _IO_least_wmarker (FILE *fp, wchar_t *end_p)
41 {
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;
47 return least_so_far;
48 }
libc_hidden_def(_IO_least_wmarker)49 libc_hidden_def (_IO_least_wmarker)
50
51 /* Switch current get area from backup buffer to (start of) main get area. */
52 void
53 _IO_switch_to_main_wget_area (FILE *fp)
54 {
55 wchar_t *tmp;
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;
67 }
libc_hidden_def(_IO_switch_to_main_wget_area)68 libc_hidden_def (_IO_switch_to_main_wget_area)
69
70
71 /* Switch current get area from main get area to (end of) backup area. */
72 void
73 _IO_switch_to_wbackup_area (FILE *fp)
74 {
75 wchar_t *tmp;
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;
87 }
libc_hidden_def(_IO_switch_to_wbackup_area)88 libc_hidden_def (_IO_switch_to_wbackup_area)
89
90
91 void
92 _IO_wsetb (FILE *f, wchar_t *b, wchar_t *eb, int a)
93 {
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;
98 if (a)
99 f->_flags2 &= ~_IO_FLAGS2_USER_WBUF;
100 else
101 f->_flags2 |= _IO_FLAGS2_USER_WBUF;
102 }
libc_hidden_def(_IO_wsetb)103 libc_hidden_def (_IO_wsetb)
104
105
106 wint_t
107 _IO_wdefault_pbackfail (FILE *fp, wint_t c)
108 {
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)
112 --fp->_IO_read_ptr;
113 else
114 {
115 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
116 if (!_IO_in_backup (fp))
117 {
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))
122 {
123 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr))
124 return WEOF;
125 }
126 else if (!_IO_have_wbackup (fp))
127 {
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
132 * sizeof (wchar_t));
133 if (bbuf == NULL)
134 return WEOF;
135 fp->_wide_data->_IO_save_base = bbuf;
136 fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base
137 + backup_size);
138 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end;
139 }
140 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr;
141 _IO_switch_to_wbackup_area (fp);
142 }
143 else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base)
144 {
145 /* Increase size of existing backup buffer. */
146 size_t new_size;
147 size_t old_size = (fp->_wide_data->_IO_read_end
148 - fp->_wide_data->_IO_read_base);
149 wchar_t *new_buf;
150 new_size = 2 * old_size;
151 new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t));
152 if (new_buf == NULL)
153 return WEOF;
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),
158 new_buf + new_size);
159 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr;
160 }
161
162 *--fp->_wide_data->_IO_read_ptr = c;
163 }
164 return c;
165 }
libc_hidden_def(_IO_wdefault_pbackfail)166 libc_hidden_def (_IO_wdefault_pbackfail)
167
168
169 void
170 _IO_wdefault_finish (FILE *fp, int dummy)
171 {
172 struct _IO_marker *mark;
173 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
174 {
175 free (fp->_wide_data->_IO_buf_base);
176 fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
177 }
178
179 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
180 mark->_sbuf = NULL;
181
182 if (fp->_IO_save_base)
183 {
184 free (fp->_wide_data->_IO_save_base);
185 fp->_IO_save_base = NULL;
186 }
187
188 #ifdef _IO_MTSAFE_IO
189 if (fp->_lock != NULL)
190 _IO_lock_fini (*fp->_lock);
191 #endif
192
193 _IO_un_link ((struct _IO_FILE_plus *) fp);
194 }
libc_hidden_def(_IO_wdefault_finish)195 libc_hidden_def (_IO_wdefault_finish)
196
197
198 wint_t
199 _IO_wdefault_uflow (FILE *fp)
200 {
201 wint_t wch;
202 wch = _IO_UNDERFLOW (fp);
203 if (wch == WEOF)
204 return WEOF;
205 return *fp->_wide_data->_IO_read_ptr++;
206 }
libc_hidden_def(_IO_wdefault_uflow)207 libc_hidden_def (_IO_wdefault_uflow)
208
209
210 wint_t
211 __woverflow (FILE *f, wint_t wch)
212 {
213 if (f->_mode == 0)
214 _IO_fwide (f, 1);
215 return _IO_OVERFLOW (f, wch);
216 }
libc_hidden_def(__woverflow)217 libc_hidden_def (__woverflow)
218
219
220 wint_t
221 __wuflow (FILE *fp)
222 {
223 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
224 return WEOF;
225
226 if (fp->_mode == 0)
227 _IO_fwide (fp, 1);
228 if (_IO_in_put_mode (fp))
229 if (_IO_switch_to_wget_mode (fp) == EOF)
230 return WEOF;
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))
234 {
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++;
238 }
239 if (_IO_have_markers (fp))
240 {
241 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
242 return WEOF;
243 }
244 else if (_IO_have_wbackup (fp))
245 _IO_free_wbackup_area (fp);
246 return _IO_UFLOW (fp);
247 }
libc_hidden_def(__wuflow)248 libc_hidden_def (__wuflow)
249
250 wint_t
251 __wunderflow (FILE *fp)
252 {
253 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
254 return WEOF;
255
256 if (fp->_mode == 0)
257 _IO_fwide (fp, 1);
258 if (_IO_in_put_mode (fp))
259 if (_IO_switch_to_wget_mode (fp) == EOF)
260 return WEOF;
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))
264 {
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;
268 }
269 if (_IO_have_markers (fp))
270 {
271 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
272 return WEOF;
273 }
274 else if (_IO_have_backup (fp))
275 _IO_free_wbackup_area (fp);
276 return _IO_UNDERFLOW (fp);
277 }
libc_hidden_def(__wunderflow)278 libc_hidden_def (__wunderflow)
279
280
281 size_t
282 _IO_wdefault_xsputn (FILE *f, const void *data, size_t n)
283 {
284 const wchar_t *s = (const wchar_t *) data;
285 size_t more = n;
286 if (more <= 0)
287 return 0;
288 for (;;)
289 {
290 /* Space available. */
291 ssize_t count = (f->_wide_data->_IO_write_end
292 - f->_wide_data->_IO_write_ptr);
293 if (count > 0)
294 {
295 if ((size_t) count > more)
296 count = more;
297 if (count > 20)
298 {
299 f->_wide_data->_IO_write_ptr =
300 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
301 s += count;
302 }
303 else if (count <= 0)
304 count = 0;
305 else
306 {
307 wchar_t *p = f->_wide_data->_IO_write_ptr;
308 ssize_t i;
309 for (i = count; --i >= 0; )
310 *p++ = *s++;
311 f->_wide_data->_IO_write_ptr = p;
312 }
313 more -= count;
314 }
315 if (more == 0 || __woverflow (f, *s++) == WEOF)
316 break;
317 more--;
318 }
319 return n - more;
320 }
libc_hidden_def(_IO_wdefault_xsputn)321 libc_hidden_def (_IO_wdefault_xsputn)
322
323
324 size_t
325 _IO_wdefault_xsgetn (FILE *fp, void *data, size_t n)
326 {
327 size_t more = n;
328 wchar_t *s = (wchar_t*) data;
329 for (;;)
330 {
331 /* Data available. */
332 ssize_t count = (fp->_wide_data->_IO_read_end
333 - fp->_wide_data->_IO_read_ptr);
334 if (count > 0)
335 {
336 if ((size_t) count > more)
337 count = more;
338 if (count > 20)
339 {
340 s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
341 fp->_wide_data->_IO_read_ptr += count;
342 }
343 else if (count <= 0)
344 count = 0;
345 else
346 {
347 wchar_t *p = fp->_wide_data->_IO_read_ptr;
348 int i = (int) count;
349 while (--i >= 0)
350 *s++ = *p++;
351 fp->_wide_data->_IO_read_ptr = p;
352 }
353 more -= count;
354 }
355 if (more == 0 || __wunderflow (fp) == WEOF)
356 break;
357 }
358 return n - more;
359 }
libc_hidden_def(_IO_wdefault_xsgetn)360 libc_hidden_def (_IO_wdefault_xsgetn)
361
362
363 void
364 _IO_wdoallocbuf (FILE *fp)
365 {
366 if (fp->_wide_data->_IO_buf_base)
367 return;
368 if (!(fp->_flags & _IO_UNBUFFERED))
369 if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
370 return;
371 _IO_wsetb (fp, fp->_wide_data->_shortbuf,
372 fp->_wide_data->_shortbuf + 1, 0);
373 }
libc_hidden_def(_IO_wdoallocbuf)374 libc_hidden_def (_IO_wdoallocbuf)
375
376
377 int
378 _IO_wdefault_doallocate (FILE *fp)
379 {
380 wchar_t *buf = (wchar_t *)malloc (BUFSIZ);
381 if (__glibc_unlikely (buf == NULL))
382 return EOF;
383
384 _IO_wsetb (fp, buf, buf + BUFSIZ / sizeof *buf, 1);
385 return 1;
386 }
libc_hidden_def(_IO_wdefault_doallocate)387 libc_hidden_def (_IO_wdefault_doallocate)
388
389
390 int
391 _IO_switch_to_wget_mode (FILE *fp)
392 {
393 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
394 if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
395 return EOF;
396 if (_IO_in_backup (fp))
397 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
398 else
399 {
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;
403 }
404 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
405
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;
408
409 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
410 return 0;
411 }
libc_hidden_def(_IO_switch_to_wget_mode)412 libc_hidden_def (_IO_switch_to_wget_mode)
413
414 void
415 _IO_free_wbackup_area (FILE *fp)
416 {
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;
423 }
libc_hidden_def(_IO_free_wbackup_area)424 libc_hidden_def (_IO_free_wbackup_area)
425
426 static int
427 save_for_wbackup (FILE *fp, wchar_t *end_p)
428 {
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)
433 - least_mark);
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. */
438 ssize_t delta;
439 struct _IO_marker *mark;
440 if (needed_size > current_Bsize)
441 {
442 wchar_t *new_buffer;
443 avail = 100;
444 new_buffer = (wchar_t *) malloc ((avail + needed_size)
445 * sizeof (wchar_t));
446 if (new_buffer == NULL)
447 return EOF; /* FIXME */
448 if (least_mark < 0)
449 {
450 __wmempcpy (__wmempcpy (new_buffer + avail,
451 fp->_wide_data->_IO_save_end + least_mark,
452 -least_mark),
453 fp->_wide_data->_IO_read_base,
454 end_p - fp->_wide_data->_IO_read_base);
455 }
456 else
457 {
458 __wmemcpy (new_buffer + avail,
459 fp->_wide_data->_IO_read_base + least_mark,
460 needed_size);
461 }
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;
465 }
466 else
467 {
468 avail = current_Bsize - needed_size;
469 if (least_mark < 0)
470 {
471 __wmemmove (fp->_wide_data->_IO_save_base + avail,
472 fp->_wide_data->_IO_save_end + least_mark,
473 -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);
477 }
478 else if (needed_size > 0)
479 __wmemcpy (fp->_wide_data->_IO_save_base + avail,
480 fp->_wide_data->_IO_read_base + least_mark,
481 needed_size);
482 }
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)
487 mark->_pos -= delta;
488 return 0;
489 }
490
491 wint_t
_IO_sputbackwc(FILE * fp,wint_t c)492 _IO_sputbackwc (FILE *fp, wint_t c)
493 {
494 wint_t result;
495
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)
498 {
499 fp->_wide_data->_IO_read_ptr--;
500 result = c;
501 }
502 else
503 result = _IO_PBACKFAIL (fp, c);
504
505 if (result != WEOF)
506 fp->_flags &= ~_IO_EOF_SEEN;
507
508 return result;
509 }
libc_hidden_def(_IO_sputbackwc)510 libc_hidden_def (_IO_sputbackwc)
511
512 wint_t
513 _IO_sungetwc (FILE *fp)
514 {
515 wint_t result;
516
517 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
518 {
519 fp->_wide_data->_IO_read_ptr--;
520 result = *fp->_wide_data->_IO_read_ptr;
521 }
522 else
523 result = _IO_PBACKFAIL (fp, EOF);
524
525 if (result != WEOF)
526 fp->_flags &= ~_IO_EOF_SEEN;
527
528 return result;
529 }
530
531
532 unsigned
_IO_adjust_wcolumn(unsigned start,const wchar_t * line,int count)533 _IO_adjust_wcolumn (unsigned start, const wchar_t *line, int count)
534 {
535 const wchar_t *ptr = line + count;
536 while (ptr > line)
537 if (*--ptr == L'\n')
538 return line + count - ptr - 1;
539 return start + count;
540 }
541
542 void
_IO_init_wmarker(struct _IO_marker * marker,FILE * fp)543 _IO_init_wmarker (struct _IO_marker *marker, FILE *fp)
544 {
545 marker->_sbuf = 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;
550 else
551 marker->_pos = (fp->_wide_data->_IO_read_ptr
552 - fp->_wide_data->_IO_read_base);
553
554 /* Should perhaps sort the chain? */
555 marker->_next = fp->_markers;
556 fp->_markers = marker;
557 }
558
559 #define BAD_DELTA EOF
560
561 /* Return difference between MARK and current position of MARK's stream. */
562 int
_IO_wmarker_delta(struct _IO_marker * mark)563 _IO_wmarker_delta (struct _IO_marker *mark)
564 {
565 int cur_pos;
566 if (mark->_sbuf == NULL)
567 return BAD_DELTA;
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);
571 else
572 cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
573 - mark->_sbuf->_wide_data->_IO_read_base);
574 return mark->_pos - cur_pos;
575 }
576
577 int
_IO_seekwmark(FILE * fp,struct _IO_marker * mark,int delta)578 _IO_seekwmark (FILE *fp, struct _IO_marker *mark, int delta)
579 {
580 if (mark->_sbuf != fp)
581 return EOF;
582 if (mark->_pos >= 0)
583 {
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
587 + mark->_pos);
588 }
589 else
590 {
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;
594 }
595 return 0;
596 }
597
598 void
_IO_unsave_wmarkers(FILE * fp)599 _IO_unsave_wmarkers (FILE *fp)
600 {
601 struct _IO_marker *mark = fp->_markers;
602 if (mark)
603 {
604 fp->_markers = 0;
605 }
606
607 if (_IO_have_backup (fp))
608 _IO_free_wbackup_area (fp);
609 }
610