main.c (de9b3b9034ee0d39f3bff03b8368361d80cf728f) main.c (e3d8671772982f3135d8d6997f3cd698cca4df19)
1/* $OpenBSD: main.c,v 1.52 2002/02/16 21:27:48 millert Exp $ */
2/* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */
3
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 21 unchanged lines hidden (view full) ---

30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
4/*-
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
10 *
11 * Redistribution and use in source and binary forms, with or without

--- 21 unchanged lines hidden (view full) ---

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