Blame libio/wstrops.c

Packit 6c4009
/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.
Packit 6c4009
Packit 6c4009
   As a special exception, if you link the code in this file with
Packit 6c4009
   files compiled with a GNU compiler to produce an executable,
Packit 6c4009
   that does not cause the resulting executable to be covered by
Packit 6c4009
   the GNU Lesser General Public License.  This exception does not
Packit 6c4009
   however invalidate any other reasons why the executable file
Packit 6c4009
   might be covered by the GNU Lesser General Public License.
Packit 6c4009
   This exception applies to code released by its copyright holders
Packit 6c4009
   in files containing the exception.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include "strfile.h"
Packit 6c4009
#include "libioP.h"
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_wstr_init_static (FILE *fp, wchar_t *ptr, size_t size,
Packit 6c4009
		      wchar_t *pstart)
Packit 6c4009
{
Packit 6c4009
  wchar_t *end;
Packit 6c4009
Packit 6c4009
  if (size == 0)
Packit 6c4009
    end = ptr + __wcslen (ptr);
Packit 6c4009
  else if ((size_t) ptr + size * sizeof (wchar_t) > (size_t) ptr)
Packit 6c4009
    end = ptr + size;
Packit 6c4009
  else
Packit 6c4009
    /* Even for misaligned ptr make sure there is integral number of wide
Packit 6c4009
       characters.  */
Packit 6c4009
    end = ptr + (-1 - (size_t) ptr) / sizeof (wchar_t);
Packit 6c4009
  _IO_wsetb (fp, ptr, end, 0);
Packit 6c4009
Packit 6c4009
  fp->_wide_data->_IO_write_base = ptr;
Packit 6c4009
  fp->_wide_data->_IO_read_base = ptr;
Packit 6c4009
  fp->_wide_data->_IO_read_ptr = ptr;
Packit 6c4009
  if (pstart)
Packit 6c4009
    {
Packit 6c4009
      fp->_wide_data->_IO_write_ptr = pstart;
Packit 6c4009
      fp->_wide_data->_IO_write_end = end;
Packit 6c4009
      fp->_wide_data->_IO_read_end = pstart;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      fp->_wide_data->_IO_write_ptr = ptr;
Packit 6c4009
      fp->_wide_data->_IO_write_end = ptr;
Packit 6c4009
      fp->_wide_data->_IO_read_end = end;
Packit 6c4009
    }
Packit 6c4009
  /* A null _allocate_buffer function flags the strfile as being static. */
Packit 6c4009
  (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
wint_t
Packit 6c4009
_IO_wstr_overflow (FILE *fp, wint_t c)
Packit 6c4009
{
Packit 6c4009
  int flush_only = c == WEOF;
Packit 6c4009
  size_t pos;
Packit 6c4009
  if (fp->_flags & _IO_NO_WRITES)
Packit 6c4009
      return flush_only ? 0 : WEOF;
Packit 6c4009
  if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
Packit 6c4009
    {
Packit 6c4009
      fp->_flags |= _IO_CURRENTLY_PUTTING;
Packit 6c4009
      fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
Packit 6c4009
      fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
Packit 6c4009
    }
Packit 6c4009
  pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
Packit 6c4009
  if (pos >= (size_t) (_IO_wblen (fp) + flush_only))
Packit 6c4009
    {
Packit 6c4009
      if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
Packit 6c4009
	return WEOF;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  wchar_t *new_buf;
Packit 6c4009
	  wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
Packit 6c4009
	  size_t old_wblen = _IO_wblen (fp);
Packit 6c4009
	  size_t new_size = 2 * old_wblen + 100;
Packit 6c4009
Packit 6c4009
	  if (__glibc_unlikely (new_size < old_wblen)
Packit 6c4009
	      || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
Packit 6c4009
	    return EOF;
Packit 6c4009
Packit 6c4009
	  new_buf = malloc (new_size * sizeof (wchar_t));
Packit 6c4009
	  if (new_buf == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /*	  __ferror(fp) = 1; */
Packit 6c4009
	      return WEOF;
Packit 6c4009
	    }
Packit 6c4009
	  if (old_buf)
Packit 6c4009
	    {
Packit 6c4009
	      __wmemcpy (new_buf, old_buf, old_wblen);
Packit 6c4009
	      free (old_buf);
Packit 6c4009
	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
Packit 6c4009
	      fp->_wide_data->_IO_buf_base = NULL;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
Packit 6c4009
Packit 6c4009
	  _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
Packit 6c4009
	  fp->_wide_data->_IO_read_base =
Packit 6c4009
	    new_buf + (fp->_wide_data->_IO_read_base - old_buf);
Packit 6c4009
	  fp->_wide_data->_IO_read_ptr =
Packit 6c4009
	    new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
Packit 6c4009
	  fp->_wide_data->_IO_read_end =
Packit 6c4009
	    new_buf + (fp->_wide_data->_IO_read_end - old_buf);
Packit 6c4009
	  fp->_wide_data->_IO_write_ptr =
Packit 6c4009
	    new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
Packit 6c4009
Packit 6c4009
	  fp->_wide_data->_IO_write_base = new_buf;
Packit 6c4009
	  fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (!flush_only)
Packit 6c4009
    *fp->_wide_data->_IO_write_ptr++ = c;
Packit 6c4009
  if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
Packit 6c4009
    fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
  return c;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
wint_t
Packit 6c4009
_IO_wstr_underflow (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
Packit 6c4009
    fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
  if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
Packit 6c4009
    {
Packit 6c4009
      fp->_flags &= ~_IO_CURRENTLY_PUTTING;
Packit 6c4009
      fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
      fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
Packit 6c4009
    }
Packit 6c4009
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
Packit 6c4009
    return *fp->_wide_data->_IO_read_ptr;
Packit 6c4009
  else
Packit 6c4009
    return WEOF;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The size of the valid part of the buffer.  */
Packit 6c4009
ssize_t
Packit 6c4009
_IO_wstr_count (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  struct _IO_wide_data *wd = fp->_wide_data;
Packit 6c4009
Packit 6c4009
  return ((wd->_IO_write_ptr > wd->_IO_read_end
Packit 6c4009
	   ? wd->_IO_write_ptr : wd->_IO_read_end)
Packit 6c4009
	  - wd->_IO_read_base);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
enlarge_userbuf (FILE *fp, off64_t offset, int reading)
Packit 6c4009
{
Packit 6c4009
  if ((ssize_t) offset <= _IO_wblen (fp))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  struct _IO_wide_data *wd = fp->_wide_data;
Packit 6c4009
Packit 6c4009
  ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
Packit 6c4009
Packit 6c4009
  /* Try to enlarge the buffer.  */
Packit 6c4009
  if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
Packit 6c4009
    /* User-provided buffer.  */
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  size_t newsize = offset + 100;
Packit 6c4009
  if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  wchar_t *oldbuf = wd->_IO_buf_base;
Packit 6c4009
  wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
Packit 6c4009
  if (newbuf == NULL)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  if (oldbuf != NULL)
Packit 6c4009
    {
Packit 6c4009
      __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
Packit 6c4009
      free (oldbuf);
Packit 6c4009
      /* Make sure _IO_setb won't try to delete
Packit 6c4009
	 _IO_buf_base. */
Packit 6c4009
      wd->_IO_buf_base = NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
Packit 6c4009
Packit 6c4009
  if (reading)
Packit 6c4009
    {
Packit 6c4009
      wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
Packit 6c4009
      wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
Packit 6c4009
      wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
Packit 6c4009
      wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
Packit 6c4009
Packit 6c4009
      wd->_IO_read_base = newbuf;
Packit 6c4009
      wd->_IO_read_end = wd->_IO_buf_end;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
Packit 6c4009
      wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
Packit 6c4009
      wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
Packit 6c4009
      wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
Packit 6c4009
Packit 6c4009
      wd->_IO_write_base = newbuf;
Packit 6c4009
      wd->_IO_write_end = wd->_IO_buf_end;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Clear the area between the last write position and th
Packit 6c4009
     new position.  */
Packit 6c4009
  assert (offset >= oldend);
Packit 6c4009
  if (reading)
Packit 6c4009
    __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
Packit 6c4009
  else
Packit 6c4009
    __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
_IO_wstr_switch_to_get_mode (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (_IO_in_backup (fp))
Packit 6c4009
    fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
Packit 6c4009
      if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
Packit 6c4009
        fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
    }
Packit 6c4009
  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
Packit 6c4009
Packit 6c4009
  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
off64_t
Packit 6c4009
_IO_wstr_seekoff (FILE *fp, off64_t offset, int dir, int mode)
Packit 6c4009
{
Packit 6c4009
  off64_t new_pos;
Packit 6c4009
Packit 6c4009
  if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
Packit 6c4009
    mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
Packit 6c4009
Packit 6c4009
  bool was_writing = (fp->_wide_data->_IO_write_ptr >
Packit 6c4009
			fp->_wide_data->_IO_write_base
Packit 6c4009
		     || _IO_in_put_mode (fp));
Packit 6c4009
  if (was_writing)
Packit 6c4009
    _IO_wstr_switch_to_get_mode (fp);
Packit 6c4009
Packit 6c4009
  if (mode == 0)
Packit 6c4009
    {
Packit 6c4009
      new_pos = (fp->_wide_data->_IO_write_ptr
Packit 6c4009
		 - fp->_wide_data->_IO_write_base);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      ssize_t cur_size = _IO_wstr_count (fp);
Packit 6c4009
      new_pos = EOF;
Packit 6c4009
Packit 6c4009
      /* Move the get pointer, if requested. */
Packit 6c4009
      if (mode & _IOS_INPUT)
Packit 6c4009
	{
Packit 6c4009
	  ssize_t base;
Packit 6c4009
	  switch (dir)
Packit 6c4009
	    {
Packit 6c4009
	    case _IO_seek_set:
Packit 6c4009
	      base = 0;
Packit 6c4009
	      break;
Packit 6c4009
	    case _IO_seek_cur:
Packit 6c4009
	      base = (fp->_wide_data->_IO_read_ptr
Packit 6c4009
		     - fp->_wide_data->_IO_read_base);
Packit 6c4009
	      break;
Packit 6c4009
	    default: /* case _IO_seek_end: */
Packit 6c4009
	      base = cur_size;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
Packit 6c4009
	  if (offset < -base || offset > maxval)
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (EINVAL);
Packit 6c4009
	      return EOF;
Packit 6c4009
	    }
Packit 6c4009
	  base += offset;
Packit 6c4009
	  if (base > cur_size
Packit 6c4009
	      && enlarge_userbuf (fp, base, 1) != 0)
Packit 6c4009
	    return EOF;
Packit 6c4009
	  fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
Packit 6c4009
					  + base);
Packit 6c4009
	  fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
Packit 6c4009
					  + cur_size);
Packit 6c4009
	  new_pos = offset;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Move the put pointer, if requested. */
Packit 6c4009
      if (mode & _IOS_OUTPUT)
Packit 6c4009
	{
Packit 6c4009
	  ssize_t base;
Packit 6c4009
	  switch (dir)
Packit 6c4009
	    {
Packit 6c4009
	    case _IO_seek_set:
Packit 6c4009
	      base = 0;
Packit 6c4009
	      break;
Packit 6c4009
	    case _IO_seek_cur:
Packit 6c4009
	      base = (fp->_wide_data->_IO_write_ptr
Packit 6c4009
		     - fp->_wide_data->_IO_write_base);
Packit 6c4009
	      break;
Packit 6c4009
	    default: /* case _IO_seek_end: */
Packit 6c4009
	      base = cur_size;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
Packit 6c4009
	  if (offset < -base || offset > maxval)
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (EINVAL);
Packit 6c4009
	      return EOF;
Packit 6c4009
	    }
Packit 6c4009
	  base += offset;
Packit 6c4009
	  if (base > cur_size
Packit 6c4009
	      && enlarge_userbuf (fp, base, 0) != 0)
Packit 6c4009
	    return EOF;
Packit 6c4009
	  fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
Packit 6c4009
					   + base);
Packit 6c4009
	  new_pos = base;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return new_pos;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
wint_t
Packit 6c4009
_IO_wstr_pbackfail (FILE *fp, wint_t c)
Packit 6c4009
{
Packit 6c4009
  if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
Packit 6c4009
    return WEOF;
Packit 6c4009
  return _IO_wdefault_pbackfail (fp, c);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_wstr_finish (FILE *fp, int dummy)
Packit 6c4009
{
Packit 6c4009
  if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
Packit 6c4009
    free (fp->_wide_data->_IO_buf_base);
Packit 6c4009
  fp->_wide_data->_IO_buf_base = NULL;
Packit 6c4009
Packit 6c4009
  _IO_wdefault_finish (fp, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
Packit 6c4009
{
Packit 6c4009
  JUMP_INIT_DUMMY,
Packit 6c4009
  JUMP_INIT(finish, _IO_wstr_finish),
Packit 6c4009
  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
Packit 6c4009
  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
Packit 6c4009
  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
Packit 6c4009
  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
Packit 6c4009
  JUMP_INIT(xsputn, _IO_wdefault_xsputn),
Packit 6c4009
  JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
Packit 6c4009
  JUMP_INIT(seekoff, _IO_wstr_seekoff),
Packit 6c4009
  JUMP_INIT(seekpos, _IO_default_seekpos),
Packit 6c4009
  JUMP_INIT(setbuf, _IO_default_setbuf),
Packit 6c4009
  JUMP_INIT(sync, _IO_default_sync),
Packit 6c4009
  JUMP_INIT(doallocate, _IO_wdefault_doallocate),
Packit 6c4009
  JUMP_INIT(read, _IO_default_read),
Packit 6c4009
  JUMP_INIT(write, _IO_default_write),
Packit 6c4009
  JUMP_INIT(seek, _IO_default_seek),
Packit 6c4009
  JUMP_INIT(close, _IO_default_close),
Packit 6c4009
  JUMP_INIT(stat, _IO_default_stat),
Packit 6c4009
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
Packit 6c4009
  JUMP_INIT(imbue, _IO_default_imbue)
Packit 6c4009
};