1 /* Copyright (C) 1993-2014 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 (fp, end_p)
55 _IO_ssize_t least_so_far = end_p - fp->_wide_data->_IO_read_base;
56 struct _IO_marker *mark;
57 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
58 if (mark->_pos < least_so_far)
59 least_so_far = mark->_pos;
62 libc_hidden_def (_IO_least_wmarker)
64 /* Switch current get area from backup buffer to (start of) main get area. */
66 _IO_switch_to_main_wget_area (fp)
70 fp->_flags &= ~_IO_IN_BACKUP;
71 /* Swap _IO_read_end and _IO_save_end. */
72 tmp = fp->_wide_data->_IO_read_end;
73 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
74 fp->_wide_data->_IO_save_end= tmp;
75 /* Swap _IO_read_base and _IO_save_base. */
76 tmp = fp->_wide_data->_IO_read_base;
77 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
78 fp->_wide_data->_IO_save_base = tmp;
79 /* Set _IO_read_ptr. */
80 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
82 libc_hidden_def (_IO_switch_to_main_wget_area)
85 /* Switch current get area from main get area to (end of) backup area. */
87 _IO_switch_to_wbackup_area (fp)
91 fp->_flags |= _IO_IN_BACKUP;
92 /* Swap _IO_read_end and _IO_save_end. */
93 tmp = fp->_wide_data->_IO_read_end;
94 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
95 fp->_wide_data->_IO_save_end = tmp;
96 /* Swap _IO_read_base and _IO_save_base. */
97 tmp = fp->_wide_data->_IO_read_base;
98 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
99 fp->_wide_data->_IO_save_base = tmp;
100 /* Set _IO_read_ptr. */
101 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
103 libc_hidden_def (_IO_switch_to_wbackup_area)
107 _IO_wsetb (f, b, eb, a)
113 if (f->_wide_data->_IO_buf_base && !(f->_flags2 & _IO_FLAGS2_USER_WBUF))
114 FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f) * sizeof (wchar_t));
115 f->_wide_data->_IO_buf_base = b;
116 f->_wide_data->_IO_buf_end = eb;
118 f->_flags2 &= ~_IO_FLAGS2_USER_WBUF;
120 f->_flags2 |= _IO_FLAGS2_USER_WBUF;
122 libc_hidden_def (_IO_wsetb)
126 _IO_wdefault_pbackfail (fp, c)
130 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
131 && !_IO_in_backup (fp)
132 && (wint_t) fp->_IO_read_ptr[-1] == c)
136 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
137 if (!_IO_in_backup (fp))
139 /* We need to keep the invariant that the main get area
140 logically follows the backup area. */
141 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
142 && _IO_have_wbackup (fp))
144 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr))
147 else if (!_IO_have_wbackup (fp))
149 /* No backup buffer: allocate one. */
150 /* Use nshort buffer, if unused? (probably not) FIXME */
151 int backup_size = 128;
152 wchar_t *bbuf = (wchar_t *) malloc (backup_size
156 fp->_wide_data->_IO_save_base = bbuf;
157 fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base
159 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end;
161 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr;
162 _IO_switch_to_wbackup_area (fp);
164 else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base)
166 /* Increase size of existing backup buffer. */
168 _IO_size_t old_size = (fp->_wide_data->_IO_read_end
169 - fp->_wide_data->_IO_read_base);
171 new_size = 2 * old_size;
172 new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t));
175 __wmemcpy (new_buf + (new_size - old_size),
176 fp->_wide_data->_IO_read_base, old_size);
177 free (fp->_wide_data->_IO_read_base);
178 _IO_wsetg (fp, new_buf, new_buf + (new_size - old_size),
180 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr;
183 *--fp->_wide_data->_IO_read_ptr = c;
187 libc_hidden_def (_IO_wdefault_pbackfail)
191 _IO_wdefault_finish (fp, dummy)
195 struct _IO_marker *mark;
196 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
198 FREE_BUF (fp->_wide_data->_IO_buf_base,
199 _IO_wblen (fp) * sizeof (wchar_t));
200 fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
203 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
206 if (fp->_IO_save_base)
208 free (fp->_wide_data->_IO_save_base);
209 fp->_IO_save_base = NULL;
213 if (fp->_lock != NULL)
214 _IO_lock_fini (*fp->_lock);
217 _IO_un_link ((struct _IO_FILE_plus *) fp);
219 libc_hidden_def (_IO_wdefault_finish)
223 _IO_wdefault_uflow (fp)
227 wch = _IO_UNDERFLOW (fp);
230 return *fp->_wide_data->_IO_read_ptr++;
232 libc_hidden_def (_IO_wdefault_uflow)
242 return _IO_OVERFLOW (f, wch);
244 libc_hidden_def (__woverflow)
251 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
256 if (_IO_in_put_mode (fp))
257 if (_IO_switch_to_wget_mode (fp) == EOF)
259 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
260 return *fp->_wide_data->_IO_read_ptr++;
261 if (_IO_in_backup (fp))
263 _IO_switch_to_main_wget_area (fp);
264 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
265 return *fp->_wide_data->_IO_read_ptr++;
267 if (_IO_have_markers (fp))
269 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
272 else if (_IO_have_wbackup (fp))
273 _IO_free_wbackup_area (fp);
274 return _IO_UFLOW (fp);
276 libc_hidden_def (__wuflow)
282 if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
287 if (_IO_in_put_mode (fp))
288 if (_IO_switch_to_wget_mode (fp) == EOF)
290 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
291 return *fp->_wide_data->_IO_read_ptr;
292 if (_IO_in_backup (fp))
294 _IO_switch_to_main_wget_area (fp);
295 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
296 return *fp->_wide_data->_IO_read_ptr;
298 if (_IO_have_markers (fp))
300 if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
303 else if (_IO_have_backup (fp))
304 _IO_free_wbackup_area (fp);
305 return _IO_UNDERFLOW (fp);
307 libc_hidden_def (__wunderflow)
311 _IO_wdefault_xsputn (f, data, n)
316 const wchar_t *s = (const wchar_t *) data;
322 /* Space available. */
323 _IO_ssize_t count = (f->_wide_data->_IO_write_end
324 - f->_wide_data->_IO_write_ptr);
327 if ((_IO_size_t) count > more)
332 f->_wide_data->_IO_write_ptr =
333 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
335 memcpy (f->_wide_data->_IO_write_ptr, s, count);
336 f->_wide_data->_IO_write_ptr += count;
344 wchar_t *p = f->_wide_data->_IO_write_ptr;
346 for (i = count; --i >= 0; )
348 f->_wide_data->_IO_write_ptr = p;
352 if (more == 0 || __woverflow (f, *s++) == WEOF)
358 libc_hidden_def (_IO_wdefault_xsputn)
362 _IO_wdefault_xsgetn (fp, data, n)
368 wchar_t *s = (wchar_t*) data;
371 /* Data available. */
372 _IO_ssize_t count = (fp->_wide_data->_IO_read_end
373 - fp->_wide_data->_IO_read_ptr);
376 if ((_IO_size_t) count > more)
381 s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
383 memcpy (s, fp->_wide_data->_IO_read_ptr, count);
386 fp->_wide_data->_IO_read_ptr += count;
392 wchar_t *p = fp->_wide_data->_IO_read_ptr;
396 fp->_wide_data->_IO_read_ptr = p;
400 if (more == 0 || __wunderflow (fp) == WEOF)
405 libc_hidden_def (_IO_wdefault_xsgetn)
412 if (fp->_wide_data->_IO_buf_base)
414 if (!(fp->_flags & _IO_UNBUFFERED))
415 if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
417 _IO_wsetb (fp, fp->_wide_data->_shortbuf,
418 fp->_wide_data->_shortbuf + 1, 0);
420 libc_hidden_def (_IO_wdoallocbuf)
424 _IO_wdefault_doallocate (fp)
429 ALLOC_WBUF (buf, _IO_BUFSIZ, EOF);
430 _IO_wsetb (fp, buf, buf + _IO_BUFSIZ, 1);
433 libc_hidden_def (_IO_wdefault_doallocate)
437 _IO_switch_to_wget_mode (fp)
440 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
441 if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
443 if (_IO_in_backup (fp))
444 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
447 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
448 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
449 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
451 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
453 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
454 = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;
456 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
459 libc_hidden_def (_IO_switch_to_wget_mode)
462 _IO_free_wbackup_area (fp)
465 if (_IO_in_backup (fp))
466 _IO_switch_to_main_wget_area (fp); /* Just in case. */
467 free (fp->_wide_data->_IO_save_base);
468 fp->_wide_data->_IO_save_base = NULL;
469 fp->_wide_data->_IO_save_end = NULL;
470 fp->_wide_data->_IO_backup_base = NULL;
472 libc_hidden_def (_IO_free_wbackup_area)
476 _IO_switch_to_wput_mode (fp)
479 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_read_ptr;
480 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
481 /* Following is wrong if line- or un-buffered? */
482 fp->_wide_data->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
483 ? fp->_wide_data->_IO_read_end
484 : fp->_wide_data->_IO_buf_end);
486 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
487 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_end;
489 fp->_flags |= _IO_CURRENTLY_PUTTING;
499 save_for_wbackup (fp, end_p)
503 /* Append [_IO_read_base..end_p] to backup area. */
504 _IO_ssize_t least_mark = _IO_least_wmarker (fp, end_p);
505 /* needed_size is how much space we need in the backup area. */
506 _IO_size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base)
508 /* FIXME: Dubious arithmetic if pointers are NULL */
509 _IO_size_t current_Bsize = (fp->_wide_data->_IO_save_end
510 - fp->_wide_data->_IO_save_base);
511 _IO_size_t avail; /* Extra space available for future expansion. */
513 struct _IO_marker *mark;
514 if (needed_size > current_Bsize)
518 new_buffer = (wchar_t *) malloc ((avail + needed_size)
520 if (new_buffer == NULL)
521 return EOF; /* FIXME */
525 __wmempcpy (__wmempcpy (new_buffer + avail,
526 fp->_wide_data->_IO_save_end + least_mark,
528 fp->_wide_data->_IO_read_base,
529 end_p - fp->_wide_data->_IO_read_base);
531 memcpy (new_buffer + avail,
532 fp->_wide_data->_IO_save_end + least_mark,
533 -least_mark * sizeof (wchar_t));
534 memcpy (new_buffer + avail - least_mark,
535 fp->_wide_data->_IO_read_base,
536 (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
542 __wmemcpy (new_buffer + avail,
543 fp->_wide_data->_IO_read_base + least_mark,
546 memcpy (new_buffer + avail,
547 fp->_wide_data->_IO_read_base + least_mark,
548 needed_size * sizeof (wchar_t));
551 free (fp->_wide_data->_IO_save_base);
552 fp->_wide_data->_IO_save_base = new_buffer;
553 fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size;
557 avail = current_Bsize - needed_size;
561 __wmemmove (fp->_wide_data->_IO_save_base + avail,
562 fp->_wide_data->_IO_save_end + least_mark,
564 __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
565 fp->_wide_data->_IO_read_base,
566 end_p - fp->_wide_data->_IO_read_base);
568 memmove (fp->_wide_data->_IO_save_base + avail,
569 fp->_wide_data->_IO_save_end + least_mark,
570 -least_mark * sizeof (wchar_t));
571 memcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
572 fp->_wide_data->_IO_read_base,
573 (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
576 else if (needed_size > 0)
578 __wmemcpy (fp->_wide_data->_IO_save_base + avail,
579 fp->_wide_data->_IO_read_base + least_mark,
582 memcpy (fp->_wide_data->_IO_save_base + avail,
583 fp->_wide_data->_IO_read_base + least_mark,
584 needed_size * sizeof (wchar_t));
587 fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail;
588 /* Adjust all the streammarkers. */
589 delta = end_p - fp->_wide_data->_IO_read_base;
590 for (mark = fp->_markers; mark != NULL; mark = mark->_next)
596 _IO_sputbackwc (fp, c)
602 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
603 && (wchar_t)fp->_wide_data->_IO_read_ptr[-1] == (wchar_t) c)
605 fp->_wide_data->_IO_read_ptr--;
609 result = _IO_PBACKFAIL (fp, c);
612 fp->_flags &= ~_IO_EOF_SEEN;
616 libc_hidden_def (_IO_sputbackwc)
624 if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
626 fp->_wide_data->_IO_read_ptr--;
627 result = *fp->_wide_data->_IO_read_ptr;
630 result = _IO_PBACKFAIL (fp, EOF);
633 fp->_flags &= ~_IO_EOF_SEEN;
640 _IO_adjust_wcolumn (start, line, count)
645 const wchar_t *ptr = line + count;
648 return line + count - ptr - 1;
649 return start + count;
653 _IO_init_wmarker (marker, fp)
654 struct _IO_marker *marker;
658 if (_IO_in_put_mode (fp))
659 _IO_switch_to_wget_mode (fp);
660 if (_IO_in_backup (fp))
661 marker->_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
663 marker->_pos = (fp->_wide_data->_IO_read_ptr
664 - fp->_wide_data->_IO_read_base);
666 /* Should perhaps sort the chain? */
667 marker->_next = fp->_markers;
668 fp->_markers = marker;
671 #define BAD_DELTA EOF
673 /* Return difference between MARK and current position of MARK's stream. */
675 _IO_wmarker_delta (mark)
676 struct _IO_marker *mark;
679 if (mark->_sbuf == NULL)
681 if (_IO_in_backup (mark->_sbuf))
682 cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
683 - mark->_sbuf->_wide_data->_IO_read_end);
685 cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
686 - mark->_sbuf->_wide_data->_IO_read_base);
687 return mark->_pos - cur_pos;
691 _IO_seekwmark (fp, mark, delta)
693 struct _IO_marker *mark;
696 if (mark->_sbuf != fp)
700 if (_IO_in_backup (fp))
701 _IO_switch_to_main_wget_area (fp);
702 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
707 if (!_IO_in_backup (fp))
708 _IO_switch_to_wbackup_area (fp);
709 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end + mark->_pos;
715 _IO_unsave_wmarkers (fp)
718 struct _IO_marker *mark = fp->_markers;
722 streampos offset = seekoff (0, ios::cur, ios::in);
725 offset += eGptr () - Gbase ();
726 for ( ; mark != NULL; mark = mark->_next)
727 mark->set_streampos (mark->_pos + offset);
731 for ( ; mark != NULL; mark = mark->_next)
732 mark->set_streampos (EOF);
738 if (_IO_have_backup (fp))
739 _IO_free_wbackup_area (fp);