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