1/* Copyright (C) 1993-2018 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>.
5
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.
10
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.
15
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/>.
19
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. */
28
29/* Generic or default I/O operations. */
30
31#include "libioP.h"
32#include <stdlib.h>
33#include <string.h>
34#include <wchar.h>
35
36
37static int save_for_wbackup (_IO_FILE *fp, wchar_t *end_p) __THROW;
38
39/* Return minimum _pos markers
40 Assumes the current get area is the main get area. */
41_IO_ssize_t
42_IO_least_wmarker (_IO_FILE *fp, wchar_t *end_p)
43{
44 _IO_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;
49 return least_so_far;
50}
51libc_hidden_def (_IO_least_wmarker)
52
53/* Switch current get area from backup buffer to (start of) main get area. */
54void
55_IO_switch_to_main_wget_area (_IO_FILE *fp)
56{
57 wchar_t *tmp;
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;
69}
70libc_hidden_def (_IO_switch_to_main_wget_area)
71
72
73/* Switch current get area from main get area to (end of) backup area. */
74void
75_IO_switch_to_wbackup_area (_IO_FILE *fp)
76{
77 wchar_t *tmp;
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;
89}
90libc_hidden_def (_IO_switch_to_wbackup_area)
91
92
93void
94_IO_wsetb (_IO_FILE *f, wchar_t *b, wchar_t *eb, int a)
95{
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;
100 if (a)
101 f->_flags2 &= ~_IO_FLAGS2_USER_WBUF;
102 else
103 f->_flags2 |= _IO_FLAGS2_USER_WBUF;
104}
105libc_hidden_def (_IO_wsetb)
106
107
108wint_t
109_IO_wdefault_pbackfail (_IO_FILE *fp, wint_t c)
110{
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)
114 --fp->_IO_read_ptr;
115 else
116 {
117 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
118 if (!_IO_in_backup (fp))
119 {
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))
124 {
125 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr))
126 return WEOF;
127 }
128 else if (!_IO_have_wbackup (fp))
129 {
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
134 * sizeof (wchar_t));
135 if (bbuf == NULL)
136 return WEOF;
137 fp->_wide_data->_IO_save_base = bbuf;
138 fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base
139 + backup_size);
140 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end;
141 }
142 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr;
143 _IO_switch_to_wbackup_area (fp);
144 }
145 else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base)
146 {
147 /* Increase size of existing backup buffer. */
148 _IO_size_t new_size;
149 _IO_size_t old_size = (fp->_wide_data->_IO_read_end
150 - fp->_wide_data->_IO_read_base);
151 wchar_t *new_buf;
152 new_size = 2 * old_size;
153 new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t));
154 if (new_buf == NULL)
155 return WEOF;
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),
160 new_buf + new_size);
161 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr;
162 }
163
164 *--fp->_wide_data->_IO_read_ptr = c;
165 }
166 return c;
167}
168libc_hidden_def (_IO_wdefault_pbackfail)
169
170
171void
172_IO_wdefault_finish (_IO_FILE *fp, int dummy)
173{
174 struct _IO_marker *mark;
175 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
176 {
177 free (fp->_wide_data->_IO_buf_base);
178 fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
179 }
180
181 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
182 mark->_sbuf = NULL;
183
184 if (fp->_IO_save_base)
185 {
186 free (fp->_wide_data->_IO_save_base);
187 fp->_IO_save_base = NULL;
188 }
189
190#ifdef _IO_MTSAFE_IO
191 if (fp->_lock != NULL)
192 _IO_lock_fini (*fp->_lock);
193#endif
194
195 _IO_un_link ((struct _IO_FILE_plus *) fp);
196}
197libc_hidden_def (_IO_wdefault_finish)
198
199
200wint_t
201_IO_wdefault_uflow (_IO_FILE *fp)
202{
203 wint_t wch;
204 wch = _IO_UNDERFLOW (fp);
205 if (wch == WEOF)
206 return WEOF;
207 return *fp->_wide_data->_IO_read_ptr++;
208}
209libc_hidden_def (_IO_wdefault_uflow)
210
211
212wint_t
213__woverflow (_IO_FILE *f, wint_t wch)
214{
215 if (f->_mode == 0)
216 _IO_fwide (f, 1);
217 return _IO_OVERFLOW (f, wch);
218}
219libc_hidden_def (__woverflow)
220
221
222wint_t
223__wuflow (_IO_FILE *fp)
224{
225 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
226 return WEOF;
227
228 if (fp->_mode == 0)
229 _IO_fwide (fp, 1);
230 if (_IO_in_put_mode (fp))
231 if (_IO_switch_to_wget_mode (fp) == EOF)
232 return WEOF;
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))
236 {
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++;
240 }
241 if (_IO_have_markers (fp))
242 {
243 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
244 return WEOF;
245 }
246 else if (_IO_have_wbackup (fp))
247 _IO_free_wbackup_area (fp);
248 return _IO_UFLOW (fp);
249}
250libc_hidden_def (__wuflow)
251
252wint_t
253__wunderflow (_IO_FILE *fp)
254{
255 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
256 return WEOF;
257
258 if (fp->_mode == 0)
259 _IO_fwide (fp, 1);
260 if (_IO_in_put_mode (fp))
261 if (_IO_switch_to_wget_mode (fp) == EOF)
262 return WEOF;
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))
266 {
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;
270 }
271 if (_IO_have_markers (fp))
272 {
273 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
274 return WEOF;
275 }
276 else if (_IO_have_backup (fp))
277 _IO_free_wbackup_area (fp);
278 return _IO_UNDERFLOW (fp);
279}
280libc_hidden_def (__wunderflow)
281
282
283_IO_size_t
284_IO_wdefault_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
285{
286 const wchar_t *s = (const wchar_t *) data;
287 _IO_size_t more = n;
288 if (more <= 0)
289 return 0;
290 for (;;)
291 {
292 /* Space available. */
293 _IO_ssize_t count = (f->_wide_data->_IO_write_end
294 - f->_wide_data->_IO_write_ptr);
295 if (count > 0)
296 {
297 if ((_IO_size_t) count > more)
298 count = more;
299 if (count > 20)
300 {
301 f->_wide_data->_IO_write_ptr =
302 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
303 s += count;
304 }
305 else if (count <= 0)
306 count = 0;
307 else
308 {
309 wchar_t *p = f->_wide_data->_IO_write_ptr;
310 _IO_ssize_t i;
311 for (i = count; --i >= 0; )
312 *p++ = *s++;
313 f->_wide_data->_IO_write_ptr = p;
314 }
315 more -= count;
316 }
317 if (more == 0 || __woverflow (f, *s++) == WEOF)
318 break;
319 more--;
320 }
321 return n - more;
322}
323libc_hidden_def (_IO_wdefault_xsputn)
324
325
326_IO_size_t
327_IO_wdefault_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
328{
329 _IO_size_t more = n;
330 wchar_t *s = (wchar_t*) data;
331 for (;;)
332 {
333 /* Data available. */
334 _IO_ssize_t count = (fp->_wide_data->_IO_read_end
335 - fp->_wide_data->_IO_read_ptr);
336 if (count > 0)
337 {
338 if ((_IO_size_t) count > more)
339 count = more;
340 if (count > 20)
341 {
342 s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
343 fp->_wide_data->_IO_read_ptr += count;
344 }
345 else if (count <= 0)
346 count = 0;
347 else
348 {
349 wchar_t *p = fp->_wide_data->_IO_read_ptr;
350 int i = (int) count;
351 while (--i >= 0)
352 *s++ = *p++;
353 fp->_wide_data->_IO_read_ptr = p;
354 }
355 more -= count;
356 }
357 if (more == 0 || __wunderflow (fp) == WEOF)
358 break;
359 }
360 return n - more;
361}
362libc_hidden_def (_IO_wdefault_xsgetn)
363
364
365void
366_IO_wdoallocbuf (_IO_FILE *fp)
367{
368 if (fp->_wide_data->_IO_buf_base)
369 return;
370 if (!(fp->_flags & _IO_UNBUFFERED))
371 if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
372 return;
373 _IO_wsetb (fp, fp->_wide_data->_shortbuf,
374 fp->_wide_data->_shortbuf + 1, 0);
375}
376libc_hidden_def (_IO_wdoallocbuf)
377
378
379int
380_IO_wdefault_doallocate (_IO_FILE *fp)
381{
382 wchar_t *buf;
383
384 buf = malloc (_IO_BUFSIZ);
385 if (__glibc_unlikely (buf == NULL))
386 return EOF;
387 _IO_wsetb (fp, buf, buf + _IO_BUFSIZ, 1);
388 return 1;
389}
390libc_hidden_def (_IO_wdefault_doallocate)
391
392
393int
394_IO_switch_to_wget_mode (_IO_FILE *fp)
395{
396 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
397 if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
398 return EOF;
399 if (_IO_in_backup (fp))
400 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
401 else
402 {
403 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
404 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
405 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
406 }
407 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
408
409 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
410 = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;
411
412 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
413 return 0;
414}
415libc_hidden_def (_IO_switch_to_wget_mode)
416
417void
418_IO_free_wbackup_area (_IO_FILE *fp)
419{
420 if (_IO_in_backup (fp))
421 _IO_switch_to_main_wget_area (fp); /* Just in case. */
422 free (fp->_wide_data->_IO_save_base);
423 fp->_wide_data->_IO_save_base = NULL;
424 fp->_wide_data->_IO_save_end = NULL;
425 fp->_wide_data->_IO_backup_base = NULL;
426}
427libc_hidden_def (_IO_free_wbackup_area)
428
429#if 0
430int
431_IO_switch_to_wput_mode (_IO_FILE *fp)
432{
433 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_read_ptr;
434 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
435 /* Following is wrong if line- or un-buffered? */
436 fp->_wide_data->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
437 ? fp->_wide_data->_IO_read_end
438 : fp->_wide_data->_IO_buf_end);
439
440 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
441 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_end;
442
443 fp->_flags |= _IO_CURRENTLY_PUTTING;
444 return 0;
445}
446#endif
447
448
449static int
450save_for_wbackup (_IO_FILE *fp, wchar_t *end_p)
451{
452 /* Append [_IO_read_base..end_p] to backup area. */
453 _IO_ssize_t least_mark = _IO_least_wmarker (fp, end_p);
454 /* needed_size is how much space we need in the backup area. */
455 _IO_size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base)
456 - least_mark);
457 /* FIXME: Dubious arithmetic if pointers are NULL */
458 _IO_size_t current_Bsize = (fp->_wide_data->_IO_save_end
459 - fp->_wide_data->_IO_save_base);
460 _IO_size_t avail; /* Extra space available for future expansion. */
461 _IO_ssize_t delta;
462 struct _IO_marker *mark;
463 if (needed_size > current_Bsize)
464 {
465 wchar_t *new_buffer;
466 avail = 100;
467 new_buffer = (wchar_t *) malloc ((avail + needed_size)
468 * sizeof (wchar_t));
469 if (new_buffer == NULL)
470 return EOF; /* FIXME */
471 if (least_mark < 0)
472 {
473 __wmempcpy (__wmempcpy (new_buffer + avail,
474 fp->_wide_data->_IO_save_end + least_mark,
475 -least_mark),
476 fp->_wide_data->_IO_read_base,
477 end_p - fp->_wide_data->_IO_read_base);
478 }
479 else
480 {
481 __wmemcpy (new_buffer + avail,
482 fp->_wide_data->_IO_read_base + least_mark,
483 needed_size);
484 }
485 free (fp->_wide_data->_IO_save_base);
486 fp->_wide_data->_IO_save_base = new_buffer;
487 fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size;
488 }
489 else
490 {
491 avail = current_Bsize - needed_size;
492 if (least_mark < 0)
493 {
494 __wmemmove (fp->_wide_data->_IO_save_base + avail,
495 fp->_wide_data->_IO_save_end + least_mark,
496 -least_mark);
497 __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
498 fp->_wide_data->_IO_read_base,
499 end_p - fp->_wide_data->_IO_read_base);
500 }
501 else if (needed_size > 0)
502 __wmemcpy (fp->_wide_data->_IO_save_base + avail,
503 fp->_wide_data->_IO_read_base + least_mark,
504 needed_size);
505 }
506 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail;
507 /* Adjust all the streammarkers. */
508 delta = end_p - fp->_wide_data->_IO_read_base;
509 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
510 mark->_pos -= delta;
511 return 0;
512}
513
514wint_t
515_IO_sputbackwc (_IO_FILE *fp, wint_t c)
516{
517 wint_t result;
518
519 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
520 && (wchar_t)fp->_wide_data->_IO_read_ptr[-1] == (wchar_t) c)
521 {
522 fp->_wide_data->_IO_read_ptr--;
523 result = c;
524 }
525 else
526 result = _IO_PBACKFAIL (fp, c);
527
528 if (result != WEOF)
529 fp->_flags &= ~_IO_EOF_SEEN;
530
531 return result;
532}
533libc_hidden_def (_IO_sputbackwc)
534
535wint_t
536_IO_sungetwc (_IO_FILE *fp)
537{
538 wint_t result;
539
540 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
541 {
542 fp->_wide_data->_IO_read_ptr--;
543 result = *fp->_wide_data->_IO_read_ptr;
544 }
545 else
546 result = _IO_PBACKFAIL (fp, EOF);
547
548 if (result != WEOF)
549 fp->_flags &= ~_IO_EOF_SEEN;
550
551 return result;
552}
553
554
555unsigned
556_IO_adjust_wcolumn (unsigned start, const wchar_t *line, int count)
557{
558 const wchar_t *ptr = line + count;
559 while (ptr > line)
560 if (*--ptr == L'\n')
561 return line + count - ptr - 1;
562 return start + count;
563}
564
565void
566_IO_init_wmarker (struct _IO_marker *marker, _IO_FILE *fp)
567{
568 marker->_sbuf = fp;
569 if (_IO_in_put_mode (fp))
570 _IO_switch_to_wget_mode (fp);
571 if (_IO_in_backup (fp))
572 marker->_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
573 else
574 marker->_pos = (fp->_wide_data->_IO_read_ptr
575 - fp->_wide_data->_IO_read_base);
576
577 /* Should perhaps sort the chain? */
578 marker->_next = fp->_markers;
579 fp->_markers = marker;
580}
581
582#define BAD_DELTA EOF
583
584/* Return difference between MARK and current position of MARK's stream. */
585int
586_IO_wmarker_delta (struct _IO_marker *mark)
587{
588 int cur_pos;
589 if (mark->_sbuf == NULL)
590 return BAD_DELTA;
591 if (_IO_in_backup (mark->_sbuf))
592 cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
593 - mark->_sbuf->_wide_data->_IO_read_end);
594 else
595 cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
596 - mark->_sbuf->_wide_data->_IO_read_base);
597 return mark->_pos - cur_pos;
598}
599
600int
601_IO_seekwmark (_IO_FILE *fp, struct _IO_marker *mark, int delta)
602{
603 if (mark->_sbuf != fp)
604 return EOF;
605 if (mark->_pos >= 0)
606 {
607 if (_IO_in_backup (fp))
608 _IO_switch_to_main_wget_area (fp);
609 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
610 + mark->_pos);
611 }
612 else
613 {
614 if (!_IO_in_backup (fp))
615 _IO_switch_to_wbackup_area (fp);
616 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end + mark->_pos;
617 }
618 return 0;
619}
620
621void
622_IO_unsave_wmarkers (_IO_FILE *fp)
623{
624 struct _IO_marker *mark = fp->_markers;
625 if (mark)
626 {
627#ifdef TODO
628 streampos offset = seekoff (0, ios::cur, ios::in);
629 if (offset != EOF)
630 {
631 offset += eGptr () - Gbase ();
632 for ( ; mark != NULL; mark = mark->_next)
633 mark->set_streampos (mark->_pos + offset);
634 }
635 else
636 {
637 for ( ; mark != NULL; mark = mark->_next)
638 mark->set_streampos (EOF);
639 }
640#endif
641 fp->_markers = 0;
642 }
643
644 if (_IO_have_backup (fp))
645 _IO_free_wbackup_area (fp);
646}
647