2006-06-19 Paul Eggert <eggert@cs.ucla.edu>
[gnulib.git] / lib / read-file.c
1 /* read-file.c -- read file contents into a string
2    Copyright (C) 2006 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 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "read-file.h"
24
25 /* Get realloc, free. */
26 #include <stdlib.h>
27
28 /* Get errno. */
29 #include <errno.h>
30
31 /* Read a STREAM and return a newly allocated string with the content,
32    and set *LENGTH to the length of the string.  The string is
33    zero-terminated, but the terminating zero byte is not counted in
34    *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
35    values set by system functions (if any), and NULL is returned. */
36 char *
37 fread_file (FILE * stream, size_t * length)
38 {
39   char *buf = NULL;
40   size_t alloc = 0;
41   size_t size = 0;
42   int save_errno;
43
44   for (;;)
45     {
46       size_t count;
47       size_t requested;
48
49       if (size + BUFSIZ + 1 > alloc)
50         {
51           char *new_buf;
52
53           alloc += alloc / 2;
54           if (alloc < size + BUFSIZ + 1)
55             alloc = size + BUFSIZ + 1;
56
57           new_buf = realloc (buf, alloc);
58           if (!new_buf)
59             {
60               save_errno = errno;
61               break;
62             }
63
64           buf = new_buf;
65         }
66
67       requested = alloc - size - 1;
68       count = fread (buf + size, 1, requested, stream);
69       size += count;
70
71       if (count != requested)
72         {
73           save_errno = errno;
74           if (ferror (stream))
75             break;
76           buf[size] = '\0';
77           *length = size;
78           return buf;
79         }
80     }
81
82   free (buf);
83   errno = save_errno;
84   return NULL;
85 }
86
87 static char *
88 internal_read_file (const char *filename, size_t * length, const char *mode)
89 {
90   FILE *stream = fopen (filename, mode);
91   char *out;
92   int save_errno;
93
94   if (!stream)
95     return NULL;
96
97   out = fread_file (stream, length);
98
99   save_errno = errno;
100
101   if (fclose (stream) != 0)
102     {
103       if (out)
104         {
105           save_errno = errno;
106           free (out);
107         }
108       errno = save_errno;
109       return NULL;
110     }
111
112   return out;
113 }
114
115 /* Open and read the contents of FILENAME, and return a newly
116    allocated string with the content, and set *LENGTH to the length of
117    the string.  The string is zero-terminated, but the terminating
118    zero byte is not counted in *LENGTH.  On errors, *LENGTH is
119    undefined, errno preserves the values set by system functions (if
120    any), and NULL is returned.  */
121 char *
122 read_file (const char *filename, size_t * length)
123 {
124   return internal_read_file (filename, length, "r");
125 }
126
127 /* Open (on non-POSIX systems, in binary mode) and read the contents
128    of FILENAME, and return a newly allocated string with the content,
129    and set LENGTH to the length of the string.  The string is
130    zero-terminated, but the terminating zero byte is not counted in
131    the LENGTH variable.  On errors, *LENGTH is undefined, errno
132    preserves the values set by system functions (if any), and NULL is
133    returned.  */
134 char *
135 read_binary_file (const char *filename, size_t * length)
136 {
137   return internal_read_file (filename, length, "rb");
138 }