xref: /original-bsd/usr.bin/m4/main.c (revision 494f5ecf)
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