154550Sbostic /*-
2*62080Sbostic * Copyright (c) 1989, 1993
3*62080Sbostic * The Regents of the University of California. All rights reserved.
438823Sbostic *
538823Sbostic * This code is derived from software contributed to Berkeley by
651769Sbostic * Ozan Yigit at York University.
738823Sbostic *
854550Sbostic * %sccs.include.redist.c%
938823Sbostic */
1038823Sbostic
1138823Sbostic #ifndef lint
12*62080Sbostic static char copyright[] =
13*62080Sbostic "@(#) Copyright (c) 1989, 1993\n\
14*62080Sbostic The Regents of the University of California. All rights reserved.\n";
1538823Sbostic #endif /* not lint */
1638823Sbostic
1754550Sbostic #ifndef lint
18*62080Sbostic static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/06/93";
1954550Sbostic #endif /* not lint */
2054550Sbostic
2138823Sbostic /*
2238823Sbostic * main.c
2338823Sbostic * Facility: m4 macro processor
2438823Sbostic * by: oz
2538823Sbostic */
2638823Sbostic
2750960Sbostic #include <sys/types.h>
2846697Sbostic #include <signal.h>
2950960Sbostic #include <errno.h>
3046697Sbostic #include <unistd.h>
3146697Sbostic #include <stdio.h>
3250960Sbostic #include <ctype.h>
3346697Sbostic #include <string.h>
3438823Sbostic #include "mdef.h"
3550960Sbostic #include "stdd.h"
3650960Sbostic #include "extern.h"
3746697Sbostic #include "pathnames.h"
3838823Sbostic
3938823Sbostic ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
4038823Sbostic char buf[BUFSIZE]; /* push-back buffer */
4151241Seric char *bufbase = buf; /* the base for current ilevel */
4251241Seric char *bbase[MAXINP]; /* the base for each ilevel */
4338823Sbostic char *bp = buf; /* first available character */
4438823Sbostic char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
4538823Sbostic stae mstack[STACKMAX+1]; /* stack of m4 machine */
4638823Sbostic char strspace[STRSPMAX+1]; /* string space for evaluation */
4738823Sbostic char *ep = strspace; /* first free char in strspace */
4838823Sbostic char *endest= strspace+STRSPMAX;/* end of string space */
4938823Sbostic int sp; /* current m4 stack pointer */
5038823Sbostic int fp; /* m4 call frame pointer */
5138823Sbostic FILE *infile[MAXINP]; /* input file stack (0=stdin) */
5238823Sbostic FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
5338823Sbostic FILE *active; /* active output file pointer */
5438823Sbostic char *m4temp; /* filename for diversions */
5538823Sbostic int ilevel = 0; /* input file stack pointer */
5638823Sbostic int oindex = 0; /* diversion index.. */
5738823Sbostic char *null = ""; /* as it says.. just a null.. */
5838823Sbostic char *m4wraps = ""; /* m4wrap string default.. */
5950960Sbostic char *progname; /* name of this program */
6038823Sbostic char lquote = LQUOTE; /* left quote character (`) */
6138823Sbostic char rquote = RQUOTE; /* right quote character (') */
6238823Sbostic char scommt = SCOMMT; /* start character for comment */
6338823Sbostic char ecommt = ECOMMT; /* end character for comment */
6450960Sbostic
6538823Sbostic struct keyblk keywrds[] = { /* m4 keywords to be installed */
6638823Sbostic "include", INCLTYPE,
6738823Sbostic "sinclude", SINCTYPE,
6838823Sbostic "define", DEFITYPE,
6938823Sbostic "defn", DEFNTYPE,
7038823Sbostic "divert", DIVRTYPE,
7138823Sbostic "expr", EXPRTYPE,
7238823Sbostic "eval", EXPRTYPE,
7338823Sbostic "substr", SUBSTYPE,
7438823Sbostic "ifelse", IFELTYPE,
7538823Sbostic "ifdef", IFDFTYPE,
7638823Sbostic "len", LENGTYPE,
7738823Sbostic "incr", INCRTYPE,
7838823Sbostic "decr", DECRTYPE,
7938823Sbostic "dnl", DNLNTYPE,
8038823Sbostic "changequote", CHNQTYPE,
8138823Sbostic "changecom", CHNCTYPE,
8238823Sbostic "index", INDXTYPE,
8338823Sbostic #ifdef EXTENDED
8438823Sbostic "paste", PASTTYPE,
8538823Sbostic "spaste", SPASTYPE,
8638823Sbostic #endif
8738823Sbostic "popdef", POPDTYPE,
8838823Sbostic "pushdef", PUSDTYPE,
8938823Sbostic "dumpdef", DUMPTYPE,
9038823Sbostic "shift", SHIFTYPE,
9138823Sbostic "translit", TRNLTYPE,
9238823Sbostic "undefine", UNDFTYPE,
9338823Sbostic "undivert", UNDVTYPE,
9438823Sbostic "divnum", DIVNTYPE,
9538823Sbostic "maketemp", MKTMTYPE,
9638823Sbostic "errprint", ERRPTYPE,
9738823Sbostic "m4wrap", M4WRTYPE,
9838823Sbostic "m4exit", EXITTYPE,
9938823Sbostic "syscmd", SYSCTYPE,
10038823Sbostic "sysval", SYSVTYPE,
10150960Sbostic
10250960Sbostic #ifdef unix
10338823Sbostic "unix", MACRTYPE,
10450960Sbostic #else
10550960Sbostic #ifdef vms
10650960Sbostic "vms", MACRTYPE,
10750960Sbostic #endif
10850960Sbostic #endif
10938823Sbostic };
11038823Sbostic
11138823Sbostic #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
11238823Sbostic
11338823Sbostic extern int optind;
11438823Sbostic extern char *optarg;
11538823Sbostic
11650960Sbostic void macro();
11750960Sbostic void initkwds();
11850960Sbostic extern int getopt();
11950960Sbostic
12050960Sbostic int
main(argc,argv)12138823Sbostic main(argc,argv)
12254550Sbostic int argc;
12354550Sbostic char *argv[];
12438823Sbostic {
12538823Sbostic register int c;
12638823Sbostic register int n;
12738823Sbostic char *p;
12850960Sbostic register FILE *ifp;
12938823Sbostic
13050960Sbostic progname = basename(argv[0]);
13150960Sbostic
13238823Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN)
13338823Sbostic signal(SIGINT, onintr);
13450960Sbostic
13538823Sbostic initkwds();
13638823Sbostic
13738823Sbostic while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
13838823Sbostic switch(c) {
13938823Sbostic
14038823Sbostic case 'D': /* define something..*/
14138823Sbostic for (p = optarg; *p; p++)
14238823Sbostic if (*p == '=')
14338823Sbostic break;
14438823Sbostic if (*p)
14538823Sbostic *p++ = EOS;
14638823Sbostic dodefine(optarg, p);
14738823Sbostic break;
14838823Sbostic case 'U': /* undefine... */
14938823Sbostic remhash(optarg, TOP);
15038823Sbostic break;
15138823Sbostic case 'o': /* specific output */
15238823Sbostic case '?':
15338823Sbostic usage();
15438823Sbostic }
15538823Sbostic
15650960Sbostic argc -= optind;
15750960Sbostic argv += optind;
15850960Sbostic
15938823Sbostic active = stdout; /* default active output */
16050960Sbostic /* filename for diversions */
16150960Sbostic m4temp = mktemp(xstrdup(_PATH_DIVNAME));
16238823Sbostic
16351241Seric bbase[0] = bufbase;
16450960Sbostic if (!argc) {
16550960Sbostic sp = -1; /* stack pointer initialized */
16650960Sbostic fp = 0; /* frame pointer initialized */
16750960Sbostic infile[0] = stdin; /* default input (naturally) */
16850960Sbostic macro();
16954550Sbostic } else
17054550Sbostic for (; argc--; ++argv) {
17154550Sbostic p = *argv;
17254550Sbostic if (p[0] == '-' && p[1] == '\0')
17354550Sbostic ifp = stdin;
17454550Sbostic else if ((ifp = fopen(p, "r")) == NULL)
17554550Sbostic oops("%s: %s", p, strerror(errno));
17654550Sbostic sp = -1;
17754550Sbostic fp = 0;
17854550Sbostic infile[0] = ifp;
17954550Sbostic macro();
18054550Sbostic if (ifp != stdin)
18154550Sbostic (void)fclose(ifp);
18250960Sbostic }
18338823Sbostic
18438823Sbostic if (*m4wraps) { /* anything for rundown ?? */
18538823Sbostic ilevel = 0; /* in case m4wrap includes.. */
18651241Seric bufbase = bp = buf; /* use the entire buffer */
18738823Sbostic putback(EOF); /* eof is a must !! */
18838823Sbostic pbstr(m4wraps); /* user-defined wrapup act */
18938823Sbostic macro(); /* last will and testament */
19038823Sbostic }
19138823Sbostic
19239102Sbostic if (active != stdout)
19339102Sbostic active = stdout; /* reset output just in case */
19439102Sbostic for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */
19539102Sbostic if (outfile[n] != NULL)
19639102Sbostic getdiv(n);
19738823Sbostic /* remove bitbucket if used */
19838823Sbostic if (outfile[0] != NULL) {
19938823Sbostic (void) fclose(outfile[0]);
20038823Sbostic m4temp[UNIQUE] = '0';
20150960Sbostic #ifdef vms
20250960Sbostic (void) remove(m4temp);
20350960Sbostic #else
20438823Sbostic (void) unlink(m4temp);
20550960Sbostic #endif
20638823Sbostic }
20738823Sbostic
20850960Sbostic return 0;
20938823Sbostic }
21038823Sbostic
21150960Sbostic ndptr inspect();
21238823Sbostic
21338823Sbostic /*
21438823Sbostic * macro - the work horse..
21538823Sbostic */
21650960Sbostic void
macro()21738823Sbostic macro() {
21838823Sbostic char token[MAXTOK];
21938823Sbostic register char *s;
22038823Sbostic register int t, l;
22138823Sbostic register ndptr p;
22238823Sbostic register int nlpar;
22338823Sbostic
22438823Sbostic cycle {
22538823Sbostic if ((t = gpbc()) == '_' || isalpha(t)) {
22638823Sbostic putback(t);
22738823Sbostic if ((p = inspect(s = token)) == nil) {
22838823Sbostic if (sp < 0)
22938823Sbostic while (*s)
23038823Sbostic putc(*s++, active);
23138823Sbostic else
23238823Sbostic while (*s)
23338823Sbostic chrsave(*s++);
23438823Sbostic }
23538823Sbostic else {
23638823Sbostic /*
23738823Sbostic * real thing.. First build a call frame:
23838823Sbostic */
23938823Sbostic pushf(fp); /* previous call frm */
24038823Sbostic pushf(p->type); /* type of the call */
24138823Sbostic pushf(0); /* parenthesis level */
24238823Sbostic fp = sp; /* new frame pointer */
24338823Sbostic /*
24438823Sbostic * now push the string arguments:
24538823Sbostic */
24638823Sbostic pushs(p->defn); /* defn string */
24738823Sbostic pushs(p->name); /* macro name */
24838823Sbostic pushs(ep); /* start next..*/
24938823Sbostic
25038823Sbostic putback(l = gpbc());
25138823Sbostic if (l != LPAREN) { /* add bracks */
25238823Sbostic putback(RPAREN);
25338823Sbostic putback(LPAREN);
25438823Sbostic }
25538823Sbostic }
25638823Sbostic }
25738823Sbostic else if (t == EOF) {
25838823Sbostic if (sp > -1)
25950960Sbostic oops("unexpected end of input", "");
26052475Sleres if (ilevel <= 0)
26138823Sbostic break; /* all done thanks.. */
26252475Sleres --ilevel;
26338823Sbostic (void) fclose(infile[ilevel+1]);
26451241Seric bufbase = bbase[ilevel];
26538823Sbostic continue;
26638823Sbostic }
26738823Sbostic /*
26838823Sbostic * non-alpha single-char token seen..
26950960Sbostic * [the order of else if .. stmts is important.]
27038823Sbostic */
27138823Sbostic else if (t == lquote) { /* strip quotes */
27238823Sbostic nlpar = 1;
27338823Sbostic do {
27438823Sbostic if ((l = gpbc()) == rquote)
27538823Sbostic nlpar--;
27638823Sbostic else if (l == lquote)
27738823Sbostic nlpar++;
27838823Sbostic else if (l == EOF)
27950960Sbostic oops("missing right quote", "");
28038823Sbostic if (nlpar > 0) {
28138823Sbostic if (sp < 0)
28238823Sbostic putc(l, active);
28338823Sbostic else
28438823Sbostic chrsave(l);
28538823Sbostic }
28638823Sbostic }
28738823Sbostic while (nlpar != 0);
28838823Sbostic }
28938823Sbostic
29038823Sbostic else if (sp < 0) { /* not in a macro at all */
29138823Sbostic if (t == scommt) { /* comment handling here */
29238823Sbostic putc(t, active);
29338823Sbostic while ((t = gpbc()) != ecommt)
29438823Sbostic putc(t, active);
29538823Sbostic }
29638823Sbostic putc(t, active); /* output directly.. */
29738823Sbostic }
29838823Sbostic
29938823Sbostic else switch(t) {
30038823Sbostic
30138823Sbostic case LPAREN:
30238823Sbostic if (PARLEV > 0)
30338823Sbostic chrsave(t);
30438823Sbostic while (isspace(l = gpbc()))
30538823Sbostic ; /* skip blank, tab, nl.. */
30638823Sbostic putback(l);
30738823Sbostic PARLEV++;
30838823Sbostic break;
30938823Sbostic
31038823Sbostic case RPAREN:
31138823Sbostic if (--PARLEV > 0)
31238823Sbostic chrsave(t);
31338823Sbostic else { /* end of argument list */
31438823Sbostic chrsave(EOS);
31538823Sbostic
31638823Sbostic if (sp == STACKMAX)
31750960Sbostic oops("internal stack overflow", "");
31838823Sbostic
31938823Sbostic if (CALTYP == MACRTYPE)
32050960Sbostic expand((char **) mstack+fp+1, sp-fp);
32138823Sbostic else
32250960Sbostic eval((char **) mstack+fp+1, sp-fp, CALTYP);
32338823Sbostic
32438823Sbostic ep = PREVEP; /* flush strspace */
32538823Sbostic sp = PREVSP; /* previous sp.. */
32638823Sbostic fp = PREVFP; /* rewind stack...*/
32738823Sbostic }
32838823Sbostic break;
32938823Sbostic
33038823Sbostic case COMMA:
33150960Sbostic if (PARLEV == 1) {
33238823Sbostic chrsave(EOS); /* new argument */
33338823Sbostic while (isspace(l = gpbc()))
33438823Sbostic ;
33538823Sbostic putback(l);
33638823Sbostic pushs(ep);
33759994Storek } else
33859994Storek chrsave(t);
33938823Sbostic break;
34059994Storek
34138823Sbostic default:
34238823Sbostic chrsave(t); /* stack the char */
34338823Sbostic break;
34438823Sbostic }
34538823Sbostic }
34638823Sbostic }
34738823Sbostic
34838823Sbostic /*
34938823Sbostic * build an input token..
35038823Sbostic * consider only those starting with _ or A-Za-z. This is a
35138823Sbostic * combo with lookup to speed things up.
35238823Sbostic */
35338823Sbostic ndptr
inspect(tp)35438823Sbostic inspect(tp)
35538823Sbostic register char *tp;
35638823Sbostic {
35738823Sbostic register char c;
35838823Sbostic register char *name = tp;
35938823Sbostic register char *etp = tp+MAXTOK;
36038823Sbostic register ndptr p;
36150960Sbostic register unsigned long h = 0;
36238823Sbostic
36350960Sbostic while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
36450960Sbostic h = (h << 5) + h + (*tp++ = c);
36538823Sbostic putback(c);
36638823Sbostic if (tp == etp)
36750960Sbostic oops("token too long", "");
36850960Sbostic
36938823Sbostic *tp = EOS;
37050960Sbostic
37138823Sbostic for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
37250960Sbostic if (STREQ(name, p->name))
37338823Sbostic break;
37450960Sbostic return p;
37538823Sbostic }
37638823Sbostic
37738823Sbostic /*
37838823Sbostic * initkwds - initialise m4 keywords as fast as possible.
37938823Sbostic * This very similar to install, but without certain overheads,
38038823Sbostic * such as calling lookup. Malloc is not used for storing the
38138823Sbostic * keyword strings, since we simply use the static pointers
38250960Sbostic * within keywrds block.
38338823Sbostic */
38450960Sbostic void
initkwds()38538823Sbostic initkwds() {
38638823Sbostic register int i;
38738823Sbostic register int h;
38838823Sbostic register ndptr p;
38938823Sbostic
39038823Sbostic for (i = 0; i < MAXKEYS; i++) {
39138823Sbostic h = hash(keywrds[i].knam);
39250960Sbostic p = (ndptr) xalloc(sizeof(struct ndblock));
39338823Sbostic p->nxtptr = hashtab[h];
39438823Sbostic hashtab[h] = p;
39538823Sbostic p->name = keywrds[i].knam;
39638823Sbostic p->defn = null;
39738823Sbostic p->type = keywrds[i].ktyp | STATIC;
39838823Sbostic }
39938823Sbostic }
400