]> git.saurik.com Git - bison.git/blame - src/files.c
Merge remote-tracking branch 'origin/maint'
[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)
9fd33c2b
AD
142 error (EXIT_FAILURE, get_errno (),
143 // On a separate line to please the "unmarked_diagnostics"
144 // syntax-check.
145 "fdopen");
22539284
AD
146 return res;
147}
148
2b81e969
AD
149/*------------------------------------------------------------------.
150| Compute ALL_BUT_EXT, ALL_BUT_TAB_EXT and output files extensions. |
151`------------------------------------------------------------------*/
234a3be3 152
d891bc49 153/* Compute extensions from the grammar file extension. */
234a3be3 154static void
f0130d39 155compute_exts_from_gf (const char *ext)
234a3be3 156{
f518dbaf 157 if (STREQ (ext, ".y"))
0e021770
PE
158 {
159 src_extension = xstrdup (language->src_extension);
160 header_extension = xstrdup (language->header_extension);
161 }
162 else
163 {
164 src_extension = xstrdup (ext);
165 header_extension = xstrdup (ext);
166 tr (src_extension, 'y', 'c');
167 tr (src_extension, 'Y', 'C');
168 tr (header_extension, 'y', 'h');
169 tr (header_extension, 'Y', 'H');
170 }
234a3be3
AD
171}
172
d891bc49 173/* Compute extensions from the given c source file extension. */
234a3be3 174static void
f0130d39 175compute_exts_from_src (const char *ext)
234a3be3 176{
4ecbf796
MA
177 /* We use this function when the user specifies `-o' or `--output',
178 so the extenions must be computed unconditionally from the file name
179 given by this option. */
f0130d39 180 src_extension = xstrdup (ext);
eb095650
PE
181 header_extension = xstrdup (ext);
182 tr (header_extension, 'c', 'h');
183 tr (header_extension, 'C', 'H');
234a3be3 184}
d8880f69 185
ae404801 186
48b16bbc
PE
187/* Decompose FILE_NAME in four parts: *BASE, *TAB, and *EXT, the fourth
188 part, (the directory) is ranging from FILE_NAME to the char before
ae404801
AD
189 *BASE, so we don't need an additional parameter.
190
191 *EXT points to the last period in the basename, or NULL if none.
192
193 If there is no *EXT, *TAB is NULL. Otherwise, *TAB points to
194 `.tab' or `_tab' if present right before *EXT, or is NULL. *TAB
195 cannot be equal to *BASE.
196
48b16bbc 197 None are allocated, they are simply pointers to parts of FILE_NAME.
ae404801
AD
198 Examples:
199
200 '/tmp/foo.tab.c' -> *BASE = 'foo.tab.c', *TAB = '.tab.c', *EXT =
201 '.c'
202
203 'foo.c' -> *BASE = 'foo.c', *TAB = NULL, *EXT = '.c'
204
205 'tab.c' -> *BASE = 'tab.c', *TAB = NULL, *EXT = '.c'
206
207 '.tab.c' -> *BASE = '.tab.c', *TAB = NULL, *EXT = '.c'
208
209 'foo.tab' -> *BASE = 'foo.tab', *TAB = NULL, *EXT = '.tab'
210
211 'foo_tab' -> *BASE = 'foo_tab', *TAB = NULL, *EXT = NULL
212
213 'foo' -> *BASE = 'foo', *TAB = NULL, *EXT = NULL. */
214
215static void
48b16bbc 216file_name_split (const char *file_name,
e9690142 217 const char **base, const char **tab, const char **ext)
ae404801 218{
cb48f191 219 *base = last_component (file_name);
ae404801
AD
220
221 /* Look for the extension, i.e., look for the last dot. */
84526bf3 222 *ext = strrchr (*base, '.');
ae404801
AD
223 *tab = NULL;
224
82129ef5 225 /* If there is an extension, check if there is a `.tab' part right
ae404801 226 before. */
82129ef5
PE
227 if (*ext)
228 {
229 size_t baselen = *ext - *base;
4663cb4d 230 size_t dottablen = sizeof (TAB_EXT) - 1;
82129ef5 231 if (dottablen < baselen
4663cb4d 232 && STRPREFIX_LIT (TAB_EXT, *ext - dottablen))
e9690142 233 *tab = *ext - dottablen;
82129ef5 234 }
ae404801
AD
235}
236
237
19c50364 238static void
2b81e969 239compute_file_name_parts (void)
54bd0db4 240{
ae404801 241 const char *base, *tab, *ext;
b0ce6046 242
2b81e969
AD
243 /* Compute ALL_BUT_EXT and ALL_BUT_TAB_EXT from SPEC_OUTFILE
244 or GRAMMAR_FILE.
19c50364
AD
245
246 The precise -o name will be used for FTABLE. For other output
247 files, remove the ".c" or ".tab.c" suffix. */
54bd0db4
RS
248 if (spec_outfile)
249 {
48b16bbc 250 file_name_split (spec_outfile, &base, &tab, &ext);
2b81e969 251 dir_prefix = xstrndup (spec_outfile, base - spec_outfile);
ae404801 252
2b81e969
AD
253 /* ALL_BUT_EXT goes up the EXT, excluding it. */
254 all_but_ext =
e9690142
JD
255 xstrndup (spec_outfile,
256 (strlen (spec_outfile) - (ext ? strlen (ext) : 0)));
b85810ae 257
2b81e969
AD
258 /* ALL_BUT_TAB_EXT goes up to TAB, excluding it. */
259 all_but_tab_ext =
e9690142
JD
260 xstrndup (spec_outfile,
261 (strlen (spec_outfile)
262 - (tab ? strlen (tab) : (ext ? strlen (ext) : 0))));
ae404801 263
ae404801 264 if (ext)
e9690142 265 compute_exts_from_src (ext);
54bd0db4 266 }
ae404801 267 else
54bd0db4 268 {
2b81e969
AD
269 file_name_split (grammar_file, &base, &tab, &ext);
270
ae404801 271 if (spec_file_prefix)
e9690142
JD
272 {
273 /* If --file-prefix=foo was specified, ALL_BUT_TAB_EXT = `foo'. */
274 dir_prefix =
cae5057f
JD
275 xstrndup (spec_file_prefix,
276 last_component (spec_file_prefix) - spec_file_prefix);
e9690142
JD
277 all_but_tab_ext = xstrdup (spec_file_prefix);
278 }
ae404801 279 else if (yacc_flag)
e9690142
JD
280 {
281 /* If --yacc, then the output is `y.tab.c'. */
282 dir_prefix = xstrdup ("");
283 all_but_tab_ext = xstrdup ("y");
284 }
ae404801 285 else
e9690142
JD
286 {
287 /* Otherwise, ALL_BUT_TAB_EXT is computed from the input
288 grammar: `foo/bar.yy' => `bar'. */
289 dir_prefix = xstrdup ("");
290 all_but_tab_ext =
291 xstrndup (base, (strlen (base) - (ext ? strlen (ext) : 0)));
292 }
9b3add5b 293
0e021770
PE
294 if (language->add_tab)
295 all_but_ext = concat2 (all_but_tab_ext, TAB_EXT);
296 else
297 all_but_ext = xstrdup (all_but_tab_ext);
ae404801 298
d891bc49 299 /* Compute the extensions from the grammar file name. */
5e5d5415 300 if (ext && !yacc_flag)
e9690142 301 compute_exts_from_gf (ext);
54bd0db4 302 }
19c50364
AD
303}
304
053658d5
PE
305
306/* Compute the output file names. Warn if we detect conflicting
307 outputs to the same file. */
342b8b6e
AD
308
309void
310compute_output_file_names (void)
311{
2b81e969 312 compute_file_name_parts ();
342b8b6e
AD
313
314 /* If not yet done. */
315 if (!src_extension)
eb095650 316 src_extension = xstrdup (".c");
342b8b6e 317 if (!header_extension)
eb095650 318 header_extension = xstrdup (".h");
fdbcd8e2 319
3f7ca628 320 parser_file_name =
eb095650
PE
321 (spec_outfile
322 ? xstrdup (spec_outfile)
323 : concat2 (all_but_ext, src_extension));
fdbcd8e2 324
053658d5
PE
325 if (defines_flag)
326 {
327 if (! spec_defines_file)
e9690142 328 spec_defines_file = concat2 (all_but_ext, header_extension);
053658d5 329 }
342b8b6e 330
053658d5
PE
331 if (graph_flag)
332 {
333 if (! spec_graph_file)
e9690142 334 spec_graph_file = concat2 (all_but_tab_ext, ".dot");
f39ab286 335 output_file_name_check (&spec_graph_file);
053658d5
PE
336 }
337
41d7a5f2
PE
338 if (xml_flag)
339 {
340 if (! spec_xml_file)
e9690142 341 spec_xml_file = concat2 (all_but_tab_ext, ".xml");
f39ab286 342 output_file_name_check (&spec_xml_file);
41d7a5f2
PE
343 }
344
053658d5
PE
345 if (report_flag)
346 {
1bb2bd75
JD
347 if (!spec_verbose_file)
348 spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
f39ab286 349 output_file_name_check (&spec_verbose_file);
053658d5 350 }
342b8b6e 351
eb095650
PE
352 free (all_but_tab_ext);
353 free (src_extension);
354 free (header_extension);
355}
356
3f7ca628 357void
f39ab286 358output_file_name_check (char **file_name)
3f7ca628 359{
f39ab286 360 bool conflict = false;
f518dbaf 361 if (STREQ (*file_name, grammar_file))
f39ab286 362 {
6fb8b256 363 complain (complaint, _("refusing to overwrite the input file %s"),
f39ab286
JD
364 quote (*file_name));
365 conflict = true;
366 }
367 else
368 {
369 int i;
370 for (i = 0; i < file_names_count; i++)
f518dbaf 371 if (STREQ (file_names[i], *file_name))
f39ab286 372 {
6fb8b256
VS
373 complain (Wother, _("conflicting outputs to file %s"),
374 quote (*file_name));
f39ab286
JD
375 conflict = true;
376 }
377 }
378 if (conflict)
379 {
380 free (*file_name);
381 *file_name = strdup ("/dev/null");
382 }
383 else
384 {
385 file_names = xnrealloc (file_names, ++file_names_count,
386 sizeof *file_names);
387 file_names[file_names_count-1] = xstrdup (*file_name);
388 }
3f7ca628
JD
389}
390
eb095650
PE
391void
392output_file_names_free (void)
393{
bd9d212b 394 free (all_but_ext);
eb095650
PE
395 free (spec_verbose_file);
396 free (spec_graph_file);
41d7a5f2 397 free (spec_xml_file);
eb095650
PE
398 free (spec_defines_file);
399 free (parser_file_name);
400 free (dir_prefix);
3f7ca628
JD
401 {
402 int i;
403 for (i = 0; i < file_names_count; i++)
404 free (file_names[i]);
405 }
406 free (file_names);
342b8b6e 407}