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