Blame libio/strops.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 <stdio_ext.h>
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
Packit 6c4009
			      char *pstart)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = &sf->_sbf._f;
Packit 6c4009
  char *end;
Packit 6c4009
Packit 6c4009
  if (size == 0)
Packit 6c4009
    end = __rawmemchr (ptr, '\0');
Packit 6c4009
  else if ((size_t) ptr + size > (size_t) ptr)
Packit 6c4009
    end = ptr + size;
Packit 6c4009
  else
Packit 6c4009
    end = (char *) -1;
Packit 6c4009
  _IO_setb (fp, ptr, end, 0);
Packit 6c4009
Packit 6c4009
  fp->_IO_write_base = ptr;
Packit 6c4009
  fp->_IO_read_base = ptr;
Packit 6c4009
  fp->_IO_read_ptr = ptr;
Packit 6c4009
  if (pstart)
Packit 6c4009
    {
Packit 6c4009
      fp->_IO_write_ptr = pstart;
Packit 6c4009
      fp->_IO_write_end = end;
Packit 6c4009
      fp->_IO_read_end = pstart;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      fp->_IO_write_ptr = ptr;
Packit 6c4009
      fp->_IO_write_end = ptr;
Packit 6c4009
      fp->_IO_read_end = end;
Packit 6c4009
    }
Packit 6c4009
  /* A null _allocate_buffer function flags the strfile as being static. */
Packit 6c4009
  sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
