bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: read-file


From: Simon Josefsson
Subject: Re: read-file
Date: Fri, 16 Jun 2006 21:28:31 +0200
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/22.0.50 (gnu/linux)

Paul Eggert <address@hidden> writes:

> Simon Josefsson <address@hidden> writes:
>
>> +  if (buf)
>> +    buf[size] = '\0';
>
> The file reading code returns NULL if the file was empty?  But the
> comments makes it sound like it will return xstrdup (""), and that
> would be more consistent.  You might also add a test case, to read
> from /dev/null.

The intention was to return strdup ("").  However, it do seem to
behave like that, from this test case:

  {
    size_t len;
    char *out = read_file (FILE2, &len);

    if (!out)
      perror ("Could not read file");

    if (out[len] != '\0')
      perror ("BAD: out[len] not zero");

    printf ("Read %d from %s...\n", len, FILE2);

    free (out);
  }

If FILE2 is /dev/zero it prints:

Read 0 from /dev/null...

Looking at the code, it seems it depends on whether feof() return true
immediately after fopen on a zero-size file.  Does the standards says
anything about this?

Anyway, I changed the code to don't assume that feof() return non-true
without a fread on zero-size files.  See below.

> The following replacement code is a bit clearer, at least to my eyes:

Incorporated too.

Thanks!

/* read-file.c -- read file contents into a string
   Copyright (C) 2006 Free Software Foundation, Inc.
   Written by Simon Josefsson and Bruno Haible.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "read-file.h"

/* Get realloc, free. */
#include <stdlib.h>

/* Get errno. */
#include <errno.h>

/* Read a STREAM and return a newly allocated string with the content,
   and set *LENGTH to the length of the string.  The string is
   zero-terminated, but the terminating zero byte is not counted in
   *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
   values set by system functions (if any), and NULL is returned. */
char *
fread_file (FILE * stream, size_t * length)
{
  char *buf = malloc (1);
  size_t alloc = 1;
  size_t size = 0;

  if (!buf)
    return NULL;

  while (!feof (stream))
    {
      size_t count;

      if (size + BUFSIZ + 1 > alloc)
        {
          char *new_buf;

          alloc += alloc / 2;
          if (alloc < size + BUFSIZ + 1)
            alloc = size + BUFSIZ + 1;

          new_buf = realloc (buf, alloc);
          if (!new_buf)
            {
              int save_errno = errno;
              free (buf);
              errno = save_errno;
              return NULL;
            }

          buf = new_buf;
        }

      count = fread (buf + size, 1, alloc - size - 1, stream);
      size += count;

      if (ferror (stream))
        {
          int save_errno = errno;
          free (buf);
          errno = save_errno;
          return NULL;
        }
    }

  buf[size] = '\0';

  *length = size;

  return buf;
}

static char *
internal_read_file (const char *filename, size_t * length, const char *mode)
{
  FILE *stream = fopen (filename, mode);
  char *out;
  int save_errno;
  int rc;

  if (!stream)
    return NULL;

  out = fread_file (stream, length);

  save_errno = errno;

  if (fclose (stream) != 0)
    {
      if (out)
        {
          save_errno = errno;
          free (out);
        }
      errno = save_errno;
      return NULL;
    }

  return out;
}

/* Open and read the contents of FILENAME, and return a newly
   allocated string with the content, and set *LENGTH to the length of
   the string.  The string is zero-terminated, but the terminating
   zero byte is not counted in *LENGTH.  On errors, *LENGTH is
   undefined, errno preserves the values set by system functions (if
   any), and NULL is returned.  */
char *
read_file (const char *filename, size_t * length)
{
  return internal_read_file (filename, length, "r");
}

/* Open (on non-POSIX systems, in binary mode) and read the contents
   of FILENAME, and return a newly allocated string with the content,
   and set LENGTH to the length of the string.  The string is
   zero-terminated, but the terminating zero byte is not counted in
   the LENGTH variable.  On errors, *LENGTH is undefined, errno
   preserves the values set by system functions (if any), and NULL is
   returned.  */
char *
read_binary_file (const char *filename, size_t * length)
{
  return internal_read_file (filename, length, "rb");
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]