regex: also remove dependency on HAVE_WCSCOLL
[gnulib.git] / lib / read-file.c
index 0a15c5a..8eff1b9 100644 (file)
@@ -1,5 +1,5 @@
 /* read-file.c -- read file contents into a string
-   Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc.
    Written by Simon Josefsson and Bruno Haible.
 
    This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,7 @@
    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.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
    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. */
+   values set by system functions (if any), and NULL is returned.  */
 char *
-fread_file (FILE * stream, size_t * length)
+fread_file (FILE *stream, size_t *length)
 {
   char *buf = NULL;
-  size_t alloc = 0;
+  size_t alloc = BUFSIZ;
 
   /* For a regular file, allocate a buffer that has exactly the right
      size.  This avoids the need to do dynamic reallocations later.  */
@@ -59,59 +58,31 @@ fread_file (FILE * stream, size_t * length)
           {
             off_t alloc_off = st.st_size - pos;
 
-            if (SIZE_MAX <= alloc_off)
+            /* '1' below, accounts for the trailing NUL.  */
+            if (SIZE_MAX - 1 < alloc_off)
               {
                 errno = ENOMEM;
                 return NULL;
               }
 
             alloc = alloc_off + 1;
-
-            buf = malloc (alloc);
-            if (!buf)
-              /* errno is ENOMEM.  */
-              return NULL;
           }
       }
   }
 
+  if (!(buf = malloc (alloc)))
+    return NULL; /* errno is ENOMEM.  */
+
   {
     size_t size = 0; /* number of bytes read so far */
     int save_errno;
 
     for (;;)
       {
-        size_t count;
-        size_t requested;
-
-        if (size + BUFSIZ + 1 > alloc)
-          {
-            char *new_buf;
-            size_t new_alloc = alloc + alloc / 2;
-
-            /* Check against overflow.  */
-            if (new_alloc < alloc)
-              {
-                save_errno = ENOMEM;
-                break;
-              }
-
-            alloc = new_alloc;
-            if (alloc < size + BUFSIZ + 1)
-              alloc = size + BUFSIZ + 1;
-
-            new_buf = realloc (buf, alloc);
-            if (!new_buf)
-              {
-                save_errno = errno;
-                break;
-              }
-
-            buf = new_buf;
-          }
-
-        requested = alloc - size - 1;
-        count = fread (buf + size, 1, requested, stream);
+        /* This reads 1 more than the size of a regular file
+           so that we get eof immediately.  */
+        size_t requested = alloc - size;
+        size_t count = fread (buf + size, 1, requested, stream);
         size += count;
 
         if (count != requested)
@@ -121,7 +92,7 @@ fread_file (FILE * stream, size_t * length)
               break;
 
             /* Shrink the allocated memory if possible.  */
-            if (size + 1 < alloc)
+            if (size < alloc - 1)
               {
                 char *smaller_buf = realloc (buf, size + 1);
                 if (smaller_buf != NULL)
@@ -132,6 +103,29 @@ fread_file (FILE * stream, size_t * length)
             *length = size;
             return buf;
           }
+
+        {
+          char *new_buf;
+
+          if (alloc == SIZE_MAX)
+            {
+              save_errno = ENOMEM;
+              break;
+            }
+
+          if (alloc < SIZE_MAX - alloc / 2)
+            alloc = alloc + alloc / 2;
+          else
+            alloc = SIZE_MAX;
+
+          if (!(new_buf = realloc (buf, alloc)))
+            {
+              save_errno = errno;
+              break;
+            }
+
+          buf = new_buf;
+        }
       }
 
     free (buf);
@@ -141,7 +135,7 @@ fread_file (FILE * stream, size_t * length)
 }
 
 static char *
-internal_read_file (const char *filename, size_t * length, const char *mode)
+internal_read_file (const char *filename, size_t *length, const char *mode)
 {
   FILE *stream = fopen (filename, mode);
   char *out;
@@ -175,7 +169,7 @@ internal_read_file (const char *filename, size_t * length, const char *mode)
    undefined, errno preserves the values set by system functions (if
    any), and NULL is returned.  */
 char *
-read_file (const char *filename, size_t * length)
+read_file (const char *filename, size_t *length)
 {
   return internal_read_file (filename, length, "r");
 }
@@ -188,7 +182,7 @@ read_file (const char *filename, size_t * length)
    preserves the values set by system functions (if any), and NULL is
    returned.  */
 char *
-read_binary_file (const char *filename, size_t * length)
+read_binary_file (const char *filename, size_t *length)
 {
   return internal_read_file (filename, length, "rb");
 }