27 |
#include "error.h" |
#include "error.h" |
28 |
#include "complain.h" |
#include "complain.h" |
29 |
|
|
30 |
|
/* From basename.c. Almost a lie, as it returns a char *. */ |
31 |
|
const char *base_name PARAMS ((char const *name)); |
32 |
|
/* From xstrndup.c. */ |
33 |
|
char *xstrndup PARAMS ((const char *s, size_t n)); |
34 |
|
|
35 |
FILE *finput = NULL; |
FILE *finput = NULL; |
36 |
|
|
37 |
struct obstack action_obstack; |
struct obstack action_obstack; |
51 |
char *infile = NULL; |
char *infile = NULL; |
52 |
char *attrsfile = NULL; |
char *attrsfile = NULL; |
53 |
|
|
54 |
static char *base_name = NULL; |
static char *full_base_name = NULL; |
55 |
static char *short_base_name = NULL; |
static char *short_base_name = NULL; |
56 |
|
|
57 |
/* C source file extension (the parser source). */ |
/* C source file extension (the parser source). */ |
118 |
{ |
{ |
119 |
macro_name = XMALLOC (char, |
macro_name = XMALLOC (char, |
120 |
strlen (prefix) + |
strlen (prefix) + |
121 |
strlen (base_name) + |
strlen (full_base_name) + |
122 |
strlen (header_extension) + 1); |
strlen (header_extension) + 1); |
123 |
cp = stpcpy (macro_name, prefix); |
cp = stpcpy (macro_name, prefix); |
124 |
cp = stpcpy (cp, base_name); |
cp = stpcpy (cp, full_base_name); |
125 |
cp = stpcpy (cp, header_extension); |
cp = stpcpy (cp, header_extension); |
126 |
} |
} |
127 |
|
|
280 |
return (temp); |
return (temp); |
281 |
} |
} |
282 |
|
|
|
/* Gets the extension index in FILENAME. Returns 0 if fails to |
|
|
find an extension. */ |
|
|
static int |
|
|
get_extension_index (const char *filename) |
|
|
{ |
|
|
int len; |
|
|
|
|
|
len = strlen (filename); |
|
|
|
|
|
if (filename[len-- - 1] == '.') |
|
|
return (0); |
|
|
|
|
|
while ((len > 0) && (filename[len - 1] != '.')) |
|
|
if (filename[len - 1] == '/') |
|
|
return (0); |
|
|
else |
|
|
len--; |
|
|
|
|
|
return (len - 1); |
|
|
} |
|
|
|
|
283 |
/* Computes extensions from the grammar file extension. */ |
/* Computes extensions from the grammar file extension. */ |
284 |
static void |
static void |
285 |
compute_exts_from_gf (const char *ext) |
compute_exts_from_gf (const char *ext) |
302 |
header_extension = tr (header_extension, 'C', 'H'); |
header_extension = tr (header_extension, 'C', 'H'); |
303 |
} |
} |
304 |
|
|
305 |
|
|
306 |
|
/* Decompose FILENAME in four parts: *BASE, *TAB, and *EXT, the fourth |
307 |
|
part, (the directory) is ranging from FILENAME to the char before |
308 |
|
*BASE, so we don't need an additional parameter. |
309 |
|
|
310 |
|
*EXT points to the last period in the basename, or NULL if none. |
311 |
|
|
312 |
|
If there is no *EXT, *TAB is NULL. Otherwise, *TAB points to |
313 |
|
`.tab' or `_tab' if present right before *EXT, or is NULL. *TAB |
314 |
|
cannot be equal to *BASE. |
315 |
|
|
316 |
|
None are allocated, they are simply pointers to parts of FILENAME. |
317 |
|
Examples: |
318 |
|
|
319 |
|
'/tmp/foo.tab.c' -> *BASE = 'foo.tab.c', *TAB = '.tab.c', *EXT = |
320 |
|
'.c' |
321 |
|
|
322 |
|
'foo.c' -> *BASE = 'foo.c', *TAB = NULL, *EXT = '.c' |
323 |
|
|
324 |
|
'tab.c' -> *BASE = 'tab.c', *TAB = NULL, *EXT = '.c' |
325 |
|
|
326 |
|
'.tab.c' -> *BASE = '.tab.c', *TAB = NULL, *EXT = '.c' |
327 |
|
|
328 |
|
'foo.tab' -> *BASE = 'foo.tab', *TAB = NULL, *EXT = '.tab' |
329 |
|
|
330 |
|
'foo_tab' -> *BASE = 'foo_tab', *TAB = NULL, *EXT = NULL |
331 |
|
|
332 |
|
'foo' -> *BASE = 'foo', *TAB = NULL, *EXT = NULL. */ |
333 |
|
|
334 |
|
static void |
335 |
|
filename_split (const char *filename, |
336 |
|
const char **base, const char **tab, const char **ext) |
337 |
|
{ |
338 |
|
*base = base_name (filename); |
339 |
|
|
340 |
|
/* Look for the extension, i.e., look for the last dot. */ |
341 |
|
*ext = strrchr (*base, '.'); |
342 |
|
*tab = NULL; |
343 |
|
|
344 |
|
/* If there is an exentension, check if there is a `.tab' part right |
345 |
|
before. */ |
346 |
|
if (*ext |
347 |
|
&& (*ext - *base) > (int) strlen (".tab") |
348 |
|
&& (!strncmp (*ext - strlen (".tab"), ".tab", strlen (".tab")) |
349 |
|
|| !strncmp (*ext - strlen ("_tab"), "_tab", strlen ("_tab")))) |
350 |
|
*tab = *ext - strlen (".tab"); |
351 |
|
} |
352 |
|
|
353 |
|
|
354 |
/* FIXME: Should use xstrndup. */ |
/* FIXME: Should use xstrndup. */ |
355 |
|
|
356 |
static void |
static void |
357 |
compute_base_names (void) |
compute_base_names (void) |
358 |
{ |
{ |
359 |
size_t base_length; |
const char *base, *tab, *ext; |
|
size_t short_base_length; |
|
|
size_t ext_index; |
|
360 |
|
|
361 |
/* If --output=foo.c was specified (SPEC_OUTFILE == foo.c), |
/* If --output=foo.c was specified (SPEC_OUTFILE == foo.c), |
362 |
BASE_NAME and SHORT_BASE_NAME are `foo'. |
BASE_NAME and SHORT_BASE_NAME are `foo'. |
368 |
files, remove the ".c" or ".tab.c" suffix. */ |
files, remove the ".c" or ".tab.c" suffix. */ |
369 |
if (spec_outfile) |
if (spec_outfile) |
370 |
{ |
{ |
371 |
#ifdef MSDOS |
filename_split (spec_outfile, &base, &tab, &ext); |
|
strlwr (spec_outfile); |
|
|
#endif /* MSDOS */ |
|
|
/* BASE_LENGTH includes ".tab" but not ".c". */ |
|
|
base_length = strlen (spec_outfile); |
|
372 |
|
|
373 |
ext_index = get_extension_index (spec_outfile); |
/* The full base name goes up the EXT, excluding it. */ |
374 |
/* If the initial segment of extension contains 'c' or a 'C', I assume |
full_base_name = |
375 |
that it is a C or C++ source file. */ |
xstrndup (spec_outfile, |
376 |
if (ext_index) |
(strlen (spec_outfile) - (ext ? strlen (ext) : 0))); |
377 |
ext_index = |
/* The short base name goes up to TAB, excluding it. */ |
378 |
(strspn (spec_outfile + ext_index + 1, "cC")) ? ext_index : 0; |
short_base_name = |
379 |
if (ext_index) |
xstrndup (spec_outfile, |
380 |
{ |
(strlen (spec_outfile) |
381 |
base_length -= strlen (spec_outfile + ext_index); |
- (tab ? strlen (tab) : (ext ? strlen (ext) : 0)))); |
|
compute_exts_from_src (spec_outfile + ext_index); |
|
|
} |
|
|
|
|
|
base_name = strndup (spec_outfile, base_length); |
|
|
/* SHORT_BASE_LENGTH includes neither ".tab" nor ".c". */ |
|
|
short_base_length = base_length; |
|
|
if (strsuffix (base_name, ".tab") || strsuffix (base_name, "_tab")) |
|
|
short_base_length -= 4; |
|
|
short_base_name = strndup (spec_outfile, short_base_length); |
|
382 |
|
|
383 |
return; |
if (ext) |
384 |
|
compute_exts_from_src (ext); |
385 |
} |
} |
386 |
|
|
387 |
/* If --file-prefix=foo was specified, BASE_NAME and SHORT_BASE_NAME |
/* If --file-prefix=foo was specified, FULL_BASE_NAME = `foo.tab' |
388 |
are `foo'. |
and SHORT_BASE_NAME = `foo'. |
389 |
|
|
390 |
Construct names from it. */ |
Construct names from it. */ |
391 |
if (spec_file_prefix) |
else |
392 |
{ |
{ |
393 |
#ifdef MSDOS |
if (spec_file_prefix) |
394 |
strlwr (spec_file_prefix); |
{ |
395 |
#endif /* MSDOS */ |
/* If --file-prefix=foo was specified, SHORT_BASE_NAME = |
396 |
short_base_name = xstrdup (spec_file_prefix); |
`foo'. */ |
397 |
base_name = XMALLOC (char, |
short_base_name = xstrdup (spec_file_prefix); |
398 |
strlen (short_base_name) + strlen (EXT_TAB) + 1); |
} |
399 |
stpcpy (stpcpy (base_name, short_base_name), EXT_TAB); |
else if (yacc_flag) |
400 |
|
{ |
401 |
/* Computes the extensions from the garmmar file name. */ |
/* If --yacc, then the output is `y.tab.c'. */ |
402 |
ext_index = get_extension_index (infile); |
short_base_name = xstrdup ("y"); |
403 |
/* If the initial segment of extension contains a 'y' or a 'Y', I assume |
} |
404 |
that it is a yacc or bison grammar file. */ |
else |
405 |
if (ext_index) |
{ |
406 |
ext_index = strspn (infile + ext_index + 1, "yY") ? ext_index : 0; |
/* Otherwise, the short base name is computed from the input |
407 |
if (ext_index) |
grammar: `foo.yy' => `foo'. */ |
408 |
compute_exts_from_gf (infile + ext_index); |
filename_split (infile, &base, &tab, &ext); |
409 |
|
short_base_name = |
410 |
return; |
xstrndup (infile, |
411 |
|
(strlen (infile) - (ext ? strlen (ext) : 0))); |
412 |
|
} |
413 |
|
|
414 |
|
/* In these cases, always append `.tab'. */ |
415 |
|
full_base_name = XMALLOC (char, |
416 |
|
strlen (short_base_name) |
417 |
|
+ strlen (EXT_TAB) + 1); |
418 |
|
stpcpy (stpcpy (full_base_name, short_base_name), EXT_TAB); |
419 |
|
|
420 |
|
/* Computes the extensions from the grammar file name. */ |
421 |
|
filename_split (infile, &base, &tab, &ext); |
422 |
|
if (ext) |
423 |
|
compute_exts_from_gf (ext); |
424 |
} |
} |
|
|
|
|
/* If neither -o nor --file-prefix were specified, and the input |
|
|
file is foo.y, BASE_NAME is `foo.tab', and SHORT_BASE_NAME is |
|
|
`foo'. |
|
|
|
|
|
If --yacc is used, do as if the input file was `y.y'. */ |
|
|
{ |
|
|
const char *name_base = yacc_flag ? "y.y" : infile; |
|
|
|
|
|
/* BASE_LENGTH gets length of BASE_NAME, sans ".y" suffix if any. */ |
|
|
|
|
|
base_length = strlen (name_base); |
|
|
|
|
|
ext_index = get_extension_index (name_base); |
|
|
/* If the initial segment of extension contains a 'y' or a 'Y', I assume |
|
|
that it is a yacc or bison grammar file. */ |
|
|
if (ext_index) |
|
|
ext_index = strspn (name_base + ext_index + 1, "yY") ? ext_index : 0; |
|
|
if (ext_index) |
|
|
{ |
|
|
base_length -= strlen (name_base + ext_index); |
|
|
compute_exts_from_gf (name_base + ext_index); |
|
|
} |
|
|
|
|
|
short_base_length = base_length; |
|
|
short_base_name = strndup (name_base, short_base_length); |
|
|
|
|
|
base_name = XMALLOC (char, |
|
|
strlen (short_base_name) + strlen (EXT_TAB) + 1); |
|
|
stpcpy (stpcpy (base_name, short_base_name), EXT_TAB); |
|
|
|
|
|
return; |
|
|
} |
|
425 |
} |
} |
426 |
|
|
427 |
|
|
428 |
/*-------------------------------------------------------. |
/*-------------------------------------------------------. |
429 |
| Close the open files, compute the output files names. | |
| Close the open files, compute the output files names. | |
430 |
`-------------------------------------------------------*/ |
`-------------------------------------------------------*/ |
442 |
|
|
443 |
/* It the defines filename if not given, we create it. */ |
/* It the defines filename if not given, we create it. */ |
444 |
if (!spec_defines_file) |
if (!spec_defines_file) |
445 |
spec_defines_file = stringappend (base_name, header_extension); |
spec_defines_file = stringappend (full_base_name, header_extension); |
446 |
|
|
447 |
/* It the graph filename if not given, we create it. */ |
/* It the graph filename if not given, we create it. */ |
448 |
if (!spec_graph_file) |
if (!spec_graph_file) |
499 |
if (spec_outfile) |
if (spec_outfile) |
500 |
obstack_save (&table_obstack, spec_outfile); |
obstack_save (&table_obstack, spec_outfile); |
501 |
else |
else |
502 |
obstack_save (&table_obstack, stringappend (base_name, src_extension)); |
obstack_save (&table_obstack, |
503 |
|
stringappend (full_base_name, src_extension)); |
504 |
obstack_free (&table_obstack, NULL); |
obstack_free (&table_obstack, NULL); |
505 |
|
|
506 |
/* Output the header file if wanted. */ |
/* Output the header file if wanted. */ |