xref: /csrg-svn/usr.bin/m4/main.c (revision 62080)
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