Commit | Line | Data |
---|---|---|
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 |
12 | static 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 | 18 | static 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 |
39 | ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ |
40 | char buf[BUFSIZE]; /* push-back buffer */ | |
1fbb93e0 EA |
41 | char *bufbase = buf; /* the base for current ilevel */ |
42 | char *bbase[MAXINP]; /* the base for each ilevel */ | |
138ca30e KB |
43 | char *bp = buf; /* first available character */ |
44 | char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ | |
45 | stae mstack[STACKMAX+1]; /* stack of m4 machine */ | |
46 | char strspace[STRSPMAX+1]; /* string space for evaluation */ | |
47 | char *ep = strspace; /* first free char in strspace */ | |
48 | char *endest= strspace+STRSPMAX;/* end of string space */ | |
49 | int sp; /* current m4 stack pointer */ | |
50 | int fp; /* m4 call frame pointer */ | |
51 | FILE *infile[MAXINP]; /* input file stack (0=stdin) */ | |
52 | FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ | |
53 | FILE *active; /* active output file pointer */ | |
54 | char *m4temp; /* filename for diversions */ | |
55 | int ilevel = 0; /* input file stack pointer */ | |
56 | int oindex = 0; /* diversion index.. */ | |
57 | char *null = ""; /* as it says.. just a null.. */ | |
58 | char *m4wraps = ""; /* m4wrap string default.. */ | |
ba487a99 | 59 | char *progname; /* name of this program */ |
138ca30e KB |
60 | char lquote = LQUOTE; /* left quote character (`) */ |
61 | char rquote = RQUOTE; /* right quote character (') */ | |
62 | char scommt = SCOMMT; /* start character for comment */ | |
63 | char ecommt = ECOMMT; /* end character for comment */ | |
ba487a99 | 64 | |
138ca30e KB |
65 | struct 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 |
113 | extern int optind; |
114 | extern char *optarg; | |
115 | ||
ba487a99 KB |
116 | void macro(); |
117 | void initkwds(); | |
118 | extern int getopt(); | |
119 | ||
120 | int | |
138ca30e | 121 | main(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 | 211 | ndptr inspect(); |
138ca30e KB |
212 | |
213 | /* | |
214 | * macro - the work horse.. | |
138ca30e | 215 | */ |
ba487a99 | 216 | void |
138ca30e KB |
217 | macro() { |
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 | */ | |
353 | ndptr | |
354 | inspect(tp) | |
355 | register 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 | 384 | void |
138ca30e KB |
385 | initkwds() { |
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 | } |