main.c revision 24360
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Ozan Yigit at York University. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 381590Srgrimesstatic char copyright[] = 391590Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 401590Srgrimes The Regents of the University of California. All rights reserved.\n"; 411590Srgrimes#endif /* not lint */ 421590Srgrimes 431590Srgrimes#ifndef lint 441590Srgrimesstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 451590Srgrimes#endif /* not lint */ 461590Srgrimes 471590Srgrimes/* 481590Srgrimes * main.c 491590Srgrimes * Facility: m4 macro processor 501590Srgrimes * by: oz 511590Srgrimes */ 521590Srgrimes 531590Srgrimes#include <sys/types.h> 541590Srgrimes#include <signal.h> 551590Srgrimes#include <errno.h> 561590Srgrimes#include <unistd.h> 571590Srgrimes#include <stdio.h> 581590Srgrimes#include <ctype.h> 591590Srgrimes#include <string.h> 601590Srgrimes#include "mdef.h" 611590Srgrimes#include "stdd.h" 621590Srgrimes#include "extern.h" 631590Srgrimes#include "pathnames.h" 641590Srgrimes 651590Srgrimesndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 665165Sacheunsigned char buf[BUFSIZE]; /* push-back buffer */ 675165Sacheunsigned char *bufbase = buf; /* the base for current ilevel */ 685165Sacheunsigned char *bbase[MAXINP]; /* the base for each ilevel */ 695165Sacheunsigned char *bp = buf; /* first available character */ 705165Sacheunsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 711590Srgrimesstae mstack[STACKMAX+1]; /* stack of m4 machine */ 721590Srgrimeschar strspace[STRSPMAX+1]; /* string space for evaluation */ 731590Srgrimeschar *ep = strspace; /* first free char in strspace */ 741590Srgrimeschar *endest= strspace+STRSPMAX;/* end of string space */ 751590Srgrimesint sp; /* current m4 stack pointer */ 761590Srgrimesint fp; /* m4 call frame pointer */ 771590SrgrimesFILE *infile[MAXINP]; /* input file stack (0=stdin) */ 781590SrgrimesFILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 791590SrgrimesFILE *active; /* active output file pointer */ 801590Srgrimeschar *m4temp; /* filename for diversions */ 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.. */ 851590Srgrimeschar *progname; /* name of this program */ 861590Srgrimeschar lquote = LQUOTE; /* left quote character (`) */ 871590Srgrimeschar rquote = RQUOTE; /* right quote character (') */ 881590Srgrimeschar scommt = SCOMMT; /* start character for comment */ 891590Srgrimeschar ecommt = ECOMMT; /* end character for comment */ 901590Srgrimes 911590Srgrimesstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 921590Srgrimes "include", INCLTYPE, 931590Srgrimes "sinclude", SINCTYPE, 941590Srgrimes "define", DEFITYPE, 951590Srgrimes "defn", DEFNTYPE, 961590Srgrimes "divert", DIVRTYPE, 971590Srgrimes "expr", EXPRTYPE, 981590Srgrimes "eval", EXPRTYPE, 991590Srgrimes "substr", SUBSTYPE, 1001590Srgrimes "ifelse", IFELTYPE, 1011590Srgrimes "ifdef", IFDFTYPE, 1021590Srgrimes "len", LENGTYPE, 1031590Srgrimes "incr", INCRTYPE, 1041590Srgrimes "decr", DECRTYPE, 1051590Srgrimes "dnl", DNLNTYPE, 1061590Srgrimes "changequote", CHNQTYPE, 1071590Srgrimes "changecom", CHNCTYPE, 1081590Srgrimes "index", INDXTYPE, 1091590Srgrimes#ifdef EXTENDED 1101590Srgrimes "paste", PASTTYPE, 1111590Srgrimes "spaste", SPASTYPE, 1121590Srgrimes#endif 1131590Srgrimes "popdef", POPDTYPE, 1141590Srgrimes "pushdef", PUSDTYPE, 1151590Srgrimes "dumpdef", DUMPTYPE, 1161590Srgrimes "shift", SHIFTYPE, 1171590Srgrimes "translit", TRNLTYPE, 1181590Srgrimes "undefine", UNDFTYPE, 1191590Srgrimes "undivert", UNDVTYPE, 1201590Srgrimes "divnum", DIVNTYPE, 1211590Srgrimes "maketemp", MKTMTYPE, 1221590Srgrimes "errprint", ERRPTYPE, 1231590Srgrimes "m4wrap", M4WRTYPE, 1241590Srgrimes "m4exit", EXITTYPE, 1251590Srgrimes "syscmd", SYSCTYPE, 1261590Srgrimes "sysval", SYSVTYPE, 1271590Srgrimes 1281590Srgrimes#ifdef unix 1291590Srgrimes "unix", MACRTYPE, 1301590Srgrimes#else 1311590Srgrimes#ifdef vms 1321590Srgrimes "vms", MACRTYPE, 1331590Srgrimes#endif 1341590Srgrimes#endif 1351590Srgrimes}; 1361590Srgrimes 1371590Srgrimes#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1381590Srgrimes 1391590Srgrimesextern int optind; 1401590Srgrimesextern char *optarg; 1411590Srgrimes 1421590Srgrimesvoid macro(); 1431590Srgrimesvoid initkwds(); 1441590Srgrimesextern int getopt(); 1451590Srgrimes 1461590Srgrimesint 1471590Srgrimesmain(argc,argv) 1481590Srgrimes int argc; 1491590Srgrimes char *argv[]; 1501590Srgrimes{ 1511590Srgrimes register int c; 1521590Srgrimes register int n; 1531590Srgrimes char *p; 1541590Srgrimes register FILE *ifp; 1551590Srgrimes 1561590Srgrimes progname = basename(argv[0]); 1571590Srgrimes 1581590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1591590Srgrimes signal(SIGINT, onintr); 1601590Srgrimes 1611590Srgrimes initkwds(); 1621590Srgrimes 16324360Simp while ((c = getopt(argc, argv, "tD:U:o:")) != -1) 1641590Srgrimes switch(c) { 1651590Srgrimes 1661590Srgrimes case 'D': /* define something..*/ 1671590Srgrimes for (p = optarg; *p; p++) 1681590Srgrimes if (*p == '=') 1691590Srgrimes break; 1701590Srgrimes if (*p) 1711590Srgrimes *p++ = EOS; 1721590Srgrimes dodefine(optarg, p); 1731590Srgrimes break; 1741590Srgrimes case 'U': /* undefine... */ 1751590Srgrimes remhash(optarg, TOP); 1761590Srgrimes break; 1771590Srgrimes case 'o': /* specific output */ 1781590Srgrimes case '?': 1791590Srgrimes usage(); 1801590Srgrimes } 1811590Srgrimes 1821590Srgrimes argc -= optind; 1831590Srgrimes argv += optind; 1841590Srgrimes 1851590Srgrimes active = stdout; /* default active output */ 1861590Srgrimes /* filename for diversions */ 1871590Srgrimes m4temp = mktemp(xstrdup(_PATH_DIVNAME)); 1881590Srgrimes 1891590Srgrimes bbase[0] = bufbase; 1901590Srgrimes if (!argc) { 1911590Srgrimes sp = -1; /* stack pointer initialized */ 1921590Srgrimes fp = 0; /* frame pointer initialized */ 1931590Srgrimes infile[0] = stdin; /* default input (naturally) */ 1941590Srgrimes macro(); 1951590Srgrimes } else 1961590Srgrimes for (; argc--; ++argv) { 1971590Srgrimes p = *argv; 1981590Srgrimes if (p[0] == '-' && p[1] == '\0') 1991590Srgrimes ifp = stdin; 2001590Srgrimes else if ((ifp = fopen(p, "r")) == NULL) 2011590Srgrimes oops("%s: %s", p, strerror(errno)); 2021590Srgrimes sp = -1; 2038874Srgrimes fp = 0; 2041590Srgrimes infile[0] = ifp; 2051590Srgrimes macro(); 2061590Srgrimes if (ifp != stdin) 2071590Srgrimes (void)fclose(ifp); 2081590Srgrimes } 2091590Srgrimes 2101590Srgrimes if (*m4wraps) { /* anything for rundown ?? */ 2111590Srgrimes ilevel = 0; /* in case m4wrap includes.. */ 2121590Srgrimes bufbase = bp = buf; /* use the entire buffer */ 2131590Srgrimes putback(EOF); /* eof is a must !! */ 2141590Srgrimes pbstr(m4wraps); /* user-defined wrapup act */ 2151590Srgrimes macro(); /* last will and testament */ 2161590Srgrimes } 2171590Srgrimes 2181590Srgrimes if (active != stdout) 2191590Srgrimes active = stdout; /* reset output just in case */ 2201590Srgrimes for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 2211590Srgrimes if (outfile[n] != NULL) 2221590Srgrimes getdiv(n); 2231590Srgrimes /* remove bitbucket if used */ 2241590Srgrimes if (outfile[0] != NULL) { 2251590Srgrimes (void) fclose(outfile[0]); 2261590Srgrimes m4temp[UNIQUE] = '0'; 2271590Srgrimes#ifdef vms 2281590Srgrimes (void) remove(m4temp); 2291590Srgrimes#else 2301590Srgrimes (void) unlink(m4temp); 2311590Srgrimes#endif 2321590Srgrimes } 2331590Srgrimes 2341590Srgrimes return 0; 2351590Srgrimes} 2361590Srgrimes 2371590Srgrimesndptr inspect(); 2381590Srgrimes 2391590Srgrimes/* 2401590Srgrimes * macro - the work horse.. 2411590Srgrimes */ 2421590Srgrimesvoid 2431590Srgrimesmacro() { 2441590Srgrimes char token[MAXTOK]; 2451590Srgrimes register char *s; 2461590Srgrimes register int t, l; 2471590Srgrimes register ndptr p; 2481590Srgrimes register int nlpar; 2491590Srgrimes 2501590Srgrimes cycle { 2515165Sache if ((t = gpbc()) == '_' || (t != EOF && isalpha(t))) { 2521590Srgrimes putback(t); 2531590Srgrimes if ((p = inspect(s = token)) == nil) { 2541590Srgrimes if (sp < 0) 2551590Srgrimes while (*s) 2561590Srgrimes putc(*s++, active); 2571590Srgrimes else 2581590Srgrimes while (*s) 2591590Srgrimes chrsave(*s++); 2601590Srgrimes } 2611590Srgrimes else { 2621590Srgrimes /* 2631590Srgrimes * real thing.. First build a call frame: 2641590Srgrimes */ 2651590Srgrimes pushf(fp); /* previous call frm */ 2661590Srgrimes pushf(p->type); /* type of the call */ 2671590Srgrimes pushf(0); /* parenthesis level */ 2681590Srgrimes fp = sp; /* new frame pointer */ 2691590Srgrimes /* 2701590Srgrimes * now push the string arguments: 2711590Srgrimes */ 2721590Srgrimes pushs(p->defn); /* defn string */ 2731590Srgrimes pushs(p->name); /* macro name */ 2741590Srgrimes pushs(ep); /* start next..*/ 2751590Srgrimes 2761590Srgrimes putback(l = gpbc()); 2771590Srgrimes if (l != LPAREN) { /* add bracks */ 2781590Srgrimes putback(RPAREN); 2791590Srgrimes putback(LPAREN); 2801590Srgrimes } 2811590Srgrimes } 2821590Srgrimes } 2831590Srgrimes else if (t == EOF) { 2841590Srgrimes if (sp > -1) 2851590Srgrimes oops("unexpected end of input", ""); 2861590Srgrimes if (ilevel <= 0) 2871590Srgrimes break; /* all done thanks.. */ 2881590Srgrimes --ilevel; 2891590Srgrimes (void) fclose(infile[ilevel+1]); 2901590Srgrimes bufbase = bbase[ilevel]; 2911590Srgrimes continue; 2921590Srgrimes } 2931590Srgrimes /* 2941590Srgrimes * non-alpha single-char token seen.. 2951590Srgrimes * [the order of else if .. stmts is important.] 2961590Srgrimes */ 2971590Srgrimes else if (t == lquote) { /* strip quotes */ 2981590Srgrimes nlpar = 1; 2991590Srgrimes do { 3001590Srgrimes if ((l = gpbc()) == rquote) 3011590Srgrimes nlpar--; 3021590Srgrimes else if (l == lquote) 3031590Srgrimes nlpar++; 3041590Srgrimes else if (l == EOF) 3051590Srgrimes oops("missing right quote", ""); 3061590Srgrimes if (nlpar > 0) { 3071590Srgrimes if (sp < 0) 3081590Srgrimes putc(l, active); 3091590Srgrimes else 3101590Srgrimes chrsave(l); 3111590Srgrimes } 3121590Srgrimes } 3131590Srgrimes while (nlpar != 0); 3141590Srgrimes } 3151590Srgrimes 3161590Srgrimes else if (sp < 0) { /* not in a macro at all */ 3171590Srgrimes if (t == scommt) { /* comment handling here */ 3181590Srgrimes putc(t, active); 3191590Srgrimes while ((t = gpbc()) != ecommt) 3201590Srgrimes putc(t, active); 3211590Srgrimes } 3221590Srgrimes putc(t, active); /* output directly.. */ 3231590Srgrimes } 3241590Srgrimes 3251590Srgrimes else switch(t) { 3261590Srgrimes 3271590Srgrimes case LPAREN: 3281590Srgrimes if (PARLEV > 0) 3291590Srgrimes chrsave(t); 3305165Sache while ((l = gpbc()) != EOF && isspace(l)) 3311590Srgrimes ; /* skip blank, tab, nl.. */ 3321590Srgrimes putback(l); 3331590Srgrimes PARLEV++; 3341590Srgrimes break; 3351590Srgrimes 3361590Srgrimes case RPAREN: 3371590Srgrimes if (--PARLEV > 0) 3381590Srgrimes chrsave(t); 3391590Srgrimes else { /* end of argument list */ 3401590Srgrimes chrsave(EOS); 3411590Srgrimes 3421590Srgrimes if (sp == STACKMAX) 3431590Srgrimes oops("internal stack overflow", ""); 3441590Srgrimes 3451590Srgrimes if (CALTYP == MACRTYPE) 3461590Srgrimes expand((char **) mstack+fp+1, sp-fp); 3471590Srgrimes else 3481590Srgrimes eval((char **) mstack+fp+1, sp-fp, CALTYP); 3491590Srgrimes 3501590Srgrimes ep = PREVEP; /* flush strspace */ 3511590Srgrimes sp = PREVSP; /* previous sp.. */ 3521590Srgrimes fp = PREVFP; /* rewind stack...*/ 3531590Srgrimes } 3541590Srgrimes break; 3551590Srgrimes 3561590Srgrimes case COMMA: 3571590Srgrimes if (PARLEV == 1) { 3581590Srgrimes chrsave(EOS); /* new argument */ 3595165Sache while ((l = gpbc()) != EOF && isspace(l)) 3601590Srgrimes ; 3611590Srgrimes putback(l); 3621590Srgrimes pushs(ep); 3631590Srgrimes } else 3641590Srgrimes chrsave(t); 3651590Srgrimes break; 3661590Srgrimes 3671590Srgrimes default: 3681590Srgrimes chrsave(t); /* stack the char */ 3691590Srgrimes break; 3701590Srgrimes } 3711590Srgrimes } 3721590Srgrimes} 3731590Srgrimes 3741590Srgrimes/* 3751590Srgrimes * build an input token.. 3761590Srgrimes * consider only those starting with _ or A-Za-z. This is a 3771590Srgrimes * combo with lookup to speed things up. 3781590Srgrimes */ 3791590Srgrimesndptr 3808874Srgrimesinspect(tp) 3811590Srgrimesregister char *tp; 3821590Srgrimes{ 3835165Sache register int c; 3841590Srgrimes register char *name = tp; 3851590Srgrimes register char *etp = tp+MAXTOK; 3861590Srgrimes register ndptr p; 3871590Srgrimes register unsigned long h = 0; 3881590Srgrimes 3895165Sache while ((c = gpbc()) != EOF && (isalnum(c) || c == '_') && tp < etp) 3901590Srgrimes h = (h << 5) + h + (*tp++ = c); 3911590Srgrimes putback(c); 3921590Srgrimes if (tp == etp) 3931590Srgrimes oops("token too long", ""); 3941590Srgrimes 3951590Srgrimes *tp = EOS; 3961590Srgrimes 3971590Srgrimes for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 3981590Srgrimes if (STREQ(name, p->name)) 3991590Srgrimes break; 4001590Srgrimes return p; 4011590Srgrimes} 4021590Srgrimes 4031590Srgrimes/* 4048874Srgrimes * initkwds - initialise m4 keywords as fast as possible. 4051590Srgrimes * This very similar to install, but without certain overheads, 4068874Srgrimes * such as calling lookup. Malloc is not used for storing the 4071590Srgrimes * keyword strings, since we simply use the static pointers 4081590Srgrimes * within keywrds block. 4091590Srgrimes */ 4101590Srgrimesvoid 4111590Srgrimesinitkwds() { 4121590Srgrimes register int i; 4131590Srgrimes register int h; 4141590Srgrimes register ndptr p; 4151590Srgrimes 4161590Srgrimes for (i = 0; i < MAXKEYS; i++) { 4171590Srgrimes h = hash(keywrds[i].knam); 4181590Srgrimes p = (ndptr) xalloc(sizeof(struct ndblock)); 4191590Srgrimes p->nxtptr = hashtab[h]; 4201590Srgrimes hashtab[h] = p; 4211590Srgrimes p->name = keywrds[i].knam; 4221590Srgrimes p->defn = null; 4231590Srgrimes p->type = keywrds[i].ktyp | STATIC; 4241590Srgrimes } 4251590Srgrimes} 426