149c8b7acSbostic /*-
2*494f5ecfSbostic * Copyright (c) 1989, 1993
3*494f5ecfSbostic * The Regents of the University of California. All rights reserved.
430ce8384Sbostic *
530ce8384Sbostic * This code is derived from software contributed to Berkeley by
6a435ab37Sbostic * Ozan Yigit at York University.
730ce8384Sbostic *
849c8b7acSbostic * %sccs.include.redist.c%
930ce8384Sbostic */
1030ce8384Sbostic
1130ce8384Sbostic #ifndef lint
12*494f5ecfSbostic static char copyright[] =
13*494f5ecfSbostic "@(#) Copyright (c) 1989, 1993\n\
14*494f5ecfSbostic The Regents of the University of California. All rights reserved.\n";
1549c8b7acSbostic #endif /* not lint */
1649c8b7acSbostic
1749c8b7acSbostic #ifndef lint
18*494f5ecfSbostic static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/06/93";
1930ce8384Sbostic #endif /* not lint */
2030ce8384Sbostic
2130ce8384Sbostic /*
2230ce8384Sbostic * main.c
2330ce8384Sbostic * Facility: m4 macro processor
2430ce8384Sbostic * by: oz
2530ce8384Sbostic */
2630ce8384Sbostic
27d3eef09bSbostic #include <sys/types.h>
28935903d7Sbostic #include <signal.h>
29d3eef09bSbostic #include <errno.h>
30935903d7Sbostic #include <unistd.h>
31935903d7Sbostic #include <stdio.h>
32d3eef09bSbostic #include <ctype.h>
33935903d7Sbostic #include <string.h>
3430ce8384Sbostic #include "mdef.h"
35d3eef09bSbostic #include "stdd.h"
36d3eef09bSbostic #include "extern.h"
37935903d7Sbostic #include "pathnames.h"
3830ce8384Sbostic
3930ce8384Sbostic ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
4030ce8384Sbostic char buf[BUFSIZE]; /* push-back buffer */
41c22b2b5fSeric char *bufbase = buf; /* the base for current ilevel */
42c22b2b5fSeric char *bbase[MAXINP]; /* the base for each ilevel */
4330ce8384Sbostic char *bp = buf; /* first available character */
4430ce8384Sbostic char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
4530ce8384Sbostic stae mstack[STACKMAX+1]; /* stack of m4 machine */
4630ce8384Sbostic char strspace[STRSPMAX+1]; /* string space for evaluation */
4730ce8384Sbostic char *ep = strspace; /* first free char in strspace */
4830ce8384Sbostic char *endest= strspace+STRSPMAX;/* end of string space */
4930ce8384Sbostic int sp; /* current m4 stack pointer */
5030ce8384Sbostic int fp; /* m4 call frame pointer */
5130ce8384Sbostic FILE *infile[MAXINP]; /* input file stack (0=stdin) */
5230ce8384Sbostic FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
5330ce8384Sbostic FILE *active; /* active output file pointer */
5430ce8384Sbostic char *m4temp; /* filename for diversions */
5530ce8384Sbostic int ilevel = 0; /* input file stack pointer */
5630ce8384Sbostic int oindex = 0; /* diversion index.. */
5730ce8384Sbostic char *null = ""; /* as it says.. just a null.. */
5830ce8384Sbostic char *m4wraps = ""; /* m4wrap string default.. */
59d3eef09bSbostic char *progname; /* name of this program */
6030ce8384Sbostic char lquote = LQUOTE; /* left quote character (`) */
6130ce8384Sbostic char rquote = RQUOTE; /* right quote character (') */
6230ce8384Sbostic char scommt = SCOMMT; /* start character for comment */
6330ce8384Sbostic char ecommt = ECOMMT; /* end character for comment */
64d3eef09bSbostic
6530ce8384Sbostic struct keyblk keywrds[] = { /* m4 keywords to be installed */
6630ce8384Sbostic "include", INCLTYPE,
6730ce8384Sbostic "sinclude", SINCTYPE,
6830ce8384Sbostic "define", DEFITYPE,
6930ce8384Sbostic "defn", DEFNTYPE,
7030ce8384Sbostic "divert", DIVRTYPE,
7130ce8384Sbostic "expr", EXPRTYPE,
7230ce8384Sbostic "eval", EXPRTYPE,
7330ce8384Sbostic "substr", SUBSTYPE,
7430ce8384Sbostic "ifelse", IFELTYPE,
7530ce8384Sbostic "ifdef", IFDFTYPE,
7630ce8384Sbostic "len", LENGTYPE,
7730ce8384Sbostic "incr", INCRTYPE,
7830ce8384Sbostic "decr", DECRTYPE,
7930ce8384Sbostic "dnl", DNLNTYPE,
8030ce8384Sbostic "changequote", CHNQTYPE,
8130ce8384Sbostic "changecom", CHNCTYPE,
8230ce8384Sbostic "index", INDXTYPE,
8330ce8384Sbostic #ifdef EXTENDED
8430ce8384Sbostic "paste", PASTTYPE,
8530ce8384Sbostic "spaste", SPASTYPE,
8630ce8384Sbostic #endif
8730ce8384Sbostic "popdef", POPDTYPE,
8830ce8384Sbostic "pushdef", PUSDTYPE,
8930ce8384Sbostic "dumpdef", DUMPTYPE,
9030ce8384Sbostic "shift", SHIFTYPE,
9130ce8384Sbostic "translit", TRNLTYPE,
9230ce8384Sbostic "undefine", UNDFTYPE,
9330ce8384Sbostic "undivert", UNDVTYPE,
9430ce8384Sbostic "divnum", DIVNTYPE,
9530ce8384Sbostic "maketemp", MKTMTYPE,
9630ce8384Sbostic "errprint", ERRPTYPE,
9730ce8384Sbostic "m4wrap", M4WRTYPE,
9830ce8384Sbostic "m4exit", EXITTYPE,
9930ce8384Sbostic "syscmd", SYSCTYPE,
10030ce8384Sbostic "sysval", SYSVTYPE,
101d3eef09bSbostic
102d3eef09bSbostic #ifdef unix
10330ce8384Sbostic "unix", MACRTYPE,
104d3eef09bSbostic #else
105d3eef09bSbostic #ifdef vms
106d3eef09bSbostic "vms", MACRTYPE,
107d3eef09bSbostic #endif
108d3eef09bSbostic #endif
10930ce8384Sbostic };
11030ce8384Sbostic
11130ce8384Sbostic #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
11230ce8384Sbostic
11330ce8384Sbostic extern int optind;
11430ce8384Sbostic extern char *optarg;
11530ce8384Sbostic
116d3eef09bSbostic void macro();
117d3eef09bSbostic void initkwds();
118d3eef09bSbostic extern int getopt();
119d3eef09bSbostic
120d3eef09bSbostic int
main(argc,argv)12130ce8384Sbostic main(argc,argv)
122935903d7Sbostic int argc;
123d3eef09bSbostic char *argv[];
12430ce8384Sbostic {
12530ce8384Sbostic register int c;
12630ce8384Sbostic register int n;
12730ce8384Sbostic char *p;
128d3eef09bSbostic register FILE *ifp;
129d3eef09bSbostic
130d3eef09bSbostic progname = basename(argv[0]);
13130ce8384Sbostic
13230ce8384Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN)
13330ce8384Sbostic signal(SIGINT, onintr);
134d3eef09bSbostic
13530ce8384Sbostic initkwds();
13630ce8384Sbostic
13730ce8384Sbostic while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
13830ce8384Sbostic switch(c) {
13930ce8384Sbostic
14030ce8384Sbostic case 'D': /* define something..*/
14130ce8384Sbostic for (p = optarg; *p; p++)
14230ce8384Sbostic if (*p == '=')
14330ce8384Sbostic break;
14430ce8384Sbostic if (*p)
14530ce8384Sbostic *p++ = EOS;
14630ce8384Sbostic dodefine(optarg, p);
14730ce8384Sbostic break;
14830ce8384Sbostic case 'U': /* undefine... */
14930ce8384Sbostic remhash(optarg, TOP);
15030ce8384Sbostic break;
15130ce8384Sbostic case 'o': /* specific output */
15230ce8384Sbostic case '?':
15330ce8384Sbostic usage();
15430ce8384Sbostic }
15530ce8384Sbostic
156d3eef09bSbostic argc -= optind;
157d3eef09bSbostic argv += optind;
15830ce8384Sbostic
159d3eef09bSbostic active = stdout; /* default active output */
160d3eef09bSbostic /* filename for diversions */
161d3eef09bSbostic m4temp = mktemp(xstrdup(_PATH_DIVNAME));
162d3eef09bSbostic
163c22b2b5fSeric bbase[0] = bufbase;
164d3eef09bSbostic if (!argc) {
16530ce8384Sbostic sp = -1; /* stack pointer initialized */
16630ce8384Sbostic fp = 0; /* frame pointer initialized */
167d3eef09bSbostic infile[0] = stdin; /* default input (naturally) */
168d3eef09bSbostic macro();
16949c8b7acSbostic } else
17049c8b7acSbostic for (; argc--; ++argv) {
17149c8b7acSbostic p = *argv;
17249c8b7acSbostic if (p[0] == '-' && p[1] == '\0')
17349c8b7acSbostic ifp = stdin;
17449c8b7acSbostic else if ((ifp = fopen(p, "r")) == NULL)
17549c8b7acSbostic oops("%s: %s", p, strerror(errno));
176d3eef09bSbostic sp = -1;
177d3eef09bSbostic fp = 0;
178d3eef09bSbostic infile[0] = ifp;
179d3eef09bSbostic macro();
18049c8b7acSbostic if (ifp != stdin)
181d3eef09bSbostic (void)fclose(ifp);
182d3eef09bSbostic }
18330ce8384Sbostic
18430ce8384Sbostic if (*m4wraps) { /* anything for rundown ?? */
18530ce8384Sbostic ilevel = 0; /* in case m4wrap includes.. */
186c22b2b5fSeric bufbase = bp = buf; /* use the entire buffer */
18730ce8384Sbostic putback(EOF); /* eof is a must !! */
18830ce8384Sbostic pbstr(m4wraps); /* user-defined wrapup act */
18930ce8384Sbostic macro(); /* last will and testament */
19030ce8384Sbostic }
19194a016b3Sbostic
19294a016b3Sbostic if (active != stdout)
19394a016b3Sbostic active = stdout; /* reset output just in case */
19494a016b3Sbostic for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */
19530ce8384Sbostic if (outfile[n] != NULL)
19630ce8384Sbostic getdiv(n);
19730ce8384Sbostic /* remove bitbucket if used */
19830ce8384Sbostic if (outfile[0] != NULL) {
19930ce8384Sbostic (void) fclose(outfile[0]);
20030ce8384Sbostic m4temp[UNIQUE] = '0';
201d3eef09bSbostic #ifdef vms
202d3eef09bSbostic (void) remove(m4temp);
203d3eef09bSbostic #else
20430ce8384Sbostic (void) unlink(m4temp);
205d3eef09bSbostic #endif
20630ce8384Sbostic }
20730ce8384Sbostic
208d3eef09bSbostic return 0;
20930ce8384Sbostic }
21030ce8384Sbostic
211d3eef09bSbostic ndptr inspect();
21230ce8384Sbostic
21330ce8384Sbostic /*
21430ce8384Sbostic * macro - the work horse..
21530ce8384Sbostic */
216d3eef09bSbostic void
macro()21730ce8384Sbostic macro() {
21830ce8384Sbostic char token[MAXTOK];
21930ce8384Sbostic register char *s;
22030ce8384Sbostic register int t, l;
22130ce8384Sbostic register ndptr p;
22230ce8384Sbostic register int nlpar;
22330ce8384Sbostic
22430ce8384Sbostic cycle {
22530ce8384Sbostic if ((t = gpbc()) == '_' || isalpha(t)) {
22630ce8384Sbostic putback(t);
22730ce8384Sbostic if ((p = inspect(s = token)) == nil) {
22830ce8384Sbostic if (sp < 0)
22930ce8384Sbostic while (*s)
23030ce8384Sbostic putc(*s++, active);
23130ce8384Sbostic else
23230ce8384Sbostic while (*s)
23330ce8384Sbostic chrsave(*s++);
23430ce8384Sbostic }
23530ce8384Sbostic else {
23630ce8384Sbostic /*
23730ce8384Sbostic * real thing.. First build a call frame:
23830ce8384Sbostic */
23930ce8384Sbostic pushf(fp); /* previous call frm */
24030ce8384Sbostic pushf(p->type); /* type of the call */
24130ce8384Sbostic pushf(0); /* parenthesis level */
24230ce8384Sbostic fp = sp; /* new frame pointer */
24330ce8384Sbostic /*
24430ce8384Sbostic * now push the string arguments:
24530ce8384Sbostic */
24630ce8384Sbostic pushs(p->defn); /* defn string */
24730ce8384Sbostic pushs(p->name); /* macro name */
24830ce8384Sbostic pushs(ep); /* start next..*/
24930ce8384Sbostic
25030ce8384Sbostic putback(l = gpbc());
25130ce8384Sbostic if (l != LPAREN) { /* add bracks */
25230ce8384Sbostic putback(RPAREN);
25330ce8384Sbostic putback(LPAREN);
25430ce8384Sbostic }
25530ce8384Sbostic }
25630ce8384Sbostic }
25730ce8384Sbostic else if (t == EOF) {
25830ce8384Sbostic if (sp > -1)
259d3eef09bSbostic oops("unexpected end of input", "");
260b31d13bcSleres if (ilevel <= 0)
26130ce8384Sbostic break; /* all done thanks.. */
262b31d13bcSleres --ilevel;
26330ce8384Sbostic (void) fclose(infile[ilevel+1]);
264c22b2b5fSeric bufbase = bbase[ilevel];
26530ce8384Sbostic continue;
26630ce8384Sbostic }
26730ce8384Sbostic /*
26830ce8384Sbostic * non-alpha single-char token seen..
269d3eef09bSbostic * [the order of else if .. stmts is important.]
27030ce8384Sbostic */
27130ce8384Sbostic else if (t == lquote) { /* strip quotes */
27230ce8384Sbostic nlpar = 1;
27330ce8384Sbostic do {
27430ce8384Sbostic if ((l = gpbc()) == rquote)
27530ce8384Sbostic nlpar--;
27630ce8384Sbostic else if (l == lquote)
27730ce8384Sbostic nlpar++;
27830ce8384Sbostic else if (l == EOF)
279d3eef09bSbostic oops("missing right quote", "");
28030ce8384Sbostic if (nlpar > 0) {
28130ce8384Sbostic if (sp < 0)
28230ce8384Sbostic putc(l, active);
28330ce8384Sbostic else
28430ce8384Sbostic chrsave(l);
28530ce8384Sbostic }
28630ce8384Sbostic }
28730ce8384Sbostic while (nlpar != 0);
28830ce8384Sbostic }
28930ce8384Sbostic
29030ce8384Sbostic else if (sp < 0) { /* not in a macro at all */
29130ce8384Sbostic if (t == scommt) { /* comment handling here */
29230ce8384Sbostic putc(t, active);
29330ce8384Sbostic while ((t = gpbc()) != ecommt)
29430ce8384Sbostic putc(t, active);
29530ce8384Sbostic }
29630ce8384Sbostic putc(t, active); /* output directly.. */
29730ce8384Sbostic }
29830ce8384Sbostic
29930ce8384Sbostic else switch(t) {
30030ce8384Sbostic
30130ce8384Sbostic case LPAREN:
30230ce8384Sbostic if (PARLEV > 0)
30330ce8384Sbostic chrsave(t);
30430ce8384Sbostic while (isspace(l = gpbc()))
30530ce8384Sbostic ; /* skip blank, tab, nl.. */
30630ce8384Sbostic putback(l);
30730ce8384Sbostic PARLEV++;
30830ce8384Sbostic break;
30930ce8384Sbostic
31030ce8384Sbostic case RPAREN:
31130ce8384Sbostic if (--PARLEV > 0)
31230ce8384Sbostic chrsave(t);
31330ce8384Sbostic else { /* end of argument list */
31430ce8384Sbostic chrsave(EOS);
31530ce8384Sbostic
31630ce8384Sbostic if (sp == STACKMAX)
317d3eef09bSbostic oops("internal stack overflow", "");
31830ce8384Sbostic
31930ce8384Sbostic if (CALTYP == MACRTYPE)
320d3eef09bSbostic expand((char **) mstack+fp+1, sp-fp);
32130ce8384Sbostic else
322d3eef09bSbostic eval((char **) mstack+fp+1, sp-fp, CALTYP);
32330ce8384Sbostic
32430ce8384Sbostic ep = PREVEP; /* flush strspace */
32530ce8384Sbostic sp = PREVSP; /* previous sp.. */
32630ce8384Sbostic fp = PREVFP; /* rewind stack...*/
32730ce8384Sbostic }
32830ce8384Sbostic break;
32930ce8384Sbostic
33030ce8384Sbostic case COMMA:
33130ce8384Sbostic if (PARLEV == 1) {
33230ce8384Sbostic chrsave(EOS); /* new argument */
33330ce8384Sbostic while (isspace(l = gpbc()))
33430ce8384Sbostic ;
33530ce8384Sbostic putback(l);
33630ce8384Sbostic pushs(ep);
33757250e19Storek } else
33857250e19Storek chrsave(t);
33930ce8384Sbostic break;
34057250e19Storek
34130ce8384Sbostic default:
34230ce8384Sbostic chrsave(t); /* stack the char */
34330ce8384Sbostic break;
34430ce8384Sbostic }
34530ce8384Sbostic }
34630ce8384Sbostic }
34730ce8384Sbostic
34830ce8384Sbostic /*
34930ce8384Sbostic * build an input token..
35030ce8384Sbostic * consider only those starting with _ or A-Za-z. This is a
35130ce8384Sbostic * combo with lookup to speed things up.
35230ce8384Sbostic */
35330ce8384Sbostic ndptr
inspect(tp)35430ce8384Sbostic inspect(tp)
35530ce8384Sbostic register char *tp;
35630ce8384Sbostic {
35730ce8384Sbostic register char c;
35830ce8384Sbostic register char *name = tp;
35930ce8384Sbostic register char *etp = tp+MAXTOK;
36030ce8384Sbostic register ndptr p;
361d3eef09bSbostic register unsigned long h = 0;
36230ce8384Sbostic
363d3eef09bSbostic while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
364d3eef09bSbostic h = (h << 5) + h + (*tp++ = c);
36530ce8384Sbostic putback(c);
36630ce8384Sbostic if (tp == etp)
367d3eef09bSbostic oops("token too long", "");
368d3eef09bSbostic
36930ce8384Sbostic *tp = EOS;
370d3eef09bSbostic
37130ce8384Sbostic for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
372d3eef09bSbostic if (STREQ(name, p->name))
37330ce8384Sbostic break;
374d3eef09bSbostic return p;
37530ce8384Sbostic }
37630ce8384Sbostic
37730ce8384Sbostic /*
37830ce8384Sbostic * initkwds - initialise m4 keywords as fast as possible.
37930ce8384Sbostic * This very similar to install, but without certain overheads,
38030ce8384Sbostic * such as calling lookup. Malloc is not used for storing the
38130ce8384Sbostic * keyword strings, since we simply use the static pointers
382d3eef09bSbostic * within keywrds block.
38330ce8384Sbostic */
384d3eef09bSbostic void
initkwds()38530ce8384Sbostic initkwds() {
38630ce8384Sbostic register int i;
38730ce8384Sbostic register int h;
38830ce8384Sbostic register ndptr p;
38930ce8384Sbostic
39030ce8384Sbostic for (i = 0; i < MAXKEYS; i++) {
39130ce8384Sbostic h = hash(keywrds[i].knam);
392d3eef09bSbostic p = (ndptr) xalloc(sizeof(struct ndblock));
39330ce8384Sbostic p->nxtptr = hashtab[h];
39430ce8384Sbostic hashtab[h] = p;
39530ce8384Sbostic p->name = keywrds[i].knam;
39630ce8384Sbostic p->defn = null;
39730ce8384Sbostic p->type = keywrds[i].ktyp | STATIC;
39830ce8384Sbostic }
39930ce8384Sbostic }
400