read-file: Don't occupy too much unused memory.
[gnulib.git] / lib / read-file.c
1 /* read-file.c -- read file contents into a string
2    Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
3    Written by Simon Josefsson and Bruno Haible.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <config.h>
20
21 #include "read-file.h"
22
23 /* Get fstat.  */
24 #include <sys/stat.h>
25
26 /* Get ftello.  */
27 #include <stdio.h>
28
29 /* Get SIZE_MAX.  */
30 #include <stdint.h>
31
32 /* Get malloc, realloc, free. */
33 #include <stdlib.h>
34
35 /* Get errno. */
36 #include <errno.h>
37
38 /* Read a STREAM and return a newly allocated string with the content,
39    and set *LENGTH to the length of the string.  The string is
40    zero-terminated, but the terminating zero byte is not counted in
41    *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
42    values set by system functions (if any), and NULL is returned. */
43 char *
44 fread_file (FILE * stream, size_t * length)
45 {
46   char *buf = NULL;
47   size_t alloc = 0;
48
49   /* For a regular file, allocate a buffer that has exactly the right
50      size.  This avoids the need to do dynamic reallocations later.  */
51   {
52     struct stat st;
53
54     if (fstat (fileno (stream), &st) >= 0 && S_ISREG (st.st_mode))
55       {
56         off_t pos = ftello (stream);
57
58         if (pos >= 0 && pos < st.st_size)
59           {
60             off_t alloc_off = st.st_size - pos;
61
62             if (SIZE_MAX <= alloc_off)
63               {
64                 errno = ENOMEM;
65                 return NULL;
66               }
67
68             alloc = alloc_off + 1;
69
70             buf = malloc (alloc);
71             if (!buf)
72               /* errno is ENOMEM.  */
73               return NULL;
74           }
75       }
76   }
77
78   {
79     size_t size = 0; /* number of bytes read so far */
80     int save_errno;
81
82     for (;;)
83       {
84         size_t count;
85         size_t requested;
86
87         if (size + BUFSIZ + 1 > alloc)
88           {
89             char *new_buf;
90             size_t new_alloc = alloc + alloc / 2;
91
92             /* Check against overflow.  */
93             if (new_alloc < alloc)
94               {
95                 save_errno = ENOMEM;
96                 break;
97               }
98
99             alloc = new_alloc;
100             if (alloc < size + BUFSIZ + 1)
101               alloc = size + BUFSIZ + 1;
102
103             new_buf = realloc (buf, alloc);
104             if (!new_buf)
105               {
106                 save_errno = errno;
107                 break;
108               }
109
110             buf = new_buf;
111           }
112
113         requested = alloc - size - 1;
114         count = fread (buf + size, 1, requested, stream);
115         size += count;
116
117         if (count != requested)
118           {
119             save_errno = errno;
120             if (ferror (stream))
121               break;
122
123             /* Shrink the allocated memory if possible.  */
124             if (size + 1 < alloc)
125               {
126                 char *smaller_buf = realloc (buf, size + 1);
127                 if (smaller_buf != NULL)
128                   buf = smaller_buf;
129               }
130
131             buf[size] = '\0';
132             *length = size;
133             return buf;
134           }
135       }
136
137     free (buf);
138     errno = save_errno;
139     return NULL;
140   }
141 }
142
143 static char *
144 internal_read_file (const char *filename, size_t * length, const char *mode)
145 {
146   FILE *stream = fopen (filename, mode);
147   char *out;
148   int save_errno;
149
150   if (!stream)
151     return NULL;
152
153   out = fread_file (stream, length);
154
155   save_errno = errno;
156
157   if (fclose (stream) != 0)
158     {
159       if (out)
160         {
161           save_errno = errno;
162           free (out);
163         }
164       errno = save_errno;
165       return NULL;
166     }
167
168   return out;
169 }
170
171 /* Open and read the contents of FILENAME, and return a newly
172    allocated string with the content, and set *LENGTH to the length of
173    the string.  The string is zero-terminated, but the terminating
174    zero byte is not counted in *LENGTH.  On errors, *LENGTH is
175    undefined, errno preserves the values set by system functions (if
176    any), and NULL is returned.  */
177 char *
178 read_file (const char *filename, size_t * length)
179 {
180   return internal_read_file (filename, length, "r");
181 }
182
183 /* Open (on non-POSIX systems, in binary mode) and read the contents
184    of FILENAME, and return a newly allocated string with the content,
185    and set LENGTH to the length of the string.  The string is
186    zero-terminated, but the terminating zero byte is not counted in
187    the LENGTH variable.  On errors, *LENGTH is undefined, errno
188    preserves the values set by system functions (if any), and NULL is
189    returned.  */
190 char *
191 read_binary_file (const char *filename, size_t * length)
192 {
193   return internal_read_file (filename, length, "rb");
194 }