main.c revision 99939
195887Sjmallett/* $OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $ */ 295060Sjmallett/* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */ 395060Sjmallett 41590Srgrimes/*- 51590Srgrimes * Copyright (c) 1989, 1993 61590Srgrimes * The Regents of the University of California. All rights reserved. 71590Srgrimes * 81590Srgrimes * This code is derived from software contributed to Berkeley by 91590Srgrimes * Ozan Yigit at York University. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 3. All advertising materials mentioning features or use of this software 201590Srgrimes * must display the following acknowledgement: 211590Srgrimes * This product includes software developed by the University of 221590Srgrimes * California, Berkeley and its contributors. 231590Srgrimes * 4. Neither the name of the University nor the names of its contributors 241590Srgrimes * may be used to endorse or promote products derived from this software 251590Srgrimes * without specific prior written permission. 261590Srgrimes * 271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371590Srgrimes * SUCH DAMAGE. 381590Srgrimes */ 391590Srgrimes 4095982Sjmallett#ifndef lint 4195982Sjmallettstatic char copyright[] = 4295982Sjmallett"@(#) Copyright (c) 1989, 1993\n\ 4395982Sjmallett The Regents of the University of California. All rights reserved.\n"; 4495982Sjmallett#endif /* not lint */ 4595982Sjmallett 4695982Sjmallett#ifndef lint 4795982Sjmallett#if 0 4895982Sjmallettstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 4995982Sjmallett#else 5095982Sjmallett#if 0 5195982Sjmallettstatic char rcsid[] = "$OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $"; 5295982Sjmallett#endif 5395982Sjmallett#endif 5495982Sjmallett#endif /* not lint */ 5595982Sjmallett 5695060Sjmallett#include <sys/cdefs.h> 5795060Sjmallett__FBSDID("$FreeBSD: head/usr.bin/m4/main.c 99939 2002-07-14 02:03:23Z jmallett $"); 581590Srgrimes 591590Srgrimes/* 601590Srgrimes * main.c 611590Srgrimes * Facility: m4 macro processor 621590Srgrimes * by: oz 631590Srgrimes */ 641590Srgrimes 651590Srgrimes#include <sys/types.h> 6695060Sjmallett#include <assert.h> 671590Srgrimes#include <signal.h> 6895060Sjmallett#include <errno.h> 6995060Sjmallett#include <unistd.h> 701590Srgrimes#include <stdio.h> 7195060Sjmallett#include <ctype.h> 7295060Sjmallett#include <string.h> 7395060Sjmallett#include <stddef.h> 7480289Sobrien#include <stdlib.h> 7595060Sjmallett#include <err.h> 761590Srgrimes#include "mdef.h" 771590Srgrimes#include "stdd.h" 781590Srgrimes#include "extern.h" 791590Srgrimes#include "pathnames.h" 801590Srgrimes 811590Srgrimesndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 8295060Sjmallettstae *mstack; /* stack of m4 machine */ 8395060Sjmallettchar *sstack; /* shadow stack, for string space extension */ 8495060Sjmallettstatic size_t STACKMAX; /* current maximum size of stack */ 851590Srgrimesint sp; /* current m4 stack pointer */ 861590Srgrimesint fp; /* m4 call frame pointer */ 8795060Sjmallettstruct input_file infile[MAXINP];/* input file stack (0=stdin) */ 8895060Sjmallettchar *inname[MAXINP]; /* names of these input files */ 8995060Sjmallettint inlineno[MAXINP]; /* current number in each input file */ 9095060SjmallettFILE **outfile; /* diversion array(0=bitbucket)*/ 9195060Sjmallettint maxout; 921590SrgrimesFILE *active; /* active output file pointer */ 931590Srgrimesint ilevel = 0; /* input file stack pointer */ 941590Srgrimesint oindex = 0; /* diversion index.. */ 9595095Sjmallettconst char *null = ""; /* as it says.. just a null.. */ 9695095Sjmallettconst char *m4wraps = ""; /* m4wrap string default.. */ 9795060Sjmallettchar lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ 9895060Sjmallettchar rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ 9995060Sjmallettchar scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ 10095060Sjmallettchar ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ 10194957Sjmallettint synccpp; /* Line synchronisation for C preprocessor */ 1021590Srgrimes 1031590Srgrimesstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 10495060Sjmallett { "include", INCLTYPE }, 10595060Sjmallett { "sinclude", SINCTYPE }, 10695060Sjmallett { "define", DEFITYPE }, 10795060Sjmallett { "defn", DEFNTYPE }, 10895060Sjmallett { "divert", DIVRTYPE | NOARGS }, 10995060Sjmallett { "expr", EXPRTYPE }, 11095060Sjmallett { "eval", EXPRTYPE }, 11195060Sjmallett { "substr", SUBSTYPE }, 11295060Sjmallett { "ifelse", IFELTYPE }, 11395060Sjmallett { "ifdef", IFDFTYPE }, 11495060Sjmallett { "len", LENGTYPE }, 11595060Sjmallett { "incr", INCRTYPE }, 11695060Sjmallett { "decr", DECRTYPE }, 11795060Sjmallett { "dnl", DNLNTYPE | NOARGS }, 11895060Sjmallett { "changequote", CHNQTYPE | NOARGS }, 11995060Sjmallett { "changecom", CHNCTYPE | NOARGS }, 12095060Sjmallett { "index", INDXTYPE }, 1211590Srgrimes#ifdef EXTENDED 12295060Sjmallett { "paste", PASTTYPE }, 12395060Sjmallett { "spaste", SPASTYPE }, 12495060Sjmallett /* Newer extensions, needed to handle gnu-m4 scripts */ 12595060Sjmallett { "indir", INDIRTYPE}, 12695060Sjmallett { "builtin", BUILTINTYPE}, 12795060Sjmallett { "patsubst", PATSTYPE}, 12895060Sjmallett { "regexp", REGEXPTYPE}, 12995060Sjmallett { "esyscmd", ESYSCMDTYPE}, 13095060Sjmallett { "__file__", FILENAMETYPE | NOARGS}, 13195060Sjmallett { "__line__", LINETYPE | NOARGS}, 1321590Srgrimes#endif 13395060Sjmallett { "popdef", POPDTYPE }, 13495060Sjmallett { "pushdef", PUSDTYPE }, 13595060Sjmallett { "dumpdef", DUMPTYPE | NOARGS }, 13695060Sjmallett { "shift", SHIFTYPE | NOARGS }, 13795060Sjmallett { "translit", TRNLTYPE }, 13895060Sjmallett { "undefine", UNDFTYPE }, 13995060Sjmallett { "undivert", UNDVTYPE | NOARGS }, 14095060Sjmallett { "divnum", DIVNTYPE | NOARGS }, 14195060Sjmallett { "maketemp", MKTMTYPE }, 14295060Sjmallett { "errprint", ERRPTYPE | NOARGS }, 14395060Sjmallett { "m4wrap", M4WRTYPE | NOARGS }, 14495060Sjmallett { "m4exit", EXITTYPE | NOARGS }, 14595060Sjmallett { "syscmd", SYSCTYPE }, 14695060Sjmallett { "sysval", SYSVTYPE | NOARGS }, 14795060Sjmallett { "traceon", TRACEONTYPE | NOARGS }, 14895060Sjmallett { "traceoff", TRACEOFFTYPE | NOARGS }, 1491590Srgrimes 15095060Sjmallett#if defined(unix) || defined(__unix__) 15195060Sjmallett { "unix", SELFTYPE | NOARGS }, 1521590Srgrimes#else 1531590Srgrimes#ifdef vms 15495060Sjmallett { "vms", SELFTYPE | NOARGS }, 1551590Srgrimes#endif 1561590Srgrimes#endif 1571590Srgrimes}; 1581590Srgrimes 1591590Srgrimes#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1601590Srgrimes 16195060Sjmallett#define MAXRECORD 50 16295060Sjmallettstatic struct position { 16395060Sjmallett char *name; 16495060Sjmallett unsigned long line; 16595060Sjmallett} quotes[MAXRECORD], paren[MAXRECORD]; 16695060Sjmallett 16795060Sjmallettstatic void record(struct position *, int); 16895060Sjmallettstatic void dump_stack(struct position *, int); 16995060Sjmallett 17095060Sjmallettstatic void macro(void); 17195060Sjmallettstatic void initkwds(void); 17295060Sjmallettstatic ndptr inspect(int, char *); 17395060Sjmallettstatic int do_look_ahead(int, const char *); 17495060Sjmallett 17595060Sjmallettstatic void enlarge_stack(void); 17695060Sjmallett 1771590Srgrimesint 17895887Sjmallettmain(int argc, char *argv[]) 1791590Srgrimes{ 18095060Sjmallett int c; 18195060Sjmallett int n; 18297296Stjr int rval; 1831590Srgrimes char *p; 1841590Srgrimes 18595060Sjmallett traceout = stderr; 18695060Sjmallett 1871590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1881590Srgrimes signal(SIGINT, onintr); 1891590Srgrimes 1901590Srgrimes initkwds(); 19195060Sjmallett initspaces(); 19295060Sjmallett STACKMAX = INITSTACKMAX; 1931590Srgrimes 19495060Sjmallett mstack = (stae *)xalloc(sizeof(stae) * STACKMAX); 19595060Sjmallett sstack = (char *)xalloc(STACKMAX); 19695060Sjmallett 19795060Sjmallett maxout = 0; 19895060Sjmallett outfile = NULL; 19995060Sjmallett resizedivs(MAXOUT); 20095060Sjmallett 20195060Sjmallett while ((c = getopt(argc, argv, "gst:d:D:U:o:I:")) != -1) 2021590Srgrimes switch(c) { 2031590Srgrimes 2041590Srgrimes case 'D': /* define something..*/ 2051590Srgrimes for (p = optarg; *p; p++) 2061590Srgrimes if (*p == '=') 2071590Srgrimes break; 2081590Srgrimes if (*p) 2091590Srgrimes *p++ = EOS; 2101590Srgrimes dodefine(optarg, p); 2111590Srgrimes break; 21295060Sjmallett case 'I': 21395060Sjmallett addtoincludepath(optarg); 21495060Sjmallett break; 2151590Srgrimes case 'U': /* undefine... */ 2161590Srgrimes remhash(optarg, TOP); 2171590Srgrimes break; 21895060Sjmallett case 'g': 21995060Sjmallett mimic_gnu = 1; 22095060Sjmallett break; 22195060Sjmallett case 'd': 22295060Sjmallett set_trace_flags(optarg); 22395060Sjmallett break; 22494957Sjmallett case 's': 22594957Sjmallett synccpp = 1; 22694957Sjmallett break; 22795060Sjmallett case 't': 22895060Sjmallett mark_traced(optarg, 1); 22995060Sjmallett break; 23095060Sjmallett case 'o': 23195060Sjmallett trace_file(optarg); 23295060Sjmallett break; 2331590Srgrimes case '?': 2341590Srgrimes usage(); 2351590Srgrimes } 2361590Srgrimes 2371590Srgrimes argc -= optind; 2381590Srgrimes argv += optind; 2391590Srgrimes 24097296Stjr rval = 0; 2411590Srgrimes active = stdout; /* default active output */ 2421590Srgrimes bbase[0] = bufbase; 2431590Srgrimes if (!argc) { 2441590Srgrimes sp = -1; /* stack pointer initialized */ 2451590Srgrimes fp = 0; /* frame pointer initialized */ 24695060Sjmallett set_input(infile+0, stdin, "stdin"); 24795060Sjmallett /* default input (naturally) */ 24894957Sjmallett if ((inname[0] = strdup("-")) == NULL) 24994957Sjmallett err(1, NULL); 25094957Sjmallett inlineno[0] = 1; 25194957Sjmallett emitline(); 2521590Srgrimes macro(); 2531590Srgrimes } else 2541590Srgrimes for (; argc--; ++argv) { 2551590Srgrimes p = *argv; 25695060Sjmallett if (p[0] == '-' && p[1] == EOS) 25795060Sjmallett set_input(infile, stdin, "stdin"); 25897296Stjr else if (fopen_trypath(infile, p) == NULL) { 25997296Stjr warn("%s", p); 26097296Stjr rval = 1; 26197296Stjr continue; 26297296Stjr } 2631590Srgrimes sp = -1; 26495060Sjmallett fp = 0; 26594957Sjmallett if ((inname[0] = strdup(p)) == NULL) 26694957Sjmallett err(1, NULL); 26794957Sjmallett inlineno[0] = 1; 26894957Sjmallett emitline(); 2691590Srgrimes macro(); 27095060Sjmallett release_input(infile); 2711590Srgrimes } 2721590Srgrimes 2731590Srgrimes if (*m4wraps) { /* anything for rundown ?? */ 2741590Srgrimes ilevel = 0; /* in case m4wrap includes.. */ 2751590Srgrimes bufbase = bp = buf; /* use the entire buffer */ 2761590Srgrimes pbstr(m4wraps); /* user-defined wrapup act */ 2771590Srgrimes macro(); /* last will and testament */ 2781590Srgrimes } 2791590Srgrimes 2801590Srgrimes if (active != stdout) 2811590Srgrimes active = stdout; /* reset output just in case */ 28295060Sjmallett for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ 2831590Srgrimes if (outfile[n] != NULL) 2841590Srgrimes getdiv(n); 2851590Srgrimes /* remove bitbucket if used */ 28695060Sjmallett if (outfile[0] != NULL) { 28795060Sjmallett (void) fclose(outfile[0]); 28895060Sjmallett } 28995060Sjmallett 29097296Stjr exit(rval); 2911590Srgrimes} 2921590Srgrimes 29395060Sjmallett/* 29495060Sjmallett * Look ahead for `token'. 29595060Sjmallett * (on input `t == token[0]') 29695060Sjmallett * Used for comment and quoting delimiters. 29795060Sjmallett * Returns 1 if `token' present; copied to output. 29895060Sjmallett * 0 if `token' not found; all characters pushed back 29995060Sjmallett */ 30095060Sjmallettstatic int 30195887Sjmallettdo_look_ahead(int t, const char *token) 30295060Sjmallett{ 30395060Sjmallett int i; 3041590Srgrimes 30595060Sjmallett assert((unsigned char)t == (unsigned char)token[0]); 30695060Sjmallett 30795060Sjmallett for (i = 1; *++token; i++) { 30895060Sjmallett t = gpbc(); 30995060Sjmallett if (t == EOF || (unsigned char)t != (unsigned char)*token) { 31095060Sjmallett putback(t); 31195060Sjmallett while (--i) 31295060Sjmallett putback(*--token); 31395060Sjmallett return 0; 31495060Sjmallett } 31595060Sjmallett } 31695060Sjmallett return 1; 31795060Sjmallett} 31895060Sjmallett 31995060Sjmallett#define LOOK_AHEAD(t, token) (t != EOF && \ 32095060Sjmallett (unsigned char)(t)==(unsigned char)(token)[0] && \ 32195060Sjmallett do_look_ahead(t,token)) 32295060Sjmallett 3231590Srgrimes/* 3241590Srgrimes * macro - the work horse.. 3251590Srgrimes */ 32695060Sjmallettstatic void 32799939Sjmallettmacro(void) 32895060Sjmallett{ 32995060Sjmallett char token[MAXTOK+1]; 33095060Sjmallett int t, l; 33195060Sjmallett ndptr p; 33295060Sjmallett int nlpar; 3331590Srgrimes 3341590Srgrimes cycle { 33595060Sjmallett t = gpbc(); 33695060Sjmallett if (t == '_' || isalpha(t)) { 33795060Sjmallett p = inspect(t, token); 33895060Sjmallett if (p != nil) 33995060Sjmallett putback(l = gpbc()); 34095060Sjmallett if (p == nil || (l != LPAREN && 34195060Sjmallett (p->type & NEEDARGS) != 0)) 34295060Sjmallett outputstr(token); 3431590Srgrimes else { 3441590Srgrimes /* 3451590Srgrimes * real thing.. First build a call frame: 3461590Srgrimes */ 3471590Srgrimes pushf(fp); /* previous call frm */ 3481590Srgrimes pushf(p->type); /* type of the call */ 3491590Srgrimes pushf(0); /* parenthesis level */ 3501590Srgrimes fp = sp; /* new frame pointer */ 3511590Srgrimes /* 3521590Srgrimes * now push the string arguments: 3531590Srgrimes */ 35495060Sjmallett pushs1(p->defn); /* defn string */ 35595060Sjmallett pushs1(p->name); /* macro name */ 35695060Sjmallett pushs(ep); /* start next..*/ 3571590Srgrimes 35895060Sjmallett if (l != LPAREN && PARLEV == 0) { 35995060Sjmallett /* no bracks */ 36095060Sjmallett chrsave(EOS); 36195060Sjmallett 36298490Sjmallett if ((uintptr_t)sp == STACKMAX) 36395060Sjmallett errx(1, "internal stack overflow"); 36495060Sjmallett eval((const char **) mstack+fp+1, 2, 36595060Sjmallett CALTYP); 36695060Sjmallett 36795060Sjmallett ep = PREVEP; /* flush strspace */ 36895060Sjmallett sp = PREVSP; /* previous sp.. */ 36995060Sjmallett fp = PREVFP; /* rewind stack...*/ 3701590Srgrimes } 3711590Srgrimes } 37295060Sjmallett } else if (t == EOF) { 37395060Sjmallett if (sp > -1) { 37495060Sjmallett warnx( "unexpected end of input, unclosed parenthesis:"); 37595060Sjmallett dump_stack(paren, PARLEV); 37695060Sjmallett exit(1); 37795060Sjmallett } 3781590Srgrimes if (ilevel <= 0) 3791590Srgrimes break; /* all done thanks.. */ 38095060Sjmallett release_input(infile+ilevel--); 38194957Sjmallett free(inname[ilevel+1]); 3821590Srgrimes bufbase = bbase[ilevel]; 38394957Sjmallett emitline(); 3841590Srgrimes continue; 3851590Srgrimes } 3861590Srgrimes /* 38795060Sjmallett * non-alpha token possibly seen.. 3881590Srgrimes * [the order of else if .. stmts is important.] 3891590Srgrimes */ 39095060Sjmallett else if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ 39195060Sjmallett nlpar = 0; 39295060Sjmallett record(quotes, nlpar++); 39395060Sjmallett /* 39495060Sjmallett * Opening quote: scan forward until matching 39595060Sjmallett * closing quote has been found. 39695060Sjmallett */ 3971590Srgrimes do { 39895060Sjmallett 39995060Sjmallett l = gpbc(); 40095060Sjmallett if (LOOK_AHEAD(l,rquote)) { 40195060Sjmallett if (--nlpar > 0) 40295060Sjmallett outputstr(rquote); 40395060Sjmallett } else if (LOOK_AHEAD(l,lquote)) { 40495060Sjmallett record(quotes, nlpar++); 40595060Sjmallett outputstr(lquote); 40695060Sjmallett } else if (l == EOF) { 40795060Sjmallett if (nlpar == 1) 40895060Sjmallett warnx("unclosed quote:"); 4091590Srgrimes else 41095060Sjmallett warnx("%d unclosed quotes:", nlpar); 41195060Sjmallett dump_stack(quotes, nlpar); 41295060Sjmallett exit(1); 41395060Sjmallett } else { 41495060Sjmallett if (nlpar > 0) { 41595060Sjmallett if (sp < 0) 41695060Sjmallett putc(l, active); 41795060Sjmallett else 41895060Sjmallett CHRSAVE(l); 41995060Sjmallett } 4201590Srgrimes } 4211590Srgrimes } 4221590Srgrimes while (nlpar != 0); 4231590Srgrimes } 4241590Srgrimes 42595060Sjmallett else if (sp < 0 && LOOK_AHEAD(t, scommt)) { 42695060Sjmallett fputs(scommt, active); 42795060Sjmallett 42895060Sjmallett for(;;) { 42995060Sjmallett t = gpbc(); 43095060Sjmallett if (LOOK_AHEAD(t, ecommt)) { 43195060Sjmallett fputs(ecommt, active); 43295060Sjmallett break; 43395060Sjmallett } 43495060Sjmallett if (t == EOF) 43595060Sjmallett break; 4361590Srgrimes putc(t, active); 4371590Srgrimes } 43895060Sjmallett } 43995060Sjmallett 44095060Sjmallett else if (sp < 0) { /* not in a macro at all */ 4411590Srgrimes putc(t, active); /* output directly.. */ 4421590Srgrimes } 4431590Srgrimes 4441590Srgrimes else switch(t) { 4451590Srgrimes 4461590Srgrimes case LPAREN: 4471590Srgrimes if (PARLEV > 0) 4481590Srgrimes chrsave(t); 44995060Sjmallett while (isspace(l = gpbc())) 4501590Srgrimes ; /* skip blank, tab, nl.. */ 4511590Srgrimes putback(l); 45295060Sjmallett record(paren, PARLEV++); 4531590Srgrimes break; 4541590Srgrimes 4551590Srgrimes case RPAREN: 4561590Srgrimes if (--PARLEV > 0) 4571590Srgrimes chrsave(t); 4581590Srgrimes else { /* end of argument list */ 4591590Srgrimes chrsave(EOS); 4601590Srgrimes 46198490Sjmallett if ((uintptr_t)sp == STACKMAX) 46227625Scharnier errx(1, "internal stack overflow"); 4631590Srgrimes 46495060Sjmallett eval((const char **) mstack+fp+1, sp-fp, 46595060Sjmallett CALTYP); 4661590Srgrimes 4671590Srgrimes ep = PREVEP; /* flush strspace */ 4681590Srgrimes sp = PREVSP; /* previous sp.. */ 4691590Srgrimes fp = PREVFP; /* rewind stack...*/ 4701590Srgrimes } 4711590Srgrimes break; 4721590Srgrimes 4731590Srgrimes case COMMA: 4741590Srgrimes if (PARLEV == 1) { 4751590Srgrimes chrsave(EOS); /* new argument */ 47695060Sjmallett while (isspace(l = gpbc())) 4771590Srgrimes ; 4781590Srgrimes putback(l); 4791590Srgrimes pushs(ep); 4801590Srgrimes } else 4811590Srgrimes chrsave(t); 4821590Srgrimes break; 4831590Srgrimes 4841590Srgrimes default: 48595060Sjmallett if (LOOK_AHEAD(t, scommt)) { 48695095Sjmallett char *pc; 48795095Sjmallett for (pc = scommt; *pc; pc++) 48895095Sjmallett chrsave(*pc); 48995060Sjmallett for(;;) { 49095060Sjmallett t = gpbc(); 49195060Sjmallett if (LOOK_AHEAD(t, ecommt)) { 49295095Sjmallett for (pc = ecommt; *pc; pc++) 49395095Sjmallett chrsave(*pc); 49495060Sjmallett break; 49595060Sjmallett } 49695060Sjmallett if (t == EOF) 49795060Sjmallett break; 49895060Sjmallett CHRSAVE(t); 49995060Sjmallett } 50095060Sjmallett } else 50195060Sjmallett CHRSAVE(t); /* stack the char */ 5021590Srgrimes break; 5031590Srgrimes } 5041590Srgrimes } 5051590Srgrimes} 5061590Srgrimes 50795060Sjmallett/* 50895060Sjmallett * output string directly, without pushing it for reparses. 50995060Sjmallett */ 51095060Sjmallettvoid 51195887Sjmallettoutputstr(const char *s) 51295060Sjmallett{ 51395060Sjmallett if (sp < 0) 51495060Sjmallett while (*s) 51595060Sjmallett putc(*s++, active); 51695060Sjmallett else 51795060Sjmallett while (*s) 51895060Sjmallett CHRSAVE(*s++); 51995060Sjmallett} 52095060Sjmallett 5211590Srgrimes/* 5221590Srgrimes * build an input token.. 5231590Srgrimes * consider only those starting with _ or A-Za-z. This is a 5241590Srgrimes * combo with lookup to speed things up. 5251590Srgrimes */ 52695060Sjmallettstatic ndptr 52795887Sjmallettinspect(int c, char *tp) 5281590Srgrimes{ 52995060Sjmallett char *name = tp; 53095060Sjmallett char *etp = tp+MAXTOK; 53195060Sjmallett ndptr p; 53295060Sjmallett unsigned int h; 53395060Sjmallett 53495060Sjmallett h = *tp++ = c; 5351590Srgrimes 53695060Sjmallett while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 5371590Srgrimes h = (h << 5) + h + (*tp++ = c); 53895060Sjmallett if (c != EOF) 53995060Sjmallett PUTBACK(c); 5401590Srgrimes *tp = EOS; 54195060Sjmallett /* token is too long, it won't match anything, but it can still 54295060Sjmallett * be output. */ 54395060Sjmallett if (tp == ep) { 54495060Sjmallett outputstr(name); 54595060Sjmallett while (isalnum(c = gpbc()) || c == '_') { 54695060Sjmallett if (sp < 0) 54795060Sjmallett putc(c, active); 54895060Sjmallett else 54995060Sjmallett CHRSAVE(c); 55095060Sjmallett } 55195060Sjmallett *name = EOS; 55295060Sjmallett return nil; 55395060Sjmallett } 5541590Srgrimes 55595060Sjmallett for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr) 55695060Sjmallett if (h == p->hv && STREQ(name, p->name)) 5571590Srgrimes break; 5581590Srgrimes return p; 5591590Srgrimes} 5601590Srgrimes 5611590Srgrimes/* 56295060Sjmallett * initkwds - initialise m4 keywords as fast as possible. 5631590Srgrimes * This very similar to install, but without certain overheads, 56495060Sjmallett * such as calling lookup. Malloc is not used for storing the 56595060Sjmallett * keyword strings, since we simply use the static pointers 5661590Srgrimes * within keywrds block. 5671590Srgrimes */ 56895060Sjmallettstatic void 56999939Sjmallettinitkwds(void) 57095060Sjmallett{ 57195060Sjmallett size_t i; 57295060Sjmallett unsigned int h; 57395060Sjmallett ndptr p; 5741590Srgrimes 5751590Srgrimes for (i = 0; i < MAXKEYS; i++) { 5761590Srgrimes h = hash(keywrds[i].knam); 57795060Sjmallett p = (ndptr) xalloc(sizeof(struct ndblock)); 57895060Sjmallett p->nxtptr = hashtab[h % HASHSIZE]; 57995060Sjmallett hashtab[h % HASHSIZE] = p; 58095060Sjmallett p->name = xstrdup(keywrds[i].knam); 58195095Sjmallett p->defn = xstrdup(null); 58295060Sjmallett p->hv = h; 58395060Sjmallett p->type = keywrds[i].ktyp & TYPEMASK; 58495060Sjmallett if ((keywrds[i].ktyp & NOARGS) == 0) 58595060Sjmallett p->type |= NEEDARGS; 5861590Srgrimes } 5871590Srgrimes} 58894957Sjmallett 58995060Sjmallett/* Look up a builtin type, even if overridden by the user */ 59095060Sjmallettint 59195887Sjmallettbuiltin_type(const char *key) 59295060Sjmallett{ 59395060Sjmallett int i; 59495060Sjmallett 59595060Sjmallett for (i = 0; i != MAXKEYS; i++) 59695060Sjmallett if (STREQ(keywrds[i].knam, key)) 59795060Sjmallett return keywrds[i].ktyp; 59895060Sjmallett return -1; 59995060Sjmallett} 60095060Sjmallett 60195095Sjmallettconst char * 60295887Sjmallettbuiltin_realname(int n) 60395060Sjmallett{ 60495060Sjmallett int i; 60595060Sjmallett 60695060Sjmallett for (i = 0; i != MAXKEYS; i++) 60795060Sjmallett if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0) 60895060Sjmallett return keywrds[i].knam; 60995060Sjmallett return NULL; 61095060Sjmallett} 61195060Sjmallett 61295060Sjmallettstatic void 61395887Sjmallettrecord(struct position *t, int lev) 61495060Sjmallett{ 61595060Sjmallett if (lev < MAXRECORD) { 61695060Sjmallett t[lev].name = CURRENT_NAME; 61795060Sjmallett t[lev].line = CURRENT_LINE; 61895060Sjmallett } 61995060Sjmallett} 62095060Sjmallett 62195060Sjmallettstatic void 62295887Sjmallettdump_stack(struct position *t, int lev) 62395060Sjmallett{ 62495060Sjmallett int i; 62595060Sjmallett 62695060Sjmallett for (i = 0; i < lev; i++) { 62795060Sjmallett if (i == MAXRECORD) { 62895060Sjmallett fprintf(stderr, " ...\n"); 62995060Sjmallett break; 63095060Sjmallett } 63195060Sjmallett fprintf(stderr, " %s at line %lu\n", 63295060Sjmallett t[i].name, t[i].line); 63395060Sjmallett } 63495060Sjmallett} 63595060Sjmallett 63695060Sjmallett 63795060Sjmallettstatic void 63899939Sjmallettenlarge_stack(void) 63995060Sjmallett{ 64095060Sjmallett STACKMAX *= 2; 64195060Sjmallett mstack = realloc(mstack, sizeof(stae) * STACKMAX); 64295060Sjmallett sstack = realloc(sstack, STACKMAX); 64395060Sjmallett if (mstack == NULL || sstack == NULL) 64495060Sjmallett errx(1, "Evaluation stack overflow (%lu)", 64595060Sjmallett (unsigned long)STACKMAX); 64695060Sjmallett} 64795060Sjmallett 64894957Sjmallett/* Emit preprocessor #line directive if -s option used. */ 64994957Sjmallettvoid 65094957Sjmallettemitline(void) 65194957Sjmallett{ 65295060Sjmallett 65394957Sjmallett if (synccpp) 65494957Sjmallett fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel], 65595060Sjmallett inname[ilevel]); 65694957Sjmallett} 657