예제 #1
0
static int
freadptrbufsize (FILE *fp)
{
  size_t size = 0;

  freadptr (fp, &size);
  return size;
}
예제 #2
0
파일: getndelim2.c 프로젝트: 4solo/cs35
ssize_t
getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
            int delim1, int delim2, FILE *stream)
{
  size_t nbytes_avail;		/* Allocated but unused bytes in *LINEPTR.  */
  char *read_pos;		/* Where we're reading into *LINEPTR. */
  ssize_t bytes_stored = -1;
  char *ptr = *lineptr;
  size_t size = *linesize;
  bool found_delimiter;

  if (!ptr)
    {
      size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
      ptr = malloc (size);
      if (!ptr)
	return -1;
    }

  if (size < offset)
    goto done;

  nbytes_avail = size - offset;
  read_pos = ptr + offset;

  if (nbytes_avail == 0 && nmax <= size)
    goto done;

  /* Normalize delimiters, since memchr2 doesn't handle EOF.  */
  if (delim1 == EOF)
    delim1 = delim2;
  else if (delim2 == EOF)
    delim2 = delim1;

  flockfile (stream);

  found_delimiter = false;
  do
    {
      /* Here always ptr + size == read_pos + nbytes_avail.
	 Also nbytes_avail > 0 || size < nmax.  */

      int c IF_LINT (= 0);
      const char *buffer;
      size_t buffer_len;

      buffer = freadptr (stream, &buffer_len);
      if (buffer)
	{
	  if (delim1 != EOF)
	    {
	      const char *end = memchr2 (buffer, delim1, delim2, buffer_len);
	      if (end)
		{
		  buffer_len = end - buffer + 1;
		  found_delimiter = true;
		}
	    }
	}
      else
	{
	  c = getc (stream);
	  if (c == EOF)
	    {
	      /* Return partial line, if any.  */
	      if (read_pos == ptr)
		goto unlock_done;
	      else
		break;
	    }
	  if (c == delim1 || c == delim2)
	    found_delimiter = true;
	  buffer_len = 1;
	}

      /* We always want at least one byte left in the buffer, since we
	 always (unless we get an error while reading the first byte)
	 NUL-terminate the line buffer.  */

      if (nbytes_avail < buffer_len + 1 && size < nmax)
	{
	  /* Grow size proportionally, not linearly, to avoid O(n^2)
	     running time.  */
	  size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
	  char *newptr;

	  /* Increase newsize so that it becomes
	     >= (read_pos - ptr) + buffer_len.  */
	  if (newsize - (read_pos - ptr) < buffer_len + 1)
	    newsize = (read_pos - ptr) + buffer_len + 1;
	  /* Respect nmax.  This handles possible integer overflow.  */
	  if (! (size < newsize && newsize <= nmax))
	    newsize = nmax;

	  if (GETNDELIM2_MAXIMUM < newsize - offset)
	    {
	      size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
	      if (size == newsizemax)
		goto unlock_done;
	      newsize = newsizemax;
	    }

	  nbytes_avail = newsize - (read_pos - ptr);
	  newptr = realloc (ptr, newsize);
	  if (!newptr)
	    goto unlock_done;
	  ptr = newptr;
	  size = newsize;
	  read_pos = size - nbytes_avail + ptr;
	}

      /* Here, if size < nmax, nbytes_avail >= buffer_len + 1.
	 If size == nmax, nbytes_avail > 0.  */

      if (1 < nbytes_avail)
	{
	  size_t copy_len = nbytes_avail - 1;
	  if (buffer_len < copy_len)
	    copy_len = buffer_len;
	  if (buffer)
	    memcpy (read_pos, buffer, copy_len);
	  else
	    *read_pos = c;
	  read_pos += copy_len;
	  nbytes_avail -= copy_len;
	}

      /* Here still nbytes_avail > 0.  */

      if (buffer && freadseek (stream, buffer_len))
	goto unlock_done;
    }
  while (!found_delimiter);

  /* Done - NUL terminate and return the number of bytes read.
     At this point we know that nbytes_avail >= 1.  */
  *read_pos = '\0';

  bytes_stored = read_pos - (ptr + offset);

 unlock_done:
  funlockfile (stream);

 done:
  *lineptr = ptr;
  *linesize = size;
  return bytes_stored ? bytes_stored : -1;
}
예제 #3
0
파일: freadseek.c 프로젝트: DonCN/haiku
int
freadseek (FILE *fp, size_t offset)
{
  size_t total_buffered;
  int fd;

  if (offset == 0)
    return 0;

  /* Seek over the already read and buffered input as quickly as possible,
     without doing any system calls.  */
  total_buffered = freadahead (fp);
  /* This loop is usually executed at most twice: once for ungetc buffer (if
     present) and once for the main buffer.  */
  while (total_buffered > 0)
    {
      size_t buffered;

      if (freadptr (fp, &buffered) != NULL && buffered > 0)
        {
          size_t increment = (buffered < offset ? buffered : offset);

          freadptrinc (fp, increment);
          offset -= increment;
          if (offset == 0)
            return 0;
          total_buffered -= increment;
          if (total_buffered == 0)
            break;
        }
      /* Read one byte.  If we were reading from the ungetc buffer, this
         switches the stream back to the main buffer.  */
      if (fgetc (fp) == EOF)
        goto eof;
      offset--;
      if (offset == 0)
        return 0;
      total_buffered--;
    }

  /* Test whether the stream is seekable or not.  */
  fd = fileno (fp);
  if (fd >= 0 && lseek (fd, 0, SEEK_CUR) >= 0)
    {
      /* FP refers to a regular file.  fseek is most efficient in this case.  */
      return fseeko (fp, offset, SEEK_CUR);
    }
  else
    {
      /* FP is a non-seekable stream, possibly not even referring to a file
         descriptor.  Read OFFSET bytes explicitly and discard them.  */
      char buf[4096];

      do
        {
          size_t count = (sizeof (buf) < offset ? sizeof (buf) : offset);
          if (fread (buf, 1, count, fp) < count)
            goto eof;
          offset -= count;
        }
      while (offset > 0);

      return 0;
   }

 eof:
  /* EOF, or error before or while reading.  */
  if (ferror (fp))
    return EOF;
  else
    /* Encountered EOF.  */
    return 0;
}
예제 #4
0
파일: test-freadptr.c 프로젝트: 4solo/cs35
int
main (int argc, char **argv)
{
  int nbytes = atoi (argv[1]);
  void *buf = malloc (nbytes);
  ASSERT (fread (buf, 1, nbytes, stdin) == nbytes);

  if (lseek (0, 0, SEEK_CUR) == nbytes)
    {
      /* An unbuffered stdio, such as BeOS or on uClibc compiled without
	 __STDIO_BUFFERS.  Or stdin is a pipe.  */
      size_t size;
      ASSERT (freadptr (stdin, &size) == NULL);
    }
  else
    {
      /* Normal buffered stdio.  */
      const char stdin_contents[] =
	"#!/bin/sh\n\n./test-freadptr${EXEEXT} 5 < \"$srcdir/test-freadptr.sh\" || exit 1\ncat \"$srcdir/test-freadptr.sh\" | ./test-freadptr${EXEEXT} 5 || exit 1\nexit 0\n";
      const char *expected = stdin_contents + nbytes;
      size_t available1;
      size_t available2;
      size_t available3;

      /* Test normal behaviour.  */
      {
	const char *ptr = freadptr (stdin, &available1);

	ASSERT (ptr != NULL);
	ASSERT (available1 != 0);
	ASSERT (available1 <= strlen (expected));
	ASSERT (memcmp (ptr, expected, available1) == 0);
      }

      /* Test behaviour after normal ungetc.  */
      ungetc (fgetc (stdin), stdin);
      {
	const char *ptr = freadptr (stdin, &available2);

	if (ptr != NULL)
	  {
	    ASSERT (available2 == available1);
	    ASSERT (memcmp (ptr, expected, available2) == 0);
	  }
      }

      /* Test behaviour after arbitrary ungetc.  */
      fgetc (stdin);
      ungetc ('@', stdin);
      {
	const char *ptr = freadptr (stdin, &available3);

	if (ptr != NULL)
	  {
	    ASSERT (available3 == 1 || available3 == available1);
	    ASSERT (ptr[0] == '@');
	    if (available3 > 1)
	      {
		ASSERT (memcmp (ptr + 1, expected + 1, available3 - 1) == 0);
	      }
	  }
      }
    }

  return 0;
}