Use gnulib pipe module instead of popen(3).
[m4.git] / src / main.c
blobc2e19bdf45cac04a70d4b882d5afd6b09cf3b1ab
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1999, 2000, 2003,
4 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <config.h>
24 #include <locale.h>
26 #include "m4.h"
28 #include "close-stream.h"
29 #include "closein.h"
30 #include "configmake.h"
31 #include "getopt.h"
32 #include "propername.h"
33 #include "quotearg.h"
34 #include "version-etc.h"
35 #include "xstrtol.h"
37 #define AUTHORS \
38 proper_name_utf8 ("Rene' Seindal", "Ren\xc3\xa9 Seindal"), \
39 proper_name ("Gary V. Vaughan"), \
40 proper_name ("Eric Blake")
42 typedef struct deferred
44 struct deferred *next;
45 int code; /* deferred optchar */
46 const char *value;
47 } deferred;
50 /* Error handling functions. */
52 #ifdef USE_STACKOVF
54 /* Tell user stack overflowed and abort. */
55 static void
56 stackovf_handler (void)
58 /* FIXME - calling gettext and error inside a signal handler is dangerous,
59 since these functions invoke functions that are not signal-safe. We
60 are sort of justified by the fact that we will exit and never return,
61 but this should really be fixed. */
62 error (EXIT_FAILURE, 0, _("stack overflow (infinite define recursion?)"));
65 #endif /* USE_STACKOVF */
69 /* Print a usage message and exit with STATUS. */
70 static void
71 usage (int status)
73 if (status != EXIT_SUCCESS)
74 xfprintf (stderr, _("Try `%s --help' for more information.\n"),
75 m4_get_program_name ());
76 else
78 xprintf (_("Usage: %s [OPTION]... [FILE]...\n"), m4_get_program_name ());
79 fputs (_("\
80 Process macros in FILEs.\n\
81 If no FILE or if FILE is `-', standard input is read. If no FILE, and both\n\
82 standard input and standard error are terminals, -i is implied.\n\
83 "), stdout);
84 puts ("");
85 fputs (_("\
86 Mandatory or optional arguments to long options are mandatory or optional\n\
87 for short options too.\n\
88 \n\
89 Operation modes:\n\
90 --help display this help and exit\n\
91 --version output version information and exit\n\
92 "), stdout);
93 fputs (_("\
94 -b, --batch buffer output, process interrupts\n\
95 -c, --discard-comments do not copy comments to the output\n\
96 -E, --fatal-warnings once: warnings become errors, twice: stop\n\
97 execution at first error\n\
98 -i, --interactive unbuffer output, ignore interrupts\n\
99 -P, --prefix-builtins force a `m4_' prefix to all builtins\n\
100 -Q, --quiet, --silent suppress some warnings for builtins\n\
101 -r, --regexp-syntax[=SPEC] set default regexp syntax to SPEC [GNU_M4]\n\
102 --safer disable potentially unsafe builtins\n\
103 -W, --warnings enable all warnings\n\
104 "), stdout);
105 puts ("");
106 fputs (_("\
107 SPEC is any one of:\n\
108 AWK, BASIC, BSD_M4, ED, EMACS, EXTENDED, GNU_AWK, GNU_EGREP, GNU_M4,\n\
109 GREP, POSIX_AWK, POSIX_EGREP, MINIMAL, MINIMAL_BASIC, SED.\n\
110 "), stdout);
111 puts ("");
112 xprintf (_("\
113 Dynamic loading features:\n\
114 -M, --module-directory=DIR add DIR to module search path before\n\
115 %s\n\
116 -m, --load-module=MODULE load dynamic MODULE\n\
117 --unload-module=MODULE unload dynamic MODULE\n\
118 "), quotearg_style (locale_quoting_style, PKGLIBEXECDIR));
119 puts ("");
120 fputs (_("\
121 Preprocessor features:\n\
122 -B, --prepend-include=DIR add DIR to include path before `.'\n\
123 -D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\
124 --import-environment import all environment variables as macros\n\
125 -I, --include=DIR add DIR to include path after `.'\n\
126 "), stdout);
127 fputs (_("\
128 --popdef=NAME popdef NAME\n\
129 -p, --pushdef=NAME[=VALUE] pushdef NAME as having VALUE, or empty\n\
130 -s, --synclines short for --syncoutput=1\n\
131 --syncoutput[=STATE] set generation of `#line NUM \"FILE\"' lines\n\
132 to STATE (0=off, 1=on, default 0)\n\
133 -U, --undefine=NAME undefine NAME\n\
134 "), stdout);
135 puts ("");
136 fputs (_("\
137 Limits control:\n\
138 -g, --gnu override -G to re-enable GNU extensions\n\
139 -G, --traditional, --posix suppress all GNU extensions\n\
140 -L, --nesting-limit=NUMBER change artificial nesting limit [1024]\n\
141 "), stdout);
142 puts ("");
143 fputs (_("\
144 Frozen state files:\n\
145 -F, --freeze-state=FILE produce a frozen state on FILE at end\n\
146 -R, --reload-state=FILE reload a frozen state from FILE at start\n\
147 "), stdout);
148 puts ("");
149 fputs (_("\
150 Debugging:\n\
151 -d, --debug[=[-|+]FLAGS], --debugmode[=[-|+]FLAGS]\n\
152 set debug level (no FLAGS implies `+adeq')\n\
153 --debugfile[=FILE] redirect debug and trace output to FILE\n\
154 (default stderr, discard if empty string)\n\
155 -l, --debuglen=NUM restrict macro tracing size\n\
156 -t, --trace=NAME, --traceon=NAME\n\
157 trace NAME when it is defined\n\
158 --traceoff=NAME no longer trace NAME\n\
159 "), stdout);
160 puts ("");
161 fputs (_("\
162 FLAGS is any of:\n\
163 a show actual arguments in trace\n\
164 c show collection line in trace\n\
165 d warn when dereferencing undefined macros (default on unless -E)\n\
166 e show expansion in trace\n\
167 f include current input file name in trace and debug\n\
168 i show changes in input files in debug\n\
169 l include current input line number in trace and debug\n\
170 "), stdout);
171 fputs (_("\
172 m show module information in trace, debug, and dumpdef\n\
173 o output dumpdef to stderr rather than debug file\n\
174 p show results of path searches in debug\n\
175 q quote values in dumpdef and trace, useful with a or e\n\
176 s show full stack of pushdef values in dumpdef\n\
177 t trace all macro calls, regardless of per-macro traceon state\n\
178 x include unique macro call id in trace, useful with c\n\
179 V shorthand for all of the above flags\n\
180 "), stdout);
181 puts ("");
182 fputs (_("\
183 If defined, the environment variable `M4PATH' is a colon-separated list\n\
184 of directories included after any specified by `-I', and the variable\n\
185 `M4MODPATH' is a colon-separated list of directories searched before any\n\
186 specified by `-M'. The environment variable `POSIXLY_CORRECT' implies\n\
187 -G -Q; otherwise GNU extensions are enabled by default.\n\
188 "), stdout);
189 puts ("");
190 fputs (_("\
191 Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\
192 mismatch, or whatever value was passed to the m4exit macro.\n\
193 "), stdout);
194 emit_bug_reporting_address ();
196 exit (status);
199 /* For long options that have no equivalent short option, use a
200 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
201 enum
203 ARGLENGTH_OPTION = CHAR_MAX + 1, /* not quite -l, because of message */
204 DEBUGFILE_OPTION, /* no short opt */
205 ERROR_OUTPUT_OPTION, /* not quite -o, because of message */
206 HASHSIZE_OPTION, /* not quite -H, because of message */
207 IMPORT_ENVIRONMENT_OPTION, /* no short opt */
208 POPDEF_OPTION, /* no short opt */
209 PREPEND_INCLUDE_OPTION, /* not quite -B, because of message */
210 SAFER_OPTION, /* -S still has old no-op semantics */
211 SYNCOUTPUT_OPTION, /* not quite -s, because of opt arg */
212 TRACEOFF_OPTION, /* no short opt */
213 UNLOAD_MODULE_OPTION, /* no short opt */
214 WORD_REGEXP_OPTION, /* deprecated, used to be -W */
216 HELP_OPTION, /* no short opt */
217 VERSION_OPTION /* no short opt */
220 /* Decode options and launch execution. */
221 static const struct option long_options[] =
223 {"batch", no_argument, NULL, 'b'},
224 {"debug", optional_argument, NULL, 'd'},
225 {"debuglen", required_argument, NULL, 'l'},
226 {"debugmode", optional_argument, NULL, 'd'},
227 {"define", required_argument, NULL, 'D'},
228 {"discard-comments", no_argument, NULL, 'c'},
229 {"fatal-warnings", no_argument, NULL, 'E'},
230 {"freeze-state", required_argument, NULL, 'F'},
231 {"gnu", no_argument, NULL, 'g'},
232 {"include", required_argument, NULL, 'I'},
233 {"interactive", no_argument, NULL, 'i'},
234 {"load-module", required_argument, NULL, 'm'},
235 {"module-directory", required_argument, NULL, 'M'},
236 {"nesting-limit", required_argument, NULL, 'L'},
237 {"posix", no_argument, NULL, 'G'},
238 {"prefix-builtins", no_argument, NULL, 'P'},
239 {"pushdef", required_argument, NULL, 'p'},
240 {"quiet", no_argument, NULL, 'Q'},
241 {"regexp-syntax", optional_argument, NULL, 'r'},
242 {"reload-state", required_argument, NULL, 'R'},
243 {"silent", no_argument, NULL, 'Q'},
244 {"synclines", no_argument, NULL, 's'},
245 {"trace", required_argument, NULL, 't'},
246 {"traceon", required_argument, NULL, 't'},
247 {"traditional", no_argument, NULL, 'G'},
248 {"undefine", required_argument, NULL, 'U'},
249 {"warnings", no_argument, NULL, 'W'},
251 {"arglength", required_argument, NULL, ARGLENGTH_OPTION},
252 {"debugfile", optional_argument, NULL, DEBUGFILE_OPTION},
253 {"hashsize", required_argument, NULL, HASHSIZE_OPTION},
254 {"error-output", required_argument, NULL, ERROR_OUTPUT_OPTION},
255 {"import-environment", no_argument, NULL, IMPORT_ENVIRONMENT_OPTION},
256 {"popdef", required_argument, NULL, POPDEF_OPTION},
257 {"prepend-include", required_argument, NULL, PREPEND_INCLUDE_OPTION},
258 {"safer", no_argument, NULL, SAFER_OPTION},
259 {"syncoutput", optional_argument, NULL, SYNCOUTPUT_OPTION},
260 {"traceoff", required_argument, NULL, TRACEOFF_OPTION},
261 {"unload-module", required_argument, NULL, UNLOAD_MODULE_OPTION},
262 {"word-regexp", required_argument, NULL, WORD_REGEXP_OPTION},
264 {"help", no_argument, NULL, HELP_OPTION},
265 {"version", no_argument, NULL, VERSION_OPTION},
267 { NULL, 0, NULL, 0 },
270 /* POSIX requires only -D, -U, and -s; and says that the first two
271 must be recognized when interspersed with file names. Traditional
272 behavior also handles -s between files. Starting OPTSTRING with
273 '-' forces getopt_long to hand back file names as arguments to opt
274 '\1', rather than reordering the command line. */
275 #define OPTSTRING "-B:D:EF:GH:I:L:M:PQR:S:T:U:Wbcd::egil:m:o:p:r::st:"
277 /* For determining whether to be interactive. */
278 enum interactive_choice
280 INTERACTIVE_UNKNOWN, /* Still processing arguments, no -b or -i yet */
281 INTERACTIVE_YES, /* -i specified last */
282 INTERACTIVE_NO /* -b specified last */
285 /* Convert OPT to size_t, reporting an error using long option index
286 OI or short option character OPTCHAR if it does not fit. */
287 static size_t
288 size_opt (char const *opt, int oi, int optchar)
290 unsigned long int size;
291 strtol_error status = xstrtoul (opt, NULL, 10, &size, "kKmMgGtTPEZY0");
292 if (SIZE_MAX < size && status == LONGINT_OK)
293 status = LONGINT_OVERFLOW;
294 if (status != LONGINT_OK)
295 xstrtol_fatal (status, oi, optchar, long_options, opt);
296 return size;
299 /* Process a command line file NAME, and return true only if it was
300 stdin. */
301 static void
302 process_file (m4 *context, const char *name)
304 if (strcmp (name, "-") == 0)
305 /* TRANSLATORS: This is a short name for `standard input', used
306 when a command line file was given as `-'. */
307 m4_push_file (context, stdin, _("stdin"), false);
308 else
310 char *full_name;
311 FILE *fp = m4_path_search (context, name, &full_name);
312 if (fp == NULL)
314 m4_error (context, 0, errno, NULL, _("cannot open %s"),
315 quotearg_style (locale_quoting_style, name));
316 return;
318 m4_push_file (context, fp, full_name, true);
319 free (full_name);
321 m4_macro_expand_input (context);
325 /* Main entry point. Parse arguments, load modules, then parse input. */
327 main (int argc, char *const *argv, char *const *envp)
329 deferred *head = NULL; /* head of deferred argument list */
330 deferred *tail = NULL;
331 deferred *defn;
332 size_t size; /* for parsing numeric option arguments */
334 bool import_environment = false; /* true to import environment */
335 bool seen_file = false;
336 const char *debugfile = NULL;
337 const char *frozen_file_to_read = NULL;
338 const char *frozen_file_to_write = NULL;
339 enum interactive_choice interactive = INTERACTIVE_UNKNOWN;
341 m4 *context;
343 int exit_status;
345 /* Initialize gnulib error module. */
346 m4_set_program_name (argv[0]);
347 atexit (close_stdin);
349 setlocale (LC_ALL, "");
350 #ifdef ENABLE_NLS
351 textdomain (PACKAGE);
352 #endif
354 LTDL_SET_PRELOADED_SYMBOLS ();
356 context = m4_create ();
358 m4__module_init (context);
360 #ifdef USE_STACKOVF
361 setup_stackovf_trap (argv, envp, stackovf_handler);
362 #endif
364 if (getenv ("POSIXLY_CORRECT"))
366 m4_set_posixly_correct_opt (context, true);
367 m4_set_suppress_warnings_opt (context, true);
369 set_quoting_style (NULL, escape_quoting_style);
370 set_char_quoting (NULL, ':', 1);
372 /* First, we decode the arguments, to size up tables and stuff.
373 Avoid lasting side effects; for example 'm4 --debugfile=oops
374 --help' must not create the file `oops'. */
375 while (1)
377 int oi = -1;
378 int optchar = getopt_long (argc, (char **) argv, OPTSTRING,
379 long_options, &oi);
380 if (optchar == -1)
381 break;
383 switch (optchar)
385 default:
386 usage (EXIT_FAILURE);
388 case 'H':
389 case HASHSIZE_OPTION:
390 /* -H was supported in 1.4.x, but is a no-op now. FIXME -
391 remove support for -H after 2.0. */
392 error (0, 0, _("Warning: `%s' is deprecated"),
393 optchar == 'H' ? "-H" : "--hashsize");
394 break;
396 case 'S':
397 case 'T':
398 /* Compatibility junk: options that other implementations
399 support, but which we ignore as no-ops and don't list in
400 --help. */
401 error (0, 0, _("Warning: `-%c' is deprecated"),
402 optchar);
403 break;
405 case WORD_REGEXP_OPTION:
406 /* Supported in 1.4.x as -W, but no longer present. */
407 error (0, 0, _("Warning: `%s' is deprecated"), "--word-regexp");
408 break;
410 case 's':
411 optchar = SYNCOUTPUT_OPTION;
412 optarg = "1";
413 /* fall through */
414 case 'D':
415 case 'U':
416 case 'm':
417 case 'p':
418 case 'r':
419 case 't':
420 case POPDEF_OPTION:
421 case SYNCOUTPUT_OPTION:
422 case TRACEOFF_OPTION:
423 case UNLOAD_MODULE_OPTION:
424 defer:
425 /* Arguments that cannot be handled until later are accumulated. */
427 defn = (deferred *) xmalloc (sizeof *defn);
428 defn->code = optchar;
429 defn->value = optarg;
430 defn->next = NULL;
432 if (head == NULL)
433 head = defn;
434 else
435 tail->next = defn;
436 tail = defn;
437 break;
439 case '\1':
440 seen_file = true;
441 goto defer;
443 case 'B':
444 /* In 1.4.x, -B<num> was a no-op option for compatibility with
445 Solaris m4. Warn if optarg is all numeric. FIXME -
446 silence this warning after 2.0. */
447 if (isdigit (to_uchar (*optarg)))
449 char *end;
450 errno = 0;
451 strtol (optarg, &end, 10);
452 if (*end == '\0' && errno == 0)
453 error (0, 0, _("Warning: recommend using `-B ./%s' instead"),
454 optarg);
456 /* fall through */
457 case PREPEND_INCLUDE_OPTION:
458 m4_add_include_directory (context, optarg, true);
459 break;
461 case 'E':
462 m4_debug_decode (context, "-d", SIZE_MAX);
463 if (m4_get_fatal_warnings_opt (context))
464 m4_set_warnings_exit_opt (context, true);
465 else
466 m4_set_fatal_warnings_opt (context, true);
467 break;
469 case 'F':
470 frozen_file_to_write = optarg;
471 break;
473 case 'G':
474 m4_set_posixly_correct_opt (context, true);
475 break;
477 case 'I':
478 m4_add_include_directory (context, optarg, false);
479 break;
481 case 'L':
482 size = size_opt (optarg, oi, optchar);
483 if (!size)
484 size = SIZE_MAX;
485 m4_set_nesting_limit_opt (context, size);
486 break;
488 case 'M':
489 if (lt_dlinsertsearchdir (lt_dlgetsearchpath (), optarg) != 0)
491 const char *dlerr = lt_dlerror ();
492 if (dlerr == NULL)
493 m4_error (context, EXIT_FAILURE, 0, NULL,
494 _("failed to add search directory %s"),
495 quotearg_style (locale_quoting_style, optarg));
496 else
497 m4_error (context, EXIT_FAILURE, 0, NULL,
498 _("failed to add search directory %s: %s"),
499 quotearg_style (locale_quoting_style, optarg),
500 dlerr);
502 break;
504 case 'P':
505 m4_set_prefix_builtins_opt (context, true);
506 break;
508 case 'Q':
509 m4_set_suppress_warnings_opt (context, true);
510 break;
512 case 'R':
513 frozen_file_to_read = optarg;
514 break;
516 case 'W':
517 /* FIXME - should W take an optional argument, to allow -Wall,
518 -Wnone, -Werror, -Wcategory, -Wno-category? If so, then have
519 -W == -Wall. */
520 m4_set_suppress_warnings_opt (context, false);
521 break;
523 case 'b':
524 interactive = INTERACTIVE_NO;
525 break;
527 case 'c':
528 m4_set_discard_comments_opt (context, true);
529 break;
531 case 'd':
532 /* Staggered handling of 'd', since -dm is useful prior to
533 first file and prior to reloading, but other -d must also
534 have effect between files. */
535 if (seen_file || frozen_file_to_read)
536 goto defer;
537 if (m4_debug_decode (context, optarg, SIZE_MAX) < 0)
538 error (0, 0, _("bad debug flags: %s"),
539 quotearg_style (locale_quoting_style, optarg));
540 break;
542 case 'e':
543 error (0, 0, _("Warning: `%s' is deprecated, use `%s' instead"),
544 "-e", "-i");
545 /* fall through */
546 case 'i':
547 interactive = INTERACTIVE_YES;
548 break;
550 case 'g':
551 m4_set_posixly_correct_opt (context, false);
552 break;
554 case ARGLENGTH_OPTION:
555 error (0, 0, _("Warning: `%s' is deprecated, use `%s' instead"),
556 "--arglength", "--debuglen");
557 /* fall through */
558 case 'l':
559 size = size_opt (optarg, oi, optchar);
560 if (!size)
561 size = SIZE_MAX;
562 m4_set_max_debug_arg_length_opt (context, size);
563 break;
565 case DEBUGFILE_OPTION:
566 /* Staggered handling of '--debugfile', since it is useful
567 prior to first file and prior to reloading, but other
568 uses must also have effect between files. */
569 if (seen_file || frozen_file_to_read)
570 goto defer;
571 debugfile = optarg;
572 break;
574 case 'o':
575 case ERROR_OUTPUT_OPTION:
576 /* FIXME: -o is inconsistent with other tools' use of
577 -o/--output for creating an output file instead of using
578 stdout, and --error-output is misnamed since it does not
579 affect error messages to stderr. Change the meaning of -o
580 after 2.1. */
581 error (0, 0, _("Warning: `%s' is deprecated, use `%s' instead"),
582 optchar == 'o' ? "-o" : "--error-output", "--debugfile");
583 /* Don't call m4_debug_set_output here, as it has side effects. */
584 debugfile = optarg;
585 break;
587 case IMPORT_ENVIRONMENT_OPTION:
588 import_environment = true;
589 break;
591 case SAFER_OPTION:
592 m4_set_safer_opt (context, true);
593 break;
595 case VERSION_OPTION:
596 version_etc (stdout, PACKAGE, PACKAGE_NAME, VERSION, AUTHORS, NULL);
597 exit (EXIT_SUCCESS);
598 break;
600 case HELP_OPTION:
601 usage (EXIT_SUCCESS);
602 break;
606 /* Interactive if specified, or if no input files and stdin and
607 stderr are terminals, to match sh behavior. Interactive mode
608 means unbuffered output, and interrupts ignored. */
610 m4_set_interactive_opt (context, (interactive == INTERACTIVE_YES
611 || (interactive == INTERACTIVE_UNKNOWN
612 && optind == argc && !seen_file
613 && isatty (STDIN_FILENO)
614 && isatty (STDERR_FILENO))));
615 if (m4_get_interactive_opt (context))
617 signal (SIGINT, SIG_IGN);
618 setbuf (stdout, NULL);
620 else
621 signal (SIGPIPE, SIG_DFL);
624 /* Do the basic initializations. */
625 if (debugfile && !m4_debug_set_output (context, NULL, debugfile))
626 m4_error (context, 0, errno, NULL, _("cannot set debug file %s"),
627 quotearg_style (locale_quoting_style, debugfile));
628 m4_input_init (context);
629 m4_output_init (context);
630 m4_include_env_init (context);
632 if (frozen_file_to_read)
633 reload_frozen_state (context, frozen_file_to_read);
634 else
636 m4_module_load (context, "m4", NULL);
637 if (m4_get_posixly_correct_opt (context))
638 m4_module_load (context, "traditional", NULL);
639 else
640 m4_module_load (context, "gnu", NULL);
643 /* Import environment variables as macros. The definition are
644 prepended to the macro definition list, so -U can override
645 environment variables. */
647 if (import_environment)
649 char *const *env;
651 for (env = envp; *env != NULL; env++)
653 defn = (deferred *) xmalloc (sizeof *defn);
654 defn->code = 'D';
655 defn->value = *env;
656 defn->next = head;
657 head = defn;
661 /* Handle deferred command line macro definitions. Must come after
662 initialization of the symbol table. */
663 defn = head;
664 while (defn != NULL)
666 deferred *next;
667 const char *arg = defn->value;
669 switch (defn->code)
671 case 'D':
672 case 'p':
674 m4_symbol_value *value = m4_symbol_value_create ();
676 const char *str = strchr (arg, '=');
677 size_t len = str ? str - arg : strlen (arg);
679 m4_set_symbol_value_text (value, xstrdup (str ? str + 1 : ""),
680 str ? strlen (str + 1) : 0, 0);
682 if (defn->code == 'D')
683 m4_symbol_define (M4SYMTAB, arg, len, value);
684 else
685 m4_symbol_pushdef (M4SYMTAB, arg, len, value);
687 break;
689 case 'U':
690 m4_symbol_delete (M4SYMTAB, arg, strlen (arg));
691 break;
693 case 'd':
694 if (m4_debug_decode (context, arg, SIZE_MAX) < 0)
695 error (0, 0, _("bad debug flags: %s"),
696 quotearg_style (locale_quoting_style, arg));
697 break;
699 case 'm':
700 /* FIXME - should loading a module result in output? */
701 m4_module_load (context, arg, NULL);
702 break;
704 case 'r':
705 m4_set_regexp_syntax_opt (context, m4_regexp_syntax_encode (arg));
706 if (m4_get_regexp_syntax_opt (context) < 0)
707 m4_error (context, EXIT_FAILURE, 0, NULL,
708 _("bad syntax-spec: %s"),
709 quotearg_style (locale_quoting_style, arg));
710 break;
712 case 't':
713 m4_set_symbol_name_traced (M4SYMTAB, arg, strlen (arg), true);
714 break;
716 case '\1':
717 process_file (context, arg);
718 break;
720 case DEBUGFILE_OPTION:
721 if (!m4_debug_set_output (context, NULL, arg))
722 m4_error (context, 0, errno, NULL, _("cannot set debug file %s"),
723 quotearg_style (locale_quoting_style,
724 arg ? arg : _("stderr")));
725 break;
727 case POPDEF_OPTION:
729 size_t len = strlen (arg);
730 if (m4_symbol_lookup (M4SYMTAB, arg, len))
731 m4_symbol_popdef (M4SYMTAB, arg, len);
733 break;
735 case SYNCOUTPUT_OPTION:
737 bool previous = m4_get_syncoutput_opt (context);
738 m4_call_info info = {0};
739 info.name = "--syncoutput";
740 info.name_len = strlen (info.name);
741 m4_set_syncoutput_opt (context,
742 m4_parse_truth_arg (context, &info, arg,
743 SIZE_MAX, previous));
745 break;
747 case TRACEOFF_OPTION:
748 m4_set_symbol_name_traced (M4SYMTAB, arg, strlen (arg), false);
749 break;
751 case UNLOAD_MODULE_OPTION:
752 /* FIXME - should unloading a module result in output? */
753 m4_module_unload (context, arg, NULL);
754 break;
756 default:
757 assert (!"INTERNAL ERROR: bad code in deferred arguments");
758 abort ();
761 next = defn->next;
762 free (defn);
763 defn = next;
766 /* Handle remaining input files. Each file is pushed on the input,
767 and the input read. */
769 if (optind == argc && !seen_file)
770 process_file (context, "-");
771 else
772 for (; optind < argc; optind++)
773 process_file (context, argv[optind]);
775 /* Now handle wrapup text.
776 FIXME - when -F is in effect, should wrapped text be frozen? */
777 while (m4_pop_wrapup (context))
778 m4_macro_expand_input (context);
780 if (frozen_file_to_write)
781 produce_frozen_state (context, frozen_file_to_write);
782 else
784 m4_make_diversion (context, 0);
785 m4_undivert_all (context);
788 /* The remaining cleanup functions systematically free all of the
789 memory we still have pointers to. By definition, if there is
790 anything left when we're done: it was caused by a memory leak.
791 Strictly, we don't need to do this, but it makes leak detection
792 a whole lot easier! */
794 m4__module_exit (context);
795 m4_output_exit ();
796 m4_input_exit ();
798 /* Change debug stream back to stderr, to force flushing the debug
799 stream and detect any errors it might have encountered. The
800 three standard streams are closed by close_stdin. */
801 m4_debug_set_output (context, NULL, NULL);
803 exit_status = m4_get_exit_status (context);
804 m4_delete (context);
806 m4_hash_exit ();
807 quotearg_free ();
809 #ifdef USE_STACKOVF
810 stackovf_exit ();
811 #endif
813 exit (exit_status);