]> git.saurik.com Git - bison.git/blame - src/files.c
Don't let Bison leak memory except when it complains.
[bison.git] / src / files.c
CommitLineData
82129ef5
PE
1/* Open and close files for Bison.
2
cb48f191
PE
3 Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006 Free Software Foundation, Inc.
54bd0db4 5
ceed8467 6 This file is part of Bison, the GNU Compiler Compiler.
54bd0db4 7
ceed8467
AD
8 Bison is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
54bd0db4 12
ceed8467
AD
13 Bison is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
54bd0db4 17
ceed8467
AD
18 You should have received a copy of the GNU General Public License
19 along with Bison; see the file COPYING. If not, write to the Free
0fb669f9
PE
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA. */
54bd0db4 22
2cec9080 23#include <config.h>
9eceb6c6 24#include "system.h"
6d441fc3
PE
25
26#include <error.h>
cb48f191 27#include <dirname.h>
6d441fc3 28#include <get-errno.h>
053658d5 29#include <quote.h>
cb48f191 30#include <stdio-safer.h>
1f65350a 31#include <xstrndup.h>
6d441fc3
PE
32
33#include "complain.h"
54bd0db4 34#include "files.h"
6d441fc3 35#include "getargs.h"
54bd0db4
RS
36#include "gram.h"
37
0dd1580a
RA
38struct obstack pre_prologue_obstack;
39struct obstack post_prologue_obstack;
8c7ebe49 40
b5b61c61
AD
41/* Initializing some values below (such SPEC_NAME_PREFIX to `yy') is
42 tempting, but don't do that: for the time being our handling of the
43 %directive vs --option leaves precedence to the options by deciding
44 that if a %directive sets a variable which is really set (i.e., not
45 NULL), then the %directive is ignored. As a result, %name-prefix,
46 for instance, will not be honored. */
47
2b81e969
AD
48char const *spec_outfile = NULL; /* for -o. */
49char const *spec_file_prefix = NULL; /* for -b. */
50char const *spec_name_prefix = NULL; /* for -p. */
eb095650
PE
51char *spec_verbose_file = NULL; /* for --verbose. */
52char *spec_graph_file = NULL; /* for -g. */
53char *spec_defines_file = NULL; /* for --defines. */
54char *parser_file_name;
54bd0db4 55
6d441fc3
PE
56uniqstr grammar_file = NULL;
57uniqstr current_file = NULL;
4a120d45 58
2b81e969
AD
59/* If --output=dir/foo.c was specified,
60 DIR_PREFIX is `dir/' and ALL_BUT_EXT and ALL_BUT_TAB_EXT are `dir/foo'.
61
62 If --output=dir/foo.tab.c was specified, DIR_PREFIX is `dir/',
63 ALL_BUT_EXT is `dir/foo.tab', and ALL_BUT_TAB_EXT is `dir/foo'.
64
65 If --output was not specified but --file-prefix=dir/foo was specified,
66 ALL_BUT_EXT = `foo.tab' and ALL_BUT_TAB_EXT = `foo'.
67
68 If neither --output nor --file was specified but the input grammar
69 is name dir/foo.y, ALL_BUT_EXT and ALL_BUT_TAB_EXT are `foo'.
70
71 If neither --output nor --file was specified, DIR_PREFIX is the
72 empty string (meaning the current directory); otherwise it is
73 `dir/'. */
b85810ae 74
eb095650
PE
75static char *all_but_ext;
76static char *all_but_tab_ext;
77char *dir_prefix;
27110317 78
f0130d39 79/* C source file extension (the parser source). */
eb095650 80static char *src_extension = NULL;
f0130d39 81/* Header file extension (if option ``-d'' is specified). */
eb095650 82static char *header_extension = NULL;
54bd0db4 83\f
358c15b7
AD
84/*-----------------------------------------------------------------.
85| Return a newly allocated string composed of the concatenation of |
6d441fc3 86| STR1, and STR2. |
358c15b7 87`-----------------------------------------------------------------*/
54bd0db4 88
6d441fc3
PE
89static char *
90concat2 (char const *str1, char const *str2)
54bd0db4 91{
6d441fc3 92 size_t len = strlen (str1) + strlen (str2);
82129ef5 93 char *res = xmalloc (len + 1);
358c15b7 94 char *cp;
6d441fc3
PE
95 cp = stpcpy (res, str1);
96 cp = stpcpy (cp, str2);
358c15b7 97 return res;
54bd0db4
RS
98}
99
cfe5fbc0
AD
100/*-----------------------------------------------------------------.
101| Try to open file NAME with mode MODE, and print an error message |
102| if fails. |
103`-----------------------------------------------------------------*/
54bd0db4 104
ff61dabd 105FILE *
8963a27b 106xfopen (const char *name, const char *mode)
cfe5fbc0 107{
8963a27b 108 FILE *ptr;
cfe5fbc0 109
3ea5f0ec 110 ptr = fopen_safer (name, mode);
cfe5fbc0 111 if (!ptr)
6d441fc3 112 error (EXIT_FAILURE, get_errno (), _("cannot open file `%s'"), name);
cfe5fbc0
AD
113
114 return ptr;
115}
116
117/*-------------------------------------------------------------.
118| Try to close file PTR, and print an error message if fails. |
119`-------------------------------------------------------------*/
120
e63ee1f1 121void
8963a27b 122xfclose (FILE *ptr)
cfe5fbc0 123{
cfe5fbc0 124 if (ptr == NULL)
e63ee1f1 125 return;
cfe5fbc0 126
e63ee1f1
PE
127 if (ferror (ptr))
128 error (EXIT_FAILURE, 0, _("I/O error"));
cfe5fbc0 129
e63ee1f1 130 if (fclose (ptr) != 0)
6d441fc3 131 error (EXIT_FAILURE, get_errno (), _("cannot close file"));
cfe5fbc0
AD
132}
133\f
f0130d39 134
2b81e969
AD
135/*------------------------------------------------------------------.
136| Compute ALL_BUT_EXT, ALL_BUT_TAB_EXT and output files extensions. |
137`------------------------------------------------------------------*/
234a3be3 138
eb095650 139/* In the string S, replace all characters FROM by TO. */
234a3be3 140static char *
eb095650 141tr (char *s, char from, char to)
234a3be3 142{
eb095650
PE
143 for (; *s; s++)
144 if (*s == from)
145 *s = to;
234a3be3
AD
146}
147
d891bc49 148/* Compute extensions from the grammar file extension. */
234a3be3 149static void
f0130d39 150compute_exts_from_gf (const char *ext)
234a3be3 151{
eb095650
PE
152 src_extension = xstrdup (ext);
153 header_extension = xstrdup (ext);
154 tr (src_extension, 'y', 'c');
155 tr (src_extension, 'Y', 'C');
156 tr (header_extension, 'y', 'h');
157 tr (header_extension, 'Y', 'H');
234a3be3
AD
158}
159
d891bc49 160/* Compute extensions from the given c source file extension. */
234a3be3 161static void
f0130d39 162compute_exts_from_src (const char *ext)
234a3be3 163{
4ecbf796
MA
164 /* We use this function when the user specifies `-o' or `--output',
165 so the extenions must be computed unconditionally from the file name
166 given by this option. */
f0130d39 167 src_extension = xstrdup (ext);
eb095650
PE
168 header_extension = xstrdup (ext);
169 tr (header_extension, 'c', 'h');
170 tr (header_extension, 'C', 'H');
234a3be3 171}
d8880f69 172
ae404801 173
48b16bbc
PE
174/* Decompose FILE_NAME in four parts: *BASE, *TAB, and *EXT, the fourth
175 part, (the directory) is ranging from FILE_NAME to the char before
ae404801
AD
176 *BASE, so we don't need an additional parameter.
177
178 *EXT points to the last period in the basename, or NULL if none.
179
180 If there is no *EXT, *TAB is NULL. Otherwise, *TAB points to
181 `.tab' or `_tab' if present right before *EXT, or is NULL. *TAB
182 cannot be equal to *BASE.
183
48b16bbc 184 None are allocated, they are simply pointers to parts of FILE_NAME.
ae404801
AD
185 Examples:
186
187 '/tmp/foo.tab.c' -> *BASE = 'foo.tab.c', *TAB = '.tab.c', *EXT =
188 '.c'
189
190 'foo.c' -> *BASE = 'foo.c', *TAB = NULL, *EXT = '.c'
191
192 'tab.c' -> *BASE = 'tab.c', *TAB = NULL, *EXT = '.c'
193
194 '.tab.c' -> *BASE = '.tab.c', *TAB = NULL, *EXT = '.c'
195
196 'foo.tab' -> *BASE = 'foo.tab', *TAB = NULL, *EXT = '.tab'
197
198 'foo_tab' -> *BASE = 'foo_tab', *TAB = NULL, *EXT = NULL
199
200 'foo' -> *BASE = 'foo', *TAB = NULL, *EXT = NULL. */
201
202static void
48b16bbc
PE
203file_name_split (const char *file_name,
204 const char **base, const char **tab, const char **ext)
ae404801 205{
cb48f191 206 *base = last_component (file_name);
ae404801
AD
207
208 /* Look for the extension, i.e., look for the last dot. */
209 *ext = strrchr (*base, '.');
210 *tab = NULL;
211
82129ef5 212 /* If there is an extension, check if there is a `.tab' part right
ae404801 213 before. */
82129ef5
PE
214 if (*ext)
215 {
216 size_t baselen = *ext - *base;
217 size_t dottablen = 4;
218 if (dottablen < baselen
219 && (strncmp (*ext - dottablen, ".tab", dottablen) == 0
220 || strncmp (*ext - dottablen, "_tab", dottablen) == 0))
221 *tab = *ext - dottablen;
222 }
ae404801
AD
223}
224
225
19c50364 226static void
2b81e969 227compute_file_name_parts (void)
54bd0db4 228{
ae404801 229 const char *base, *tab, *ext;
b0ce6046 230
2b81e969
AD
231 /* Compute ALL_BUT_EXT and ALL_BUT_TAB_EXT from SPEC_OUTFILE
232 or GRAMMAR_FILE.
19c50364
AD
233
234 The precise -o name will be used for FTABLE. For other output
235 files, remove the ".c" or ".tab.c" suffix. */
54bd0db4
RS
236 if (spec_outfile)
237 {
48b16bbc 238 file_name_split (spec_outfile, &base, &tab, &ext);
2b81e969 239 dir_prefix = xstrndup (spec_outfile, base - spec_outfile);
ae404801 240
2b81e969
AD
241 /* ALL_BUT_EXT goes up the EXT, excluding it. */
242 all_but_ext =
ae404801
AD
243 xstrndup (spec_outfile,
244 (strlen (spec_outfile) - (ext ? strlen (ext) : 0)));
b85810ae 245
2b81e969
AD
246 /* ALL_BUT_TAB_EXT goes up to TAB, excluding it. */
247 all_but_tab_ext =
ae404801
AD
248 xstrndup (spec_outfile,
249 (strlen (spec_outfile)
250 - (tab ? strlen (tab) : (ext ? strlen (ext) : 0))));
251
ae404801
AD
252 if (ext)
253 compute_exts_from_src (ext);
54bd0db4 254 }
ae404801 255 else
54bd0db4 256 {
2b81e969
AD
257 file_name_split (grammar_file, &base, &tab, &ext);
258
ae404801
AD
259 if (spec_file_prefix)
260 {
02d7cce6
PE
261 /* If --file-prefix=foo was specified, ALL_BUT_TAB_EXT = `foo'. */
262 dir_prefix = xstrndup (grammar_file, base - grammar_file);
263 all_but_tab_ext = xstrdup (spec_file_prefix);
ae404801
AD
264 }
265 else if (yacc_flag)
266 {
02d7cce6 267 /* If --yacc, then the output is `y.tab.c'. */
eb095650
PE
268 dir_prefix = xstrdup ("");
269 all_but_tab_ext = xstrdup ("y");
ae404801
AD
270 }
271 else
272 {
02d7cce6 273 /* Otherwise, ALL_BUT_TAB_EXT is computed from the input
8c165d89 274 grammar: `foo/bar.yy' => `bar'. */
eb095650 275 dir_prefix = xstrdup ("");
02d7cce6
PE
276 all_but_tab_ext =
277 xstrndup (base, (strlen (base) - (ext ? strlen (ext) : 0)));
ae404801 278 }
9b3add5b 279
2b81e969 280 all_but_ext = concat2 (all_but_tab_ext, TAB_EXT);
ae404801 281
d891bc49 282 /* Compute the extensions from the grammar file name. */
5e5d5415 283 if (ext && !yacc_flag)
ae404801 284 compute_exts_from_gf (ext);
54bd0db4 285 }
19c50364
AD
286}
287
053658d5
PE
288
289/* Compute the output file names. Warn if we detect conflicting
290 outputs to the same file. */
342b8b6e
AD
291
292void
293compute_output_file_names (void)
294{
053658d5
PE
295 char const *name[4];
296 int i;
297 int j;
298 int names = 0;
299
2b81e969 300 compute_file_name_parts ();
342b8b6e
AD
301
302 /* If not yet done. */
303 if (!src_extension)
eb095650 304 src_extension = xstrdup (".c");
342b8b6e 305 if (!header_extension)
eb095650 306 header_extension = xstrdup (".h");
fdbcd8e2 307
053658d5 308 name[names++] = parser_file_name =
eb095650
PE
309 (spec_outfile
310 ? xstrdup (spec_outfile)
311 : concat2 (all_but_ext, src_extension));
fdbcd8e2 312
053658d5
PE
313 if (defines_flag)
314 {
315 if (! spec_defines_file)
02d7cce6 316 spec_defines_file = concat2 (all_but_ext, header_extension);
053658d5
PE
317 name[names++] = spec_defines_file;
318 }
342b8b6e 319
053658d5
PE
320 if (graph_flag)
321 {
322 if (! spec_graph_file)
35fe0834 323 spec_graph_file = concat2 (all_but_tab_ext, ".dot");
053658d5
PE
324 name[names++] = spec_graph_file;
325 }
326
327 if (report_flag)
328 {
2b81e969 329 spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
053658d5
PE
330 name[names++] = spec_verbose_file;
331 }
342b8b6e 332
053658d5
PE
333 for (j = 0; j < names; j++)
334 for (i = 0; i < j; i++)
335 if (strcmp (name[i], name[j]) == 0)
336 warn (_("conflicting outputs to file %s"), quote (name[i]));
eb095650
PE
337
338 free (all_but_ext);
339 free (all_but_tab_ext);
340 free (src_extension);
341 free (header_extension);
342}
343
344void
345output_file_names_free (void)
346{
347 free (spec_verbose_file);
348 free (spec_graph_file);
349 free (spec_defines_file);
350 free (parser_file_name);
351 free (dir_prefix);
342b8b6e 352}