main.c revision 95060
195060Sjmallett/* $OpenBSD: main.c,v 1.52 2002/02/16 21:27:48 millert 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 4095060Sjmallett#include <sys/cdefs.h> 4195060Sjmallett__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ 4295060Sjmallett The Regents of the University of California. All rights reserved.\n"); 4395060Sjmallett__SCCSID("@(#)main.c 8.1 (Berkeley) 6/6/93"); 4495060Sjmallett__RCSID_SOURCE("$OpenBSD: main.c,v 1.52 2002/02/16 21:27:48 millert Exp $"); 4595060Sjmallett__FBSDID("$FreeBSD: head/usr.bin/m4/main.c 95060 2002-04-19 17:26:21Z jmallett $"); 461590Srgrimes 471590Srgrimes/* 481590Srgrimes * main.c 491590Srgrimes * Facility: m4 macro processor 501590Srgrimes * by: oz 511590Srgrimes */ 521590Srgrimes 531590Srgrimes#include <sys/types.h> 5495060Sjmallett#include <assert.h> 551590Srgrimes#include <signal.h> 5695060Sjmallett#include <errno.h> 5795060Sjmallett#include <unistd.h> 581590Srgrimes#include <stdio.h> 5995060Sjmallett#include <ctype.h> 6095060Sjmallett#include <string.h> 6195060Sjmallett#include <stddef.h> 6280289Sobrien#include <stdlib.h> 6395060Sjmallett#include <err.h> 641590Srgrimes#include "mdef.h" 651590Srgrimes#include "stdd.h" 661590Srgrimes#include "extern.h" 671590Srgrimes#include "pathnames.h" 681590Srgrimes 691590Srgrimesndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 7095060Sjmallettstae *mstack; /* stack of m4 machine */ 7195060Sjmallettchar *sstack; /* shadow stack, for string space extension */ 7295060Sjmallettstatic size_t STACKMAX; /* current maximum size of stack */ 731590Srgrimesint sp; /* current m4 stack pointer */ 741590Srgrimesint fp; /* m4 call frame pointer */ 7595060Sjmallettstruct input_file infile[MAXINP];/* input file stack (0=stdin) */ 7695060Sjmallettchar *inname[MAXINP]; /* names of these input files */ 7795060Sjmallettint inlineno[MAXINP]; /* current number in each input file */ 7895060SjmallettFILE **outfile; /* diversion array(0=bitbucket)*/ 7995060Sjmallettint maxout; 801590SrgrimesFILE *active; /* active output file pointer */ 811590Srgrimesint ilevel = 0; /* input file stack pointer */ 821590Srgrimesint oindex = 0; /* diversion index.. */ 831590Srgrimeschar *null = ""; /* as it says.. just a null.. */ 841590Srgrimeschar *m4wraps = ""; /* m4wrap string default.. */ 8595060Sjmallettchar lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ 8695060Sjmallettchar rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ 8795060Sjmallettchar scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ 8895060Sjmallettchar ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ 8994957Sjmallettint synccpp; /* Line synchronisation for C preprocessor */ 9094957Sjmallettint chscratch; /* Scratch space for gpbc() macro */ 911590Srgrimes 921590Srgrimesstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 9395060Sjmallett { "include", INCLTYPE }, 9495060Sjmallett { "sinclude", SINCTYPE }, 9595060Sjmallett { "define", DEFITYPE }, 9695060Sjmallett { "defn", DEFNTYPE }, 9795060Sjmallett { "divert", DIVRTYPE | NOARGS }, 9895060Sjmallett { "expr", EXPRTYPE }, 9995060Sjmallett { "eval", EXPRTYPE }, 10095060Sjmallett { "substr", SUBSTYPE }, 10195060Sjmallett { "ifelse", IFELTYPE }, 10295060Sjmallett { "ifdef", IFDFTYPE }, 10395060Sjmallett { "len", LENGTYPE }, 10495060Sjmallett { "incr", INCRTYPE }, 10595060Sjmallett { "decr", DECRTYPE }, 10695060Sjmallett { "dnl", DNLNTYPE | NOARGS }, 10795060Sjmallett { "changequote", CHNQTYPE | NOARGS }, 10895060Sjmallett { "changecom", CHNCTYPE | NOARGS }, 10995060Sjmallett { "index", INDXTYPE }, 1101590Srgrimes#ifdef EXTENDED 11195060Sjmallett { "paste", PASTTYPE }, 11295060Sjmallett { "spaste", SPASTYPE }, 11395060Sjmallett /* Newer extensions, needed to handle gnu-m4 scripts */ 11495060Sjmallett { "indir", INDIRTYPE}, 11595060Sjmallett { "builtin", BUILTINTYPE}, 11695060Sjmallett { "patsubst", PATSTYPE}, 11795060Sjmallett { "regexp", REGEXPTYPE}, 11895060Sjmallett { "esyscmd", ESYSCMDTYPE}, 11995060Sjmallett { "__file__", FILENAMETYPE | NOARGS}, 12095060Sjmallett { "__line__", LINETYPE | NOARGS}, 1211590Srgrimes#endif 12295060Sjmallett { "popdef", POPDTYPE }, 12395060Sjmallett { "pushdef", PUSDTYPE }, 12495060Sjmallett { "dumpdef", DUMPTYPE | NOARGS }, 12595060Sjmallett { "shift", SHIFTYPE | NOARGS }, 12695060Sjmallett { "translit", TRNLTYPE }, 12795060Sjmallett { "undefine", UNDFTYPE }, 12895060Sjmallett { "undivert", UNDVTYPE | NOARGS }, 12995060Sjmallett { "divnum", DIVNTYPE | NOARGS }, 13095060Sjmallett { "maketemp", MKTMTYPE }, 13195060Sjmallett { "errprint", ERRPTYPE | NOARGS }, 13295060Sjmallett { "m4wrap", M4WRTYPE | NOARGS }, 13395060Sjmallett { "m4exit", EXITTYPE | NOARGS }, 13495060Sjmallett { "syscmd", SYSCTYPE }, 13595060Sjmallett { "sysval", SYSVTYPE | NOARGS }, 13695060Sjmallett { "traceon", TRACEONTYPE | NOARGS }, 13795060Sjmallett { "traceoff", TRACEOFFTYPE | NOARGS }, 1381590Srgrimes 13995060Sjmallett#if defined(unix) || defined(__unix__) 14095060Sjmallett { "unix", SELFTYPE | NOARGS }, 1411590Srgrimes#else 1421590Srgrimes#ifdef vms 14395060Sjmallett { "vms", SELFTYPE | NOARGS }, 1441590Srgrimes#endif 1451590Srgrimes#endif 1461590Srgrimes}; 1471590Srgrimes 1481590Srgrimes#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1491590Srgrimes 15095060Sjmallettextern int optind; 15195060Sjmallettextern char *optarg; 1521590Srgrimes 15395060Sjmallett#define MAXRECORD 50 15495060Sjmallettstatic struct position { 15595060Sjmallett char *name; 15695060Sjmallett unsigned long line; 15795060Sjmallett} quotes[MAXRECORD], paren[MAXRECORD]; 15895060Sjmallett 15995060Sjmallettstatic void record(struct position *, int); 16095060Sjmallettstatic void dump_stack(struct position *, int); 16195060Sjmallett 16295060Sjmallettstatic void macro(void); 16395060Sjmallettstatic void initkwds(void); 16495060Sjmallettstatic ndptr inspect(int, char *); 16595060Sjmallettstatic int do_look_ahead(int, const char *); 16695060Sjmallett 16795060Sjmallettstatic void enlarge_stack(void); 16895060Sjmallett 16995060Sjmallettint main(int, char *[]); 17095060Sjmallett 1711590Srgrimesint 1721590Srgrimesmain(argc,argv) 1731590Srgrimes int argc; 1741590Srgrimes char *argv[]; 1751590Srgrimes{ 17695060Sjmallett int c; 17795060Sjmallett int n; 1781590Srgrimes char *p; 1791590Srgrimes 18095060Sjmallett traceout = stderr; 18195060Sjmallett 1821590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1831590Srgrimes signal(SIGINT, onintr); 1841590Srgrimes 1851590Srgrimes initkwds(); 18695060Sjmallett initspaces(); 18795060Sjmallett STACKMAX = INITSTACKMAX; 1881590Srgrimes 18995060Sjmallett mstack = (stae *)xalloc(sizeof(stae) * STACKMAX); 19095060Sjmallett sstack = (char *)xalloc(STACKMAX); 19195060Sjmallett 19295060Sjmallett maxout = 0; 19395060Sjmallett outfile = NULL; 19495060Sjmallett resizedivs(MAXOUT); 19595060Sjmallett 19695060Sjmallett while ((c = getopt(argc, argv, "gst:d:D:U:o:I:")) != -1) 1971590Srgrimes switch(c) { 1981590Srgrimes 1991590Srgrimes case 'D': /* define something..*/ 2001590Srgrimes for (p = optarg; *p; p++) 2011590Srgrimes if (*p == '=') 2021590Srgrimes break; 2031590Srgrimes if (*p) 2041590Srgrimes *p++ = EOS; 2051590Srgrimes dodefine(optarg, p); 2061590Srgrimes break; 20795060Sjmallett case 'I': 20895060Sjmallett addtoincludepath(optarg); 20995060Sjmallett break; 2101590Srgrimes case 'U': /* undefine... */ 2111590Srgrimes remhash(optarg, TOP); 2121590Srgrimes break; 21395060Sjmallett case 'g': 21495060Sjmallett mimic_gnu = 1; 21595060Sjmallett break; 21695060Sjmallett case 'd': 21795060Sjmallett set_trace_flags(optarg); 21895060Sjmallett break; 21994957Sjmallett case 's': 22094957Sjmallett synccpp = 1; 22194957Sjmallett break; 22295060Sjmallett case 't': 22395060Sjmallett mark_traced(optarg, 1); 22495060Sjmallett break; 22595060Sjmallett case 'o': 22695060Sjmallett trace_file(optarg); 22795060Sjmallett break; 2281590Srgrimes case '?': 2291590Srgrimes usage(); 2301590Srgrimes } 2311590Srgrimes 2321590Srgrimes argc -= optind; 2331590Srgrimes argv += optind; 2341590Srgrimes 2351590Srgrimes active = stdout; /* default active output */ 2361590Srgrimes bbase[0] = bufbase; 2371590Srgrimes if (!argc) { 2381590Srgrimes sp = -1; /* stack pointer initialized */ 2391590Srgrimes fp = 0; /* frame pointer initialized */ 24095060Sjmallett set_input(infile+0, stdin, "stdin"); 24195060Sjmallett /* default input (naturally) */ 24294957Sjmallett if ((inname[0] = strdup("-")) == NULL) 24394957Sjmallett err(1, NULL); 24494957Sjmallett inlineno[0] = 1; 24594957Sjmallett emitline(); 2461590Srgrimes macro(); 2471590Srgrimes } else 2481590Srgrimes for (; argc--; ++argv) { 2491590Srgrimes p = *argv; 25095060Sjmallett if (p[0] == '-' && p[1] == EOS) 25195060Sjmallett set_input(infile, stdin, "stdin"); 25295060Sjmallett else if (fopen_trypath(infile, p) == NULL) 25327625Scharnier err(1, "%s", p); 2541590Srgrimes sp = -1; 25595060Sjmallett fp = 0; 25694957Sjmallett if ((inname[0] = strdup(p)) == NULL) 25794957Sjmallett err(1, NULL); 25894957Sjmallett inlineno[0] = 1; 25994957Sjmallett emitline(); 2601590Srgrimes macro(); 26195060Sjmallett release_input(infile); 2621590Srgrimes } 2631590Srgrimes 2641590Srgrimes if (*m4wraps) { /* anything for rundown ?? */ 2651590Srgrimes ilevel = 0; /* in case m4wrap includes.. */ 2661590Srgrimes bufbase = bp = buf; /* use the entire buffer */ 2671590Srgrimes pbstr(m4wraps); /* user-defined wrapup act */ 2681590Srgrimes macro(); /* last will and testament */ 2691590Srgrimes } 2701590Srgrimes 2711590Srgrimes if (active != stdout) 2721590Srgrimes active = stdout; /* reset output just in case */ 27395060Sjmallett for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ 2741590Srgrimes if (outfile[n] != NULL) 2751590Srgrimes getdiv(n); 2761590Srgrimes /* remove bitbucket if used */ 27795060Sjmallett if (outfile[0] != NULL) { 27895060Sjmallett (void) fclose(outfile[0]); 27995060Sjmallett } 28095060Sjmallett 2811590Srgrimes return 0; 2821590Srgrimes} 2831590Srgrimes 28495060Sjmallett/* 28595060Sjmallett * Look ahead for `token'. 28695060Sjmallett * (on input `t == token[0]') 28795060Sjmallett * Used for comment and quoting delimiters. 28895060Sjmallett * Returns 1 if `token' present; copied to output. 28995060Sjmallett * 0 if `token' not found; all characters pushed back 29095060Sjmallett */ 29195060Sjmallettstatic int 29295060Sjmallettdo_look_ahead(t, token) 29395060Sjmallett int t; 29495060Sjmallett const char *token; 29595060Sjmallett{ 29695060Sjmallett int i; 2971590Srgrimes 29895060Sjmallett assert((unsigned char)t == (unsigned char)token[0]); 29995060Sjmallett 30095060Sjmallett for (i = 1; *++token; i++) { 30195060Sjmallett t = gpbc(); 30295060Sjmallett if (t == EOF || (unsigned char)t != (unsigned char)*token) { 30395060Sjmallett putback(t); 30495060Sjmallett while (--i) 30595060Sjmallett putback(*--token); 30695060Sjmallett return 0; 30795060Sjmallett } 30895060Sjmallett } 30995060Sjmallett return 1; 31095060Sjmallett} 31195060Sjmallett 31295060Sjmallett#define LOOK_AHEAD(t, token) (t != EOF && \ 31395060Sjmallett (unsigned char)(t)==(unsigned char)(token)[0] && \ 31495060Sjmallett do_look_ahead(t,token)) 31595060Sjmallett 3161590Srgrimes/* 3171590Srgrimes * macro - the work horse.. 3181590Srgrimes */ 31995060Sjmallettstatic void 32095060Sjmallettmacro() 32195060Sjmallett{ 32295060Sjmallett char token[MAXTOK+1]; 32395060Sjmallett int t, l; 32495060Sjmallett ndptr p; 32595060Sjmallett int nlpar; 3261590Srgrimes 3271590Srgrimes cycle { 32895060Sjmallett t = gpbc(); 32995060Sjmallett if (t == '_' || isalpha(t)) { 33095060Sjmallett p = inspect(t, token); 33195060Sjmallett if (p != nil) 33295060Sjmallett putback(l = gpbc()); 33395060Sjmallett if (p == nil || (l != LPAREN && 33495060Sjmallett (p->type & NEEDARGS) != 0)) 33595060Sjmallett outputstr(token); 3361590Srgrimes else { 3371590Srgrimes /* 3381590Srgrimes * real thing.. First build a call frame: 3391590Srgrimes */ 3401590Srgrimes pushf(fp); /* previous call frm */ 3411590Srgrimes pushf(p->type); /* type of the call */ 3421590Srgrimes pushf(0); /* parenthesis level */ 3431590Srgrimes fp = sp; /* new frame pointer */ 3441590Srgrimes /* 3451590Srgrimes * now push the string arguments: 3461590Srgrimes */ 34795060Sjmallett pushs1(p->defn); /* defn string */ 34895060Sjmallett pushs1(p->name); /* macro name */ 34995060Sjmallett pushs(ep); /* start next..*/ 3501590Srgrimes 35195060Sjmallett if (l != LPAREN && PARLEV == 0) { 35295060Sjmallett /* no bracks */ 35395060Sjmallett chrsave(EOS); 35495060Sjmallett 35595060Sjmallett if (sp == STACKMAX) 35695060Sjmallett errx(1, "internal stack overflow"); 35795060Sjmallett eval((const char **) mstack+fp+1, 2, 35895060Sjmallett CALTYP); 35995060Sjmallett 36095060Sjmallett ep = PREVEP; /* flush strspace */ 36195060Sjmallett sp = PREVSP; /* previous sp.. */ 36295060Sjmallett fp = PREVFP; /* rewind stack...*/ 3631590Srgrimes } 3641590Srgrimes } 36595060Sjmallett } else if (t == EOF) { 36695060Sjmallett if (sp > -1) { 36795060Sjmallett warnx( "unexpected end of input, unclosed parenthesis:"); 36895060Sjmallett dump_stack(paren, PARLEV); 36995060Sjmallett exit(1); 37095060Sjmallett } 3711590Srgrimes if (ilevel <= 0) 3721590Srgrimes break; /* all done thanks.. */ 37395060Sjmallett release_input(infile+ilevel--); 37494957Sjmallett free(inname[ilevel+1]); 3751590Srgrimes bufbase = bbase[ilevel]; 37694957Sjmallett emitline(); 3771590Srgrimes continue; 3781590Srgrimes } 3791590Srgrimes /* 38095060Sjmallett * non-alpha token possibly seen.. 3811590Srgrimes * [the order of else if .. stmts is important.] 3821590Srgrimes */ 38395060Sjmallett else if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ 38495060Sjmallett nlpar = 0; 38595060Sjmallett record(quotes, nlpar++); 38695060Sjmallett /* 38795060Sjmallett * Opening quote: scan forward until matching 38895060Sjmallett * closing quote has been found. 38995060Sjmallett */ 3901590Srgrimes do { 39195060Sjmallett 39295060Sjmallett l = gpbc(); 39395060Sjmallett if (LOOK_AHEAD(l,rquote)) { 39495060Sjmallett if (--nlpar > 0) 39595060Sjmallett outputstr(rquote); 39695060Sjmallett } else if (LOOK_AHEAD(l,lquote)) { 39795060Sjmallett record(quotes, nlpar++); 39895060Sjmallett outputstr(lquote); 39995060Sjmallett } else if (l == EOF) { 40095060Sjmallett if (nlpar == 1) 40195060Sjmallett warnx("unclosed quote:"); 4021590Srgrimes else 40395060Sjmallett warnx("%d unclosed quotes:", nlpar); 40495060Sjmallett dump_stack(quotes, nlpar); 40595060Sjmallett exit(1); 40695060Sjmallett } else { 40795060Sjmallett if (nlpar > 0) { 40895060Sjmallett if (sp < 0) 40995060Sjmallett putc(l, active); 41095060Sjmallett else 41195060Sjmallett CHRSAVE(l); 41295060Sjmallett } 4131590Srgrimes } 4141590Srgrimes } 4151590Srgrimes while (nlpar != 0); 4161590Srgrimes } 4171590Srgrimes 41895060Sjmallett else if (sp < 0 && LOOK_AHEAD(t, scommt)) { 41995060Sjmallett fputs(scommt, active); 42095060Sjmallett 42195060Sjmallett for(;;) { 42295060Sjmallett t = gpbc(); 42395060Sjmallett if (LOOK_AHEAD(t, ecommt)) { 42495060Sjmallett fputs(ecommt, active); 42595060Sjmallett break; 42695060Sjmallett } 42795060Sjmallett if (t == EOF) 42895060Sjmallett break; 4291590Srgrimes putc(t, active); 4301590Srgrimes } 43195060Sjmallett } 43295060Sjmallett 43395060Sjmallett else if (sp < 0) { /* not in a macro at all */ 4341590Srgrimes putc(t, active); /* output directly.. */ 4351590Srgrimes } 4361590Srgrimes 4371590Srgrimes else switch(t) { 4381590Srgrimes 4391590Srgrimes case LPAREN: 4401590Srgrimes if (PARLEV > 0) 4411590Srgrimes chrsave(t); 44295060Sjmallett while (isspace(l = gpbc())) 4431590Srgrimes ; /* skip blank, tab, nl.. */ 4441590Srgrimes putback(l); 44595060Sjmallett record(paren, PARLEV++); 4461590Srgrimes break; 4471590Srgrimes 4481590Srgrimes case RPAREN: 4491590Srgrimes if (--PARLEV > 0) 4501590Srgrimes chrsave(t); 4511590Srgrimes else { /* end of argument list */ 4521590Srgrimes chrsave(EOS); 4531590Srgrimes 4541590Srgrimes if (sp == STACKMAX) 45527625Scharnier errx(1, "internal stack overflow"); 4561590Srgrimes 45795060Sjmallett eval((const char **) mstack+fp+1, sp-fp, 45895060Sjmallett CALTYP); 4591590Srgrimes 4601590Srgrimes ep = PREVEP; /* flush strspace */ 4611590Srgrimes sp = PREVSP; /* previous sp.. */ 4621590Srgrimes fp = PREVFP; /* rewind stack...*/ 4631590Srgrimes } 4641590Srgrimes break; 4651590Srgrimes 4661590Srgrimes case COMMA: 4671590Srgrimes if (PARLEV == 1) { 4681590Srgrimes chrsave(EOS); /* new argument */ 46995060Sjmallett while (isspace(l = gpbc())) 4701590Srgrimes ; 4711590Srgrimes putback(l); 4721590Srgrimes pushs(ep); 4731590Srgrimes } else 4741590Srgrimes chrsave(t); 4751590Srgrimes break; 4761590Srgrimes 4771590Srgrimes default: 47895060Sjmallett if (LOOK_AHEAD(t, scommt)) { 47995060Sjmallett char *p; 48095060Sjmallett for (p = scommt; *p; p++) 48195060Sjmallett chrsave(*p); 48295060Sjmallett for(;;) { 48395060Sjmallett t = gpbc(); 48495060Sjmallett if (LOOK_AHEAD(t, ecommt)) { 48595060Sjmallett for (p = ecommt; *p; p++) 48695060Sjmallett chrsave(*p); 48795060Sjmallett break; 48895060Sjmallett } 48995060Sjmallett if (t == EOF) 49095060Sjmallett break; 49195060Sjmallett CHRSAVE(t); 49295060Sjmallett } 49395060Sjmallett } else 49495060Sjmallett CHRSAVE(t); /* stack the char */ 4951590Srgrimes break; 4961590Srgrimes } 4971590Srgrimes } 4981590Srgrimes} 4991590Srgrimes 50095060Sjmallett/* 50195060Sjmallett * output string directly, without pushing it for reparses. 50295060Sjmallett */ 50395060Sjmallettvoid 50495060Sjmallettoutputstr(s) 50595060Sjmallett const char *s; 50695060Sjmallett{ 50795060Sjmallett if (sp < 0) 50895060Sjmallett while (*s) 50995060Sjmallett putc(*s++, active); 51095060Sjmallett else 51195060Sjmallett while (*s) 51295060Sjmallett CHRSAVE(*s++); 51395060Sjmallett} 51495060Sjmallett 5151590Srgrimes/* 5161590Srgrimes * build an input token.. 5171590Srgrimes * consider only those starting with _ or A-Za-z. This is a 5181590Srgrimes * combo with lookup to speed things up. 5191590Srgrimes */ 52095060Sjmallettstatic ndptr 52195060Sjmallettinspect(c, tp) 52295060Sjmallett int c; 52395060Sjmallett char *tp; 5241590Srgrimes{ 52595060Sjmallett char *name = tp; 52695060Sjmallett char *etp = tp+MAXTOK; 52795060Sjmallett ndptr p; 52895060Sjmallett unsigned int h; 52995060Sjmallett 53095060Sjmallett h = *tp++ = c; 5311590Srgrimes 53295060Sjmallett while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 5331590Srgrimes h = (h << 5) + h + (*tp++ = c); 53495060Sjmallett if (c != EOF) 53595060Sjmallett PUTBACK(c); 5361590Srgrimes *tp = EOS; 53795060Sjmallett /* token is too long, it won't match anything, but it can still 53895060Sjmallett * be output. */ 53995060Sjmallett if (tp == ep) { 54095060Sjmallett outputstr(name); 54195060Sjmallett while (isalnum(c = gpbc()) || c == '_') { 54295060Sjmallett if (sp < 0) 54395060Sjmallett putc(c, active); 54495060Sjmallett else 54595060Sjmallett CHRSAVE(c); 54695060Sjmallett } 54795060Sjmallett *name = EOS; 54895060Sjmallett return nil; 54995060Sjmallett } 5501590Srgrimes 55195060Sjmallett for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr) 55295060Sjmallett if (h == p->hv && STREQ(name, p->name)) 5531590Srgrimes break; 5541590Srgrimes return p; 5551590Srgrimes} 5561590Srgrimes 5571590Srgrimes/* 55895060Sjmallett * initkwds - initialise m4 keywords as fast as possible. 5591590Srgrimes * This very similar to install, but without certain overheads, 56095060Sjmallett * such as calling lookup. Malloc is not used for storing the 56195060Sjmallett * keyword strings, since we simply use the static pointers 5621590Srgrimes * within keywrds block. 5631590Srgrimes */ 56495060Sjmallettstatic void 56595060Sjmallettinitkwds() 56695060Sjmallett{ 56795060Sjmallett size_t i; 56895060Sjmallett unsigned int h; 56995060Sjmallett ndptr p; 5701590Srgrimes 5711590Srgrimes for (i = 0; i < MAXKEYS; i++) { 5721590Srgrimes h = hash(keywrds[i].knam); 57395060Sjmallett p = (ndptr) xalloc(sizeof(struct ndblock)); 57495060Sjmallett p->nxtptr = hashtab[h % HASHSIZE]; 57595060Sjmallett hashtab[h % HASHSIZE] = p; 57695060Sjmallett p->name = xstrdup(keywrds[i].knam); 5771590Srgrimes p->defn = null; 57895060Sjmallett p->hv = h; 57995060Sjmallett p->type = keywrds[i].ktyp & TYPEMASK; 58095060Sjmallett if ((keywrds[i].ktyp & NOARGS) == 0) 58195060Sjmallett p->type |= NEEDARGS; 5821590Srgrimes } 5831590Srgrimes} 58494957Sjmallett 58595060Sjmallett/* Look up a builtin type, even if overridden by the user */ 58695060Sjmallettint 58795060Sjmallettbuiltin_type(key) 58895060Sjmallett const char *key; 58995060Sjmallett{ 59095060Sjmallett int i; 59195060Sjmallett 59295060Sjmallett for (i = 0; i != MAXKEYS; i++) 59395060Sjmallett if (STREQ(keywrds[i].knam, key)) 59495060Sjmallett return keywrds[i].ktyp; 59595060Sjmallett return -1; 59695060Sjmallett} 59795060Sjmallett 59895060Sjmallettchar * 59995060Sjmallettbuiltin_realname(n) 60095060Sjmallett int n; 60195060Sjmallett{ 60295060Sjmallett int i; 60395060Sjmallett 60495060Sjmallett for (i = 0; i != MAXKEYS; i++) 60595060Sjmallett if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0) 60695060Sjmallett return keywrds[i].knam; 60795060Sjmallett return NULL; 60895060Sjmallett} 60995060Sjmallett 61095060Sjmallettstatic void 61195060Sjmallettrecord(t, lev) 61295060Sjmallett struct position *t; 61395060Sjmallett int lev; 61495060Sjmallett{ 61595060Sjmallett if (lev < MAXRECORD) { 61695060Sjmallett t[lev].name = CURRENT_NAME; 61795060Sjmallett t[lev].line = CURRENT_LINE; 61895060Sjmallett } 61995060Sjmallett} 62095060Sjmallett 62195060Sjmallettstatic void 62295060Sjmallettdump_stack(t, lev) 62395060Sjmallett struct position *t; 62495060Sjmallett int lev; 62595060Sjmallett{ 62695060Sjmallett int i; 62795060Sjmallett 62895060Sjmallett for (i = 0; i < lev; i++) { 62995060Sjmallett if (i == MAXRECORD) { 63095060Sjmallett fprintf(stderr, " ...\n"); 63195060Sjmallett break; 63295060Sjmallett } 63395060Sjmallett fprintf(stderr, " %s at line %lu\n", 63495060Sjmallett t[i].name, t[i].line); 63595060Sjmallett } 63695060Sjmallett} 63795060Sjmallett 63895060Sjmallett 63995060Sjmallettstatic void 64095060Sjmallettenlarge_stack() 64195060Sjmallett{ 64295060Sjmallett STACKMAX *= 2; 64395060Sjmallett mstack = realloc(mstack, sizeof(stae) * STACKMAX); 64495060Sjmallett sstack = realloc(sstack, STACKMAX); 64595060Sjmallett if (mstack == NULL || sstack == NULL) 64695060Sjmallett errx(1, "Evaluation stack overflow (%lu)", 64795060Sjmallett (unsigned long)STACKMAX); 64895060Sjmallett} 64995060Sjmallett 65094957Sjmallett/* Emit preprocessor #line directive if -s option used. */ 65194957Sjmallettvoid 65294957Sjmallettemitline(void) 65394957Sjmallett{ 65495060Sjmallett 65594957Sjmallett if (synccpp) 65694957Sjmallett fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel], 65795060Sjmallett inname[ilevel]); 65894957Sjmallett} 659