main.c revision 1.29 1 1.29 tv /* $NetBSD: main.c,v 1.29 2002/01/21 21:49:58 tv Exp $ */
2 1.27 tv /* $OpenBSD: main.c,v 1.51 2001/10/06 10:52:25 espie Exp $ */
3 1.9 tls
4 1.8 glass /*-
5 1.8 glass * Copyright (c) 1989, 1993
6 1.8 glass * The Regents of the University of California. All rights reserved.
7 1.8 glass *
8 1.8 glass * This code is derived from software contributed to Berkeley by
9 1.8 glass * Ozan Yigit at York University.
10 1.8 glass *
11 1.8 glass * Redistribution and use in source and binary forms, with or without
12 1.8 glass * modification, are permitted provided that the following conditions
13 1.8 glass * are met:
14 1.8 glass * 1. Redistributions of source code must retain the above copyright
15 1.8 glass * notice, this list of conditions and the following disclaimer.
16 1.8 glass * 2. Redistributions in binary form must reproduce the above copyright
17 1.8 glass * notice, this list of conditions and the following disclaimer in the
18 1.8 glass * documentation and/or other materials provided with the distribution.
19 1.8 glass * 3. All advertising materials mentioning features or use of this software
20 1.8 glass * must display the following acknowledgement:
21 1.8 glass * This product includes software developed by the University of
22 1.8 glass * California, Berkeley and its contributors.
23 1.8 glass * 4. Neither the name of the University nor the names of its contributors
24 1.8 glass * may be used to endorse or promote products derived from this software
25 1.8 glass * without specific prior written permission.
26 1.8 glass *
27 1.8 glass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.8 glass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.8 glass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.8 glass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.8 glass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.8 glass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.8 glass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.8 glass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.8 glass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.8 glass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.8 glass * SUCH DAMAGE.
38 1.8 glass */
39 1.1 cgd
40 1.13 lukem #include <sys/cdefs.h>
41 1.8 glass #ifndef lint
42 1.13 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
43 1.13 lukem The Regents of the University of California. All rights reserved.\n");
44 1.8 glass #endif /* not lint */
45 1.8 glass
46 1.8 glass #ifndef lint
47 1.9 tls #if 0
48 1.8 glass static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
49 1.9 tls #else
50 1.29 tv __RCSID("$NetBSD: main.c,v 1.29 2002/01/21 21:49:58 tv Exp $");
51 1.9 tls #endif
52 1.8 glass #endif /* not lint */
53 1.1 cgd
54 1.1 cgd /*
55 1.8 glass * main.c
56 1.8 glass * Facility: m4 macro processor
57 1.8 glass * by: oz
58 1.1 cgd */
59 1.1 cgd
60 1.8 glass #include <sys/types.h>
61 1.27 tv #include <assert.h>
62 1.13 lukem #include <ctype.h>
63 1.13 lukem #include <errno.h>
64 1.8 glass #include <signal.h>
65 1.27 tv #include <stddef.h>
66 1.8 glass #include <stdio.h>
67 1.16 kleink #include <stdlib.h>
68 1.8 glass #include <string.h>
69 1.8 glass #include "mdef.h"
70 1.8 glass #include "stdd.h"
71 1.8 glass #include "extern.h"
72 1.8 glass #include "pathnames.h"
73 1.8 glass
74 1.8 glass ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
75 1.27 tv stae *mstack; /* stack of m4 machine */
76 1.27 tv char *sstack; /* shadow stack, for string space extension */
77 1.27 tv static size_t STACKMAX; /* current maximum size of stack */
78 1.1 cgd int sp; /* current m4 stack pointer */
79 1.1 cgd int fp; /* m4 call frame pointer */
80 1.27 tv struct input_file infile[MAXINP];/* input file stack (0=stdin) */
81 1.27 tv FILE **outfile; /* diversion array(0=bitbucket)*/
82 1.27 tv int maxout;
83 1.1 cgd FILE *active; /* active output file pointer */
84 1.1 cgd int ilevel = 0; /* input file stack pointer */
85 1.1 cgd int oindex = 0; /* diversion index.. */
86 1.1 cgd char *null = ""; /* as it says.. just a null.. */
87 1.1 cgd char *m4wraps = ""; /* m4wrap string default.. */
88 1.22 tv int m4prefix = 0; /* prefix keywords with m4_ */
89 1.11 pk char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
90 1.11 pk char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
91 1.11 pk char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
92 1.11 pk char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
93 1.2 glass
94 1.8 glass struct keyblk keywrds[] = { /* m4 keywords to be installed */
95 1.13 lukem { "include", INCLTYPE },
96 1.13 lukem { "sinclude", SINCTYPE },
97 1.13 lukem { "define", DEFITYPE },
98 1.13 lukem { "defn", DEFNTYPE },
99 1.27 tv { "divert", DIVRTYPE | NOARGS },
100 1.13 lukem { "expr", EXPRTYPE },
101 1.13 lukem { "eval", EXPRTYPE },
102 1.13 lukem { "substr", SUBSTYPE },
103 1.13 lukem { "ifelse", IFELTYPE },
104 1.13 lukem { "ifdef", IFDFTYPE },
105 1.13 lukem { "len", LENGTYPE },
106 1.13 lukem { "incr", INCRTYPE },
107 1.13 lukem { "decr", DECRTYPE },
108 1.27 tv { "dnl", DNLNTYPE | NOARGS },
109 1.27 tv { "changequote", CHNQTYPE | NOARGS },
110 1.27 tv { "changecom", CHNCTYPE | NOARGS },
111 1.13 lukem { "index", INDXTYPE },
112 1.8 glass #ifdef EXTENDED
113 1.13 lukem { "paste", PASTTYPE },
114 1.13 lukem { "spaste", SPASTYPE },
115 1.27 tv /* Newer extensions, needed to handle gnu-m4 scripts */
116 1.27 tv { "indir", INDIRTYPE},
117 1.27 tv { "builtin", BUILTINTYPE},
118 1.27 tv { "patsubst", PATSTYPE},
119 1.27 tv { "regexp", REGEXPTYPE},
120 1.27 tv { "esyscmd", ESYSCMDTYPE},
121 1.27 tv { "__file__", FILENAMETYPE | NOARGS},
122 1.27 tv { "__line__", LINETYPE | NOARGS},
123 1.8 glass #endif
124 1.13 lukem { "popdef", POPDTYPE },
125 1.13 lukem { "pushdef", PUSDTYPE },
126 1.27 tv { "dumpdef", DUMPTYPE | NOARGS },
127 1.27 tv { "shift", SHIFTYPE | NOARGS },
128 1.13 lukem { "translit", TRNLTYPE },
129 1.13 lukem { "undefine", UNDFTYPE },
130 1.27 tv { "undivert", UNDVTYPE | NOARGS },
131 1.27 tv { "divnum", DIVNTYPE | NOARGS },
132 1.13 lukem { "maketemp", MKTMTYPE },
133 1.27 tv { "errprint", ERRPTYPE | NOARGS },
134 1.27 tv { "m4wrap", M4WRTYPE | NOARGS },
135 1.27 tv { "m4exit", EXITTYPE | NOARGS },
136 1.13 lukem { "syscmd", SYSCTYPE },
137 1.27 tv { "sysval", SYSVTYPE | NOARGS },
138 1.27 tv { "traceon", TRACEONTYPE | NOARGS },
139 1.27 tv { "traceoff", TRACEOFFTYPE | NOARGS },
140 1.2 glass
141 1.27 tv #if defined(unix) || defined(__unix__)
142 1.27 tv { "unix", SELFTYPE | NOARGS },
143 1.2 glass #else
144 1.8 glass #ifdef vms
145 1.27 tv { "vms", SELFTYPE | NOARGS },
146 1.1 cgd #endif
147 1.1 cgd #endif
148 1.8 glass };
149 1.8 glass
150 1.8 glass #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
151 1.1 cgd
152 1.27 tv extern int optind;
153 1.27 tv extern char *optarg;
154 1.27 tv
155 1.27 tv #define MAXRECORD 50
156 1.27 tv static struct position {
157 1.27 tv char *name;
158 1.27 tv unsigned long line;
159 1.27 tv } quotes[MAXRECORD], paren[MAXRECORD];
160 1.27 tv
161 1.27 tv static void record __P((struct position *, int));
162 1.27 tv static void dump_stack __P((struct position *, int));
163 1.27 tv
164 1.27 tv static void macro __P((void));
165 1.27 tv static void initkwds __P((void));
166 1.27 tv static ndptr inspect __P((int, char *));
167 1.27 tv static int do_look_ahead __P((int, const char *));
168 1.27 tv
169 1.27 tv static void enlarge_stack __P((void));
170 1.27 tv
171 1.27 tv int main __P((int, char *[]));
172 1.1 cgd
173 1.8 glass int
174 1.8 glass main(argc,argv)
175 1.8 glass int argc;
176 1.8 glass char *argv[];
177 1.8 glass {
178 1.13 lukem int c;
179 1.13 lukem int n;
180 1.8 glass char *p;
181 1.8 glass
182 1.8 glass if (signal(SIGINT, SIG_IGN) != SIG_IGN)
183 1.8 glass signal(SIGINT, onintr);
184 1.1 cgd
185 1.22 tv /*
186 1.22 tv * We need to know if -P is there before checking -D and -U.
187 1.22 tv */
188 1.28 tv while ((c = getopt(argc, argv, "D:I:PU:d:go:t:")) != -1)
189 1.22 tv if (c == 'P')
190 1.22 tv m4prefix = 1;
191 1.22 tv optind = 1;
192 1.22 tv
193 1.8 glass initkwds();
194 1.27 tv initspaces();
195 1.27 tv STACKMAX = INITSTACKMAX;
196 1.27 tv
197 1.27 tv mstack = (stae *)xalloc(sizeof(stae) * STACKMAX);
198 1.27 tv sstack = (char *)xalloc(STACKMAX);
199 1.1 cgd
200 1.27 tv maxout = 0;
201 1.27 tv outfile = NULL;
202 1.27 tv resizedivs(MAXOUT);
203 1.1 cgd
204 1.27 tv while ((c = getopt(argc, argv, "D:I:PU:d:go:t:")) != -1)
205 1.27 tv switch (c) {
206 1.8 glass case 'D': /* define something..*/
207 1.8 glass for (p = optarg; *p; p++)
208 1.8 glass if (*p == '=')
209 1.8 glass break;
210 1.8 glass if (*p)
211 1.8 glass *p++ = EOS;
212 1.8 glass dodefine(optarg, p);
213 1.8 glass break;
214 1.27 tv case 'I':
215 1.27 tv addtoincludepath(optarg);
216 1.27 tv break;
217 1.27 tv case 'P':
218 1.27 tv break;
219 1.8 glass case 'U': /* undefine... */
220 1.8 glass remhash(optarg, TOP);
221 1.8 glass break;
222 1.27 tv case 'd':
223 1.27 tv set_trace_flags(optarg);
224 1.27 tv break;
225 1.27 tv case 'g':
226 1.27 tv mimic_gnu = 1;
227 1.27 tv break;
228 1.27 tv case 'o':
229 1.27 tv trace_file(optarg);
230 1.27 tv break;
231 1.27 tv case 't':
232 1.27 tv mark_traced(optarg, 1);
233 1.22 tv break;
234 1.8 glass case '?':
235 1.22 tv default:
236 1.28 tv usage(argv[0]);
237 1.2 glass }
238 1.1 cgd
239 1.8 glass argc -= optind;
240 1.8 glass argv += optind;
241 1.2 glass
242 1.8 glass active = stdout; /* default active output */
243 1.8 glass bbase[0] = bufbase;
244 1.8 glass if (!argc) {
245 1.8 glass sp = -1; /* stack pointer initialized */
246 1.8 glass fp = 0; /* frame pointer initialized */
247 1.27 tv set_input(infile+0, stdin, "stdin");
248 1.27 tv /* default input (naturally) */
249 1.8 glass macro();
250 1.8 glass } else
251 1.8 glass for (; argc--; ++argv) {
252 1.8 glass p = *argv;
253 1.27 tv if (p[0] == '-' && p[1] == EOS)
254 1.27 tv set_input(infile, stdin, "stdin");
255 1.27 tv else if (fopen_trypath(infile, p) == NULL)
256 1.13 lukem err(1, "%s", p);
257 1.8 glass sp = -1;
258 1.8 glass fp = 0;
259 1.8 glass macro();
260 1.27 tv release_input(infile);
261 1.8 glass }
262 1.2 glass
263 1.8 glass if (*m4wraps) { /* anything for rundown ?? */
264 1.8 glass ilevel = 0; /* in case m4wrap includes.. */
265 1.8 glass bufbase = bp = buf; /* use the entire buffer */
266 1.8 glass pbstr(m4wraps); /* user-defined wrapup act */
267 1.8 glass macro(); /* last will and testament */
268 1.8 glass }
269 1.2 glass
270 1.8 glass if (active != stdout)
271 1.8 glass active = stdout; /* reset output just in case */
272 1.27 tv for (n = 1; n < maxout; n++) /* default wrap-up: undivert */
273 1.8 glass if (outfile[n] != NULL)
274 1.8 glass getdiv(n);
275 1.27 tv /* remove bitbucket if used */
276 1.27 tv if (outfile[0] != NULL) {
277 1.8 glass (void) fclose(outfile[0]);
278 1.27 tv }
279 1.8 glass
280 1.8 glass return 0;
281 1.8 glass }
282 1.2 glass
283 1.8 glass /*
284 1.27 tv * Look ahead for `token'.
285 1.11 pk * (on input `t == token[0]')
286 1.11 pk * Used for comment and quoting delimiters.
287 1.11 pk * Returns 1 if `token' present; copied to output.
288 1.11 pk * 0 if `token' not found; all characters pushed back
289 1.11 pk */
290 1.27 tv static int
291 1.11 pk do_look_ahead(t, token)
292 1.11 pk int t;
293 1.27 tv const char *token;
294 1.11 pk {
295 1.11 pk int i;
296 1.11 pk
297 1.27 tv assert((unsigned char)t == (unsigned char)token[0]);
298 1.11 pk
299 1.11 pk for (i = 1; *++token; i++) {
300 1.11 pk t = gpbc();
301 1.27 tv if (t == EOF || (unsigned char)t != (unsigned char)*token) {
302 1.27 tv putback(t);
303 1.11 pk while (--i)
304 1.11 pk putback(*--token);
305 1.11 pk return 0;
306 1.11 pk }
307 1.11 pk }
308 1.11 pk return 1;
309 1.11 pk }
310 1.11 pk
311 1.27 tv #define LOOK_AHEAD(t, token) (t != EOF && \
312 1.27 tv (unsigned char)(t)==(unsigned char)(token)[0] && \
313 1.27 tv do_look_ahead(t,token))
314 1.11 pk
315 1.11 pk /*
316 1.8 glass * macro - the work horse..
317 1.8 glass */
318 1.27 tv static void
319 1.13 lukem macro()
320 1.13 lukem {
321 1.27 tv char token[MAXTOK+1];
322 1.13 lukem int t, l;
323 1.13 lukem ndptr p;
324 1.13 lukem int nlpar;
325 1.1 cgd
326 1.8 glass cycle {
327 1.11 pk t = gpbc();
328 1.11 pk if (t == '_' || isalpha(t)) {
329 1.27 tv p = inspect(t, token);
330 1.27 tv if (p != nil)
331 1.27 tv putback(l = gpbc());
332 1.27 tv if (p == nil || (l != LPAREN &&
333 1.27 tv (p->type & NEEDARGS) != 0))
334 1.27 tv outputstr(token);
335 1.8 glass else {
336 1.8 glass /*
337 1.8 glass * real thing.. First build a call frame:
338 1.8 glass */
339 1.8 glass pushf(fp); /* previous call frm */
340 1.8 glass pushf(p->type); /* type of the call */
341 1.8 glass pushf(0); /* parenthesis level */
342 1.8 glass fp = sp; /* new frame pointer */
343 1.8 glass /*
344 1.8 glass * now push the string arguments:
345 1.8 glass */
346 1.27 tv pushs1(p->defn); /* defn string */
347 1.27 tv pushs1(p->name); /* macro name */
348 1.27 tv pushs(ep); /* start next..*/
349 1.27 tv
350 1.27 tv if (l != LPAREN && PARLEV == 0) {
351 1.27 tv /* no bracks */
352 1.27 tv chrsave(EOS);
353 1.27 tv
354 1.27 tv if (sp == STACKMAX)
355 1.27 tv errx(1, "internal stack overflow");
356 1.27 tv eval((const char **) mstack+fp+1, 2,
357 1.27 tv CALTYP);
358 1.27 tv
359 1.27 tv ep = PREVEP; /* flush strspace */
360 1.27 tv sp = PREVSP; /* previous sp.. */
361 1.27 tv fp = PREVFP; /* rewind stack...*/
362 1.2 glass }
363 1.8 glass }
364 1.27 tv } else if (t == EOF) {
365 1.27 tv if (sp > -1) {
366 1.27 tv warnx( "unexpected end of input, unclosed parenthesis:");
367 1.27 tv dump_stack(paren, PARLEV);
368 1.27 tv exit(1);
369 1.27 tv }
370 1.8 glass if (ilevel <= 0)
371 1.8 glass break; /* all done thanks.. */
372 1.27 tv release_input(infile+ilevel--);
373 1.8 glass bufbase = bbase[ilevel];
374 1.8 glass continue;
375 1.8 glass }
376 1.8 glass /*
377 1.12 cgd * non-alpha token possibly seen..
378 1.8 glass * [the order of else if .. stmts is important.]
379 1.8 glass */
380 1.11 pk else if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
381 1.27 tv nlpar = 0;
382 1.27 tv record(quotes, nlpar++);
383 1.27 tv /*
384 1.27 tv * Opening quote: scan forward until matching
385 1.27 tv * closing quote has been found.
386 1.27 tv */
387 1.8 glass do {
388 1.12 cgd
389 1.11 pk l = gpbc();
390 1.12 cgd if (LOOK_AHEAD(l,rquote)) {
391 1.27 tv if (--nlpar > 0)
392 1.27 tv outputstr(rquote);
393 1.12 cgd } else if (LOOK_AHEAD(l,lquote)) {
394 1.27 tv record(quotes, nlpar++);
395 1.27 tv outputstr(lquote);
396 1.27 tv } else if (l == EOF) {
397 1.27 tv if (nlpar == 1)
398 1.27 tv warnx("unclosed quote:");
399 1.8 glass else
400 1.27 tv warnx("%d unclosed quotes:", nlpar);
401 1.27 tv dump_stack(quotes, nlpar);
402 1.27 tv exit(1);
403 1.27 tv } else {
404 1.27 tv if (nlpar > 0) {
405 1.27 tv if (sp < 0)
406 1.27 tv putc(l, active);
407 1.27 tv else
408 1.27 tv CHRSAVE(l);
409 1.27 tv }
410 1.2 glass }
411 1.8 glass }
412 1.8 glass while (nlpar != 0);
413 1.8 glass }
414 1.1 cgd
415 1.11 pk else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
416 1.27 tv fputs(scommt, active);
417 1.11 pk
418 1.11 pk for(;;) {
419 1.11 pk t = gpbc();
420 1.11 pk if (LOOK_AHEAD(t, ecommt)) {
421 1.27 tv fputs(ecommt, active);
422 1.11 pk break;
423 1.11 pk }
424 1.11 pk if (t == EOF)
425 1.11 pk break;
426 1.8 glass putc(t, active);
427 1.1 cgd }
428 1.11 pk }
429 1.11 pk
430 1.11 pk else if (sp < 0) { /* not in a macro at all */
431 1.8 glass putc(t, active); /* output directly.. */
432 1.8 glass }
433 1.1 cgd
434 1.8 glass else switch(t) {
435 1.2 glass
436 1.8 glass case LPAREN:
437 1.8 glass if (PARLEV > 0)
438 1.8 glass chrsave(t);
439 1.8 glass while (isspace(l = gpbc()))
440 1.8 glass ; /* skip blank, tab, nl.. */
441 1.8 glass putback(l);
442 1.27 tv record(paren, PARLEV++);
443 1.8 glass break;
444 1.1 cgd
445 1.8 glass case RPAREN:
446 1.8 glass if (--PARLEV > 0)
447 1.8 glass chrsave(t);
448 1.8 glass else { /* end of argument list */
449 1.8 glass chrsave(EOS);
450 1.8 glass
451 1.8 glass if (sp == STACKMAX)
452 1.13 lukem errx(1, "internal stack overflow");
453 1.8 glass
454 1.27 tv eval((const char **) mstack+fp+1, sp-fp,
455 1.27 tv CALTYP);
456 1.8 glass
457 1.8 glass ep = PREVEP; /* flush strspace */
458 1.8 glass sp = PREVSP; /* previous sp.. */
459 1.8 glass fp = PREVFP; /* rewind stack...*/
460 1.8 glass }
461 1.8 glass break;
462 1.1 cgd
463 1.8 glass case COMMA:
464 1.8 glass if (PARLEV == 1) {
465 1.8 glass chrsave(EOS); /* new argument */
466 1.8 glass while (isspace(l = gpbc()))
467 1.8 glass ;
468 1.8 glass putback(l);
469 1.8 glass pushs(ep);
470 1.8 glass } else
471 1.8 glass chrsave(t);
472 1.8 glass break;
473 1.2 glass
474 1.2 glass default:
475 1.27 tv if (LOOK_AHEAD(t, scommt)) {
476 1.27 tv char *p;
477 1.27 tv for (p = scommt; *p; p++)
478 1.27 tv chrsave(*p);
479 1.27 tv for(;;) {
480 1.27 tv t = gpbc();
481 1.27 tv if (LOOK_AHEAD(t, ecommt)) {
482 1.27 tv for (p = ecommt; *p; p++)
483 1.27 tv chrsave(*p);
484 1.27 tv break;
485 1.27 tv }
486 1.27 tv if (t == EOF)
487 1.27 tv break;
488 1.27 tv CHRSAVE(t);
489 1.27 tv }
490 1.27 tv } else
491 1.27 tv CHRSAVE(t); /* stack the char */
492 1.8 glass break;
493 1.8 glass }
494 1.2 glass }
495 1.8 glass }
496 1.2 glass
497 1.27 tv /*
498 1.27 tv * output string directly, without pushing it for reparses.
499 1.27 tv */
500 1.27 tv void
501 1.27 tv outputstr(s)
502 1.27 tv const char *s;
503 1.27 tv {
504 1.27 tv if (sp < 0)
505 1.27 tv while (*s)
506 1.27 tv putc(*s++, active);
507 1.27 tv else
508 1.27 tv while (*s)
509 1.27 tv CHRSAVE(*s++);
510 1.27 tv }
511 1.27 tv
512 1.8 glass /*
513 1.8 glass * build an input token..
514 1.8 glass * consider only those starting with _ or A-Za-z. This is a
515 1.8 glass * combo with lookup to speed things up.
516 1.8 glass */
517 1.27 tv static ndptr
518 1.27 tv inspect(c, tp)
519 1.27 tv int c;
520 1.13 lukem char *tp;
521 1.8 glass {
522 1.13 lukem char *name = tp;
523 1.13 lukem char *etp = tp+MAXTOK;
524 1.13 lukem ndptr p;
525 1.27 tv unsigned int h;
526 1.27 tv
527 1.27 tv h = *tp++ = c;
528 1.2 glass
529 1.27 tv while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
530 1.8 glass h = (h << 5) + h + (*tp++ = c);
531 1.27 tv if (c != EOF)
532 1.27 tv PUTBACK(c);
533 1.8 glass *tp = EOS;
534 1.27 tv /* token is too long, it won't match anything, but it can still
535 1.27 tv * be output. */
536 1.27 tv if (tp == ep) {
537 1.27 tv outputstr(name);
538 1.27 tv while (isalnum(c = gpbc()) || c == '_') {
539 1.27 tv if (sp < 0)
540 1.27 tv putc(c, active);
541 1.27 tv else
542 1.27 tv CHRSAVE(c);
543 1.27 tv }
544 1.27 tv *name = EOS;
545 1.27 tv return nil;
546 1.27 tv }
547 1.1 cgd
548 1.27 tv for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr)
549 1.27 tv if (h == p->hv && STREQ(name, p->name))
550 1.8 glass break;
551 1.8 glass return p;
552 1.8 glass }
553 1.7 cgd
554 1.8 glass /*
555 1.24 jdolecek * initkwds - initialise m4 keywords as fast as possible.
556 1.8 glass * This very similar to install, but without certain overheads,
557 1.24 jdolecek * such as calling lookup. Malloc is not used for storing the
558 1.13 lukem * keyword strings, since we simply use the static pointers
559 1.8 glass * within keywrds block.
560 1.8 glass */
561 1.27 tv static void
562 1.13 lukem initkwds()
563 1.13 lukem {
564 1.27 tv size_t i;
565 1.27 tv unsigned int h;
566 1.13 lukem ndptr p;
567 1.22 tv char *k;
568 1.1 cgd
569 1.8 glass for (i = 0; i < MAXKEYS; i++) {
570 1.26 wiz k = (char *)keywrds[i].knam;
571 1.27 tv if (m4prefix) {
572 1.29 tv size_t klen = strlen(k);
573 1.29 tv char *newk = malloc(klen + 4);
574 1.29 tv
575 1.29 tv if (snprintf(newk, klen, "m4_%s", k) == -1)
576 1.29 tv err(1, "snprintf");
577 1.29 tv keywrds[i].knam = newk;
578 1.27 tv }
579 1.22 tv h = hash(k);
580 1.8 glass p = (ndptr) xalloc(sizeof(struct ndblock));
581 1.27 tv p->nxtptr = hashtab[h % HASHSIZE];
582 1.27 tv hashtab[h % HASHSIZE] = p;
583 1.27 tv p->name = xstrdup(keywrds[i].knam);
584 1.8 glass p->defn = null;
585 1.27 tv p->hv = h;
586 1.27 tv p->type = keywrds[i].ktyp & TYPEMASK;
587 1.27 tv if ((keywrds[i].ktyp & NOARGS) == 0)
588 1.27 tv p->type |= NEEDARGS;
589 1.1 cgd }
590 1.27 tv }
591 1.27 tv
592 1.27 tv /* Look up a builtin type, even if overridden by the user */
593 1.27 tv int
594 1.27 tv builtin_type(key)
595 1.27 tv const char *key;
596 1.27 tv {
597 1.27 tv int i;
598 1.27 tv
599 1.27 tv for (i = 0; i != MAXKEYS; i++)
600 1.27 tv if (STREQ(keywrds[i].knam, key))
601 1.27 tv return keywrds[i].ktyp;
602 1.27 tv return -1;
603 1.27 tv }
604 1.27 tv
605 1.27 tv const char *
606 1.27 tv builtin_realname(n)
607 1.27 tv int n;
608 1.27 tv {
609 1.27 tv int i;
610 1.27 tv
611 1.27 tv for (i = 0; i != MAXKEYS; i++)
612 1.27 tv if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0)
613 1.27 tv return keywrds[i].knam;
614 1.27 tv return NULL;
615 1.27 tv }
616 1.27 tv
617 1.27 tv static void
618 1.27 tv record(t, lev)
619 1.27 tv struct position *t;
620 1.27 tv int lev;
621 1.27 tv {
622 1.27 tv if (lev < MAXRECORD) {
623 1.27 tv t[lev].name = CURRENT_NAME;
624 1.27 tv t[lev].line = CURRENT_LINE;
625 1.27 tv }
626 1.27 tv }
627 1.27 tv
628 1.27 tv static void
629 1.27 tv dump_stack(t, lev)
630 1.27 tv struct position *t;
631 1.27 tv int lev;
632 1.27 tv {
633 1.27 tv int i;
634 1.27 tv
635 1.27 tv for (i = 0; i < lev; i++) {
636 1.27 tv if (i == MAXRECORD) {
637 1.27 tv fprintf(stderr, " ...\n");
638 1.27 tv break;
639 1.27 tv }
640 1.27 tv fprintf(stderr, " %s at line %lu\n",
641 1.27 tv t[i].name, t[i].line);
642 1.27 tv }
643 1.27 tv }
644 1.27 tv
645 1.27 tv
646 1.27 tv static void
647 1.27 tv enlarge_stack()
648 1.27 tv {
649 1.27 tv STACKMAX *= 2;
650 1.27 tv mstack = realloc(mstack, sizeof(stae) * STACKMAX);
651 1.27 tv sstack = realloc(sstack, STACKMAX);
652 1.27 tv if (mstack == NULL || sstack == NULL)
653 1.27 tv errx(1, "Evaluation stack overflow (%lu)",
654 1.27 tv (unsigned long)STACKMAX);
655 1.8 glass }
656