main.c revision 1.47 1 /* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */
2 /* $NetBSD: main.c,v 1.47 2019/03/26 15:00:34 christos Exp $ */
3
4 /*-
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 /*
37 * main.c
38 * Facility: m4 macro processor
39 * by: oz
40 */
41 #if HAVE_NBTOOL_CONFIG_H
42 #include "nbtool_config.h"
43 #endif
44 #include <sys/cdefs.h>
45 __RCSID("$NetBSD: main.c,v 1.47 2019/03/26 15:00:34 christos Exp $");
46 #include <assert.h>
47 #include <signal.h>
48 #include <getopt.h>
49 #include <err.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <string.h>
55 #include <stddef.h>
56 #include <stdint.h>
57 #include <stdlib.h>
58 #include <ohash.h>
59 #include "mdef.h"
60 #include "stdd.h"
61 #include "extern.h"
62 #include "pathnames.h"
63
64 ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
65 stae *mstack; /* stack of m4 machine */
66 char *sstack; /* shadow stack, for string space extension */
67 static size_t STACKMAX; /* current maximum size of stack */
68 int sp; /* current m4 stack pointer */
69 int fp; /* m4 call frame pointer */
70 struct input_file infile[MAXINP];/* input file stack (0=stdin) */
71 FILE **outfile; /* diversion array(0=bitbucket)*/
72 int maxout;
73 FILE *active; /* active output file pointer */
74 int ilevel = 0; /* input file stack pointer */
75 int oindex = 0; /* diversion index.. */
76 const char *null = ""; /* as it says.. just a null.. */
77 char **m4wraps = NULL; /* m4wraps array. */
78 int maxwraps = 0; /* size of m4wraps array */
79 int wrapindex = 0; /* current offset in m4wraps */
80 char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
81 char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
82 char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
83 char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
84 int synch_lines = 0; /* line synchronisation for C preprocessor */
85 int prefix_builtins = 0; /* -P option to prefix builtin keywords */
86 int fatal_warnings = 0; /* -E option to exit on warnings */
87 int quiet = 0; /* -Q option to silence warnings */
88 int nesting_limit = -1; /* -L for nesting limit */
89 const char *freeze = NULL; /* -F to freeze state */
90 const char *reload = NULL; /* -R to reload state */
91 #ifndef REAL_FREEZE
92 FILE *freezef = NULL;
93 int thawing = 0;
94 #endif
95
96 struct keyblk {
97 const char *knam; /* keyword name */
98 int ktyp; /* keyword type */
99 };
100
101 struct keyblk keywrds[] = { /* m4 keywords to be installed */
102 { "include", INCLTYPE },
103 { "sinclude", SINCTYPE },
104 { "define", DEFITYPE },
105 { "defn", DEFNTYPE },
106 { "divert", DIVRTYPE | NOARGS },
107 { "expr", EXPRTYPE },
108 { "eval", EXPRTYPE },
109 { "substr", SUBSTYPE },
110 { "ifelse", IFELTYPE },
111 { "ifdef", IFDFTYPE },
112 { "len", LENGTYPE },
113 { "incr", INCRTYPE },
114 { "decr", DECRTYPE },
115 { "dnl", DNLNTYPE | NOARGS },
116 { "changequote", CHNQTYPE | NOARGS },
117 { "changecom", CHNCTYPE | NOARGS },
118 { "index", INDXTYPE },
119 #ifdef EXTENDED
120 { "paste", PASTTYPE },
121 { "spaste", SPASTYPE },
122 /* Newer extensions, needed to handle gnu-m4 scripts */
123 { "indir", INDIRTYPE},
124 { "builtin", BUILTINTYPE},
125 { "patsubst", PATSTYPE},
126 { "regexp", REGEXPTYPE},
127 { "esyscmd", ESYSCMDTYPE},
128 { "__file__", FILENAMETYPE | NOARGS},
129 { "__line__", LINETYPE | NOARGS},
130 #endif
131 { "popdef", POPDTYPE },
132 { "pushdef", PUSDTYPE },
133 { "dumpdef", DUMPTYPE | NOARGS },
134 { "shift", SHIFTYPE | NOARGS },
135 { "translit", TRNLTYPE },
136 { "undefine", UNDFTYPE },
137 { "undivert", UNDVTYPE | NOARGS },
138 { "divnum", DIVNTYPE | NOARGS },
139 { "maketemp", MKTMTYPE },
140 { "errprint", ERRPTYPE | NOARGS },
141 { "m4wrap", M4WRTYPE | NOARGS },
142 { "m4exit", EXITTYPE | NOARGS },
143 { "syscmd", SYSCTYPE },
144 { "sysval", SYSVTYPE | NOARGS },
145 { "traceon", TRACEONTYPE | NOARGS },
146 { "traceoff", TRACEOFFTYPE | NOARGS },
147
148 #if defined(unix) || defined(__unix__)
149 { "unix", SELFTYPE | NOARGS },
150 #else
151 #ifdef vms
152 { "vms", SELFTYPE | NOARGS },
153 #endif
154 #endif
155 };
156
157 #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
158
159 #define MAXRECORD 50
160 static struct position {
161 char *name;
162 unsigned long line;
163 } quotes[MAXRECORD], paren[MAXRECORD];
164
165 static void record(struct position *, int);
166 static void dump_stack(struct position *, int);
167
168 static void macro(void);
169 static void initkwds(void);
170 static ndptr inspect(int, char *);
171 static int do_look_ahead(int, const char *);
172 static void reallyoutputstr(const char *);
173 static void reallyputchar(int);
174
175 static void enlarge_stack(void);
176 static void help(void);
177
178 static void
179 usage(FILE *f)
180 {
181 fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] "
182 "[-I dirname] [-o filename] [-L limit]\n"
183 "\t[-t macro] [-Uname] [file ...]\n", getprogname());
184 }
185
186 __dead static void
187 onintr(int signo)
188 {
189 char intrmessage[] = "m4: interrupted.\n";
190 write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
191 _exit(1);
192 }
193
194 #define OPT_HELP 1
195
196 struct option longopts[] = {
197 { "debug", optional_argument, 0, 'd' },
198 { "define", required_argument, 0, 'D' },
199 { "error-output", required_argument, 0, 'e' },
200 { "fatal-warnings", no_argument, 0, 'E' },
201 { "freeze-state", required_argument, 0, 'F' },
202 { "gnu", no_argument, 0, 'g' },
203 { "help", no_argument, 0, OPT_HELP },
204 { "include", required_argument, 0, 'I' },
205 { "interactive", no_argument, 0, 'i' },
206 { "nesting-limit", required_argument, 0, 'L' },
207 { "prefix-builtins", no_argument, 0, 'P' },
208 { "quiet", no_argument, 0, 'Q' },
209 { "reload-state", required_argument, 0, 'R' },
210 { "silent", no_argument, 0, 'Q' },
211 { "synclines", no_argument, 0, 's' },
212 { "trace", required_argument, 0, 't' },
213 { "traditional", no_argument, 0, 'G' },
214 { "undefine", required_argument, 0, 'U' },
215 { "version", no_argument, 0, 'v' },
216 #ifdef notyet
217 { "arglength", required_argument, 0, 'l' },
218 { "debugfile", optional_argument, 0, OPT_DEBUGFILE },
219 { "hashsize", required_argument, 0, 'H' },
220 { "warn-macro-sequence",optional_argument, 0, OPT_WARN_SEQUENCE },
221 #endif
222 { 0, 0, 0, 0 },
223 };
224
225 int
226 main(int argc, char *argv[])
227 {
228 int c;
229 int n;
230 char *p;
231 FILE *sfp;
232
233 setprogname(argv[0]);
234
235 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
236 signal(SIGINT, onintr);
237
238 init_macros();
239 initspaces();
240 STACKMAX = INITSTACKMAX;
241
242 mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL);
243 sstack = (char *)xalloc(STACKMAX, NULL);
244
245 maxout = 0;
246 outfile = NULL;
247 resizedivs(MAXOUT);
248
249 while ((c = getopt_long(argc, argv, "D:d:e:EF:GgI:iL:o:PR:Qst:U:v",
250 longopts, NULL)) != -1)
251 switch(c) {
252 case 'D': /* define something..*/
253 for (p = optarg; *p; p++)
254 if (*p == '=')
255 break;
256 if (*p)
257 *p++ = EOS;
258 dodefine(optarg, p);
259 break;
260 case 'd':
261 set_trace_flags(optarg);
262 break;
263 case 'E':
264 fatal_warnings++;
265 break;
266 case 'e':
267 /*
268 * Don't use freopen here because if it fails
269 * we lose stderr, instead trash it.
270 */
271 if ((sfp = fopen(optarg, "w+")) == NULL) {
272 warn("Can't redirect errors to `%s'", optarg);
273 break;
274 }
275 fclose(stderr);
276 memcpy(stderr, sfp, sizeof(*sfp));
277 break;
278 case 'F':
279 freeze = optarg;
280 #ifndef REAL_FREEZE
281 if ((freezef = fopen(freeze, "w")) == NULL)
282 err(EXIT_FAILURE, "Can't open `%s'", freeze);
283 #endif
284 break;
285 case 'I':
286 addtoincludepath(optarg);
287 break;
288 case 'i':
289 setvbuf(stdout, NULL, _IONBF, 0);
290 signal(SIGINT, SIG_IGN);
291 break;
292 case 'G':
293 mimic_gnu = 0;
294 break;
295 case 'g':
296 mimic_gnu = 1;
297 break;
298 case 'L':
299 nesting_limit = atoi(optarg);
300 break;
301 case 'o':
302 trace_file(optarg);
303 break;
304 case 'P':
305 prefix_builtins = 1;
306 break;
307 case 'Q':
308 quiet++;
309 break;
310 case 'R':
311 reload = optarg;
312 break;
313 case 's':
314 synch_lines = 1;
315 break;
316 case 't':
317 mark_traced(optarg, 1);
318 break;
319 case 'U': /* undefine... */
320 macro_popdef(optarg);
321 break;
322 case 'v':
323 fprintf(stderr, "%s version %d\n", getprogname(),
324 VERSION);
325 return EXIT_SUCCESS;
326 case OPT_HELP:
327 help();
328 return EXIT_SUCCESS;
329 case '?':
330 default:
331 usage(stderr);
332 return EXIT_FAILURE;
333 }
334
335 #ifdef REDIRECT
336 /*
337 * This is meant only for debugging; it makes all output
338 * go to a known file, even if the command line options
339 * send it elsewhere. It should not be turned of in production code.
340 */
341 if (freopen("/tmp/m4", "w+", stderr) == NULL)
342 err(EXIT_FAILURE, "Can't redirect errors to `%s'",
343 "/tmp/m4");
344 #endif
345 argc -= optind;
346 argv += optind;
347
348
349 initkwds();
350 if (mimic_gnu)
351 setup_builtin("format", FORMATTYPE);
352
353 active = stdout; /* default active output */
354 bbase[0] = bufbase;
355
356 if (reload) {
357 #ifdef REAL_FREEZE
358 thaw_state(reload);
359 #else
360 if (fopen_trypath(infile, reload) == NULL)
361 err(1, "Can't open `%s'", reload);
362 sp = -1;
363 fp = 0;
364 thawing = 1;
365 macro();
366 thawing = 0;
367 release_input(infile);
368 #endif
369 }
370
371 if (!argc) {
372 sp = -1; /* stack pointer initialized */
373 fp = 0; /* frame pointer initialized */
374 set_input(infile+0, stdin, "stdin");
375 /* default input (naturally) */
376 macro();
377 } else
378 for (; argc--; ++argv) {
379 p = *argv;
380 if (p[0] == '-' && p[1] == EOS)
381 set_input(infile, stdin, "stdin");
382 else if (fopen_trypath(infile, p) == NULL)
383 err(1, "%s", p);
384 sp = -1;
385 fp = 0;
386 macro();
387 release_input(infile);
388 }
389
390 if (wrapindex) {
391 int i;
392
393 ilevel = 0; /* in case m4wrap includes.. */
394 bufbase = bp = buf; /* use the entire buffer */
395 if (mimic_gnu) {
396 while (wrapindex != 0) {
397 for (i = 0; i < wrapindex; i++)
398 pbstr(m4wraps[i]);
399 wrapindex =0;
400 macro();
401 }
402 } else {
403 for (i = 0; i < wrapindex; i++) {
404 pbstr(m4wraps[i]);
405 macro();
406 }
407 }
408 }
409
410 if (active != stdout)
411 active = stdout; /* reset output just in case */
412 for (n = 1; n < maxout; n++) /* default wrap-up: undivert */
413 if (outfile[n] != NULL)
414 getdiv(n);
415 /* remove bitbucket if used */
416 if (outfile[0] != NULL) {
417 (void) fclose(outfile[0]);
418 }
419
420 #ifdef REAL_FREEZE
421 if (freeze)
422 freeze_state(freeze);
423 #else
424 if (freezef)
425 fclose(freezef);
426 #endif
427
428 return 0;
429 }
430
431 /*
432 * Look ahead for `token'.
433 * (on input `t == token[0]')
434 * Used for comment and quoting delimiters.
435 * Returns 1 if `token' present; copied to output.
436 * 0 if `token' not found; all characters pushed back
437 */
438 static int
439 do_look_ahead(int t, const char *token)
440 {
441 int i;
442
443 assert((unsigned char)t == (unsigned char)token[0]);
444
445 for (i = 1; *++token; i++) {
446 t = gpbc();
447 if (t == EOF || (unsigned char)t != (unsigned char)*token) {
448 pushback(t);
449 while (--i)
450 pushback(*--token);
451 return 0;
452 }
453 }
454 return 1;
455 }
456
457 #define LOOK_AHEAD(t, token) (t != EOF && \
458 (unsigned char)(t)==(unsigned char)(token)[0] && \
459 do_look_ahead(t,token))
460
461 /*
462 * macro - the work horse..
463 */
464 static void
465 macro(void)
466 {
467 char token[MAXTOK+1];
468 int t, l;
469 ndptr p;
470 int nlpar;
471
472 cycle {
473 t = gpbc();
474
475 if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
476 nlpar = 0;
477 record(quotes, nlpar++);
478 /*
479 * Opening quote: scan forward until matching
480 * closing quote has been found.
481 */
482 do {
483
484 l = gpbc();
485 if (LOOK_AHEAD(l,rquote)) {
486 if (--nlpar > 0)
487 outputstr(rquote);
488 } else if (LOOK_AHEAD(l,lquote)) {
489 record(quotes, nlpar++);
490 outputstr(lquote);
491 } else if (l == EOF) {
492 if (!quiet) {
493 if (nlpar == 1)
494 warnx("unclosed quote:");
495 else
496 warnx(
497 "%d unclosed quotes:",
498 nlpar);
499 dump_stack(quotes, nlpar);
500 }
501 exit(EXIT_FAILURE);
502 } else {
503 if (nlpar > 0) {
504 if (sp < 0)
505 reallyputchar(l);
506 else
507 CHRSAVE(l);
508 }
509 }
510 }
511 while (nlpar != 0);
512 } else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
513 reallyoutputstr(scommt);
514
515 for(;;) {
516 t = gpbc();
517 if (LOOK_AHEAD(t, ecommt)) {
518 reallyoutputstr(ecommt);
519 break;
520 }
521 if (t == EOF)
522 break;
523 reallyputchar(t);
524 }
525 } else if (t == '_' || isalpha(t)) {
526 p = inspect(t, token);
527 if (p != NULL)
528 pushback(l = gpbc());
529 if (p == NULL || (l != LPAREN &&
530 (macro_getdef(p)->type & NEEDARGS) != 0))
531 outputstr(token);
532 else {
533 /*
534 * real thing.. First build a call frame:
535 */
536 pushf(fp); /* previous call frm */
537 pushf(macro_getdef(p)->type); /* type of the call */
538 pushf(is_traced(p));
539 pushf(0); /* parenthesis level */
540 fp = sp; /* new frame pointer */
541 /*
542 * now push the string arguments:
543 */
544 pushs1(macro_getdef(p)->defn); /* defn string */
545 pushs1((char *)macro_name(p)); /* macro name */
546 pushs(ep); /* start next..*/
547
548 if (l != LPAREN && PARLEV == 0) {
549 /* no bracks */
550 chrsave(EOS);
551
552 if ((size_t)sp == STACKMAX)
553 errx(1, "internal stack overflow");
554 eval((const char **) mstack+fp+1, 2,
555 CALTYP, TRACESTATUS);
556
557 ep = PREVEP; /* flush strspace */
558 sp = PREVSP; /* previous sp.. */
559 fp = PREVFP; /* rewind stack...*/
560 }
561 }
562 } else if (t == EOF) {
563 if (sp > -1 && ilevel <= 0) {
564 if (!quiet) {
565 warnx("unexpected end of input, "
566 "unclosed parenthesis:");
567 dump_stack(paren, PARLEV);
568 }
569 exit(EXIT_FAILURE);
570 }
571 if (ilevel <= 0)
572 break; /* all done thanks.. */
573 release_input(infile+ilevel--);
574 emit_synchline();
575 bufbase = bbase[ilevel];
576 continue;
577 } else if (sp < 0) { /* not in a macro at all */
578 reallyputchar(t); /* output directly.. */
579 }
580
581 else switch(t) {
582
583 case LPAREN:
584 if (PARLEV > 0)
585 chrsave(t);
586 while (isspace(l = gpbc())) /* skip blank, tab, nl.. */
587 if (PARLEV > 0)
588 chrsave(l);
589 pushback(l);
590 record(paren, PARLEV++);
591 break;
592
593 case RPAREN:
594 if (--PARLEV > 0)
595 chrsave(t);
596 else { /* end of argument list */
597 chrsave(EOS);
598
599 if ((size_t)sp == STACKMAX)
600 errx(1, "internal stack overflow");
601
602 eval((const char **) mstack+fp+1, sp-fp,
603 CALTYP, TRACESTATUS);
604
605 ep = PREVEP; /* flush strspace */
606 sp = PREVSP; /* previous sp.. */
607 fp = PREVFP; /* rewind stack...*/
608 }
609 break;
610
611 case COMMA:
612 if (PARLEV == 1) {
613 chrsave(EOS); /* new argument */
614 while (isspace(l = gpbc()))
615 ;
616 pushback(l);
617 pushs(ep);
618 } else
619 chrsave(t);
620 break;
621
622 default:
623 if (LOOK_AHEAD(t, scommt)) {
624 char *q;
625 for (q = scommt; *q; q++)
626 chrsave(*q);
627 for(;;) {
628 t = gpbc();
629 if (LOOK_AHEAD(t, ecommt)) {
630 for (q = ecommt; *q; q++)
631 chrsave(*q);
632 break;
633 }
634 if (t == EOF)
635 break;
636 CHRSAVE(t);
637 }
638 } else
639 CHRSAVE(t); /* stack the char */
640 break;
641 }
642 }
643 }
644
645 /*
646 * output string directly, without pushing it for reparses.
647 */
648 void
649 outputstr(const char *s)
650 {
651 if (sp < 0)
652 reallyoutputstr(s);
653 else
654 while (*s)
655 CHRSAVE(*s++);
656 }
657
658 void
659 reallyoutputstr(const char *s)
660 {
661 if (synch_lines) {
662 while (*s) {
663 fputc(*s, active);
664 if (*s++ == '\n') {
665 infile[ilevel].synch_lineno++;
666 if (infile[ilevel].synch_lineno !=
667 infile[ilevel].lineno)
668 do_emit_synchline();
669 }
670 }
671 } else
672 fputs(s, active);
673 }
674
675 void
676 reallyputchar(int c)
677 {
678 putc(c, active);
679 if (synch_lines && c == '\n') {
680 infile[ilevel].synch_lineno++;
681 if (infile[ilevel].synch_lineno != infile[ilevel].lineno)
682 do_emit_synchline();
683 }
684 }
685
686 /*
687 * build an input token..
688 * consider only those starting with _ or A-Za-z.
689 */
690 static ndptr
691 inspect(int c, char *tp)
692 {
693 char *name = tp;
694 char *etp = tp+MAXTOK;
695 ndptr p;
696
697 *tp++ = c;
698
699 while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
700 *tp++ = c;
701 if (c != EOF)
702 PUSHBACK(c);
703 *tp = EOS;
704 /* token is too long, it won't match anything, but it can still
705 * be output. */
706 if (tp == ep) {
707 outputstr(name);
708 while (isalnum(c = gpbc()) || c == '_') {
709 if (sp < 0)
710 reallyputchar(c);
711 else
712 CHRSAVE(c);
713 }
714 *name = EOS;
715 return NULL;
716 }
717
718 p = ohash_find(¯os, ohash_qlookupi(¯os, name, (void *)&tp));
719 if (p == NULL)
720 return NULL;
721 if (macro_getdef(p) == NULL)
722 return NULL;
723 return p;
724 }
725
726 /*
727 * initkwds - initialise m4 keywords as fast as possible.
728 * This very similar to install, but without certain overheads,
729 * such as calling lookup. Malloc is not used for storing the
730 * keyword strings, since we simply use the static pointers
731 * within keywrds block.
732 */
733 static void
734 initkwds(void)
735 {
736 unsigned int type;
737 size_t i;
738
739 for (i = 0; i < MAXKEYS; i++) {
740 type = keywrds[i].ktyp;
741 if ((keywrds[i].ktyp & NOARGS) == 0)
742 type |= NEEDARGS;
743 setup_builtin(keywrds[i].knam, type);
744 }
745 }
746
747 static void
748 record(struct position *t, int lev)
749 {
750 if (lev < MAXRECORD) {
751 t[lev].name = CURRENT_NAME;
752 t[lev].line = CURRENT_LINE;
753 }
754 }
755
756 static void
757 dump_stack(struct position *t, int lev)
758 {
759 int i;
760
761 for (i = 0; i < lev; i++) {
762 if (i == MAXRECORD) {
763 fprintf(stderr, " ...\n");
764 break;
765 }
766 fprintf(stderr, " %s at line %lu\n",
767 t[i].name, t[i].line);
768 }
769 }
770
771
772 static void
773 enlarge_stack(void)
774 {
775 STACKMAX += STACKMAX/2;
776 mstack = xrealloc(mstack, sizeof(stae) * STACKMAX,
777 "Evaluation stack overflow (%lu)",
778 (unsigned long)STACKMAX);
779 sstack = xrealloc(sstack, STACKMAX,
780 "Evaluation stack overflow (%lu)",
781 (unsigned long)STACKMAX);
782 }
783
784 static const struct {
785 const char *n;
786 const char *d;
787 } nd [] = {
788 { "-d, --debug[=flags]", "set debug flags" },
789 { "-D, --define=name[=value]", "define macro" },
790 { "-e, --error-output=file", "send error output to file" },
791 { "-E, --fatal-warnings", "exit on warnings" },
792 { "-F, --freeze-state=file", "save state to file" },
793 { "-g, --gnu", "enable gnu extensions" },
794 { " --help", "print this message and exit" },
795 { "-I, --include=file", "include file" },
796 { "-i, --interactive", "unbuffer output, ignore tty signals" },
797 { "-L, --nesting-limit=num", "macro expansion nesting limit (unimpl)" },
798 { "-P, --prefix-builtins", "prefix builtins with m4_" },
799 { "-Q, --quiet", "don't print warnings" },
800 { "-R, --reload-state=file", "restore state from file" },
801 { "-Q, --silent", "don't print warnings" },
802 { "-s, --synclines", "output line directives for cpp(1)" },
803 { "-t, --trace=macro", "trace the named macro" },
804 { "-G, --traditional", "disable gnu extensions" },
805 { "-U, --undefine=name", "undefine the named macro" },
806 { "-v, --version", "print the version number and exit" },
807 };
808
809 static void
810 help(void)
811 {
812 size_t i;
813 fprintf(stdout, "%s version %d\n\n", getprogname(), VERSION);
814 usage(stdout);
815
816 fprintf(stdout, "\nThe long options are:\n");
817 for (i = 0; i < __arraycount(nd); i++)
818 fprintf(stdout, "\t%-25.25s\t%s\n", nd[i].n, nd[i].d);
819 }
820