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