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*51241Seric static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/02/91"; 1338823Sbostic #endif /* not lint */ 1438823Sbostic 1538823Sbostic /* 1638823Sbostic * main.c 1738823Sbostic * Facility: m4 macro processor 1838823Sbostic * by: oz 1938823Sbostic */ 2038823Sbostic 2150960Sbostic #include <sys/types.h> 2246697Sbostic #include <signal.h> 2350960Sbostic #include <errno.h> 2446697Sbostic #include <unistd.h> 2546697Sbostic #include <stdio.h> 2650960Sbostic #include <ctype.h> 2746697Sbostic #include <string.h> 2838823Sbostic #include "mdef.h" 2950960Sbostic #include "stdd.h" 3050960Sbostic #include "extern.h" 3146697Sbostic #include "pathnames.h" 3238823Sbostic 3338823Sbostic ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 3438823Sbostic char buf[BUFSIZE]; /* push-back buffer */ 35*51241Seric char *bufbase = buf; /* the base for current ilevel */ 36*51241Seric char *bbase[MAXINP]; /* the base for each ilevel */ 3738823Sbostic char *bp = buf; /* first available character */ 3838823Sbostic char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 3938823Sbostic stae mstack[STACKMAX+1]; /* stack of m4 machine */ 4038823Sbostic char strspace[STRSPMAX+1]; /* string space for evaluation */ 4138823Sbostic char *ep = strspace; /* first free char in strspace */ 4238823Sbostic char *endest= strspace+STRSPMAX;/* end of string space */ 4338823Sbostic int sp; /* current m4 stack pointer */ 4438823Sbostic int fp; /* m4 call frame pointer */ 4538823Sbostic FILE *infile[MAXINP]; /* input file stack (0=stdin) */ 4638823Sbostic FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 4738823Sbostic FILE *active; /* active output file pointer */ 4838823Sbostic char *m4temp; /* filename for diversions */ 4938823Sbostic int ilevel = 0; /* input file stack pointer */ 5038823Sbostic int oindex = 0; /* diversion index.. */ 5138823Sbostic char *null = ""; /* as it says.. just a null.. */ 5238823Sbostic char *m4wraps = ""; /* m4wrap string default.. */ 5350960Sbostic char *progname; /* name of this program */ 5438823Sbostic char lquote = LQUOTE; /* left quote character (`) */ 5538823Sbostic char rquote = RQUOTE; /* right quote character (') */ 5638823Sbostic char scommt = SCOMMT; /* start character for comment */ 5738823Sbostic char ecommt = ECOMMT; /* end character for comment */ 5850960Sbostic 5938823Sbostic struct keyblk keywrds[] = { /* m4 keywords to be installed */ 6038823Sbostic "include", INCLTYPE, 6138823Sbostic "sinclude", SINCTYPE, 6238823Sbostic "define", DEFITYPE, 6338823Sbostic "defn", DEFNTYPE, 6438823Sbostic "divert", DIVRTYPE, 6538823Sbostic "expr", EXPRTYPE, 6638823Sbostic "eval", EXPRTYPE, 6738823Sbostic "substr", SUBSTYPE, 6838823Sbostic "ifelse", IFELTYPE, 6938823Sbostic "ifdef", IFDFTYPE, 7038823Sbostic "len", LENGTYPE, 7138823Sbostic "incr", INCRTYPE, 7238823Sbostic "decr", DECRTYPE, 7338823Sbostic "dnl", DNLNTYPE, 7438823Sbostic "changequote", CHNQTYPE, 7538823Sbostic "changecom", CHNCTYPE, 7638823Sbostic "index", INDXTYPE, 7738823Sbostic #ifdef EXTENDED 7838823Sbostic "paste", PASTTYPE, 7938823Sbostic "spaste", SPASTYPE, 8038823Sbostic #endif 8138823Sbostic "popdef", POPDTYPE, 8238823Sbostic "pushdef", PUSDTYPE, 8338823Sbostic "dumpdef", DUMPTYPE, 8438823Sbostic "shift", SHIFTYPE, 8538823Sbostic "translit", TRNLTYPE, 8638823Sbostic "undefine", UNDFTYPE, 8738823Sbostic "undivert", UNDVTYPE, 8838823Sbostic "divnum", DIVNTYPE, 8938823Sbostic "maketemp", MKTMTYPE, 9038823Sbostic "errprint", ERRPTYPE, 9138823Sbostic "m4wrap", M4WRTYPE, 9238823Sbostic "m4exit", EXITTYPE, 9338823Sbostic "syscmd", SYSCTYPE, 9438823Sbostic "sysval", SYSVTYPE, 9550960Sbostic 9650960Sbostic #ifdef unix 9738823Sbostic "unix", MACRTYPE, 9850960Sbostic #else 9950960Sbostic #ifdef vms 10050960Sbostic "vms", MACRTYPE, 10150960Sbostic #endif 10250960Sbostic #endif 10338823Sbostic }; 10438823Sbostic 10538823Sbostic #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 10638823Sbostic 10738823Sbostic extern int optind; 10838823Sbostic extern char *optarg; 10938823Sbostic 11050960Sbostic void macro(); 11150960Sbostic void initkwds(); 11250960Sbostic extern int getopt(); 11350960Sbostic 11450960Sbostic int 11538823Sbostic main(argc,argv) 11650960Sbostic int argc; 11750960Sbostic char *argv[]; 11838823Sbostic { 11938823Sbostic register int c; 12038823Sbostic register int n; 12138823Sbostic char *p; 12250960Sbostic register FILE *ifp; 12338823Sbostic 12450960Sbostic progname = basename(argv[0]); 12550960Sbostic 12638823Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN) 12738823Sbostic signal(SIGINT, onintr); 12850960Sbostic 12938823Sbostic initkwds(); 13038823Sbostic 13138823Sbostic while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) 13238823Sbostic switch(c) { 13338823Sbostic 13438823Sbostic case 'D': /* define something..*/ 13538823Sbostic for (p = optarg; *p; p++) 13638823Sbostic if (*p == '=') 13738823Sbostic break; 13838823Sbostic if (*p) 13938823Sbostic *p++ = EOS; 14038823Sbostic dodefine(optarg, p); 14138823Sbostic break; 14238823Sbostic case 'U': /* undefine... */ 14338823Sbostic remhash(optarg, TOP); 14438823Sbostic break; 14538823Sbostic case 'o': /* specific output */ 14638823Sbostic case '?': 14738823Sbostic usage(); 14838823Sbostic } 14938823Sbostic 15050960Sbostic argc -= optind; 15150960Sbostic argv += optind; 15250960Sbostic 15338823Sbostic active = stdout; /* default active output */ 15450960Sbostic /* filename for diversions */ 15550960Sbostic m4temp = mktemp(xstrdup(_PATH_DIVNAME)); 15638823Sbostic 157*51241Seric bbase[0] = bufbase; 15850960Sbostic if (!argc) { 15950960Sbostic sp = -1; /* stack pointer initialized */ 16050960Sbostic fp = 0; /* frame pointer initialized */ 16150960Sbostic infile[0] = stdin; /* default input (naturally) */ 16250960Sbostic macro(); 16350960Sbostic } 16450960Sbostic else 16550960Sbostic while (argc--) { 16650960Sbostic if ((ifp = fopen(*argv, "r")) == NULL) 16750960Sbostic oops("%s: %s", *argv, strerror(errno)); 16850960Sbostic else { 16950960Sbostic sp = -1; 17050960Sbostic fp = 0; 17150960Sbostic infile[0] = ifp; 17250960Sbostic macro(); 17350960Sbostic (void) fclose(ifp); 17450960Sbostic } 17550960Sbostic argv++; 17650960Sbostic } 17738823Sbostic 17838823Sbostic 17938823Sbostic if (*m4wraps) { /* anything for rundown ?? */ 18038823Sbostic ilevel = 0; /* in case m4wrap includes.. */ 181*51241Seric bufbase = bp = buf; /* use the entire buffer */ 18238823Sbostic putback(EOF); /* eof is a must !! */ 18338823Sbostic pbstr(m4wraps); /* user-defined wrapup act */ 18438823Sbostic macro(); /* last will and testament */ 18538823Sbostic } 18638823Sbostic 18739102Sbostic if (active != stdout) 18839102Sbostic active = stdout; /* reset output just in case */ 18939102Sbostic for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 19039102Sbostic if (outfile[n] != NULL) 19139102Sbostic getdiv(n); 19238823Sbostic /* remove bitbucket if used */ 19338823Sbostic if (outfile[0] != NULL) { 19438823Sbostic (void) fclose(outfile[0]); 19538823Sbostic m4temp[UNIQUE] = '0'; 19650960Sbostic #ifdef vms 19750960Sbostic (void) remove(m4temp); 19850960Sbostic #else 19938823Sbostic (void) unlink(m4temp); 20050960Sbostic #endif 20138823Sbostic } 20238823Sbostic 20350960Sbostic return 0; 20438823Sbostic } 20538823Sbostic 20650960Sbostic ndptr inspect(); 20738823Sbostic 20838823Sbostic /* 20938823Sbostic * macro - the work horse.. 21038823Sbostic */ 21150960Sbostic void 21238823Sbostic macro() { 21338823Sbostic char token[MAXTOK]; 21438823Sbostic register char *s; 21538823Sbostic register int t, l; 21638823Sbostic register ndptr p; 21738823Sbostic register int nlpar; 21838823Sbostic 21938823Sbostic cycle { 22038823Sbostic if ((t = gpbc()) == '_' || isalpha(t)) { 22138823Sbostic putback(t); 22238823Sbostic if ((p = inspect(s = token)) == nil) { 22338823Sbostic if (sp < 0) 22438823Sbostic while (*s) 22538823Sbostic putc(*s++, active); 22638823Sbostic else 22738823Sbostic while (*s) 22838823Sbostic chrsave(*s++); 22938823Sbostic } 23038823Sbostic else { 23138823Sbostic /* 23238823Sbostic * real thing.. First build a call frame: 23338823Sbostic */ 23438823Sbostic pushf(fp); /* previous call frm */ 23538823Sbostic pushf(p->type); /* type of the call */ 23638823Sbostic pushf(0); /* parenthesis level */ 23738823Sbostic fp = sp; /* new frame pointer */ 23838823Sbostic /* 23938823Sbostic * now push the string arguments: 24038823Sbostic */ 24138823Sbostic pushs(p->defn); /* defn string */ 24238823Sbostic pushs(p->name); /* macro name */ 24338823Sbostic pushs(ep); /* start next..*/ 24438823Sbostic 24538823Sbostic putback(l = gpbc()); 24638823Sbostic if (l != LPAREN) { /* add bracks */ 24738823Sbostic putback(RPAREN); 24838823Sbostic putback(LPAREN); 24938823Sbostic } 25038823Sbostic } 25138823Sbostic } 25238823Sbostic else if (t == EOF) { 25338823Sbostic if (sp > -1) 25450960Sbostic oops("unexpected end of input", ""); 25538823Sbostic if (--ilevel < 0) 25638823Sbostic break; /* all done thanks.. */ 25738823Sbostic (void) fclose(infile[ilevel+1]); 258*51241Seric bufbase = bbase[ilevel]; 25938823Sbostic continue; 26038823Sbostic } 26138823Sbostic /* 26238823Sbostic * non-alpha single-char token seen.. 26350960Sbostic * [the order of else if .. stmts is important.] 26438823Sbostic */ 26538823Sbostic else if (t == lquote) { /* strip quotes */ 26638823Sbostic nlpar = 1; 26738823Sbostic do { 26838823Sbostic if ((l = gpbc()) == rquote) 26938823Sbostic nlpar--; 27038823Sbostic else if (l == lquote) 27138823Sbostic nlpar++; 27238823Sbostic else if (l == EOF) 27350960Sbostic oops("missing right quote", ""); 27438823Sbostic if (nlpar > 0) { 27538823Sbostic if (sp < 0) 27638823Sbostic putc(l, active); 27738823Sbostic else 27838823Sbostic chrsave(l); 27938823Sbostic } 28038823Sbostic } 28138823Sbostic while (nlpar != 0); 28238823Sbostic } 28338823Sbostic 28438823Sbostic else if (sp < 0) { /* not in a macro at all */ 28538823Sbostic if (t == scommt) { /* comment handling here */ 28638823Sbostic putc(t, active); 28738823Sbostic while ((t = gpbc()) != ecommt) 28838823Sbostic putc(t, active); 28938823Sbostic } 29038823Sbostic putc(t, active); /* output directly.. */ 29138823Sbostic } 29238823Sbostic 29338823Sbostic else switch(t) { 29438823Sbostic 29538823Sbostic case LPAREN: 29638823Sbostic if (PARLEV > 0) 29738823Sbostic chrsave(t); 29838823Sbostic while (isspace(l = gpbc())) 29938823Sbostic ; /* skip blank, tab, nl.. */ 30038823Sbostic putback(l); 30138823Sbostic PARLEV++; 30238823Sbostic break; 30338823Sbostic 30438823Sbostic case RPAREN: 30538823Sbostic if (--PARLEV > 0) 30638823Sbostic chrsave(t); 30738823Sbostic else { /* end of argument list */ 30838823Sbostic chrsave(EOS); 30938823Sbostic 31038823Sbostic if (sp == STACKMAX) 31150960Sbostic oops("internal stack overflow", ""); 31238823Sbostic 31338823Sbostic if (CALTYP == MACRTYPE) 31450960Sbostic expand((char **) mstack+fp+1, sp-fp); 31538823Sbostic else 31650960Sbostic eval((char **) mstack+fp+1, sp-fp, CALTYP); 31738823Sbostic 31838823Sbostic ep = PREVEP; /* flush strspace */ 31938823Sbostic sp = PREVSP; /* previous sp.. */ 32038823Sbostic fp = PREVFP; /* rewind stack...*/ 32138823Sbostic } 32238823Sbostic break; 32338823Sbostic 32438823Sbostic case COMMA: 32550960Sbostic if (PARLEV == 1) { 32638823Sbostic chrsave(EOS); /* new argument */ 32738823Sbostic while (isspace(l = gpbc())) 32838823Sbostic ; 32938823Sbostic putback(l); 33038823Sbostic pushs(ep); 33138823Sbostic } 33238823Sbostic break; 33338823Sbostic default: 33438823Sbostic chrsave(t); /* stack the char */ 33538823Sbostic break; 33638823Sbostic } 33738823Sbostic } 33838823Sbostic } 33938823Sbostic 34038823Sbostic /* 34138823Sbostic * build an input token.. 34238823Sbostic * consider only those starting with _ or A-Za-z. This is a 34338823Sbostic * combo with lookup to speed things up. 34438823Sbostic */ 34538823Sbostic ndptr 34638823Sbostic inspect(tp) 34738823Sbostic register char *tp; 34838823Sbostic { 34938823Sbostic register char c; 35038823Sbostic register char *name = tp; 35138823Sbostic register char *etp = tp+MAXTOK; 35238823Sbostic register ndptr p; 35350960Sbostic register unsigned long h = 0; 35438823Sbostic 35550960Sbostic while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 35650960Sbostic h = (h << 5) + h + (*tp++ = c); 35738823Sbostic putback(c); 35838823Sbostic if (tp == etp) 35950960Sbostic oops("token too long", ""); 36050960Sbostic 36138823Sbostic *tp = EOS; 36250960Sbostic 36338823Sbostic for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 36450960Sbostic if (STREQ(name, p->name)) 36538823Sbostic break; 36650960Sbostic return p; 36738823Sbostic } 36838823Sbostic 36938823Sbostic /* 37038823Sbostic * initkwds - initialise m4 keywords as fast as possible. 37138823Sbostic * This very similar to install, but without certain overheads, 37238823Sbostic * such as calling lookup. Malloc is not used for storing the 37338823Sbostic * keyword strings, since we simply use the static pointers 37450960Sbostic * within keywrds block. 37538823Sbostic */ 37650960Sbostic void 37738823Sbostic initkwds() { 37838823Sbostic register int i; 37938823Sbostic register int h; 38038823Sbostic register ndptr p; 38138823Sbostic 38238823Sbostic for (i = 0; i < MAXKEYS; i++) { 38338823Sbostic h = hash(keywrds[i].knam); 38450960Sbostic p = (ndptr) xalloc(sizeof(struct ndblock)); 38538823Sbostic p->nxtptr = hashtab[h]; 38638823Sbostic hashtab[h] = p; 38738823Sbostic p->name = keywrds[i].knam; 38838823Sbostic p->defn = null; 38938823Sbostic p->type = keywrds[i].ktyp | STATIC; 39038823Sbostic } 39138823Sbostic } 392