source: trunk/essentials/sys-devel/m4/src/m4.c

Last change on this file was 3090, checked in by bird, 18 years ago

m4 1.4.8

File size: 15.3 KB
Line 
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
28static void usage (int);
29
30/* Enable sync output for /lib/cpp (-s). */
31int sync_output = 0;
32
33/* Debug (-d[flags]). */
34int debug_level = 0;
35
36/* Hash table size (should be a prime) (-Hsize). */
37size_t hash_table_size = HASHMAX;
38
39/* Disable GNU extensions (-G). */
40int no_gnu_extensions = 0;
41
42/* Prefix all builtin functions by `m4_'. */
43int prefix_all_builtins = 0;
44
45/* Max length of arguments in trace output (-lsize). */
46int max_debug_argument_length = 0;
47
48/* Suppress warnings about missing arguments. */
49int suppress_warnings = 0;
50
51/* If not zero, then value of exit status for warning diagnostics. */
52int warning_status = 0;
53
54/* Artificial limit for expansion_level in macro.c. */
55int nesting_limit = 1024;
56
57#ifdef ENABLE_CHANGEWORD
58/* User provided regexp for describing m4 words. */
59const char *user_word_regexp = "";
60#endif
61
62/* The name this program was run with. */
63const char *program_name;
64
65struct macro_definition
66{
67 struct macro_definition *next;
68 int code; /* D, U, s, t, or '\1' */
69 const char *arg;
70};
71typedef struct macro_definition macro_definition;
72
73
74/* Error handling functions. */
75
76/*-----------------------.
77| Wrapper around error. |
78`-----------------------*/
79
80void
81m4_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
93void
94m4_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
108static void
109stackovf_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
123static void
124usage (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 ("\
132Process macros in FILEs. If no FILE or if FILE is `-', standard input\n\
133is read.\n\
134", stdout);
135 fputs ("\
136\n\
137Mandatory or optional arguments to long options are mandatory or optional\n\
138for short options too.\n\
139\n\
140Operation 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\
155Preprocessor 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\
163Limits 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\
170Frozen 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\
176Debugging:\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\
184FLAGS 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\
199If defined, the environment variable `M4PATH' is a colon-separated list\n\
200of directories included after any specified by `-I'.\n\
201", stdout);
202 fputs ("\
203\n\
204Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\
205mismatch, 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. */
218enum
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
227static 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. */
260int retcode;
261
262/* Process a command line file NAME, and return true only if it was
263 stdin. */
264static bool
265process_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
307int
308main (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 ("\
459Copyright (C) 2006 Free Software Foundation, Inc.\n\
460This is free software; see the source for copying conditions. There is NO\n\
461warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
462\n\
463Written 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}
Note: See TracBrowser for help on using the repository browser.