Annotation of src/usr.bin/m4/main.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: main.c,v 1.10 1995/09/29 00:27:51 cgd Exp $ */
2:
3: /*-
4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * Ozan Yigit at York University.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: #ifndef lint
40: static char copyright[] =
41: "@(#) Copyright (c) 1989, 1993\n\
42: The Regents of the University of California. All rights reserved.\n";
43: #endif /* not lint */
44:
45: #ifndef lint
46: #if 0
47: static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
48: #else
49: static char rcsid[] = "$NetBSD: main.c,v 1.10 1995/09/29 00:27:51 cgd Exp $";
50: #endif
51: #endif /* not lint */
52:
53: /*
54: * main.c
55: * Facility: m4 macro processor
56: * by: oz
57: */
58:
59: #include <sys/types.h>
60: #include <signal.h>
61: #include <errno.h>
62: #include <unistd.h>
63: #include <stdio.h>
64: #include <ctype.h>
65: #include <string.h>
66: #include "mdef.h"
67: #include "stdd.h"
68: #include "extern.h"
69: #include "pathnames.h"
70:
71: ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
72: char buf[BUFSIZE]; /* push-back buffer */
73: char *bufbase = buf; /* the base for current ilevel */
74: char *bbase[MAXINP]; /* the base for each ilevel */
75: char *bp = buf; /* first available character */
76: char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
77: stae mstack[STACKMAX+1]; /* stack of m4 machine */
78: char strspace[STRSPMAX+1]; /* string space for evaluation */
79: char *ep = strspace; /* first free char in strspace */
80: char *endest= strspace+STRSPMAX;/* end of string space */
81: int sp; /* current m4 stack pointer */
82: int fp; /* m4 call frame pointer */
83: FILE *infile[MAXINP]; /* input file stack (0=stdin) */
84: FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
85: FILE *active; /* active output file pointer */
86: char *m4temp; /* filename for diversions */
87: int ilevel = 0; /* input file stack pointer */
88: int oindex = 0; /* diversion index.. */
89: char *null = ""; /* as it says.. just a null.. */
90: char *m4wraps = ""; /* m4wrap string default.. */
91: char *progname; /* name of this program */
92: char lquote = LQUOTE; /* left quote character (`) */
93: char rquote = RQUOTE; /* right quote character (') */
94: char scommt = SCOMMT; /* start character for comment */
95: char ecommt = ECOMMT; /* end character for comment */
96:
97: struct keyblk keywrds[] = { /* m4 keywords to be installed */
98: "include", INCLTYPE,
99: "sinclude", SINCTYPE,
100: "define", DEFITYPE,
101: "defn", DEFNTYPE,
102: "divert", DIVRTYPE,
103: "expr", EXPRTYPE,
104: "eval", EXPRTYPE,
105: "substr", SUBSTYPE,
106: "ifelse", IFELTYPE,
107: "ifdef", IFDFTYPE,
108: "len", LENGTYPE,
109: "incr", INCRTYPE,
110: "decr", DECRTYPE,
111: "dnl", DNLNTYPE,
112: "changequote", CHNQTYPE,
113: "changecom", CHNCTYPE,
114: "index", INDXTYPE,
115: #ifdef EXTENDED
116: "paste", PASTTYPE,
117: "spaste", SPASTYPE,
118: #endif
119: "popdef", POPDTYPE,
120: "pushdef", PUSDTYPE,
121: "dumpdef", DUMPTYPE,
122: "shift", SHIFTYPE,
123: "translit", TRNLTYPE,
124: "undefine", UNDFTYPE,
125: "undivert", UNDVTYPE,
126: "divnum", DIVNTYPE,
127: "maketemp", MKTMTYPE,
128: "errprint", ERRPTYPE,
129: "m4wrap", M4WRTYPE,
130: "m4exit", EXITTYPE,
131: "syscmd", SYSCTYPE,
132: "sysval", SYSVTYPE,
133:
134: #if defined(unix) || defined(__NetBSD__)
135: "unix", MACRTYPE,
136: #else
137: #ifdef vms
138: "vms", MACRTYPE,
139: #endif
140: #endif
141: };
142:
143: #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
144:
145: extern int optind;
146: extern char *optarg;
147:
148: void macro();
149: void initkwds();
150: extern int getopt();
151:
152: int
153: main(argc,argv)
154: int argc;
155: char *argv[];
156: {
157: register int c;
158: register int n;
159: char *p;
160: register FILE *ifp;
161:
162: progname = basename(argv[0]);
163:
164: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
165: signal(SIGINT, onintr);
166:
167: initkwds();
168:
169: while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
170: switch(c) {
171:
172: case 'D': /* define something..*/
173: for (p = optarg; *p; p++)
174: if (*p == '=')
175: break;
176: if (*p)
177: *p++ = EOS;
178: dodefine(optarg, p);
179: break;
180: case 'U': /* undefine... */
181: remhash(optarg, TOP);
182: break;
183: case 'o': /* specific output */
184: case '?':
185: usage();
186: }
187:
188: argc -= optind;
189: argv += optind;
190:
191: active = stdout; /* default active output */
192: /* filename for diversions */
193: m4temp = mktemp(xstrdup(_PATH_DIVNAME));
194:
195: bbase[0] = bufbase;
196: if (!argc) {
197: sp = -1; /* stack pointer initialized */
198: fp = 0; /* frame pointer initialized */
199: infile[0] = stdin; /* default input (naturally) */
200: macro();
201: } else
202: for (; argc--; ++argv) {
203: p = *argv;
204: if (p[0] == '-' && p[1] == '\0')
205: ifp = stdin;
206: else if ((ifp = fopen(p, "r")) == NULL)
207: oops("%s: %s", p, strerror(errno));
208: sp = -1;
209: fp = 0;
210: infile[0] = ifp;
211: macro();
212: if (ifp != stdin)
213: (void)fclose(ifp);
214: }
215:
216: if (*m4wraps) { /* anything for rundown ?? */
217: ilevel = 0; /* in case m4wrap includes.. */
218: bufbase = bp = buf; /* use the entire buffer */
219: putback(EOF); /* eof is a must !! */
220: pbstr(m4wraps); /* user-defined wrapup act */
221: macro(); /* last will and testament */
222: }
223:
224: if (active != stdout)
225: active = stdout; /* reset output just in case */
226: for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */
227: if (outfile[n] != NULL)
228: getdiv(n);
229: /* remove bitbucket if used */
230: if (outfile[0] != NULL) {
231: (void) fclose(outfile[0]);
232: m4temp[UNIQUE] = '0';
233: #ifdef vms
234: (void) remove(m4temp);
235: #else
236: (void) unlink(m4temp);
237: #endif
238: }
239:
240: return 0;
241: }
242:
243: ndptr inspect();
244:
245: /*
246: * macro - the work horse..
247: */
248: void
249: macro() {
250: char token[MAXTOK];
251: register char *s;
252: register int t, l;
253: register ndptr p;
254: register int nlpar;
255:
256: cycle {
257: if ((t = gpbc()) == '_' || isalpha(t)) {
258: putback(t);
259: if ((p = inspect(s = token)) == nil) {
260: if (sp < 0)
261: while (*s)
262: putc(*s++, active);
263: else
264: while (*s)
265: chrsave(*s++);
266: }
267: else {
268: /*
269: * real thing.. First build a call frame:
270: */
271: pushf(fp); /* previous call frm */
272: pushf(p->type); /* type of the call */
273: pushf(0); /* parenthesis level */
274: fp = sp; /* new frame pointer */
275: /*
276: * now push the string arguments:
277: */
278: pushs(p->defn); /* defn string */
279: pushs(p->name); /* macro name */
280: pushs(ep); /* start next..*/
281:
282: putback(l = gpbc());
283: if (l != LPAREN) { /* add bracks */
284: putback(RPAREN);
285: putback(LPAREN);
286: }
287: }
288: }
289: else if (t == EOF) {
290: if (sp > -1)
291: oops("unexpected end of input", "");
292: if (ilevel <= 0)
293: break; /* all done thanks.. */
294: --ilevel;
295: (void) fclose(infile[ilevel+1]);
296: bufbase = bbase[ilevel];
297: continue;
298: }
299: /*
300: * non-alpha single-char token seen..
301: * [the order of else if .. stmts is important.]
302: */
303: else if (t == lquote) { /* strip quotes */
304: nlpar = 1;
305: do {
306: if ((l = gpbc()) == rquote)
307: nlpar--;
308: else if (l == lquote)
309: nlpar++;
310: else if (l == EOF)
311: oops("missing right quote", "");
312: if (nlpar > 0) {
313: if (sp < 0)
314: putc(l, active);
315: else
316: chrsave(l);
317: }
318: }
319: while (nlpar != 0);
320: }
321:
322: else if (sp < 0) { /* not in a macro at all */
323: if (t == scommt) { /* comment handling here */
324: putc(t, active);
325: while ((t = gpbc()) != ecommt)
326: putc(t, active);
327: }
328: putc(t, active); /* output directly.. */
329: }
330:
331: else switch(t) {
332:
333: case LPAREN:
334: if (PARLEV > 0)
335: chrsave(t);
336: while (isspace(l = gpbc()))
337: ; /* skip blank, tab, nl.. */
338: putback(l);
339: PARLEV++;
340: break;
341:
342: case RPAREN:
343: if (--PARLEV > 0)
344: chrsave(t);
345: else { /* end of argument list */
346: chrsave(EOS);
347:
348: if (sp == STACKMAX)
349: oops("internal stack overflow", "");
350:
351: if (CALTYP == MACRTYPE)
352: expand((char **) mstack+fp+1, sp-fp);
353: else
354: eval((char **) mstack+fp+1, sp-fp, CALTYP);
355:
356: ep = PREVEP; /* flush strspace */
357: sp = PREVSP; /* previous sp.. */
358: fp = PREVFP; /* rewind stack...*/
359: }
360: break;
361:
362: case COMMA:
363: if (PARLEV == 1) {
364: chrsave(EOS); /* new argument */
365: while (isspace(l = gpbc()))
366: ;
367: putback(l);
368: pushs(ep);
369: } else
370: chrsave(t);
371: break;
372:
373: default:
374: chrsave(t); /* stack the char */
375: break;
376: }
377: }
378: }
379:
380: /*
381: * build an input token..
382: * consider only those starting with _ or A-Za-z. This is a
383: * combo with lookup to speed things up.
384: */
385: ndptr
386: inspect(tp)
387: register char *tp;
388: {
389: register char c;
390: register char *name = tp;
391: register char *etp = tp+MAXTOK;
392: register ndptr p;
393: register unsigned long h = 0;
394:
395: while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
396: h = (h << 5) + h + (*tp++ = c);
397: putback(c);
398: if (tp == etp)
399: oops("token too long", "");
400:
401: *tp = EOS;
402:
403: for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
404: if (STREQ(name, p->name))
405: break;
406: return p;
407: }
408:
409: /*
410: * initkwds - initialise m4 keywords as fast as possible.
411: * This very similar to install, but without certain overheads,
412: * such as calling lookup. Malloc is not used for storing the
413: * keyword strings, since we simply use the static pointers
414: * within keywrds block.
415: */
416: void
417: initkwds() {
418: register int i;
419: register int h;
420: register ndptr p;
421:
422: for (i = 0; i < MAXKEYS; i++) {
423: h = hash(keywrds[i].knam);
424: p = (ndptr) xalloc(sizeof(struct ndblock));
425: p->nxtptr = hashtab[h];
426: hashtab[h] = p;
427: p->name = keywrds[i].knam;
428: p->defn = null;
429: p->type = keywrds[i].ktyp | STATIC;
430: }
431: }