wint_t _IO_wdefault_pbackfail (FILE *fp, wint_t c) { if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base && !_IO_in_backup (fp) && (wint_t) fp->_IO_read_ptr[-1] == c) --fp->_IO_read_ptr; else { /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/ if (!_IO_in_backup (fp)) { /* We need to keep the invariant that the main get area logically follows the backup area. */ if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base && _IO_have_wbackup (fp)) { if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr)) return WEOF; } else if (!_IO_have_wbackup (fp)) { /* No backup buffer: allocate one. */ /* Use nshort buffer, if unused? (probably not) FIXME */ int backup_size = 128; wchar_t *bbuf = (wchar_t *) malloc (backup_size * sizeof (wchar_t)); if (bbuf == NULL) return WEOF; fp->_wide_data->_IO_save_base = bbuf; fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base + backup_size); fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end; } fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr; _IO_switch_to_wbackup_area (fp); } else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base) { /* Increase size of existing backup buffer. */ size_t new_size; size_t old_size = (fp->_wide_data->_IO_read_end - fp->_wide_data->_IO_read_base); wchar_t *new_buf; new_size = 2 * old_size; new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t)); if (new_buf == NULL) return WEOF; __wmemcpy (new_buf + (new_size - old_size), fp->_wide_data->_IO_read_base, old_size); free (fp->_wide_data->_IO_read_base); _IO_wsetg (fp, new_buf, new_buf + (new_size - old_size), new_buf + new_size); fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr; } *--fp->_wide_data->_IO_read_ptr = c; } return c; }
/* Copy no more than N wide-characters of SRC to DEST, returning the address of the last character written into DEST. */ wchar_t * __wcpncpy (wchar_t *dest, const wchar_t *src, size_t n) { size_t size = __wcsnlen (src, n); __wmemcpy (dest, src, size); dest += size; if (size == n) return dest; return wmemset (dest, L'\0', (n - size)); }
/* Copy SRC to DEST. */ wchar_t * __wcscpy (wchar_t *dest, const wchar_t *src) { #ifndef UNROLL_NTIMES return __wmemcpy (dest, src, __wcslen (src) + 1); #else /* Some architectures might have costly tail function call (powerpc for instance) where wmemcpy call overhead for smalls sizes might be more costly than just unrolling the main loop. */ wchar_t *wcp = dest; #define ITERATION(index) \ ({ \ wchar_t c = *src++; \ *wcp++ = c; \ c != L'\0'; \ }) while (1) UNROLL_REPEAT(UNROLL_NTIMES, ITERATION); return dest; #endif }
_IO_wint_t _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) { int flush_only = c == WEOF; _IO_size_t pos; if (fp->_flags & _IO_NO_WRITES) return flush_only ? 0 : WEOF; if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING)) { fp->_flags |= _IO_CURRENTLY_PUTTING; fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr; fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end; } pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base; if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only)) { if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */ return WEOF; else { wchar_t *new_buf; wchar_t *old_buf = fp->_wide_data->_IO_buf_base; size_t old_wblen = _IO_wblen (fp); _IO_size_t new_size = 2 * old_wblen + 100; if (__glibc_unlikely (new_size < old_wblen) || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t))) return EOF; new_buf = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size * sizeof (wchar_t)); if (new_buf == NULL) { /* __ferror(fp) = 1; */ return WEOF; } if (old_buf) { __wmemcpy (new_buf, old_buf, old_wblen); (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_wide_data->_IO_buf_base = NULL; } __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen); _IO_wsetb (fp, new_buf, new_buf + new_size, 1); fp->_wide_data->_IO_read_base = new_buf + (fp->_wide_data->_IO_read_base - old_buf); fp->_wide_data->_IO_read_ptr = new_buf + (fp->_wide_data->_IO_read_ptr - old_buf); fp->_wide_data->_IO_read_end = new_buf + (fp->_wide_data->_IO_read_end - old_buf); fp->_wide_data->_IO_write_ptr = new_buf + (fp->_wide_data->_IO_write_ptr - old_buf); fp->_wide_data->_IO_write_base = new_buf; fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end; } } if (!flush_only) *fp->_wide_data->_IO_write_ptr++ = c; if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end) fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr; return c; }
static int enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) { if ((_IO_ssize_t) offset <= _IO_wblen (fp)) return 0; struct _IO_wide_data *wd = fp->_wide_data; _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base; /* Try to enlarge the buffer. */ if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* User-provided buffer. */ return 1; _IO_size_t newsize = offset + 100; if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t))) return 1; wchar_t *oldbuf = wd->_IO_buf_base; wchar_t *newbuf = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize * sizeof (wchar_t)); if (newbuf == NULL) return 1; if (oldbuf != NULL) { __wmemcpy (newbuf, oldbuf, _IO_wblen (fp)); (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ wd->_IO_buf_base = NULL; } _IO_wsetb (fp, newbuf, newbuf + newsize, 1); if (reading) { wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf); wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf); wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf); wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf); wd->_IO_read_base = newbuf; wd->_IO_read_end = wd->_IO_buf_end; } else { wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf); wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf); wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf); wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf); wd->_IO_write_base = newbuf; wd->_IO_write_end = wd->_IO_buf_end; } /* Clear the area between the last write position and th new position. */ assert (offset >= oldend); if (reading) __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend); else __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend); return 0; }
static int save_for_wbackup (FILE *fp, wchar_t *end_p) { /* Append [_IO_read_base..end_p] to backup area. */ ssize_t least_mark = _IO_least_wmarker (fp, end_p); /* needed_size is how much space we need in the backup area. */ size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base) - least_mark); /* FIXME: Dubious arithmetic if pointers are NULL */ size_t current_Bsize = (fp->_wide_data->_IO_save_end - fp->_wide_data->_IO_save_base); size_t avail; /* Extra space available for future expansion. */ ssize_t delta; struct _IO_marker *mark; if (needed_size > current_Bsize) { wchar_t *new_buffer; avail = 100; new_buffer = (wchar_t *) malloc ((avail + needed_size) * sizeof (wchar_t)); if (new_buffer == NULL) return EOF; /* FIXME */ if (least_mark < 0) { __wmempcpy (__wmempcpy (new_buffer + avail, fp->_wide_data->_IO_save_end + least_mark, -least_mark), fp->_wide_data->_IO_read_base, end_p - fp->_wide_data->_IO_read_base); } else { __wmemcpy (new_buffer + avail, fp->_wide_data->_IO_read_base + least_mark, needed_size); } free (fp->_wide_data->_IO_save_base); fp->_wide_data->_IO_save_base = new_buffer; fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size; } else { avail = current_Bsize - needed_size; if (least_mark < 0) { __wmemmove (fp->_wide_data->_IO_save_base + avail, fp->_wide_data->_IO_save_end + least_mark, -least_mark); __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark, fp->_wide_data->_IO_read_base, end_p - fp->_wide_data->_IO_read_base); } else if (needed_size > 0) __wmemcpy (fp->_wide_data->_IO_save_base + avail, fp->_wide_data->_IO_read_base + least_mark, needed_size); } fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail; /* Adjust all the streammarkers. */ delta = end_p - fp->_wide_data->_IO_read_base; for (mark = fp->_markers; mark != NULL; mark = mark->_next) mark->_pos -= delta; return 0; }