Commit | Line | Data |
---|---|---|
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 | |
a93b814a | 6 | * Ozan Yigit at York University. |
138ca30e | 7 | * |
6ecf3d85 | 8 | * %sccs.include.redist.c% |
138ca30e KB |
9 | */ |
10 | ||
11 | #ifndef lint | |
a93b814a | 12 | static char sccsid[] = "@(#)main.c 5.9 (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 |
33 | ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ |
34 | char buf[BUFSIZE]; /* push-back buffer */ | |
1fbb93e0 EA |
35 | char *bufbase = buf; /* the base for current ilevel */ |
36 | char *bbase[MAXINP]; /* the base for each ilevel */ | |
138ca30e KB |
37 | char *bp = buf; /* first available character */ |
38 | char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ | |
39 | stae mstack[STACKMAX+1]; /* stack of m4 machine */ | |
40 | char strspace[STRSPMAX+1]; /* string space for evaluation */ | |
41 | char *ep = strspace; /* first free char in strspace */ | |
42 | char *endest= strspace+STRSPMAX;/* end of string space */ | |
43 | int sp; /* current m4 stack pointer */ | |
44 | int fp; /* m4 call frame pointer */ | |
45 | FILE *infile[MAXINP]; /* input file stack (0=stdin) */ | |
46 | FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ | |
47 | FILE *active; /* active output file pointer */ | |
48 | char *m4temp; /* filename for diversions */ | |
49 | int ilevel = 0; /* input file stack pointer */ | |
50 | int oindex = 0; /* diversion index.. */ | |
51 | char *null = ""; /* as it says.. just a null.. */ | |
52 | char *m4wraps = ""; /* m4wrap string default.. */ | |
ba487a99 | 53 | char *progname; /* name of this program */ |
138ca30e KB |
54 | char lquote = LQUOTE; /* left quote character (`) */ |
55 | char rquote = RQUOTE; /* right quote character (') */ | |
56 | char scommt = SCOMMT; /* start character for comment */ | |
57 | char ecommt = ECOMMT; /* end character for comment */ | |
ba487a99 | 58 | |
138ca30e KB |
59 | struct 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 |
107 | extern int optind; |
108 | extern char *optarg; | |
109 | ||
ba487a99 KB |
110 | void macro(); |
111 | void initkwds(); | |
112 | extern int getopt(); | |
113 | ||
114 | int | |
138ca30e | 115 | main(argc,argv) |
ba487a99 KB |
116 | int argc; |
117 | char *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 | 206 | ndptr inspect(); |
138ca30e KB |
207 | |
208 | /* | |
209 | * macro - the work horse.. | |
138ca30e | 210 | */ |
ba487a99 | 211 | void |
138ca30e KB |
212 | macro() { |
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 | */ | |
345 | ndptr | |
346 | inspect(tp) | |
347 | register 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 | 376 | void |
138ca30e KB |
377 | initkwds() { |
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 | } |