Packit 6c4009
{
Packit 6c4009
  return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
Packit 6c4009
{
Packit 6c4009
  _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
Packit 6c4009
  sf->_sbf._f._flags |= _IO_NO_WRITES;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_str_overflow (FILE *fp, int c)
Packit 6c4009
{
Packit 6c4009
  int flush_only = c == EOF;
Packit 6c4009
  size_t pos;
Packit 6c4009
  if (fp->_flags & _IO_NO_WRITES)
Packit 6c4009
      return flush_only ? 0 : EOF;
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->_IO_write_ptr = fp->_IO_read_ptr;
Packit 6c4009
      fp->_IO_read_ptr = fp->_IO_read_end;
Packit 6c4009
    }
Packit 6c4009
  pos = fp->_IO_write_ptr - fp->_IO_write_base;
Packit 6c4009
  if (pos >= (size_t) (_IO_blen (fp) + flush_only))
Packit 6c4009
    {
Packit 6c4009
      if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
Packit 6c4009
	return EOF;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  char *new_buf;
Packit 6c4009
	  char *old_buf = fp->_IO_buf_base;
Packit 6c4009
	  size_t old_blen = _IO_blen (fp);
Packit 6c4009
	  size_t new_size = 2 * old_blen + 100;
Packit 6c4009
	  if (new_size < old_blen)
Packit 6c4009
	    return EOF;
Packit 6c4009
	  new_buf = malloc (new_size);
Packit 6c4009
	  if (new_buf == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /*	  __ferror(fp) = 1; */
Packit 6c4009
	      return EOF;
Packit 6c4009
	    }
Packit 6c4009
	  if (old_buf)
Packit 6c4009
	    {
Packit 6c4009
	      memcpy (new_buf, old_buf, old_blen);
Packit 6c4009
	      free (old_buf);
Packit 6c4009
	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
Packit 6c4009
	      fp->_IO_buf_base = NULL;
Packit 6c4009
	    }
Packit 6c4009
	  memset (new_buf + old_blen, '\0', new_size - old_blen);
Packit 6c4009
Packit 6c4009
	  _IO_setb (fp, new_buf, new_buf + new_size, 1);
Packit 6c4009
	  fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
Packit 6c4009
	  fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
Packit 6c4009
	  fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
Packit 6c4009
	  fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
Packit 6c4009
Packit 6c4009
	  fp->_IO_write_base = new_buf;
Packit 6c4009
	  fp->_IO_write_end = fp->_IO_buf_end;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (!flush_only)
Packit 6c4009
    *fp->_IO_write_ptr++ = (unsigned char) c;
Packit 6c4009
  if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit 6c4009
    fp->_IO_read_end = fp->_IO_write_ptr;
Packit 6c4009
  return c;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_str_overflow)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_str_underflow (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit 6c4009
    fp->_IO_read_end = fp->_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->_IO_read_ptr = fp->_IO_write_ptr;
Packit 6c4009
      fp->_IO_write_ptr = fp->_IO_write_end;
Packit 6c4009
    }
Packit 6c4009
  if (fp->_IO_read_ptr < fp->_IO_read_end)
Packit 6c4009
    return *((unsigned char *) fp->_IO_read_ptr);
Packit 6c4009
  else
Packit 6c4009
    return EOF;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_str_underflow)
Packit 6c4009
Packit 6c4009
/* The size of the valid part of the buffer.  */
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
_IO_str_count (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  return ((fp->_IO_write_ptr > fp->_IO_read_end
Packit 6c4009
	   ? fp->_IO_write_ptr : fp->_IO_read_end)
Packit 6c4009
	  - fp->_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_blen (fp))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
Packit 6c4009
Packit 6c4009
  /* Try to enlarge the buffer.  */
Packit 6c4009
  if (fp->_flags & _IO_USER_BUF)
Packit 6c4009
    /* User-provided buffer.  */
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  size_t newsize = offset + 100;
Packit 6c4009
  char *oldbuf = fp->_IO_buf_base;
Packit 6c4009
  char *newbuf = malloc (newsize);
Packit 6c4009
  if (newbuf == NULL)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  if (oldbuf != NULL)
Packit 6c4009
    {
Packit 6c4009
      memcpy (newbuf, oldbuf, _IO_blen (fp));
Packit 6c4009
      free (oldbuf);
Packit 6c4009
      /* Make sure _IO_setb won't try to delete
Packit 6c4009
	 _IO_buf_base. */
Packit 6c4009
      fp->_IO_buf_base = NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  _IO_setb (fp, newbuf, newbuf + newsize, 1);
Packit 6c4009
Packit 6c4009
  if (reading)
Packit 6c4009
    {
Packit 6c4009
      fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
Packit 6c4009
      fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
Packit 6c4009
      fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
Packit 6c4009
      fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
Packit 6c4009
Packit 6c4009
      fp->_IO_read_base = newbuf;
Packit 6c4009
      fp->_IO_read_end = fp->_IO_buf_end;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
Packit 6c4009
      fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
Packit 6c4009
      fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
Packit 6c4009
      fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
Packit 6c4009
Packit 6c4009
      fp->_IO_write_base = newbuf;
Packit 6c4009
      fp->_IO_write_end = fp->_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
    memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
Packit 6c4009
  else
Packit 6c4009
    memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
_IO_str_switch_to_get_mode (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (_IO_in_backup (fp))
Packit 6c4009
    fp->_IO_read_base = fp->_IO_backup_base;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      fp->_IO_read_base = fp->_IO_buf_base;
Packit 6c4009
      if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit 6c4009
        fp->_IO_read_end = fp->_IO_write_ptr;
Packit 6c4009
    }
Packit 6c4009
  fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
Packit 6c4009
Packit 6c4009
  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
off64_t
Packit 6c4009
_IO_str_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->_IO_write_ptr > fp->_IO_write_base
Packit 6c4009
		     || _IO_in_put_mode (fp));
Packit 6c4009
  if (was_writing)
Packit 6c4009
    _IO_str_switch_to_get_mode (fp);
Packit 6c4009
Packit 6c4009
  if (mode == 0)
Packit 6c4009
    {
Packit 6c4009
      new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      ssize_t cur_size = _IO_str_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->_IO_read_ptr - fp->_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 - 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->_IO_read_ptr = fp->_IO_read_base + base;
Packit 6c4009
	  fp->_IO_read_end = fp->_IO_read_base + cur_size;
Packit 6c4009
	  new_pos = base;
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->_IO_write_ptr - fp->_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 - 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->_IO_write_ptr = fp->_IO_write_base + base;
Packit 6c4009
	  new_pos = base;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return new_pos;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_str_seekoff)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_str_pbackfail (FILE *fp, int c)
Packit 6c4009
{
Packit 6c4009
  if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
Packit 6c4009
    return EOF;
Packit 6c4009
  return _IO_default_pbackfail (fp, c);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_str_pbackfail)
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_str_finish (FILE *fp, int dummy)
Packit 6c4009
{
Packit 6c4009
  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
Packit 6c4009
    free (fp->_IO_buf_base);
Packit 6c4009
  fp->_IO_buf_base = NULL;
Packit 6c4009
Packit 6c4009
  _IO_default_finish (fp, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
const struct _IO_jump_t _IO_str_jumps libio_vtable =
Packit 6c4009
{
Packit 6c4009
  JUMP_INIT_DUMMY,
Packit 6c4009
  JUMP_INIT(finish, _IO_str_finish),
Packit 6c4009
  JUMP_INIT(overflow, _IO_str_overflow),
Packit 6c4009
  JUMP_INIT(underflow, _IO_str_underflow),
Packit 6c4009
  JUMP_INIT(uflow, _IO_default_uflow),
Packit 6c4009
  JUMP_INIT(pbackfail, _IO_str_pbackfail),
Packit 6c4009
  JUMP_INIT(xsputn, _IO_default_xsputn),
Packit 6c4009
  JUMP_INIT(xsgetn, _IO_default_xsgetn),
Packit 6c4009
  JUMP_INIT(seekoff, _IO_str_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_default_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
};