main.c revision 69030
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 3827625Scharnierstatic const 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 4427625Scharnier#if 0 451590Srgrimesstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 4627625Scharnier#endif 4727625Scharnierstatic const char rcsid[] = 4850477Speter "$FreeBSD: head/usr.bin/m4/main.c 69030 2000-11-22 11:09:30Z kris $"; 491590Srgrimes#endif /* not lint */ 501590Srgrimes 511590Srgrimes/* 521590Srgrimes * main.c 531590Srgrimes * Facility: m4 macro processor 541590Srgrimes * by: oz 551590Srgrimes */ 561590Srgrimes 571590Srgrimes#include <sys/types.h> 5827625Scharnier#include <ctype.h> 5927625Scharnier#include <err.h> 601590Srgrimes#include <signal.h> 611590Srgrimes#include <stdio.h> 621590Srgrimes#include <string.h> 6327625Scharnier#include <unistd.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. */ 705165Sacheunsigned char buf[BUFSIZE]; /* push-back buffer */ 715165Sacheunsigned char *bufbase = buf; /* the base for current ilevel */ 725165Sacheunsigned char *bbase[MAXINP]; /* the base for each ilevel */ 735165Sacheunsigned char *bp = buf; /* first available character */ 745165Sacheunsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 751590Srgrimesstae mstack[STACKMAX+1]; /* stack of m4 machine */ 761590Srgrimeschar strspace[STRSPMAX+1]; /* string space for evaluation */ 771590Srgrimeschar *ep = strspace; /* first free char in strspace */ 781590Srgrimeschar *endest= strspace+STRSPMAX;/* end of string space */ 791590Srgrimesint sp; /* current m4 stack pointer */ 801590Srgrimesint fp; /* m4 call frame pointer */ 811590SrgrimesFILE *infile[MAXINP]; /* input file stack (0=stdin) */ 821590SrgrimesFILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 831590SrgrimesFILE *active; /* active output file pointer */ 841590Srgrimeschar *m4temp; /* filename for diversions */ 8569030Skrischar *m4dir; /* directory for diversions */ 861590Srgrimesint ilevel = 0; /* input file stack pointer */ 871590Srgrimesint oindex = 0; /* diversion index.. */ 881590Srgrimeschar *null = ""; /* as it says.. just a null.. */ 891590Srgrimeschar *m4wraps = ""; /* m4wrap string default.. */ 901590Srgrimeschar lquote = LQUOTE; /* left quote character (`) */ 911590Srgrimeschar rquote = RQUOTE; /* right quote character (') */ 921590Srgrimeschar scommt = SCOMMT; /* start character for comment */ 931590Srgrimeschar ecommt = ECOMMT; /* end character for comment */ 941590Srgrimes 951590Srgrimesstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 961590Srgrimes "include", INCLTYPE, 971590Srgrimes "sinclude", SINCTYPE, 981590Srgrimes "define", DEFITYPE, 991590Srgrimes "defn", DEFNTYPE, 1001590Srgrimes "divert", DIVRTYPE, 1011590Srgrimes "expr", EXPRTYPE, 1021590Srgrimes "eval", EXPRTYPE, 1031590Srgrimes "substr", SUBSTYPE, 1041590Srgrimes "ifelse", IFELTYPE, 1051590Srgrimes "ifdef", IFDFTYPE, 1061590Srgrimes "len", LENGTYPE, 1071590Srgrimes "incr", INCRTYPE, 1081590Srgrimes "decr", DECRTYPE, 1091590Srgrimes "dnl", DNLNTYPE, 1101590Srgrimes "changequote", CHNQTYPE, 1111590Srgrimes "changecom", CHNCTYPE, 1121590Srgrimes "index", INDXTYPE, 1131590Srgrimes#ifdef EXTENDED 1141590Srgrimes "paste", PASTTYPE, 1151590Srgrimes "spaste", SPASTYPE, 1161590Srgrimes#endif 1171590Srgrimes "popdef", POPDTYPE, 1181590Srgrimes "pushdef", PUSDTYPE, 1191590Srgrimes "dumpdef", DUMPTYPE, 1201590Srgrimes "shift", SHIFTYPE, 1211590Srgrimes "translit", TRNLTYPE, 1221590Srgrimes "undefine", UNDFTYPE, 1231590Srgrimes "undivert", UNDVTYPE, 1241590Srgrimes "divnum", DIVNTYPE, 1251590Srgrimes "maketemp", MKTMTYPE, 1261590Srgrimes "errprint", ERRPTYPE, 1271590Srgrimes "m4wrap", M4WRTYPE, 1281590Srgrimes "m4exit", EXITTYPE, 1291590Srgrimes "syscmd", SYSCTYPE, 1301590Srgrimes "sysval", SYSVTYPE, 1311590Srgrimes 1321590Srgrimes#ifdef unix 1331590Srgrimes "unix", MACRTYPE, 1341590Srgrimes#else 1351590Srgrimes#ifdef vms 1361590Srgrimes "vms", MACRTYPE, 1371590Srgrimes#endif 1381590Srgrimes#endif 1391590Srgrimes}; 1401590Srgrimes 1411590Srgrimes#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1421590Srgrimes 1431590Srgrimesvoid macro(); 1441590Srgrimesvoid initkwds(); 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 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1571590Srgrimes signal(SIGINT, onintr); 1581590Srgrimes 1591590Srgrimes initkwds(); 1601590Srgrimes 16124360Simp while ((c = getopt(argc, argv, "tD:U:o:")) != -1) 1621590Srgrimes switch(c) { 1631590Srgrimes 1641590Srgrimes case 'D': /* define something..*/ 1651590Srgrimes for (p = optarg; *p; p++) 1661590Srgrimes if (*p == '=') 1671590Srgrimes break; 1681590Srgrimes if (*p) 1691590Srgrimes *p++ = EOS; 1701590Srgrimes dodefine(optarg, p); 1711590Srgrimes break; 1721590Srgrimes case 'U': /* undefine... */ 1731590Srgrimes remhash(optarg, TOP); 1741590Srgrimes break; 1751590Srgrimes case 'o': /* specific output */ 1761590Srgrimes case '?': 1771590Srgrimes usage(); 1781590Srgrimes } 1791590Srgrimes 1801590Srgrimes argc -= optind; 1811590Srgrimes argv += optind; 1821590Srgrimes 1831590Srgrimes active = stdout; /* default active output */ 1841590Srgrimes /* filename for diversions */ 18569030Skris m4dir = mkdtemp(xstrdup(_PATH_DIVDIRNAME)); 18669030Skris (void) asprintf(&m4temp, "%s/%s", m4dir, _PATH_DIVNAME); 1871590Srgrimes 1881590Srgrimes bbase[0] = bufbase; 1891590Srgrimes if (!argc) { 1901590Srgrimes sp = -1; /* stack pointer initialized */ 1911590Srgrimes fp = 0; /* frame pointer initialized */ 1921590Srgrimes infile[0] = stdin; /* default input (naturally) */ 1931590Srgrimes macro(); 1941590Srgrimes } else 1951590Srgrimes for (; argc--; ++argv) { 1961590Srgrimes p = *argv; 1971590Srgrimes if (p[0] == '-' && p[1] == '\0') 1981590Srgrimes ifp = stdin; 1991590Srgrimes else if ((ifp = fopen(p, "r")) == NULL) 20027625Scharnier err(1, "%s", p); 2011590Srgrimes sp = -1; 2028874Srgrimes fp = 0; 2031590Srgrimes infile[0] = ifp; 2041590Srgrimes macro(); 2051590Srgrimes if (ifp != stdin) 2061590Srgrimes (void)fclose(ifp); 2071590Srgrimes } 2081590Srgrimes 2091590Srgrimes if (*m4wraps) { /* anything for rundown ?? */ 2101590Srgrimes ilevel = 0; /* in case m4wrap includes.. */ 2111590Srgrimes bufbase = bp = buf; /* use the entire buffer */ 2121590Srgrimes putback(EOF); /* eof is a must !! */ 2131590Srgrimes pbstr(m4wraps); /* user-defined wrapup act */ 2141590Srgrimes macro(); /* last will and testament */ 2151590Srgrimes } 2161590Srgrimes 2171590Srgrimes if (active != stdout) 2181590Srgrimes active = stdout; /* reset output just in case */ 2191590Srgrimes for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 2201590Srgrimes if (outfile[n] != NULL) 2211590Srgrimes getdiv(n); 2221590Srgrimes /* remove bitbucket if used */ 2231590Srgrimes if (outfile[0] != NULL) { 2241590Srgrimes (void) fclose(outfile[0]); 2251590Srgrimes m4temp[UNIQUE] = '0'; 2261590Srgrimes#ifdef vms 2271590Srgrimes (void) remove(m4temp); 2281590Srgrimes#else 2291590Srgrimes (void) unlink(m4temp); 23069030Skris (void) rmdir(m4dir); 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) 28527625Scharnier errx(1, "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) 30527625Scharnier errx(1, "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) 34327625Scharnier errx(1, "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) 39327625Scharnier errx(1, "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