Home | History | Annotate | Download | only in src
      1 /* Open and close files for Bison.
      2 
      3    Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004, 2005
      4    Free Software Foundation, Inc.
      5 
      6    This file is part of Bison, the GNU Compiler Compiler.
      7 
      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.
     12 
     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.
     17 
     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
     20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     21    02110-1301, USA.  */
     22 
     23 #include <config.h>
     24 #include "system.h"
     25 
     26 #include <error.h>
     27 #include <get-errno.h>
     28 #include <quote.h>
     29 #include <xstrndup.h>
     30 
     31 #include "complain.h"
     32 #include "dirname.h"
     33 #include "files.h"
     34 #include "getargs.h"
     35 #include "gram.h"
     36 #include "stdio-safer.h"
     37 
     38 struct obstack pre_prologue_obstack;
     39 struct obstack post_prologue_obstack;
     40 
     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 
     48 char const *spec_outfile = NULL;       /* for -o. */
     49 char const *spec_file_prefix = NULL;   /* for -b. */
     50 char const *spec_name_prefix = NULL;   /* for -p. */
     51 char const *spec_verbose_file = NULL;  /* for --verbose. */
     52 char const *spec_graph_file = NULL;    /* for -g. */
     53 char const *spec_defines_file = NULL;  /* for --defines. */
     54 char const *parser_file_name;
     55 
     56 uniqstr grammar_file = NULL;
     57 uniqstr current_file = NULL;
     58 
     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/'.  */
     74 
     75 static char const *all_but_ext;
     76 static char const *all_but_tab_ext;
     77 char const *dir_prefix;
     78 
     79 /* C source file extension (the parser source).  */
     80 static char const *src_extension = NULL;
     81 /* Header file extension (if option ``-d'' is specified).  */
     82 static char const *header_extension = NULL;
     83 
     84 /*-----------------------------------------------------------------.
     86 | Return a newly allocated string composed of the concatenation of |
     87 | STR1, and STR2.                                                  |
     88 `-----------------------------------------------------------------*/
     89 
     90 static char *
     91 concat2 (char const *str1, char const *str2)
     92 {
     93   size_t len = strlen (str1) + strlen (str2);
     94   char *res = xmalloc (len + 1);
     95   char *cp;
     96   cp = stpcpy (res, str1);
     97   cp = stpcpy (cp, str2);
     98   return res;
     99 }
    100 
    101 /*-----------------------------------------------------------------.
    102 | Try to open file NAME with mode MODE, and print an error message |
    103 | if fails.                                                        |
    104 `-----------------------------------------------------------------*/
    105 
    106 FILE *
    107 xfopen (const char *name, const char *mode)
    108 {
    109   FILE *ptr;
    110 
    111   ptr = fopen_safer (name, mode);
    112   if (!ptr)
    113     error (EXIT_FAILURE, get_errno (), _("cannot open file `%s'"), name);
    114 
    115   return ptr;
    116 }
    117 
    118 /*-------------------------------------------------------------.
    119 | Try to close file PTR, and print an error message if fails.  |
    120 `-------------------------------------------------------------*/
    121 
    122 void
    123 xfclose (FILE *ptr)
    124 {
    125   if (ptr == NULL)
    126     return;
    127 
    128   if (ferror (ptr))
    129     error (EXIT_FAILURE, 0, _("I/O error"));
    130 
    131   if (fclose (ptr) != 0)
    132     error (EXIT_FAILURE, get_errno (), _("cannot close file"));
    133 }
    134 
    135 
    137 /*------------------------------------------------------------------.
    138 | Compute ALL_BUT_EXT, ALL_BUT_TAB_EXT and output files extensions. |
    139 `------------------------------------------------------------------*/
    140 
    141 /* Replace all characters FROM by TO in the string IN.
    142    and returns a new allocated string.  */
    143 static char *
    144 tr (const char *in, char from, char to)
    145 {
    146   char *temp;
    147   char *out = xmalloc (strlen (in) + 1);
    148 
    149   for (temp = out; *in; in++, out++)
    150     if (*in == from)
    151       *out = to;
    152     else
    153       *out = *in;
    154   *out = 0;
    155   return (temp);
    156 }
    157 
    158 /* Compute extensions from the grammar file extension.  */
    159 static void
    160 compute_exts_from_gf (const char *ext)
    161 {
    162   src_extension = tr (ext, 'y', 'c');
    163   src_extension = tr (src_extension, 'Y', 'C');
    164   header_extension = tr (ext, 'y', 'h');
    165   header_extension = tr (header_extension, 'Y', 'H');
    166 }
    167 
    168 /* Compute extensions from the given c source file extension.  */
    169 static void
    170 compute_exts_from_src (const char *ext)
    171 {
    172   /* We use this function when the user specifies `-o' or `--output',
    173      so the extenions must be computed unconditionally from the file name
    174      given by this option.  */
    175   src_extension = xstrdup (ext);
    176   header_extension = tr (ext, 'c', 'h');
    177   header_extension = tr (header_extension, 'C', 'H');
    178 }
    179 
    180 
    181 /* Decompose FILE_NAME in four parts: *BASE, *TAB, and *EXT, the fourth
    182    part, (the directory) is ranging from FILE_NAME to the char before
    183    *BASE, so we don't need an additional parameter.
    184 
    185    *EXT points to the last period in the basename, or NULL if none.
    186 
    187    If there is no *EXT, *TAB is NULL.  Otherwise, *TAB points to
    188    `.tab' or `_tab' if present right before *EXT, or is NULL. *TAB
    189    cannot be equal to *BASE.
    190 
    191    None are allocated, they are simply pointers to parts of FILE_NAME.
    192    Examples:
    193 
    194    '/tmp/foo.tab.c' -> *BASE = 'foo.tab.c', *TAB = '.tab.c', *EXT =
    195    '.c'
    196 
    197    'foo.c' -> *BASE = 'foo.c', *TAB = NULL, *EXT = '.c'
    198 
    199    'tab.c' -> *BASE = 'tab.c', *TAB = NULL, *EXT = '.c'
    200 
    201    '.tab.c' -> *BASE = '.tab.c', *TAB = NULL, *EXT = '.c'
    202 
    203    'foo.tab' -> *BASE = 'foo.tab', *TAB = NULL, *EXT = '.tab'
    204 
    205    'foo_tab' -> *BASE = 'foo_tab', *TAB = NULL, *EXT = NULL
    206 
    207    'foo' -> *BASE = 'foo', *TAB = NULL, *EXT = NULL.  */
    208 
    209 static void
    210 file_name_split (const char *file_name,
    211 		 const char **base, const char **tab, const char **ext)
    212 {
    213   *base = base_name (file_name);
    214 
    215   /* Look for the extension, i.e., look for the last dot. */
    216   *ext = strrchr (*base, '.');
    217   *tab = NULL;
    218 
    219   /* If there is an extension, check if there is a `.tab' part right
    220      before.  */
    221   if (*ext)
    222     {
    223       size_t baselen = *ext - *base;
    224       size_t dottablen = 4;
    225       if (dottablen < baselen
    226 	  && (strncmp (*ext - dottablen, ".tab", dottablen) == 0
    227 	      || strncmp (*ext - dottablen, "_tab", dottablen) == 0))
    228 	*tab = *ext - dottablen;
    229     }
    230 }
    231 
    232 
    233 static void
    234 compute_file_name_parts (void)
    235 {
    236   const char *base, *tab, *ext;
    237 
    238   /* Compute ALL_BUT_EXT and ALL_BUT_TAB_EXT from SPEC_OUTFILE
    239      or GRAMMAR_FILE.
    240 
    241      The precise -o name will be used for FTABLE.  For other output
    242      files, remove the ".c" or ".tab.c" suffix.  */
    243   if (spec_outfile)
    244     {
    245       file_name_split (spec_outfile, &base, &tab, &ext);
    246       dir_prefix = xstrndup (spec_outfile, base - spec_outfile);
    247 
    248       /* ALL_BUT_EXT goes up the EXT, excluding it. */
    249       all_but_ext =
    250 	xstrndup (spec_outfile,
    251 		  (strlen (spec_outfile) - (ext ? strlen (ext) : 0)));
    252 
    253       /* ALL_BUT_TAB_EXT goes up to TAB, excluding it.  */
    254       all_but_tab_ext =
    255 	xstrndup (spec_outfile,
    256 		  (strlen (spec_outfile)
    257 		   - (tab ? strlen (tab) : (ext ? strlen (ext) : 0))));
    258 
    259       if (ext)
    260 	compute_exts_from_src (ext);
    261     }
    262   else
    263     {
    264       file_name_split (grammar_file, &base, &tab, &ext);
    265 
    266       if (spec_file_prefix)
    267 	{
    268 	  /* If --file-prefix=foo was specified, ALL_BUT_TAB_EXT = `foo'.  */
    269 	  dir_prefix = xstrndup (grammar_file, base - grammar_file);
    270 	  all_but_tab_ext = xstrdup (spec_file_prefix);
    271 	}
    272       else if (yacc_flag)
    273 	{
    274 	  /* If --yacc, then the output is `y.tab.c'.  */
    275 	  dir_prefix = "";
    276 	  all_but_tab_ext = "y";
    277 	}
    278       else
    279 	{
    280 	  /* Otherwise, ALL_BUT_TAB_EXT is computed from the input
    281 	     grammar: `foo/bar.yy' => `bar'.  */
    282 	  dir_prefix = "";
    283 	  all_but_tab_ext =
    284 	    xstrndup (base, (strlen (base) - (ext ? strlen (ext) : 0)));
    285 	}
    286 
    287       all_but_ext = concat2 (all_but_tab_ext, TAB_EXT);
    288 
    289       /* Compute the extensions from the grammar file name.  */
    290       if (ext && !yacc_flag)
    291 	compute_exts_from_gf (ext);
    292     }
    293 }
    294 
    295 
    296 /* Compute the output file names.  Warn if we detect conflicting
    297    outputs to the same file.  */
    298 
    299 void
    300 compute_output_file_names (void)
    301 {
    302   char const *name[4];
    303   int i;
    304   int j;
    305   int names = 0;
    306 
    307   compute_file_name_parts ();
    308 
    309   /* If not yet done. */
    310   if (!src_extension)
    311     src_extension = ".c";
    312   if (!header_extension)
    313     header_extension = ".h";
    314 
    315   name[names++] = parser_file_name =
    316     spec_outfile ? spec_outfile : concat2 (all_but_ext, src_extension);
    317 
    318   if (defines_flag)
    319     {
    320       if (! spec_defines_file)
    321 	spec_defines_file = concat2 (all_but_ext, header_extension);
    322       name[names++] = spec_defines_file;
    323     }
    324 
    325   if (graph_flag)
    326     {
    327       if (! spec_graph_file)
    328 	spec_graph_file = concat2 (all_but_tab_ext, ".vcg");
    329       name[names++] = spec_graph_file;
    330     }
    331 
    332   if (report_flag)
    333     {
    334       spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
    335       name[names++] = spec_verbose_file;
    336     }
    337 
    338   for (j = 0; j < names; j++)
    339     for (i = 0; i < j; i++)
    340       if (strcmp (name[i], name[j]) == 0)
    341 	warn (_("conflicting outputs to file %s"), quote (name[i]));
    342 }
    343