]> git.saurik.com Git - bison.git/blame_incremental - src/files.c
* configure.in: Use AC_FUNC_STRNLEN.
[bison.git] / src / files.c
... / ...
CommitLineData
1/* Open and close files for bison,
2 Copyright 1984, 1986, 1989, 1992, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 Bison is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 Bison is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bison; see the file COPYING. If not, write to the Free
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22
23#include "system.h"
24#include "getargs.h"
25#include "files.h"
26#include "gram.h"
27#include "error.h"
28#include "complain.h"
29
30/* From basename.c. Almost a lie, as it returns a char *. */
31const char *base_name PARAMS ((char const *name));
32
33FILE *finput = NULL;
34
35struct obstack action_obstack;
36struct obstack attrs_obstack;
37struct obstack output_obstack;
38
39/* Initializing some values below (such SPEC_NAME_PREFIX to `yy') is
40 tempting, but don't do that: for the time being our handling of the
41 %directive vs --option leaves precedence to the options by deciding
42 that if a %directive sets a variable which is really set (i.e., not
43 NULL), then the %directive is ignored. As a result, %name-prefix,
44 for instance, will not be honored. */
45
46char *spec_outfile = NULL; /* for -o. */
47char *spec_file_prefix = NULL; /* for -b. */
48const char *spec_name_prefix = NULL; /* for -p. */
49char *spec_verbose_file = NULL; /* for --verbose. */
50char *spec_graph_file = NULL; /* for -g. */
51char *spec_defines_file = NULL; /* for --defines. */
52char *parser_file_name = NULL;
53
54char *infile = NULL;
55char *attrsfile = NULL;
56
57static char *full_base_name = NULL;
58
59/* Prefix used to generate output file names. */
60char *short_base_name = NULL;
61
62/* Infix used to generate output file names (i.e., `.tab', or `_tab',
63 or `'). */
64char *output_infix = NULL;
65
66/* C source file extension (the parser source). */
67const char *src_extension = NULL;
68/* Header file extension (if option ``-d'' is specified). */
69const char *header_extension = NULL;
70\f
71
72/*--------------------------.
73| Is SUFFIX ending STRING? |
74`--------------------------*/
75
76int
77strsuffix (const char *string, const char *suffix)
78{
79 size_t string_len = strlen (string);
80 size_t suffix_len = strlen (suffix);
81 if (suffix_len <= string_len)
82 return !strcmp (string + string_len - suffix_len, suffix);
83 else
84 return 0;
85}
86
87
88/*-----------------------------------------------------------------.
89| Return a newly allocated string composed of the concatenation of |
90| STRING1, and STRING2. |
91`-----------------------------------------------------------------*/
92
93char*
94stringappend (const char *string1, const char *string2)
95{
96 size_t len = strlen (string1) + strlen (string2);
97 char *res = XMALLOC (char, len + 1);
98 char *cp;
99 cp = stpcpy (res, string1);
100 cp = stpcpy (cp, string2);
101 return res;
102}
103
104
105/*-----------------------------------------------------------------.
106| Computes the macro name used to avoid double inclusion in the |
107| header of the parser and store it in header_macro_name. Be sure |
108| to produce valid CPP names (don't start with digit, remain |
109| alphanumerical + underscore). |
110`-----------------------------------------------------------------*/
111
112char *
113compute_header_macro (void)
114{
115 const char *prefix = "BISON_";
116 char *macro_name, *cp;
117
118 if (spec_defines_file)
119 {
120 macro_name = XMALLOC (char,
121 strlen (prefix) +
122 strlen (spec_defines_file) + 1);
123 cp = stpcpy (macro_name, prefix);
124 cp = stpcpy (cp, spec_defines_file);
125 }
126 else
127 {
128 macro_name = XMALLOC (char,
129 strlen (prefix) +
130 strlen (full_base_name) +
131 strlen (header_extension) + 1);
132 cp = stpcpy (macro_name, prefix);
133 cp = stpcpy (cp, full_base_name);
134 cp = stpcpy (cp, header_extension);
135 }
136
137 for (cp = macro_name; *cp; ++cp)
138 if (islower (*cp))
139 *cp = toupper (*cp);
140 else if (!isalnum (*cp))
141 *cp = '_';
142
143 return macro_name;
144}
145
146
147/*-----------------------------------------------------------------.
148| Try to open file NAME with mode MODE, and print an error message |
149| if fails. |
150`-----------------------------------------------------------------*/
151
152FILE *
153xfopen (const char *name, const char *mode)
154{
155 FILE *ptr;
156
157 ptr = fopen (name, mode);
158 if (!ptr)
159 error (2, errno, _("cannot open file `%s'"), name);
160
161 return ptr;
162}
163
164/*-------------------------------------------------------------.
165| Try to close file PTR, and print an error message if fails. |
166`-------------------------------------------------------------*/
167
168int
169xfclose (FILE *ptr)
170{
171 int result;
172
173 if (ptr == NULL)
174 return 0;
175
176 result = fclose (ptr);
177 if (result == EOF)
178 error (2, errno, _("cannot close file"));
179
180 return result;
181}
182
183
184/*------------------------------------------------------------------.
185| Return the path to the skeleton which locaction might be given in |
186| ENVVAR, otherwise return SKELETON_NAME. |
187`------------------------------------------------------------------*/
188
189const char *
190skeleton_find (const char *envvar, const char *skeleton_name)
191{
192 const char *res = getenv (envvar);
193
194#if defined (MSDOS) || defined (_WIN32)
195 if (!res)
196 {
197 /* Skeleton file name without path */
198 const char *skel_name = strrchr (skeleton_name, '/');
199 if (!skel_name)
200 skel_name = strrchr (skeleton_name, '\\');
201 if (!skel_name)
202 skel_name = skeleton_name;
203 else
204 ++skel_name;
205
206 /* File doesn't exist in current directory; try in INIT directory. */
207 const char *cp = getenv ("INIT");
208 if (cp)
209 {
210 res = XMALLOC (char, strlen (cp) + strlen (skel_name) + 2);
211 sprintf (res, "%s%c%s", cp, '\\', skel_name);
212 }
213 else if (access (skel_name, 4) == 0) /* Look in current dir. */
214 res = skel_name;
215 else
216 {
217 /* Look in program locations dir. */
218 extern char *program_name;
219 cp = strrchr(program_name, '\\');
220 if (!cp)
221 return skeleton_name;
222 else
223 ++cp;
224 res = XMALLOC (char, cp - program_name + strlen (skel_name) + 1);
225 strncpy (res, program_name, cp - program_name);
226 strcpy (res + (cp - program_name), skel_name);
227 }
228 }
229#endif /* defined (MSDOS) || defined (_WIN32) */
230 if (!res)
231 res = skeleton_name;
232
233 return res;
234}
235\f
236
237/*----------------------------------------------------------------.
238| Compute BASE_NAME, SHORT_BASE_NAME and output files extensions. |
239`----------------------------------------------------------------*/
240
241/* Replace all characters FROM by TO in the string IN.
242 and returns a new allocated string. */
243static char *
244tr (const char *in, char from, char to)
245{
246 char *temp;
247 char *out;
248
249 out = XMALLOC (char, strlen (in) + 1);
250
251 for (temp = out; *in; in++, out++)
252 if (*in == from)
253 *out = to;
254 else
255 *out = *in;
256 *out = 0;
257 return (temp);
258}
259
260/* Computes extensions from the grammar file extension. */
261static void
262compute_exts_from_gf (const char *ext)
263{
264 src_extension = tr (ext, 'y', 'c');
265 src_extension = tr (src_extension, 'Y', 'C');
266 header_extension = tr (ext, 'y', 'h');
267 header_extension = tr (header_extension, 'Y', 'H');
268}
269
270/* Computes extensions from the given c source file extension. */
271static void
272compute_exts_from_src (const char *ext)
273{
274 /* We use this function when the user specifies `-o' or `--output',
275 so the extenions must be computed unconditionally from the file name
276 given by this option. */
277 src_extension = xstrdup (ext);
278 header_extension = tr (ext, 'c', 'h');
279 header_extension = tr (header_extension, 'C', 'H');
280}
281
282
283/* Decompose FILENAME in four parts: *BASE, *TAB, and *EXT, the fourth
284 part, (the directory) is ranging from FILENAME to the char before
285 *BASE, so we don't need an additional parameter.
286
287 *EXT points to the last period in the basename, or NULL if none.
288
289 If there is no *EXT, *TAB is NULL. Otherwise, *TAB points to
290 `.tab' or `_tab' if present right before *EXT, or is NULL. *TAB
291 cannot be equal to *BASE.
292
293 None are allocated, they are simply pointers to parts of FILENAME.
294 Examples:
295
296 '/tmp/foo.tab.c' -> *BASE = 'foo.tab.c', *TAB = '.tab.c', *EXT =
297 '.c'
298
299 'foo.c' -> *BASE = 'foo.c', *TAB = NULL, *EXT = '.c'
300
301 'tab.c' -> *BASE = 'tab.c', *TAB = NULL, *EXT = '.c'
302
303 '.tab.c' -> *BASE = '.tab.c', *TAB = NULL, *EXT = '.c'
304
305 'foo.tab' -> *BASE = 'foo.tab', *TAB = NULL, *EXT = '.tab'
306
307 'foo_tab' -> *BASE = 'foo_tab', *TAB = NULL, *EXT = NULL
308
309 'foo' -> *BASE = 'foo', *TAB = NULL, *EXT = NULL. */
310
311static void
312filename_split (const char *filename,
313 const char **base, const char **tab, const char **ext)
314{
315 *base = base_name (filename);
316
317 /* Look for the extension, i.e., look for the last dot. */
318 *ext = strrchr (*base, '.');
319 *tab = NULL;
320
321 /* If there is an exentension, check if there is a `.tab' part right
322 before. */
323 if (*ext
324 && (*ext - *base) > (int) strlen (".tab")
325 && (!strncmp (*ext - strlen (".tab"), ".tab", strlen (".tab"))
326 || !strncmp (*ext - strlen ("_tab"), "_tab", strlen ("_tab"))))
327 *tab = *ext - strlen (".tab");
328}
329
330
331/* FIXME: Should use xstrndup. */
332
333static void
334compute_base_names (void)
335{
336 const char *base, *tab, *ext;
337
338 /* If --output=foo.c was specified (SPEC_OUTFILE == foo.c),
339 BASE_NAME and SHORT_BASE_NAME are `foo'.
340
341 If --output=foo.tab.c was specified, BASE_NAME is `foo.tab' and
342 SHORT_BASE_NAME is `foo'.
343
344 The precise -o name will be used for FTABLE. For other output
345 files, remove the ".c" or ".tab.c" suffix. */
346 if (spec_outfile)
347 {
348 filename_split (spec_outfile, &base, &tab, &ext);
349
350 /* The full base name goes up the EXT, excluding it. */
351 full_base_name =
352 xstrndup (spec_outfile,
353 (strlen (spec_outfile) - (ext ? strlen (ext) : 0)));
354
355 /* The short base name goes up to TAB, excluding it. */
356 short_base_name =
357 xstrndup (spec_outfile,
358 (strlen (spec_outfile)
359 - (tab ? strlen (tab) : (ext ? strlen (ext) : 0))));
360
361 if (tab)
362 output_infix = xstrndup (tab,
363 (strlen (tab) - (ext ? strlen (ext) : 0)));
364
365 if (ext)
366 compute_exts_from_src (ext);
367 }
368
369 /* If --file-prefix=foo was specified, FULL_BASE_NAME = `foo.tab'
370 and SHORT_BASE_NAME = `foo'.
371
372 Construct names from it. */
373 else
374 {
375 if (spec_file_prefix)
376 {
377 /* If --file-prefix=foo was specified, SHORT_BASE_NAME =
378 `foo'. */
379 short_base_name = xstrdup (spec_file_prefix);
380 }
381 else if (yacc_flag)
382 {
383 /* If --yacc, then the output is `y.tab.c'. */
384 short_base_name = xstrdup ("y");
385 }
386 else
387 {
388 /* Otherwise, the short base name is computed from the input
389 grammar: `foo.yy' => `foo'. */
390 filename_split (infile, &base, &tab, &ext);
391 short_base_name =
392 xstrndup (infile,
393 (strlen (infile) - (ext ? strlen (ext) : 0)));
394 }
395
396 /* In these cases, always append `.tab'. */
397 output_infix = xstrdup (EXT_TAB);
398
399 full_base_name = XMALLOC (char,
400 strlen (short_base_name)
401 + strlen (EXT_TAB) + 1);
402 stpcpy (stpcpy (full_base_name, short_base_name), EXT_TAB);
403
404 /* Computes the extensions from the grammar file name. */
405 filename_split (infile, &base, &tab, &ext);
406 if (ext)
407 compute_exts_from_gf (ext);
408 }
409}
410
411/*-------------------------------------------------------.
412| Close the open files, compute the output files names. |
413`-------------------------------------------------------*/
414
415void
416compute_output_file_names (void)
417{
418 compute_base_names ();
419
420 parser_file_name =
421 spec_outfile ? spec_outfile : stringappend (full_base_name, src_extension);
422
423 /* If not yet done. */
424 if (!src_extension)
425 src_extension = ".c";
426 if (!header_extension)
427 header_extension = ".h";
428
429 /* It the defines filename if not given, we create it. */
430 if (!spec_defines_file)
431 spec_defines_file = stringappend (full_base_name, header_extension);
432
433 /* It the graph filename if not given, we create it. */
434 if (!spec_graph_file)
435 spec_graph_file = stringappend (short_base_name, ".vcg");
436
437 spec_verbose_file = stringappend (short_base_name, EXT_OUTPUT);
438
439 attrsfile = stringappend (short_base_name, EXT_STYPE_H);
440}