main.c revision 94957
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 94957 2002-04-17 17:26:32Z jmallett $"; 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> 6280289Sobrien#include <stdlib.h> 631590Srgrimes#include <string.h> 6427625Scharnier#include <unistd.h> 651590Srgrimes#include "mdef.h" 661590Srgrimes#include "stdd.h" 671590Srgrimes#include "extern.h" 681590Srgrimes#include "pathnames.h" 691590Srgrimes 701590Srgrimesndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 715165Sacheunsigned char buf[BUFSIZE]; /* push-back buffer */ 725165Sacheunsigned char *bufbase = buf; /* the base for current ilevel */ 735165Sacheunsigned char *bbase[MAXINP]; /* the base for each ilevel */ 745165Sacheunsigned char *bp = buf; /* first available character */ 755165Sacheunsigned char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 761590Srgrimesstae mstack[STACKMAX+1]; /* stack of m4 machine */ 771590Srgrimeschar strspace[STRSPMAX+1]; /* string space for evaluation */ 781590Srgrimeschar *ep = strspace; /* first free char in strspace */ 791590Srgrimeschar *endest= strspace+STRSPMAX;/* end of string space */ 801590Srgrimesint sp; /* current m4 stack pointer */ 811590Srgrimesint fp; /* m4 call frame pointer */ 821590SrgrimesFILE *infile[MAXINP]; /* input file stack (0=stdin) */ 8394957Sjmallettchar *inname[MAXINP]; /* names of these input files */ 8494957Sjmallettint inlineno[MAXINP]; /* current number in each input*/ 851590SrgrimesFILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 861590SrgrimesFILE *active; /* active output file pointer */ 871590Srgrimeschar *m4temp; /* filename for diversions */ 8869030Skrischar *m4dir; /* directory for diversions */ 891590Srgrimesint ilevel = 0; /* input file stack pointer */ 901590Srgrimesint oindex = 0; /* diversion index.. */ 911590Srgrimeschar *null = ""; /* as it says.. just a null.. */ 921590Srgrimeschar *m4wraps = ""; /* m4wrap string default.. */ 931590Srgrimeschar lquote = LQUOTE; /* left quote character (`) */ 941590Srgrimeschar rquote = RQUOTE; /* right quote character (') */ 951590Srgrimeschar scommt = SCOMMT; /* start character for comment */ 961590Srgrimeschar ecommt = ECOMMT; /* end character for comment */ 9794957Sjmallettint synccpp; /* Line synchronisation for C preprocessor */ 9894957Sjmallettint chscratch; /* Scratch space for gpbc() macro */ 991590Srgrimes 1001590Srgrimesstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 1011590Srgrimes "include", INCLTYPE, 1021590Srgrimes "sinclude", SINCTYPE, 1031590Srgrimes "define", DEFITYPE, 1041590Srgrimes "defn", DEFNTYPE, 1051590Srgrimes "divert", DIVRTYPE, 1061590Srgrimes "expr", EXPRTYPE, 1071590Srgrimes "eval", EXPRTYPE, 1081590Srgrimes "substr", SUBSTYPE, 1091590Srgrimes "ifelse", IFELTYPE, 1101590Srgrimes "ifdef", IFDFTYPE, 1111590Srgrimes "len", LENGTYPE, 1121590Srgrimes "incr", INCRTYPE, 1131590Srgrimes "decr", DECRTYPE, 1141590Srgrimes "dnl", DNLNTYPE, 1151590Srgrimes "changequote", CHNQTYPE, 1161590Srgrimes "changecom", CHNCTYPE, 1171590Srgrimes "index", INDXTYPE, 1181590Srgrimes#ifdef EXTENDED 1191590Srgrimes "paste", PASTTYPE, 1201590Srgrimes "spaste", SPASTYPE, 1211590Srgrimes#endif 1221590Srgrimes "popdef", POPDTYPE, 1231590Srgrimes "pushdef", PUSDTYPE, 1241590Srgrimes "dumpdef", DUMPTYPE, 1251590Srgrimes "shift", SHIFTYPE, 1261590Srgrimes "translit", TRNLTYPE, 1271590Srgrimes "undefine", UNDFTYPE, 1281590Srgrimes "undivert", UNDVTYPE, 1291590Srgrimes "divnum", DIVNTYPE, 1301590Srgrimes "maketemp", MKTMTYPE, 1311590Srgrimes "errprint", ERRPTYPE, 1321590Srgrimes "m4wrap", M4WRTYPE, 1331590Srgrimes "m4exit", EXITTYPE, 1341590Srgrimes "syscmd", SYSCTYPE, 1351590Srgrimes "sysval", SYSVTYPE, 1361590Srgrimes 1371590Srgrimes#ifdef unix 1381590Srgrimes "unix", MACRTYPE, 1391590Srgrimes#else 1401590Srgrimes#ifdef vms 1411590Srgrimes "vms", MACRTYPE, 1421590Srgrimes#endif 1431590Srgrimes#endif 1441590Srgrimes}; 1451590Srgrimes 1461590Srgrimes#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1471590Srgrimes 1481590Srgrimesvoid macro(); 1491590Srgrimesvoid initkwds(); 1501590Srgrimes 1511590Srgrimesint 1521590Srgrimesmain(argc,argv) 1531590Srgrimes int argc; 1541590Srgrimes char *argv[]; 1551590Srgrimes{ 1561590Srgrimes register int c; 1571590Srgrimes register int n; 1581590Srgrimes char *p; 1591590Srgrimes register FILE *ifp; 1601590Srgrimes 1611590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1621590Srgrimes signal(SIGINT, onintr); 1631590Srgrimes 1641590Srgrimes initkwds(); 1651590Srgrimes 16694957Sjmallett while ((c = getopt(argc, argv, "D:U:s")) != -1) 1671590Srgrimes switch(c) { 1681590Srgrimes 1691590Srgrimes case 'D': /* define something..*/ 1701590Srgrimes for (p = optarg; *p; p++) 1711590Srgrimes if (*p == '=') 1721590Srgrimes break; 1731590Srgrimes if (*p) 1741590Srgrimes *p++ = EOS; 1751590Srgrimes dodefine(optarg, p); 1761590Srgrimes break; 1771590Srgrimes case 'U': /* undefine... */ 1781590Srgrimes remhash(optarg, TOP); 1791590Srgrimes break; 18094957Sjmallett case 's': 18194957Sjmallett synccpp = 1; 18294957Sjmallett break; 1831590Srgrimes case '?': 1841590Srgrimes usage(); 1851590Srgrimes } 1861590Srgrimes 1871590Srgrimes argc -= optind; 1881590Srgrimes argv += optind; 1891590Srgrimes 1901590Srgrimes active = stdout; /* default active output */ 19180289Sobrien if ((p = strdup(_PATH_DIVDIRNAME)) == NULL) 19280289Sobrien err(1, "strdup"); 19380289Sobrien 1941590Srgrimes /* filename for diversions */ 19580289Sobrien m4dir = mkdtemp(p); 19675551Sgshapiro err_set_exit(cleanup); 19769030Skris (void) asprintf(&m4temp, "%s/%s", m4dir, _PATH_DIVNAME); 1981590Srgrimes 1991590Srgrimes bbase[0] = bufbase; 2001590Srgrimes if (!argc) { 2011590Srgrimes sp = -1; /* stack pointer initialized */ 2021590Srgrimes fp = 0; /* frame pointer initialized */ 2031590Srgrimes infile[0] = stdin; /* default input (naturally) */ 20494957Sjmallett if ((inname[0] = strdup("-")) == NULL) 20594957Sjmallett err(1, NULL); 20694957Sjmallett inlineno[0] = 1; 20794957Sjmallett emitline(); 2081590Srgrimes macro(); 2091590Srgrimes } else 2101590Srgrimes for (; argc--; ++argv) { 2111590Srgrimes p = *argv; 2121590Srgrimes if (p[0] == '-' && p[1] == '\0') 2131590Srgrimes ifp = stdin; 2141590Srgrimes else if ((ifp = fopen(p, "r")) == NULL) 21527625Scharnier err(1, "%s", p); 2161590Srgrimes sp = -1; 2178874Srgrimes fp = 0; 2181590Srgrimes infile[0] = ifp; 21994957Sjmallett if ((inname[0] = strdup(p)) == NULL) 22094957Sjmallett err(1, NULL); 22194957Sjmallett inlineno[0] = 1; 22294957Sjmallett emitline(); 2231590Srgrimes macro(); 2241590Srgrimes if (ifp != stdin) 2251590Srgrimes (void)fclose(ifp); 2261590Srgrimes } 2271590Srgrimes 2281590Srgrimes if (*m4wraps) { /* anything for rundown ?? */ 2291590Srgrimes ilevel = 0; /* in case m4wrap includes.. */ 2301590Srgrimes bufbase = bp = buf; /* use the entire buffer */ 2311590Srgrimes putback(EOF); /* eof is a must !! */ 2321590Srgrimes pbstr(m4wraps); /* user-defined wrapup act */ 2331590Srgrimes macro(); /* last will and testament */ 2341590Srgrimes } 2351590Srgrimes 2361590Srgrimes if (active != stdout) 2371590Srgrimes active = stdout; /* reset output just in case */ 2381590Srgrimes for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 2391590Srgrimes if (outfile[n] != NULL) 2401590Srgrimes getdiv(n); 2411590Srgrimes /* remove bitbucket if used */ 24275551Sgshapiro cleanup(0); 2431590Srgrimes return 0; 2441590Srgrimes} 2451590Srgrimes 2461590Srgrimesndptr inspect(); 2471590Srgrimes 2481590Srgrimes/* 2491590Srgrimes * macro - the work horse.. 2501590Srgrimes */ 2511590Srgrimesvoid 2521590Srgrimesmacro() { 2531590Srgrimes char token[MAXTOK]; 2541590Srgrimes register char *s; 2551590Srgrimes register int t, l; 2561590Srgrimes register ndptr p; 2571590Srgrimes register int nlpar; 2581590Srgrimes 2591590Srgrimes cycle { 2605165Sache if ((t = gpbc()) == '_' || (t != EOF && isalpha(t))) { 2611590Srgrimes putback(t); 2621590Srgrimes if ((p = inspect(s = token)) == nil) { 2631590Srgrimes if (sp < 0) 2641590Srgrimes while (*s) 2651590Srgrimes putc(*s++, active); 2661590Srgrimes else 2671590Srgrimes while (*s) 2681590Srgrimes chrsave(*s++); 2691590Srgrimes } 2701590Srgrimes else { 2711590Srgrimes /* 2721590Srgrimes * real thing.. First build a call frame: 2731590Srgrimes */ 2741590Srgrimes pushf(fp); /* previous call frm */ 2751590Srgrimes pushf(p->type); /* type of the call */ 2761590Srgrimes pushf(0); /* parenthesis level */ 2771590Srgrimes fp = sp; /* new frame pointer */ 2781590Srgrimes /* 2791590Srgrimes * now push the string arguments: 2801590Srgrimes */ 2811590Srgrimes pushs(p->defn); /* defn string */ 2821590Srgrimes pushs(p->name); /* macro name */ 2831590Srgrimes pushs(ep); /* start next..*/ 2841590Srgrimes 2851590Srgrimes putback(l = gpbc()); 2861590Srgrimes if (l != LPAREN) { /* add bracks */ 2871590Srgrimes putback(RPAREN); 2881590Srgrimes putback(LPAREN); 2891590Srgrimes } 2901590Srgrimes } 2911590Srgrimes } 2921590Srgrimes else if (t == EOF) { 2931590Srgrimes if (sp > -1) 29427625Scharnier errx(1, "unexpected end of input"); 2951590Srgrimes if (ilevel <= 0) 2961590Srgrimes break; /* all done thanks.. */ 2971590Srgrimes --ilevel; 2981590Srgrimes (void) fclose(infile[ilevel+1]); 29994957Sjmallett free(inname[ilevel+1]); 3001590Srgrimes bufbase = bbase[ilevel]; 30194957Sjmallett emitline(); 3021590Srgrimes continue; 3031590Srgrimes } 3041590Srgrimes /* 3051590Srgrimes * non-alpha single-char token seen.. 3061590Srgrimes * [the order of else if .. stmts is important.] 3071590Srgrimes */ 3081590Srgrimes else if (t == lquote) { /* strip quotes */ 3091590Srgrimes nlpar = 1; 3101590Srgrimes do { 3111590Srgrimes if ((l = gpbc()) == rquote) 3121590Srgrimes nlpar--; 3131590Srgrimes else if (l == lquote) 3141590Srgrimes nlpar++; 3151590Srgrimes else if (l == EOF) 31627625Scharnier errx(1, "missing right quote"); 3171590Srgrimes if (nlpar > 0) { 3181590Srgrimes if (sp < 0) 3191590Srgrimes putc(l, active); 3201590Srgrimes else 3211590Srgrimes chrsave(l); 3221590Srgrimes } 3231590Srgrimes } 3241590Srgrimes while (nlpar != 0); 3251590Srgrimes } 3261590Srgrimes 3271590Srgrimes else if (sp < 0) { /* not in a macro at all */ 3281590Srgrimes if (t == scommt) { /* comment handling here */ 3291590Srgrimes putc(t, active); 3301590Srgrimes while ((t = gpbc()) != ecommt) 3311590Srgrimes putc(t, active); 3321590Srgrimes } 3331590Srgrimes putc(t, active); /* output directly.. */ 3341590Srgrimes } 3351590Srgrimes 3361590Srgrimes else switch(t) { 3371590Srgrimes 3381590Srgrimes case LPAREN: 3391590Srgrimes if (PARLEV > 0) 3401590Srgrimes chrsave(t); 3415165Sache while ((l = gpbc()) != EOF && isspace(l)) 3421590Srgrimes ; /* skip blank, tab, nl.. */ 3431590Srgrimes putback(l); 3441590Srgrimes PARLEV++; 3451590Srgrimes break; 3461590Srgrimes 3471590Srgrimes case RPAREN: 3481590Srgrimes if (--PARLEV > 0) 3491590Srgrimes chrsave(t); 3501590Srgrimes else { /* end of argument list */ 3511590Srgrimes chrsave(EOS); 3521590Srgrimes 3531590Srgrimes if (sp == STACKMAX) 35427625Scharnier errx(1, "internal stack overflow"); 3551590Srgrimes 3561590Srgrimes if (CALTYP == MACRTYPE) 3571590Srgrimes expand((char **) mstack+fp+1, sp-fp); 3581590Srgrimes else 3591590Srgrimes eval((char **) mstack+fp+1, sp-fp, CALTYP); 3601590Srgrimes 3611590Srgrimes ep = PREVEP; /* flush strspace */ 3621590Srgrimes sp = PREVSP; /* previous sp.. */ 3631590Srgrimes fp = PREVFP; /* rewind stack...*/ 3641590Srgrimes } 3651590Srgrimes break; 3661590Srgrimes 3671590Srgrimes case COMMA: 3681590Srgrimes if (PARLEV == 1) { 3691590Srgrimes chrsave(EOS); /* new argument */ 3705165Sache while ((l = gpbc()) != EOF && isspace(l)) 3711590Srgrimes ; 3721590Srgrimes putback(l); 3731590Srgrimes pushs(ep); 3741590Srgrimes } else 3751590Srgrimes chrsave(t); 3761590Srgrimes break; 3771590Srgrimes 3781590Srgrimes default: 3791590Srgrimes chrsave(t); /* stack the char */ 3801590Srgrimes break; 3811590Srgrimes } 3821590Srgrimes } 3831590Srgrimes} 3841590Srgrimes 3851590Srgrimes/* 3861590Srgrimes * build an input token.. 3871590Srgrimes * consider only those starting with _ or A-Za-z. This is a 3881590Srgrimes * combo with lookup to speed things up. 3891590Srgrimes */ 3901590Srgrimesndptr 3918874Srgrimesinspect(tp) 3921590Srgrimesregister char *tp; 3931590Srgrimes{ 3945165Sache register int c; 3951590Srgrimes register char *name = tp; 3961590Srgrimes register char *etp = tp+MAXTOK; 3971590Srgrimes register ndptr p; 3981590Srgrimes register unsigned long h = 0; 3991590Srgrimes 4005165Sache while ((c = gpbc()) != EOF && (isalnum(c) || c == '_') && tp < etp) 4011590Srgrimes h = (h << 5) + h + (*tp++ = c); 4021590Srgrimes putback(c); 4031590Srgrimes if (tp == etp) 40427625Scharnier errx(1, "token too long"); 4051590Srgrimes 4061590Srgrimes *tp = EOS; 4071590Srgrimes 4081590Srgrimes for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 4091590Srgrimes if (STREQ(name, p->name)) 4101590Srgrimes break; 4111590Srgrimes return p; 4121590Srgrimes} 4131590Srgrimes 4141590Srgrimes/* 4158874Srgrimes * initkwds - initialise m4 keywords as fast as possible. 4161590Srgrimes * This very similar to install, but without certain overheads, 4178874Srgrimes * such as calling lookup. Malloc is not used for storing the 4181590Srgrimes * keyword strings, since we simply use the static pointers 4191590Srgrimes * within keywrds block. 4201590Srgrimes */ 4211590Srgrimesvoid 4221590Srgrimesinitkwds() { 4231590Srgrimes register int i; 4241590Srgrimes register int h; 4251590Srgrimes register ndptr p; 4261590Srgrimes 4271590Srgrimes for (i = 0; i < MAXKEYS; i++) { 4281590Srgrimes h = hash(keywrds[i].knam); 42980289Sobrien if ((p = malloc(sizeof(struct ndblock))) == NULL) 43080289Sobrien err(1, "malloc"); 4311590Srgrimes p->nxtptr = hashtab[h]; 4321590Srgrimes hashtab[h] = p; 4331590Srgrimes p->name = keywrds[i].knam; 4341590Srgrimes p->defn = null; 4351590Srgrimes p->type = keywrds[i].ktyp | STATIC; 4361590Srgrimes } 4371590Srgrimes} 43894957Sjmallett 43994957Sjmallett/* Emit preprocessor #line directive if -s option used. */ 44094957Sjmallettvoid 44194957Sjmallettemitline(void) 44294957Sjmallett{ 44394957Sjmallett if (synccpp) 44494957Sjmallett fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel], 44594957Sjmallett inname[ilevel]); 44694957Sjmallett} 447