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