xref: /csrg-svn/usr.bin/m4/main.c (revision 50960)
138823Sbostic /*
238823Sbostic  * Copyright (c) 1989 The Regents of the University of California.
338823Sbostic  * All rights reserved.
438823Sbostic  *
538823Sbostic  * This code is derived from software contributed to Berkeley by
638823Sbostic  * Ozan Yigit.
738823Sbostic  *
842689Sbostic  * %sccs.include.redist.c%
938823Sbostic  */
1038823Sbostic 
1138823Sbostic #ifndef lint
12*50960Sbostic static char sccsid[] = "@(#)main.c	5.7 (Berkeley) 09/03/91";
1338823Sbostic #endif /* not lint */
1438823Sbostic 
1538823Sbostic /*
1638823Sbostic  * main.c
1738823Sbostic  * Facility: m4 macro processor
1838823Sbostic  * by: oz
1938823Sbostic  */
2038823Sbostic 
21*50960Sbostic #include <sys/types.h>
2246697Sbostic #include <signal.h>
23*50960Sbostic #include <errno.h>
2446697Sbostic #include <unistd.h>
2546697Sbostic #include <stdio.h>
26*50960Sbostic #include <ctype.h>
2746697Sbostic #include <string.h>
2838823Sbostic #include "mdef.h"
29*50960Sbostic #include "stdd.h"
30*50960Sbostic #include "extern.h"
3146697Sbostic #include "pathnames.h"
3238823Sbostic 
3338823Sbostic ndptr hashtab[HASHSIZE];	/* hash table for macros etc.  */
3438823Sbostic char buf[BUFSIZE];		/* push-back buffer	       */
3538823Sbostic char *bp = buf; 		/* first available character   */
3638823Sbostic char *endpbb = buf+BUFSIZE;	/* end of push-back buffer     */
3738823Sbostic stae mstack[STACKMAX+1]; 	/* stack of m4 machine         */
3838823Sbostic char strspace[STRSPMAX+1];	/* string space for evaluation */
3938823Sbostic char *ep = strspace;		/* first free char in strspace */
4038823Sbostic char *endest= strspace+STRSPMAX;/* end of string space	       */
4138823Sbostic int sp; 			/* current m4  stack pointer   */
4238823Sbostic int fp; 			/* m4 call frame pointer       */
4338823Sbostic FILE *infile[MAXINP];		/* input file stack (0=stdin)  */
4438823Sbostic FILE *outfile[MAXOUT];		/* diversion array(0=bitbucket)*/
4538823Sbostic FILE *active;			/* active output file pointer  */
4638823Sbostic char *m4temp;			/* filename for diversions     */
4738823Sbostic int ilevel = 0; 		/* input file stack pointer    */
4838823Sbostic int oindex = 0; 		/* diversion index..	       */
4938823Sbostic char *null = "";                /* as it says.. just a null..  */
5038823Sbostic char *m4wraps = "";             /* m4wrap string default..     */
51*50960Sbostic char *progname;			/* name of this program        */
5238823Sbostic char lquote = LQUOTE;		/* left quote character  (`)   */
5338823Sbostic char rquote = RQUOTE;		/* right quote character (')   */
5438823Sbostic char scommt = SCOMMT;		/* start character for comment */
5538823Sbostic char ecommt = ECOMMT;		/* end character for comment   */
56*50960Sbostic 
5738823Sbostic struct keyblk keywrds[] = {	/* m4 keywords to be installed */
5838823Sbostic 	"include",      INCLTYPE,
5938823Sbostic 	"sinclude",     SINCTYPE,
6038823Sbostic 	"define",       DEFITYPE,
6138823Sbostic 	"defn",         DEFNTYPE,
6238823Sbostic 	"divert",       DIVRTYPE,
6338823Sbostic 	"expr",         EXPRTYPE,
6438823Sbostic 	"eval",         EXPRTYPE,
6538823Sbostic 	"substr",       SUBSTYPE,
6638823Sbostic 	"ifelse",       IFELTYPE,
6738823Sbostic 	"ifdef",        IFDFTYPE,
6838823Sbostic 	"len",          LENGTYPE,
6938823Sbostic 	"incr",         INCRTYPE,
7038823Sbostic 	"decr",         DECRTYPE,
7138823Sbostic 	"dnl",          DNLNTYPE,
7238823Sbostic 	"changequote",  CHNQTYPE,
7338823Sbostic 	"changecom",    CHNCTYPE,
7438823Sbostic 	"index",        INDXTYPE,
7538823Sbostic #ifdef EXTENDED
7638823Sbostic 	"paste",        PASTTYPE,
7738823Sbostic 	"spaste",       SPASTYPE,
7838823Sbostic #endif
7938823Sbostic 	"popdef",       POPDTYPE,
8038823Sbostic 	"pushdef",      PUSDTYPE,
8138823Sbostic 	"dumpdef",      DUMPTYPE,
8238823Sbostic 	"shift",        SHIFTYPE,
8338823Sbostic 	"translit",     TRNLTYPE,
8438823Sbostic 	"undefine",     UNDFTYPE,
8538823Sbostic 	"undivert",     UNDVTYPE,
8638823Sbostic 	"divnum",       DIVNTYPE,
8738823Sbostic 	"maketemp",     MKTMTYPE,
8838823Sbostic 	"errprint",     ERRPTYPE,
8938823Sbostic 	"m4wrap",       M4WRTYPE,
9038823Sbostic 	"m4exit",       EXITTYPE,
9138823Sbostic 	"syscmd",       SYSCTYPE,
9238823Sbostic 	"sysval",       SYSVTYPE,
93*50960Sbostic 
94*50960Sbostic #ifdef unix
9538823Sbostic 	"unix",         MACRTYPE,
96*50960Sbostic #else
97*50960Sbostic #ifdef vms
98*50960Sbostic 	"vms",          MACRTYPE,
99*50960Sbostic #endif
100*50960Sbostic #endif
10138823Sbostic };
10238823Sbostic 
10338823Sbostic #define MAXKEYS	(sizeof(keywrds)/sizeof(struct keyblk))
10438823Sbostic 
10538823Sbostic extern int optind;
10638823Sbostic extern char *optarg;
10738823Sbostic 
108*50960Sbostic void macro();
109*50960Sbostic void initkwds();
110*50960Sbostic extern int getopt();
111*50960Sbostic 
112*50960Sbostic int
11338823Sbostic main(argc,argv)
114*50960Sbostic int argc;
115*50960Sbostic char *argv[];
11638823Sbostic {
11738823Sbostic 	register int c;
11838823Sbostic 	register int n;
11938823Sbostic 	char *p;
120*50960Sbostic 	register FILE *ifp;
12138823Sbostic 
122*50960Sbostic 	progname = basename(argv[0]);
123*50960Sbostic 
12438823Sbostic 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
12538823Sbostic 		signal(SIGINT, onintr);
126*50960Sbostic 
12738823Sbostic 	initkwds();
12838823Sbostic 
12938823Sbostic 	while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
13038823Sbostic 		switch(c) {
13138823Sbostic 
13238823Sbostic 		case 'D':               /* define something..*/
13338823Sbostic 			for (p = optarg; *p; p++)
13438823Sbostic 				if (*p == '=')
13538823Sbostic 					break;
13638823Sbostic 			if (*p)
13738823Sbostic 				*p++ = EOS;
13838823Sbostic 			dodefine(optarg, p);
13938823Sbostic 			break;
14038823Sbostic 		case 'U':               /* undefine...       */
14138823Sbostic 			remhash(optarg, TOP);
14238823Sbostic 			break;
14338823Sbostic 		case 'o':		/* specific output   */
14438823Sbostic 		case '?':
14538823Sbostic 			usage();
14638823Sbostic 		}
14738823Sbostic 
148*50960Sbostic         argc -= optind;
149*50960Sbostic         argv += optind;
150*50960Sbostic 
15138823Sbostic 	active = stdout;		/* default active output     */
152*50960Sbostic 					/* filename for diversions   */
153*50960Sbostic 	m4temp = mktemp(xstrdup(_PATH_DIVNAME));
15438823Sbostic 
155*50960Sbostic         if (!argc) {
156*50960Sbostic  		sp = -1;		/* stack pointer initialized */
157*50960Sbostic 		fp = 0; 		/* frame pointer initialized */
158*50960Sbostic 		infile[0] = stdin;	/* default input (naturally) */
159*50960Sbostic 		macro();
160*50960Sbostic 	}
161*50960Sbostic         else
162*50960Sbostic                 while (argc--) {
163*50960Sbostic                         if ((ifp = fopen(*argv, "r")) == NULL)
164*50960Sbostic                                 oops("%s: %s", *argv, strerror(errno));
165*50960Sbostic                         else {
166*50960Sbostic 				sp = -1;
167*50960Sbostic 				fp = 0;
168*50960Sbostic 				infile[0] = ifp;
169*50960Sbostic 				macro();
170*50960Sbostic 				(void) fclose(ifp);
171*50960Sbostic 			}
172*50960Sbostic                         argv++;
173*50960Sbostic 		}
17438823Sbostic 
17538823Sbostic 
17638823Sbostic 	if (*m4wraps) { 		/* anything for rundown ??   */
17738823Sbostic 		ilevel = 0;		/* in case m4wrap includes.. */
17838823Sbostic 		putback(EOF);		/* eof is a must !!	     */
17938823Sbostic 		pbstr(m4wraps); 	/* user-defined wrapup act   */
18038823Sbostic 		macro();		/* last will and testament   */
18138823Sbostic 	}
18238823Sbostic 
18339102Sbostic 	if (active != stdout)
18439102Sbostic 		active = stdout;	/* reset output just in case */
18539102Sbostic 	for (n = 1; n < MAXOUT; n++)	/* default wrap-up: undivert */
18639102Sbostic 		if (outfile[n] != NULL)
18739102Sbostic 			getdiv(n);
18838823Sbostic 					/* remove bitbucket if used  */
18938823Sbostic 	if (outfile[0] != NULL) {
19038823Sbostic 		(void) fclose(outfile[0]);
19138823Sbostic 		m4temp[UNIQUE] = '0';
192*50960Sbostic #ifdef vms
193*50960Sbostic 		(void) remove(m4temp);
194*50960Sbostic #else
19538823Sbostic 		(void) unlink(m4temp);
196*50960Sbostic #endif
19738823Sbostic 	}
19838823Sbostic 
199*50960Sbostic 	return 0;
20038823Sbostic }
20138823Sbostic 
202*50960Sbostic ndptr inspect();
20338823Sbostic 
20438823Sbostic /*
20538823Sbostic  * macro - the work horse..
20638823Sbostic  */
207*50960Sbostic void
20838823Sbostic macro() {
20938823Sbostic 	char token[MAXTOK];
21038823Sbostic 	register char *s;
21138823Sbostic 	register int t, l;
21238823Sbostic 	register ndptr p;
21338823Sbostic 	register int  nlpar;
21438823Sbostic 
21538823Sbostic 	cycle {
21638823Sbostic 		if ((t = gpbc()) == '_' || isalpha(t)) {
21738823Sbostic 			putback(t);
21838823Sbostic 			if ((p = inspect(s = token)) == nil) {
21938823Sbostic 				if (sp < 0)
22038823Sbostic 					while (*s)
22138823Sbostic 						putc(*s++, active);
22238823Sbostic 				else
22338823Sbostic 					while (*s)
22438823Sbostic 						chrsave(*s++);
22538823Sbostic 			}
22638823Sbostic 			else {
22738823Sbostic 		/*
22838823Sbostic 		 * real thing.. First build a call frame:
22938823Sbostic 		 */
23038823Sbostic 				pushf(fp);	/* previous call frm */
23138823Sbostic 				pushf(p->type); /* type of the call  */
23238823Sbostic 				pushf(0);	/* parenthesis level */
23338823Sbostic 				fp = sp;	/* new frame pointer */
23438823Sbostic 		/*
23538823Sbostic 		 * now push the string arguments:
23638823Sbostic 		 */
23738823Sbostic 				pushs(p->defn);	      /* defn string */
23838823Sbostic 				pushs(p->name);	      /* macro name  */
23938823Sbostic 				pushs(ep);	      /* start next..*/
24038823Sbostic 
24138823Sbostic 				putback(l = gpbc());
24238823Sbostic 				if (l != LPAREN)  {   /* add bracks  */
24338823Sbostic 					putback(RPAREN);
24438823Sbostic 					putback(LPAREN);
24538823Sbostic 				}
24638823Sbostic 			}
24738823Sbostic 		}
24838823Sbostic 		else if (t == EOF) {
24938823Sbostic 			if (sp > -1)
250*50960Sbostic 				oops("unexpected end of input", "");
25138823Sbostic 			if (--ilevel < 0)
25238823Sbostic 				break;			/* all done thanks.. */
25338823Sbostic 			(void) fclose(infile[ilevel+1]);
25438823Sbostic 			continue;
25538823Sbostic 		}
25638823Sbostic 	/*
25738823Sbostic 	 * non-alpha single-char token seen..
258*50960Sbostic 	 * [the order of else if .. stmts is important.]
25938823Sbostic 	 */
26038823Sbostic 		else if (t == lquote) { 		/* strip quotes */
26138823Sbostic 			nlpar = 1;
26238823Sbostic 			do {
26338823Sbostic 				if ((l = gpbc()) == rquote)
26438823Sbostic 					nlpar--;
26538823Sbostic 				else if (l == lquote)
26638823Sbostic 					nlpar++;
26738823Sbostic 				else if (l == EOF)
268*50960Sbostic 					oops("missing right quote", "");
26938823Sbostic 				if (nlpar > 0) {
27038823Sbostic 					if (sp < 0)
27138823Sbostic 						putc(l, active);
27238823Sbostic 					else
27338823Sbostic 						chrsave(l);
27438823Sbostic 				}
27538823Sbostic 			}
27638823Sbostic 			while (nlpar != 0);
27738823Sbostic 		}
27838823Sbostic 
27938823Sbostic 		else if (sp < 0) {		/* not in a macro at all */
28038823Sbostic 			if (t == scommt) {	/* comment handling here */
28138823Sbostic 				putc(t, active);
28238823Sbostic 				while ((t = gpbc()) != ecommt)
28338823Sbostic 					putc(t, active);
28438823Sbostic 			}
28538823Sbostic 			putc(t, active);	/* output directly..	 */
28638823Sbostic 		}
28738823Sbostic 
28838823Sbostic 		else switch(t) {
28938823Sbostic 
29038823Sbostic 		case LPAREN:
29138823Sbostic 			if (PARLEV > 0)
29238823Sbostic 				chrsave(t);
29338823Sbostic 			while (isspace(l = gpbc()))
29438823Sbostic 				;		/* skip blank, tab, nl.. */
29538823Sbostic 			putback(l);
29638823Sbostic 			PARLEV++;
29738823Sbostic 			break;
29838823Sbostic 
29938823Sbostic 		case RPAREN:
30038823Sbostic 			if (--PARLEV > 0)
30138823Sbostic 				chrsave(t);
30238823Sbostic 			else {			/* end of argument list */
30338823Sbostic 				chrsave(EOS);
30438823Sbostic 
30538823Sbostic 				if (sp == STACKMAX)
306*50960Sbostic 					oops("internal stack overflow", "");
30738823Sbostic 
30838823Sbostic 				if (CALTYP == MACRTYPE)
309*50960Sbostic 					expand((char **) mstack+fp+1, sp-fp);
31038823Sbostic 				else
311*50960Sbostic 					eval((char **) mstack+fp+1, sp-fp, CALTYP);
31238823Sbostic 
31338823Sbostic 				ep = PREVEP;	/* flush strspace */
31438823Sbostic 				sp = PREVSP;	/* previous sp..  */
31538823Sbostic 				fp = PREVFP;	/* rewind stack...*/
31638823Sbostic 			}
31738823Sbostic 			break;
31838823Sbostic 
31938823Sbostic 		case COMMA:
320*50960Sbostic 			if (PARLEV == 1) {
32138823Sbostic 				chrsave(EOS);		/* new argument   */
32238823Sbostic 				while (isspace(l = gpbc()))
32338823Sbostic 					;
32438823Sbostic 				putback(l);
32538823Sbostic 				pushs(ep);
32638823Sbostic 			}
32738823Sbostic 			break;
32838823Sbostic 		default:
32938823Sbostic 			chrsave(t);			/* stack the char */
33038823Sbostic 			break;
33138823Sbostic 		}
33238823Sbostic 	}
33338823Sbostic }
33438823Sbostic 
33538823Sbostic /*
33638823Sbostic  * build an input token..
33738823Sbostic  * consider only those starting with _ or A-Za-z. This is a
33838823Sbostic  * combo with lookup to speed things up.
33938823Sbostic  */
34038823Sbostic ndptr
34138823Sbostic inspect(tp)
34238823Sbostic register char *tp;
34338823Sbostic {
34438823Sbostic 	register char c;
34538823Sbostic 	register char *name = tp;
34638823Sbostic 	register char *etp = tp+MAXTOK;
34738823Sbostic 	register ndptr p;
348*50960Sbostic 	register unsigned long h = 0;
34938823Sbostic 
350*50960Sbostic 	while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
351*50960Sbostic 		h = (h << 5) + h + (*tp++ = c);
35238823Sbostic 	putback(c);
35338823Sbostic 	if (tp == etp)
354*50960Sbostic 		oops("token too long", "");
355*50960Sbostic 
35638823Sbostic 	*tp = EOS;
357*50960Sbostic 
35838823Sbostic 	for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
359*50960Sbostic 		if (STREQ(name, p->name))
36038823Sbostic 			break;
361*50960Sbostic 	return p;
36238823Sbostic }
36338823Sbostic 
36438823Sbostic /*
36538823Sbostic  * initkwds - initialise m4 keywords as fast as possible.
36638823Sbostic  * This very similar to install, but without certain overheads,
36738823Sbostic  * such as calling lookup. Malloc is not used for storing the
36838823Sbostic  * keyword strings, since we simply use the static  pointers
369*50960Sbostic  * within keywrds block.
37038823Sbostic  */
371*50960Sbostic void
37238823Sbostic initkwds() {
37338823Sbostic 	register int i;
37438823Sbostic 	register int h;
37538823Sbostic 	register ndptr p;
37638823Sbostic 
37738823Sbostic 	for (i = 0; i < MAXKEYS; i++) {
37838823Sbostic 		h = hash(keywrds[i].knam);
379*50960Sbostic 		p = (ndptr) xalloc(sizeof(struct ndblock));
38038823Sbostic 		p->nxtptr = hashtab[h];
38138823Sbostic 		hashtab[h] = p;
38238823Sbostic 		p->name = keywrds[i].knam;
38338823Sbostic 		p->defn = null;
38438823Sbostic 		p->type = keywrds[i].ktyp | STATIC;
38538823Sbostic 	}
38638823Sbostic }
387