138823Sbostic /* 238823Sbostic * Copyright (c) 1989 The Regents of the University of California. 338823Sbostic * All rights reserved. 438823Sbostic * 538823Sbostic * This code is derived from software contributed to Berkeley by 638823Sbostic * Ozan Yigit. 738823Sbostic * 842689Sbostic * %sccs.include.redist.c% 938823Sbostic */ 1038823Sbostic 1138823Sbostic #ifndef lint 12*50960Sbostic static char sccsid[] = "@(#)main.c 5.7 (Berkeley) 09/03/91"; 1338823Sbostic #endif /* not lint */ 1438823Sbostic 1538823Sbostic /* 1638823Sbostic * main.c 1738823Sbostic * Facility: m4 macro processor 1838823Sbostic * by: oz 1938823Sbostic */ 2038823Sbostic 21*50960Sbostic #include <sys/types.h> 2246697Sbostic #include <signal.h> 23*50960Sbostic #include <errno.h> 2446697Sbostic #include <unistd.h> 2546697Sbostic #include <stdio.h> 26*50960Sbostic #include <ctype.h> 2746697Sbostic #include <string.h> 2838823Sbostic #include "mdef.h" 29*50960Sbostic #include "stdd.h" 30*50960Sbostic #include "extern.h" 3146697Sbostic #include "pathnames.h" 3238823Sbostic 3338823Sbostic ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 3438823Sbostic char buf[BUFSIZE]; /* push-back buffer */ 3538823Sbostic char *bp = buf; /* first available character */ 3638823Sbostic char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 3738823Sbostic stae mstack[STACKMAX+1]; /* stack of m4 machine */ 3838823Sbostic char strspace[STRSPMAX+1]; /* string space for evaluation */ 3938823Sbostic char *ep = strspace; /* first free char in strspace */ 4038823Sbostic char *endest= strspace+STRSPMAX;/* end of string space */ 4138823Sbostic int sp; /* current m4 stack pointer */ 4238823Sbostic int fp; /* m4 call frame pointer */ 4338823Sbostic FILE *infile[MAXINP]; /* input file stack (0=stdin) */ 4438823Sbostic FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 4538823Sbostic FILE *active; /* active output file pointer */ 4638823Sbostic char *m4temp; /* filename for diversions */ 4738823Sbostic int ilevel = 0; /* input file stack pointer */ 4838823Sbostic int oindex = 0; /* diversion index.. */ 4938823Sbostic char *null = ""; /* as it says.. just a null.. */ 5038823Sbostic char *m4wraps = ""; /* m4wrap string default.. */ 51*50960Sbostic char *progname; /* name of this program */ 5238823Sbostic char lquote = LQUOTE; /* left quote character (`) */ 5338823Sbostic char rquote = RQUOTE; /* right quote character (') */ 5438823Sbostic char scommt = SCOMMT; /* start character for comment */ 5538823Sbostic char ecommt = ECOMMT; /* end character for comment */ 56*50960Sbostic 5738823Sbostic struct keyblk keywrds[] = { /* m4 keywords to be installed */ 5838823Sbostic "include", INCLTYPE, 5938823Sbostic "sinclude", SINCTYPE, 6038823Sbostic "define", DEFITYPE, 6138823Sbostic "defn", DEFNTYPE, 6238823Sbostic "divert", DIVRTYPE, 6338823Sbostic "expr", EXPRTYPE, 6438823Sbostic "eval", EXPRTYPE, 6538823Sbostic "substr", SUBSTYPE, 6638823Sbostic "ifelse", IFELTYPE, 6738823Sbostic "ifdef", IFDFTYPE, 6838823Sbostic "len", LENGTYPE, 6938823Sbostic "incr", INCRTYPE, 7038823Sbostic "decr", DECRTYPE, 7138823Sbostic "dnl", DNLNTYPE, 7238823Sbostic "changequote", CHNQTYPE, 7338823Sbostic "changecom", CHNCTYPE, 7438823Sbostic "index", INDXTYPE, 7538823Sbostic #ifdef EXTENDED 7638823Sbostic "paste", PASTTYPE, 7738823Sbostic "spaste", SPASTYPE, 7838823Sbostic #endif 7938823Sbostic "popdef", POPDTYPE, 8038823Sbostic "pushdef", PUSDTYPE, 8138823Sbostic "dumpdef", DUMPTYPE, 8238823Sbostic "shift", SHIFTYPE, 8338823Sbostic "translit", TRNLTYPE, 8438823Sbostic "undefine", UNDFTYPE, 8538823Sbostic "undivert", UNDVTYPE, 8638823Sbostic "divnum", DIVNTYPE, 8738823Sbostic "maketemp", MKTMTYPE, 8838823Sbostic "errprint", ERRPTYPE, 8938823Sbostic "m4wrap", M4WRTYPE, 9038823Sbostic "m4exit", EXITTYPE, 9138823Sbostic "syscmd", SYSCTYPE, 9238823Sbostic "sysval", SYSVTYPE, 93*50960Sbostic 94*50960Sbostic #ifdef unix 9538823Sbostic "unix", MACRTYPE, 96*50960Sbostic #else 97*50960Sbostic #ifdef vms 98*50960Sbostic "vms", MACRTYPE, 99*50960Sbostic #endif 100*50960Sbostic #endif 10138823Sbostic }; 10238823Sbostic 10338823Sbostic #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 10438823Sbostic 10538823Sbostic extern int optind; 10638823Sbostic extern char *optarg; 10738823Sbostic 108*50960Sbostic void macro(); 109*50960Sbostic void initkwds(); 110*50960Sbostic extern int getopt(); 111*50960Sbostic 112*50960Sbostic int 11338823Sbostic main(argc,argv) 114*50960Sbostic int argc; 115*50960Sbostic char *argv[]; 11638823Sbostic { 11738823Sbostic register int c; 11838823Sbostic register int n; 11938823Sbostic char *p; 120*50960Sbostic register FILE *ifp; 12138823Sbostic 122*50960Sbostic progname = basename(argv[0]); 123*50960Sbostic 12438823Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN) 12538823Sbostic signal(SIGINT, onintr); 126*50960Sbostic 12738823Sbostic initkwds(); 12838823Sbostic 12938823Sbostic while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) 13038823Sbostic switch(c) { 13138823Sbostic 13238823Sbostic case 'D': /* define something..*/ 13338823Sbostic for (p = optarg; *p; p++) 13438823Sbostic if (*p == '=') 13538823Sbostic break; 13638823Sbostic if (*p) 13738823Sbostic *p++ = EOS; 13838823Sbostic dodefine(optarg, p); 13938823Sbostic break; 14038823Sbostic case 'U': /* undefine... */ 14138823Sbostic remhash(optarg, TOP); 14238823Sbostic break; 14338823Sbostic case 'o': /* specific output */ 14438823Sbostic case '?': 14538823Sbostic usage(); 14638823Sbostic } 14738823Sbostic 148*50960Sbostic argc -= optind; 149*50960Sbostic argv += optind; 150*50960Sbostic 15138823Sbostic active = stdout; /* default active output */ 152*50960Sbostic /* filename for diversions */ 153*50960Sbostic m4temp = mktemp(xstrdup(_PATH_DIVNAME)); 15438823Sbostic 155*50960Sbostic if (!argc) { 156*50960Sbostic sp = -1; /* stack pointer initialized */ 157*50960Sbostic fp = 0; /* frame pointer initialized */ 158*50960Sbostic infile[0] = stdin; /* default input (naturally) */ 159*50960Sbostic macro(); 160*50960Sbostic } 161*50960Sbostic else 162*50960Sbostic while (argc--) { 163*50960Sbostic if ((ifp = fopen(*argv, "r")) == NULL) 164*50960Sbostic oops("%s: %s", *argv, strerror(errno)); 165*50960Sbostic else { 166*50960Sbostic sp = -1; 167*50960Sbostic fp = 0; 168*50960Sbostic infile[0] = ifp; 169*50960Sbostic macro(); 170*50960Sbostic (void) fclose(ifp); 171*50960Sbostic } 172*50960Sbostic argv++; 173*50960Sbostic } 17438823Sbostic 17538823Sbostic 17638823Sbostic if (*m4wraps) { /* anything for rundown ?? */ 17738823Sbostic ilevel = 0; /* in case m4wrap includes.. */ 17838823Sbostic putback(EOF); /* eof is a must !! */ 17938823Sbostic pbstr(m4wraps); /* user-defined wrapup act */ 18038823Sbostic macro(); /* last will and testament */ 18138823Sbostic } 18238823Sbostic 18339102Sbostic if (active != stdout) 18439102Sbostic active = stdout; /* reset output just in case */ 18539102Sbostic for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 18639102Sbostic if (outfile[n] != NULL) 18739102Sbostic getdiv(n); 18838823Sbostic /* remove bitbucket if used */ 18938823Sbostic if (outfile[0] != NULL) { 19038823Sbostic (void) fclose(outfile[0]); 19138823Sbostic m4temp[UNIQUE] = '0'; 192*50960Sbostic #ifdef vms 193*50960Sbostic (void) remove(m4temp); 194*50960Sbostic #else 19538823Sbostic (void) unlink(m4temp); 196*50960Sbostic #endif 19738823Sbostic } 19838823Sbostic 199*50960Sbostic return 0; 20038823Sbostic } 20138823Sbostic 202*50960Sbostic ndptr inspect(); 20338823Sbostic 20438823Sbostic /* 20538823Sbostic * macro - the work horse.. 20638823Sbostic */ 207*50960Sbostic void 20838823Sbostic macro() { 20938823Sbostic char token[MAXTOK]; 21038823Sbostic register char *s; 21138823Sbostic register int t, l; 21238823Sbostic register ndptr p; 21338823Sbostic register int nlpar; 21438823Sbostic 21538823Sbostic cycle { 21638823Sbostic if ((t = gpbc()) == '_' || isalpha(t)) { 21738823Sbostic putback(t); 21838823Sbostic if ((p = inspect(s = token)) == nil) { 21938823Sbostic if (sp < 0) 22038823Sbostic while (*s) 22138823Sbostic putc(*s++, active); 22238823Sbostic else 22338823Sbostic while (*s) 22438823Sbostic chrsave(*s++); 22538823Sbostic } 22638823Sbostic else { 22738823Sbostic /* 22838823Sbostic * real thing.. First build a call frame: 22938823Sbostic */ 23038823Sbostic pushf(fp); /* previous call frm */ 23138823Sbostic pushf(p->type); /* type of the call */ 23238823Sbostic pushf(0); /* parenthesis level */ 23338823Sbostic fp = sp; /* new frame pointer */ 23438823Sbostic /* 23538823Sbostic * now push the string arguments: 23638823Sbostic */ 23738823Sbostic pushs(p->defn); /* defn string */ 23838823Sbostic pushs(p->name); /* macro name */ 23938823Sbostic pushs(ep); /* start next..*/ 24038823Sbostic 24138823Sbostic putback(l = gpbc()); 24238823Sbostic if (l != LPAREN) { /* add bracks */ 24338823Sbostic putback(RPAREN); 24438823Sbostic putback(LPAREN); 24538823Sbostic } 24638823Sbostic } 24738823Sbostic } 24838823Sbostic else if (t == EOF) { 24938823Sbostic if (sp > -1) 250*50960Sbostic oops("unexpected end of input", ""); 25138823Sbostic if (--ilevel < 0) 25238823Sbostic break; /* all done thanks.. */ 25338823Sbostic (void) fclose(infile[ilevel+1]); 25438823Sbostic continue; 25538823Sbostic } 25638823Sbostic /* 25738823Sbostic * non-alpha single-char token seen.. 258*50960Sbostic * [the order of else if .. stmts is important.] 25938823Sbostic */ 26038823Sbostic else if (t == lquote) { /* strip quotes */ 26138823Sbostic nlpar = 1; 26238823Sbostic do { 26338823Sbostic if ((l = gpbc()) == rquote) 26438823Sbostic nlpar--; 26538823Sbostic else if (l == lquote) 26638823Sbostic nlpar++; 26738823Sbostic else if (l == EOF) 268*50960Sbostic oops("missing right quote", ""); 26938823Sbostic if (nlpar > 0) { 27038823Sbostic if (sp < 0) 27138823Sbostic putc(l, active); 27238823Sbostic else 27338823Sbostic chrsave(l); 27438823Sbostic } 27538823Sbostic } 27638823Sbostic while (nlpar != 0); 27738823Sbostic } 27838823Sbostic 27938823Sbostic else if (sp < 0) { /* not in a macro at all */ 28038823Sbostic if (t == scommt) { /* comment handling here */ 28138823Sbostic putc(t, active); 28238823Sbostic while ((t = gpbc()) != ecommt) 28338823Sbostic putc(t, active); 28438823Sbostic } 28538823Sbostic putc(t, active); /* output directly.. */ 28638823Sbostic } 28738823Sbostic 28838823Sbostic else switch(t) { 28938823Sbostic 29038823Sbostic case LPAREN: 29138823Sbostic if (PARLEV > 0) 29238823Sbostic chrsave(t); 29338823Sbostic while (isspace(l = gpbc())) 29438823Sbostic ; /* skip blank, tab, nl.. */ 29538823Sbostic putback(l); 29638823Sbostic PARLEV++; 29738823Sbostic break; 29838823Sbostic 29938823Sbostic case RPAREN: 30038823Sbostic if (--PARLEV > 0) 30138823Sbostic chrsave(t); 30238823Sbostic else { /* end of argument list */ 30338823Sbostic chrsave(EOS); 30438823Sbostic 30538823Sbostic if (sp == STACKMAX) 306*50960Sbostic oops("internal stack overflow", ""); 30738823Sbostic 30838823Sbostic if (CALTYP == MACRTYPE) 309*50960Sbostic expand((char **) mstack+fp+1, sp-fp); 31038823Sbostic else 311*50960Sbostic eval((char **) mstack+fp+1, sp-fp, CALTYP); 31238823Sbostic 31338823Sbostic ep = PREVEP; /* flush strspace */ 31438823Sbostic sp = PREVSP; /* previous sp.. */ 31538823Sbostic fp = PREVFP; /* rewind stack...*/ 31638823Sbostic } 31738823Sbostic break; 31838823Sbostic 31938823Sbostic case COMMA: 320*50960Sbostic if (PARLEV == 1) { 32138823Sbostic chrsave(EOS); /* new argument */ 32238823Sbostic while (isspace(l = gpbc())) 32338823Sbostic ; 32438823Sbostic putback(l); 32538823Sbostic pushs(ep); 32638823Sbostic } 32738823Sbostic break; 32838823Sbostic default: 32938823Sbostic chrsave(t); /* stack the char */ 33038823Sbostic break; 33138823Sbostic } 33238823Sbostic } 33338823Sbostic } 33438823Sbostic 33538823Sbostic /* 33638823Sbostic * build an input token.. 33738823Sbostic * consider only those starting with _ or A-Za-z. This is a 33838823Sbostic * combo with lookup to speed things up. 33938823Sbostic */ 34038823Sbostic ndptr 34138823Sbostic inspect(tp) 34238823Sbostic register char *tp; 34338823Sbostic { 34438823Sbostic register char c; 34538823Sbostic register char *name = tp; 34638823Sbostic register char *etp = tp+MAXTOK; 34738823Sbostic register ndptr p; 348*50960Sbostic register unsigned long h = 0; 34938823Sbostic 350*50960Sbostic while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 351*50960Sbostic h = (h << 5) + h + (*tp++ = c); 35238823Sbostic putback(c); 35338823Sbostic if (tp == etp) 354*50960Sbostic oops("token too long", ""); 355*50960Sbostic 35638823Sbostic *tp = EOS; 357*50960Sbostic 35838823Sbostic for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 359*50960Sbostic if (STREQ(name, p->name)) 36038823Sbostic break; 361*50960Sbostic return p; 36238823Sbostic } 36338823Sbostic 36438823Sbostic /* 36538823Sbostic * initkwds - initialise m4 keywords as fast as possible. 36638823Sbostic * This very similar to install, but without certain overheads, 36738823Sbostic * such as calling lookup. Malloc is not used for storing the 36838823Sbostic * keyword strings, since we simply use the static pointers 369*50960Sbostic * within keywrds block. 37038823Sbostic */ 371*50960Sbostic void 37238823Sbostic initkwds() { 37338823Sbostic register int i; 37438823Sbostic register int h; 37538823Sbostic register ndptr p; 37638823Sbostic 37738823Sbostic for (i = 0; i < MAXKEYS; i++) { 37838823Sbostic h = hash(keywrds[i].knam); 379*50960Sbostic p = (ndptr) xalloc(sizeof(struct ndblock)); 38038823Sbostic p->nxtptr = hashtab[h]; 38138823Sbostic hashtab[h] = p; 38238823Sbostic p->name = keywrds[i].knam; 38338823Sbostic p->defn = null; 38438823Sbostic p->type = keywrds[i].ktyp | STATIC; 38538823Sbostic } 38638823Sbostic } 387