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