| 1 | /* GNU m4 -- A simple macro processor
|
|---|
| 2 |
|
|---|
| 3 | Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006 Free
|
|---|
| 4 | Software Foundation, Inc.
|
|---|
| 5 |
|
|---|
| 6 | This program is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2 of the License, or
|
|---|
| 9 | (at your option) any later version.
|
|---|
| 10 |
|
|---|
| 11 | This program is distributed in the hope that it will be useful,
|
|---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 14 | GNU General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with this program; if not, write to the Free Software
|
|---|
| 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|---|
| 19 | 02110-1301 USA
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | #include "m4.h"
|
|---|
| 23 |
|
|---|
| 24 | #include <getopt.h>
|
|---|
| 25 | #include <limits.h>
|
|---|
| 26 | #include <signal.h>
|
|---|
| 27 |
|
|---|
| 28 | static void usage (int);
|
|---|
| 29 |
|
|---|
| 30 | /* Enable sync output for /lib/cpp (-s). */
|
|---|
| 31 | int sync_output = 0;
|
|---|
| 32 |
|
|---|
| 33 | /* Debug (-d[flags]). */
|
|---|
| 34 | int debug_level = 0;
|
|---|
| 35 |
|
|---|
| 36 | /* Hash table size (should be a prime) (-Hsize). */
|
|---|
| 37 | size_t hash_table_size = HASHMAX;
|
|---|
| 38 |
|
|---|
| 39 | /* Disable GNU extensions (-G). */
|
|---|
| 40 | int no_gnu_extensions = 0;
|
|---|
| 41 |
|
|---|
| 42 | /* Prefix all builtin functions by `m4_'. */
|
|---|
| 43 | int prefix_all_builtins = 0;
|
|---|
| 44 |
|
|---|
| 45 | /* Max length of arguments in trace output (-lsize). */
|
|---|
| 46 | int max_debug_argument_length = 0;
|
|---|
| 47 |
|
|---|
| 48 | /* Suppress warnings about missing arguments. */
|
|---|
| 49 | int suppress_warnings = 0;
|
|---|
| 50 |
|
|---|
| 51 | /* If not zero, then value of exit status for warning diagnostics. */
|
|---|
| 52 | int warning_status = 0;
|
|---|
| 53 |
|
|---|
| 54 | /* Artificial limit for expansion_level in macro.c. */
|
|---|
| 55 | int nesting_limit = 1024;
|
|---|
| 56 |
|
|---|
| 57 | #ifdef ENABLE_CHANGEWORD
|
|---|
| 58 | /* User provided regexp for describing m4 words. */
|
|---|
| 59 | const char *user_word_regexp = "";
|
|---|
| 60 | #endif
|
|---|
| 61 |
|
|---|
| 62 | /* The name this program was run with. */
|
|---|
| 63 | const char *program_name;
|
|---|
| 64 |
|
|---|
| 65 | struct macro_definition
|
|---|
| 66 | {
|
|---|
| 67 | struct macro_definition *next;
|
|---|
| 68 | int code; /* D, U, s, t, or '\1' */
|
|---|
| 69 | const char *arg;
|
|---|
| 70 | };
|
|---|
| 71 | typedef struct macro_definition macro_definition;
|
|---|
| 72 | |
|---|
| 73 |
|
|---|
| 74 | /* Error handling functions. */
|
|---|
| 75 |
|
|---|
| 76 | /*-----------------------.
|
|---|
| 77 | | Wrapper around error. |
|
|---|
| 78 | `-----------------------*/
|
|---|
| 79 |
|
|---|
| 80 | void
|
|---|
| 81 | m4_error (int status, int errnum, const char *format, ...)
|
|---|
| 82 | {
|
|---|
| 83 | va_list args;
|
|---|
| 84 | va_start (args, format);
|
|---|
| 85 | verror_at_line (status, errnum, current_line ? current_file : NULL,
|
|---|
| 86 | current_line, format, args);
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | /*-------------------------------.
|
|---|
| 90 | | Wrapper around error_at_line. |
|
|---|
| 91 | `-------------------------------*/
|
|---|
| 92 |
|
|---|
| 93 | void
|
|---|
| 94 | m4_error_at_line (int status, int errnum, const char *file, int line,
|
|---|
| 95 | const char *format, ...)
|
|---|
| 96 | {
|
|---|
| 97 | va_list args;
|
|---|
| 98 | va_start (args, format);
|
|---|
| 99 | verror_at_line (status, errnum, line ? file : NULL, line, format, args);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | #ifdef USE_STACKOVF
|
|---|
| 103 |
|
|---|
| 104 | /*---------------------------------------.
|
|---|
| 105 | | Tell user stack overflowed and abort. |
|
|---|
| 106 | `---------------------------------------*/
|
|---|
| 107 |
|
|---|
| 108 | static void
|
|---|
| 109 | stackovf_handler (void)
|
|---|
| 110 | {
|
|---|
| 111 | M4ERROR ((EXIT_FAILURE, 0,
|
|---|
| 112 | "ERROR: stack overflow. (Infinite define recursion?)"));
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | #endif /* USE_STACKOV */
|
|---|
| 116 | |
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 | /*---------------------------------------------.
|
|---|
| 120 | | Print a usage message and exit with STATUS. |
|
|---|
| 121 | `---------------------------------------------*/
|
|---|
| 122 |
|
|---|
| 123 | static void
|
|---|
| 124 | usage (int status)
|
|---|
| 125 | {
|
|---|
| 126 | if (status != EXIT_SUCCESS)
|
|---|
| 127 | fprintf (stderr, "Try `%s --help' for more information.\n", program_name);
|
|---|
| 128 | else
|
|---|
| 129 | {
|
|---|
| 130 | printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
|
|---|
| 131 | fputs ("\
|
|---|
| 132 | Process macros in FILEs. If no FILE or if FILE is `-', standard input\n\
|
|---|
| 133 | is read.\n\
|
|---|
| 134 | ", stdout);
|
|---|
| 135 | fputs ("\
|
|---|
| 136 | \n\
|
|---|
| 137 | Mandatory or optional arguments to long options are mandatory or optional\n\
|
|---|
| 138 | for short options too.\n\
|
|---|
| 139 | \n\
|
|---|
| 140 | Operation modes:\n\
|
|---|
| 141 | --help display this help and exit\n\
|
|---|
| 142 | --version output version information and exit\n\
|
|---|
| 143 | -E, --fatal-warnings stop execution after first warning\n\
|
|---|
| 144 | -i, --interactive unbuffer output, ignore interrupts\n\
|
|---|
| 145 | -P, --prefix-builtins force a `m4_' prefix to all builtins\n\
|
|---|
| 146 | -Q, --quiet, --silent suppress some warnings for builtins\n\
|
|---|
| 147 | ", stdout);
|
|---|
| 148 | #ifdef ENABLE_CHANGEWORD
|
|---|
| 149 | fputs ("\
|
|---|
| 150 | -W, --word-regexp=REGEXP use REGEXP for macro name syntax\n\
|
|---|
| 151 | ", stdout);
|
|---|
| 152 | #endif
|
|---|
| 153 | fputs ("\
|
|---|
| 154 | \n\
|
|---|
| 155 | Preprocessor features:\n\
|
|---|
| 156 | -D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\
|
|---|
| 157 | -I, --include=DIRECTORY append DIRECTORY to include path\n\
|
|---|
| 158 | -s, --synclines generate `#line NUM \"FILE\"' lines\n\
|
|---|
| 159 | -U, --undefine=NAME undefine NAME\n\
|
|---|
| 160 | ", stdout);
|
|---|
| 161 | fputs ("\
|
|---|
| 162 | \n\
|
|---|
| 163 | Limits control:\n\
|
|---|
| 164 | -G, --traditional suppress all GNU extensions\n\
|
|---|
| 165 | -H, --hashsize=PRIME set symbol lookup hash table size [509]\n\
|
|---|
| 166 | -L, --nesting-limit=NUMBER change artificial nesting limit [1024]\n\
|
|---|
| 167 | ", stdout);
|
|---|
| 168 | fputs ("\
|
|---|
| 169 | \n\
|
|---|
| 170 | Frozen state files:\n\
|
|---|
| 171 | -F, --freeze-state=FILE produce a frozen state on FILE at end\n\
|
|---|
| 172 | -R, --reload-state=FILE reload a frozen state from FILE at start\n\
|
|---|
| 173 | ", stdout);
|
|---|
| 174 | fputs ("\
|
|---|
| 175 | \n\
|
|---|
| 176 | Debugging:\n\
|
|---|
| 177 | -d, --debug[=FLAGS] set debug level (no FLAGS implies `aeq')\n\
|
|---|
| 178 | --debugfile=FILE redirect debug and trace output\n\
|
|---|
| 179 | -l, --arglength=NUM restrict macro tracing size\n\
|
|---|
| 180 | -t, --trace=NAME trace NAME when it is defined\n\
|
|---|
| 181 | ", stdout);
|
|---|
| 182 | fputs ("\
|
|---|
| 183 | \n\
|
|---|
| 184 | FLAGS is any of:\n\
|
|---|
| 185 | a show actual arguments\n\
|
|---|
| 186 | c show before collect, after collect and after call\n\
|
|---|
| 187 | e show expansion\n\
|
|---|
| 188 | f say current input file name\n\
|
|---|
| 189 | i show changes in input files\n\
|
|---|
| 190 | l say current input line number\n\
|
|---|
| 191 | p show results of path searches\n\
|
|---|
| 192 | q quote values as necessary, with a or e flag\n\
|
|---|
| 193 | t trace for all macro calls, not only traceon'ed\n\
|
|---|
| 194 | x add a unique macro call id, useful with c flag\n\
|
|---|
| 195 | V shorthand for all of the above flags\n\
|
|---|
| 196 | ", stdout);
|
|---|
| 197 | fputs ("\
|
|---|
| 198 | \n\
|
|---|
| 199 | If defined, the environment variable `M4PATH' is a colon-separated list\n\
|
|---|
| 200 | of directories included after any specified by `-I'.\n\
|
|---|
| 201 | ", stdout);
|
|---|
| 202 | fputs ("\
|
|---|
| 203 | \n\
|
|---|
| 204 | Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\
|
|---|
| 205 | mismatch, or whatever value was passed to the m4exit macro.\n\
|
|---|
| 206 | ", stdout);
|
|---|
| 207 | printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
|
|---|
| 208 | }
|
|---|
| 209 | exit (status);
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | /*--------------------------------------.
|
|---|
| 213 | | Decode options and launch execution. |
|
|---|
| 214 | `--------------------------------------*/
|
|---|
| 215 |
|
|---|
| 216 | /* For long options that have no equivalent short option, use a
|
|---|
| 217 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
|---|
| 218 | enum
|
|---|
| 219 | {
|
|---|
| 220 | DEBUGFILE_OPTION = CHAR_MAX + 1, /* no short opt */
|
|---|
| 221 | DIVERSIONS_OPTION, /* not quite -N, because of message */
|
|---|
| 222 |
|
|---|
| 223 | HELP_OPTION, /* no short opt */
|
|---|
| 224 | VERSION_OPTION /* no short opt */
|
|---|
| 225 | };
|
|---|
| 226 |
|
|---|
| 227 | static const struct option long_options[] =
|
|---|
| 228 | {
|
|---|
| 229 | {"arglength", required_argument, NULL, 'l'},
|
|---|
| 230 | {"debug", optional_argument, NULL, 'd'},
|
|---|
| 231 | {"define", required_argument, NULL, 'D'},
|
|---|
| 232 | {"error-output", required_argument, NULL, 'o'}, /* FIXME: deprecate in 2.0 */
|
|---|
| 233 | {"fatal-warnings", no_argument, NULL, 'E'},
|
|---|
| 234 | {"freeze-state", required_argument, NULL, 'F'},
|
|---|
| 235 | {"hashsize", required_argument, NULL, 'H'},
|
|---|
| 236 | {"include", required_argument, NULL, 'I'},
|
|---|
| 237 | {"interactive", no_argument, NULL, 'i'},
|
|---|
| 238 | {"nesting-limit", required_argument, NULL, 'L'},
|
|---|
| 239 | {"prefix-builtins", no_argument, NULL, 'P'},
|
|---|
| 240 | {"quiet", no_argument, NULL, 'Q'},
|
|---|
| 241 | {"reload-state", required_argument, NULL, 'R'},
|
|---|
| 242 | {"silent", no_argument, NULL, 'Q'},
|
|---|
| 243 | {"synclines", no_argument, NULL, 's'},
|
|---|
| 244 | {"trace", required_argument, NULL, 't'},
|
|---|
| 245 | {"traditional", no_argument, NULL, 'G'},
|
|---|
| 246 | {"undefine", required_argument, NULL, 'U'},
|
|---|
| 247 | {"word-regexp", required_argument, NULL, 'W'},
|
|---|
| 248 |
|
|---|
| 249 | {"debugfile", required_argument, NULL, DEBUGFILE_OPTION},
|
|---|
| 250 | {"diversions", required_argument, NULL, DIVERSIONS_OPTION},
|
|---|
| 251 |
|
|---|
| 252 | {"help", no_argument, NULL, HELP_OPTION},
|
|---|
| 253 | {"version", no_argument, NULL, VERSION_OPTION},
|
|---|
| 254 |
|
|---|
| 255 | { NULL, 0, NULL, 0 },
|
|---|
| 256 | };
|
|---|
| 257 |
|
|---|
| 258 | /* Global catchall for any errors that should affect final error status, but
|
|---|
| 259 | where we try to continue execution in the meantime. */
|
|---|
| 260 | int retcode;
|
|---|
| 261 |
|
|---|
| 262 | /* Process a command line file NAME, and return true only if it was
|
|---|
| 263 | stdin. */
|
|---|
| 264 | static bool
|
|---|
| 265 | process_file (const char *name)
|
|---|
| 266 | {
|
|---|
| 267 | bool result = false;
|
|---|
| 268 | if (strcmp (name, "-") == 0)
|
|---|
| 269 | {
|
|---|
| 270 | /* If stdin is a terminal, we want to allow 'm4 - file -'
|
|---|
| 271 | to read input from stdin twice, like GNU cat. Besides,
|
|---|
| 272 | there is no point closing stdin before wrapped text, to
|
|---|
| 273 | minimize bugs in syscmd called from wrapped text. */
|
|---|
| 274 | push_file (stdin, "stdin", false);
|
|---|
| 275 | result = true;
|
|---|
| 276 | }
|
|---|
| 277 | else
|
|---|
| 278 | {
|
|---|
| 279 | char *full_name;
|
|---|
| 280 | FILE *fp = m4_path_search (name, &full_name);
|
|---|
| 281 | if (fp == NULL)
|
|---|
| 282 | {
|
|---|
| 283 | error (0, errno, "%s", name);
|
|---|
| 284 | /* Set the status to EXIT_FAILURE, even though we
|
|---|
| 285 | continue to process files after a missing file. */
|
|---|
| 286 | retcode = EXIT_FAILURE;
|
|---|
| 287 | return false;
|
|---|
| 288 | }
|
|---|
| 289 | push_file (fp, full_name, true);
|
|---|
| 290 | free (full_name);
|
|---|
| 291 | }
|
|---|
| 292 | expand_input ();
|
|---|
| 293 | return result;
|
|---|
| 294 | }
|
|---|
| 295 |
|
|---|
| 296 | /* POSIX requires only -D, -U, and -s; and says that the first two
|
|---|
| 297 | must be recognized when interspersed with file names. Traditional
|
|---|
| 298 | behavior also handles -s between files. Starting OPTSTRING with
|
|---|
| 299 | '-' forces getopt_long to hand back file names as arguments to opt
|
|---|
| 300 | '\1', rather than reordering the command line. */
|
|---|
| 301 | #ifdef ENABLE_CHANGEWORD
|
|---|
| 302 | #define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:W:d::eil:o:st:"
|
|---|
| 303 | #else
|
|---|
| 304 | #define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:d::eil:o:st:"
|
|---|
| 305 | #endif
|
|---|
| 306 |
|
|---|
| 307 | int
|
|---|
| 308 | main (int argc, char *const *argv, char *const *envp)
|
|---|
| 309 | {
|
|---|
| 310 | macro_definition *head; /* head of deferred argument list */
|
|---|
| 311 | macro_definition *tail;
|
|---|
| 312 | macro_definition *defn;
|
|---|
| 313 | int optchar; /* option character */
|
|---|
| 314 |
|
|---|
| 315 | macro_definition *defines;
|
|---|
| 316 | bool read_stdin = false;
|
|---|
| 317 | bool interactive = false;
|
|---|
| 318 | bool seen_file = false;
|
|---|
| 319 | const char *debugfile = NULL;
|
|---|
| 320 | const char *frozen_file_to_read = NULL;
|
|---|
| 321 | const char *frozen_file_to_write = NULL;
|
|---|
| 322 |
|
|---|
| 323 | program_name = argv[0];
|
|---|
| 324 | retcode = EXIT_SUCCESS;
|
|---|
| 325 | atexit (close_stdout);
|
|---|
| 326 |
|
|---|
| 327 | include_init ();
|
|---|
| 328 | debug_init ();
|
|---|
| 329 | #ifdef USE_STACKOVF
|
|---|
| 330 | setup_stackovf_trap (argv, envp, stackovf_handler);
|
|---|
| 331 | #endif
|
|---|
| 332 |
|
|---|
| 333 | /* First, we decode the arguments, to size up tables and stuff. */
|
|---|
| 334 |
|
|---|
| 335 | head = tail = NULL;
|
|---|
| 336 |
|
|---|
| 337 | while ((optchar = getopt_long (argc, (char **) argv, OPTSTRING,
|
|---|
| 338 | long_options, NULL)) != -1)
|
|---|
| 339 | switch (optchar)
|
|---|
| 340 | {
|
|---|
| 341 | default:
|
|---|
| 342 | usage (EXIT_FAILURE);
|
|---|
| 343 |
|
|---|
| 344 | case 'B':
|
|---|
| 345 | case 'S':
|
|---|
| 346 | case 'T':
|
|---|
| 347 | /* Compatibility junk: options that other implementations
|
|---|
| 348 | support, but which we ignore as no-ops and don't list in
|
|---|
| 349 | --help. */
|
|---|
| 350 | error (0, 0, "Warning: `m4 -%c' may be removed in a future release",
|
|---|
| 351 | optchar);
|
|---|
| 352 | break;
|
|---|
| 353 |
|
|---|
| 354 | case 'N':
|
|---|
| 355 | case DIVERSIONS_OPTION:
|
|---|
| 356 | /* -N became an obsolete no-op in 1.4.x. */
|
|---|
| 357 | error (0, 0, "Warning: `m4 %s' is deprecated",
|
|---|
| 358 | optchar == 'N' ? "-N" : "--diversions");
|
|---|
| 359 |
|
|---|
| 360 | case 'D':
|
|---|
| 361 | case 'U':
|
|---|
| 362 | case 's':
|
|---|
| 363 | case 't':
|
|---|
| 364 | case '\1':
|
|---|
| 365 | /* Arguments that cannot be handled until later are accumulated. */
|
|---|
| 366 |
|
|---|
| 367 | defn = (macro_definition *) xmalloc (sizeof (macro_definition));
|
|---|
| 368 | defn->code = optchar;
|
|---|
| 369 | defn->arg = optarg;
|
|---|
| 370 | defn->next = NULL;
|
|---|
| 371 |
|
|---|
| 372 | if (head == NULL)
|
|---|
| 373 | head = defn;
|
|---|
| 374 | else
|
|---|
| 375 | tail->next = defn;
|
|---|
| 376 | tail = defn;
|
|---|
| 377 |
|
|---|
| 378 | break;
|
|---|
| 379 |
|
|---|
| 380 | case 'E':
|
|---|
| 381 | warning_status = EXIT_FAILURE;
|
|---|
| 382 | break;
|
|---|
| 383 |
|
|---|
| 384 | case 'F':
|
|---|
| 385 | frozen_file_to_write = optarg;
|
|---|
| 386 | break;
|
|---|
| 387 |
|
|---|
| 388 | case 'G':
|
|---|
| 389 | no_gnu_extensions = 1;
|
|---|
| 390 | break;
|
|---|
| 391 |
|
|---|
| 392 | case 'H':
|
|---|
| 393 | hash_table_size = atol (optarg);
|
|---|
| 394 | if (hash_table_size == 0)
|
|---|
| 395 | hash_table_size = HASHMAX;
|
|---|
| 396 | break;
|
|---|
| 397 |
|
|---|
| 398 | case 'I':
|
|---|
| 399 | add_include_directory (optarg);
|
|---|
| 400 | break;
|
|---|
| 401 |
|
|---|
| 402 | case 'L':
|
|---|
| 403 | nesting_limit = atoi (optarg);
|
|---|
| 404 | break;
|
|---|
| 405 |
|
|---|
| 406 | case 'P':
|
|---|
| 407 | prefix_all_builtins = 1;
|
|---|
| 408 | break;
|
|---|
| 409 |
|
|---|
| 410 | case 'Q':
|
|---|
| 411 | suppress_warnings = 1;
|
|---|
| 412 | break;
|
|---|
| 413 |
|
|---|
| 414 | case 'R':
|
|---|
| 415 | frozen_file_to_read = optarg;
|
|---|
| 416 | break;
|
|---|
| 417 |
|
|---|
| 418 | #ifdef ENABLE_CHANGEWORD
|
|---|
| 419 | case 'W':
|
|---|
| 420 | user_word_regexp = optarg;
|
|---|
| 421 | break;
|
|---|
| 422 | #endif
|
|---|
| 423 |
|
|---|
| 424 | case 'd':
|
|---|
| 425 | debug_level = debug_decode (optarg);
|
|---|
| 426 | if (debug_level < 0)
|
|---|
| 427 | {
|
|---|
| 428 | error (0, 0, "bad debug flags: `%s'", optarg);
|
|---|
| 429 | debug_level = 0;
|
|---|
| 430 | }
|
|---|
| 431 | break;
|
|---|
| 432 |
|
|---|
| 433 | case 'e':
|
|---|
| 434 | error (0, 0, "Warning: `m4 -e' is deprecated, use `-i' instead");
|
|---|
| 435 | /* fall through */
|
|---|
| 436 | case 'i':
|
|---|
| 437 | interactive = true;
|
|---|
| 438 | break;
|
|---|
| 439 |
|
|---|
| 440 | case 'l':
|
|---|
| 441 | max_debug_argument_length = atoi (optarg);
|
|---|
| 442 | if (max_debug_argument_length <= 0)
|
|---|
| 443 | max_debug_argument_length = 0;
|
|---|
| 444 | break;
|
|---|
| 445 |
|
|---|
| 446 | case 'o':
|
|---|
| 447 | /* -o/--error-output are deprecated synonyms of --debugfile,
|
|---|
| 448 | but don't issue a deprecation warning until autoconf 2.61
|
|---|
| 449 | or later is more widely established, as such a warning
|
|---|
| 450 | would interfere with all earlier versions of autoconf. */
|
|---|
| 451 | case DEBUGFILE_OPTION:
|
|---|
| 452 | /* Don't call debug_set_output here, as it has side effects. */
|
|---|
| 453 | debugfile = optarg;
|
|---|
| 454 | break;
|
|---|
| 455 |
|
|---|
| 456 | case VERSION_OPTION:
|
|---|
| 457 | printf ("%s\n", PACKAGE_STRING);
|
|---|
| 458 | fputs ("\
|
|---|
| 459 | Copyright (C) 2006 Free Software Foundation, Inc.\n\
|
|---|
| 460 | This is free software; see the source for copying conditions. There is NO\n\
|
|---|
| 461 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
|---|
| 462 | \n\
|
|---|
| 463 | Written by Rene' Seindal.\n\
|
|---|
| 464 | ", stdout);
|
|---|
| 465 | exit (EXIT_SUCCESS);
|
|---|
| 466 | break;
|
|---|
| 467 |
|
|---|
| 468 | case HELP_OPTION:
|
|---|
| 469 | usage (EXIT_SUCCESS);
|
|---|
| 470 | break;
|
|---|
| 471 | }
|
|---|
| 472 |
|
|---|
| 473 | defines = head;
|
|---|
| 474 |
|
|---|
| 475 | /* Do the basic initializations. */
|
|---|
| 476 | if (debugfile && !debug_set_output (debugfile))
|
|---|
| 477 | M4ERROR ((0, errno, "cannot set debug file `%s'", debugfile));
|
|---|
| 478 |
|
|---|
| 479 | input_init ();
|
|---|
| 480 | output_init ();
|
|---|
| 481 | symtab_init ();
|
|---|
| 482 | include_env_init ();
|
|---|
| 483 |
|
|---|
| 484 | if (frozen_file_to_read)
|
|---|
| 485 | reload_frozen_state (frozen_file_to_read);
|
|---|
| 486 | else
|
|---|
| 487 | builtin_init ();
|
|---|
| 488 |
|
|---|
| 489 | /* Interactive mode means unbuffered output, and interrupts ignored. */
|
|---|
| 490 |
|
|---|
| 491 | if (interactive)
|
|---|
| 492 | {
|
|---|
| 493 | signal (SIGINT, SIG_IGN);
|
|---|
| 494 | setbuf (stdout, (char *) NULL);
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | /* Handle deferred command line macro definitions. Must come after
|
|---|
| 498 | initialization of the symbol table. */
|
|---|
| 499 |
|
|---|
| 500 | while (defines != NULL)
|
|---|
| 501 | {
|
|---|
| 502 | macro_definition *next;
|
|---|
| 503 | symbol *sym;
|
|---|
| 504 |
|
|---|
| 505 | switch (defines->code)
|
|---|
| 506 | {
|
|---|
| 507 | case 'D':
|
|---|
| 508 | {
|
|---|
| 509 | /* defines->arg is read-only, so we need a copy. */
|
|---|
| 510 | char *macro_name = xstrdup (defines->arg);
|
|---|
| 511 | char *macro_value = strchr (macro_name, '=');
|
|---|
| 512 | if (macro_value)
|
|---|
| 513 | *macro_value++ = '\0';
|
|---|
| 514 | define_user_macro (macro_name, macro_value, SYMBOL_INSERT);
|
|---|
| 515 | free (macro_name);
|
|---|
| 516 | }
|
|---|
| 517 | break;
|
|---|
| 518 |
|
|---|
| 519 | case 'U':
|
|---|
| 520 | lookup_symbol (defines->arg, SYMBOL_DELETE);
|
|---|
| 521 | break;
|
|---|
| 522 |
|
|---|
| 523 | case 't':
|
|---|
| 524 | sym = lookup_symbol (defines->arg, SYMBOL_INSERT);
|
|---|
| 525 | SYMBOL_TRACED (sym) = true;
|
|---|
| 526 | break;
|
|---|
| 527 |
|
|---|
| 528 | case 's':
|
|---|
| 529 | sync_output = 1;
|
|---|
| 530 | break;
|
|---|
| 531 |
|
|---|
| 532 | case '\1':
|
|---|
| 533 | seen_file = true;
|
|---|
| 534 | if (process_file (defines->arg))
|
|---|
| 535 | read_stdin = true;
|
|---|
| 536 | break;
|
|---|
| 537 |
|
|---|
| 538 | default:
|
|---|
| 539 | M4ERROR ((warning_status, 0,
|
|---|
| 540 | "INTERNAL ERROR: bad code in deferred arguments"));
|
|---|
| 541 | abort ();
|
|---|
| 542 | }
|
|---|
| 543 |
|
|---|
| 544 | next = defines->next;
|
|---|
| 545 | free (defines);
|
|---|
| 546 | defines = next;
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | /* Handle remaining input files. Each file is pushed on the input,
|
|---|
| 550 | and the input read. Wrapup text is handled separately later. */
|
|---|
| 551 |
|
|---|
| 552 | if (optind == argc && !seen_file)
|
|---|
| 553 | read_stdin = process_file ("-");
|
|---|
| 554 | else
|
|---|
| 555 | for (; optind < argc; optind++)
|
|---|
| 556 | if (process_file (defines->arg))
|
|---|
| 557 | read_stdin = true;
|
|---|
| 558 |
|
|---|
| 559 | /* Now handle wrapup text. */
|
|---|
| 560 |
|
|---|
| 561 | while (pop_wrapup ())
|
|---|
| 562 | expand_input ();
|
|---|
| 563 |
|
|---|
| 564 | /* Change debug stream back to stderr, to force flushing the debug
|
|---|
| 565 | stream and detect any errors it might have encountered. Close
|
|---|
| 566 | stdin if we read from it, to detect any errors. */
|
|---|
| 567 | debug_set_output (NULL);
|
|---|
| 568 | if (read_stdin && fclose (stdin) == EOF)
|
|---|
| 569 | {
|
|---|
| 570 | M4ERROR ((warning_status, errno, "error reading file"));
|
|---|
| 571 | retcode = EXIT_FAILURE;
|
|---|
| 572 | }
|
|---|
| 573 |
|
|---|
| 574 | if (frozen_file_to_write)
|
|---|
| 575 | produce_frozen_state (frozen_file_to_write);
|
|---|
| 576 | else
|
|---|
| 577 | {
|
|---|
| 578 | make_diversion (0);
|
|---|
| 579 | undivert_all ();
|
|---|
| 580 | }
|
|---|
| 581 | output_exit ();
|
|---|
| 582 | exit (retcode);
|
|---|
| 583 | }
|
|---|