xref: /csrg-svn/usr.bin/m4/main.c (revision 51241)
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*51241Seric static char sccsid[] = "@(#)main.c	5.8 (Berkeley) 10/02/91";
1338823Sbostic #endif /* not lint */
1438823Sbostic 
1538823Sbostic /*
1638823Sbostic  * main.c
1738823Sbostic  * Facility: m4 macro processor
1838823Sbostic  * by: oz
1938823Sbostic  */
2038823Sbostic 
2150960Sbostic #include <sys/types.h>
2246697Sbostic #include <signal.h>
2350960Sbostic #include <errno.h>
2446697Sbostic #include <unistd.h>
2546697Sbostic #include <stdio.h>
2650960Sbostic #include <ctype.h>
2746697Sbostic #include <string.h>
2838823Sbostic #include "mdef.h"
2950960Sbostic #include "stdd.h"
3050960Sbostic #include "extern.h"
3146697Sbostic #include "pathnames.h"
3238823Sbostic 
3338823Sbostic ndptr hashtab[HASHSIZE];	/* hash table for macros etc.  */
3438823Sbostic char buf[BUFSIZE];		/* push-back buffer	       */
35*51241Seric char *bufbase = buf;		/* the base for current ilevel */
36*51241Seric char *bbase[MAXINP];		/* the base for each ilevel    */
3738823Sbostic char *bp = buf; 		/* first available character   */
3838823Sbostic char *endpbb = buf+BUFSIZE;	/* end of push-back buffer     */
3938823Sbostic stae mstack[STACKMAX+1]; 	/* stack of m4 machine         */
4038823Sbostic char strspace[STRSPMAX+1];	/* string space for evaluation */
4138823Sbostic char *ep = strspace;		/* first free char in strspace */
4238823Sbostic char *endest= strspace+STRSPMAX;/* end of string space	       */
4338823Sbostic int sp; 			/* current m4  stack pointer   */
4438823Sbostic int fp; 			/* m4 call frame pointer       */
4538823Sbostic FILE *infile[MAXINP];		/* input file stack (0=stdin)  */
4638823Sbostic FILE *outfile[MAXOUT];		/* diversion array(0=bitbucket)*/
4738823Sbostic FILE *active;			/* active output file pointer  */
4838823Sbostic char *m4temp;			/* filename for diversions     */
4938823Sbostic int ilevel = 0; 		/* input file stack pointer    */
5038823Sbostic int oindex = 0; 		/* diversion index..	       */
5138823Sbostic char *null = "";                /* as it says.. just a null..  */
5238823Sbostic char *m4wraps = "";             /* m4wrap string default..     */
5350960Sbostic char *progname;			/* name of this program        */
5438823Sbostic char lquote = LQUOTE;		/* left quote character  (`)   */
5538823Sbostic char rquote = RQUOTE;		/* right quote character (')   */
5638823Sbostic char scommt = SCOMMT;		/* start character for comment */
5738823Sbostic char ecommt = ECOMMT;		/* end character for comment   */
5850960Sbostic 
5938823Sbostic struct keyblk keywrds[] = {	/* m4 keywords to be installed */
6038823Sbostic 	"include",      INCLTYPE,
6138823Sbostic 	"sinclude",     SINCTYPE,
6238823Sbostic 	"define",       DEFITYPE,
6338823Sbostic 	"defn",         DEFNTYPE,
6438823Sbostic 	"divert",       DIVRTYPE,
6538823Sbostic 	"expr",         EXPRTYPE,
6638823Sbostic 	"eval",         EXPRTYPE,
6738823Sbostic 	"substr",       SUBSTYPE,
6838823Sbostic 	"ifelse",       IFELTYPE,
6938823Sbostic 	"ifdef",        IFDFTYPE,
7038823Sbostic 	"len",          LENGTYPE,
7138823Sbostic 	"incr",         INCRTYPE,
7238823Sbostic 	"decr",         DECRTYPE,
7338823Sbostic 	"dnl",          DNLNTYPE,
7438823Sbostic 	"changequote",  CHNQTYPE,
7538823Sbostic 	"changecom",    CHNCTYPE,
7638823Sbostic 	"index",        INDXTYPE,
7738823Sbostic #ifdef EXTENDED
7838823Sbostic 	"paste",        PASTTYPE,
7938823Sbostic 	"spaste",       SPASTYPE,
8038823Sbostic #endif
8138823Sbostic 	"popdef",       POPDTYPE,
8238823Sbostic 	"pushdef",      PUSDTYPE,
8338823Sbostic 	"dumpdef",      DUMPTYPE,
8438823Sbostic 	"shift",        SHIFTYPE,
8538823Sbostic 	"translit",     TRNLTYPE,
8638823Sbostic 	"undefine",     UNDFTYPE,
8738823Sbostic 	"undivert",     UNDVTYPE,
8838823Sbostic 	"divnum",       DIVNTYPE,
8938823Sbostic 	"maketemp",     MKTMTYPE,
9038823Sbostic 	"errprint",     ERRPTYPE,
9138823Sbostic 	"m4wrap",       M4WRTYPE,
9238823Sbostic 	"m4exit",       EXITTYPE,
9338823Sbostic 	"syscmd",       SYSCTYPE,
9438823Sbostic 	"sysval",       SYSVTYPE,
9550960Sbostic 
9650960Sbostic #ifdef unix
9738823Sbostic 	"unix",         MACRTYPE,
9850960Sbostic #else
9950960Sbostic #ifdef vms
10050960Sbostic 	"vms",          MACRTYPE,
10150960Sbostic #endif
10250960Sbostic #endif
10338823Sbostic };
10438823Sbostic 
10538823Sbostic #define MAXKEYS	(sizeof(keywrds)/sizeof(struct keyblk))
10638823Sbostic 
10738823Sbostic extern int optind;
10838823Sbostic extern char *optarg;
10938823Sbostic 
11050960Sbostic void macro();
11150960Sbostic void initkwds();
11250960Sbostic extern int getopt();
11350960Sbostic 
11450960Sbostic int
11538823Sbostic main(argc,argv)
11650960Sbostic int argc;
11750960Sbostic char *argv[];
11838823Sbostic {
11938823Sbostic 	register int c;
12038823Sbostic 	register int n;
12138823Sbostic 	char *p;
12250960Sbostic 	register FILE *ifp;
12338823Sbostic 
12450960Sbostic 	progname = basename(argv[0]);
12550960Sbostic 
12638823Sbostic 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
12738823Sbostic 		signal(SIGINT, onintr);
12850960Sbostic 
12938823Sbostic 	initkwds();
13038823Sbostic 
13138823Sbostic 	while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
13238823Sbostic 		switch(c) {
13338823Sbostic 
13438823Sbostic 		case 'D':               /* define something..*/
13538823Sbostic 			for (p = optarg; *p; p++)
13638823Sbostic 				if (*p == '=')
13738823Sbostic 					break;
13838823Sbostic 			if (*p)
13938823Sbostic 				*p++ = EOS;
14038823Sbostic 			dodefine(optarg, p);
14138823Sbostic 			break;
14238823Sbostic 		case 'U':               /* undefine...       */
14338823Sbostic 			remhash(optarg, TOP);
14438823Sbostic 			break;
14538823Sbostic 		case 'o':		/* specific output   */
14638823Sbostic 		case '?':
14738823Sbostic 			usage();
14838823Sbostic 		}
14938823Sbostic 
15050960Sbostic         argc -= optind;
15150960Sbostic         argv += optind;
15250960Sbostic 
15338823Sbostic 	active = stdout;		/* default active output     */
15450960Sbostic 					/* filename for diversions   */
15550960Sbostic 	m4temp = mktemp(xstrdup(_PATH_DIVNAME));
15638823Sbostic 
157*51241Seric 	bbase[0] = bufbase;
15850960Sbostic         if (!argc) {
15950960Sbostic  		sp = -1;		/* stack pointer initialized */
16050960Sbostic 		fp = 0; 		/* frame pointer initialized */
16150960Sbostic 		infile[0] = stdin;	/* default input (naturally) */
16250960Sbostic 		macro();
16350960Sbostic 	}
16450960Sbostic         else
16550960Sbostic                 while (argc--) {
16650960Sbostic                         if ((ifp = fopen(*argv, "r")) == NULL)
16750960Sbostic                                 oops("%s: %s", *argv, strerror(errno));
16850960Sbostic                         else {
16950960Sbostic 				sp = -1;
17050960Sbostic 				fp = 0;
17150960Sbostic 				infile[0] = ifp;
17250960Sbostic 				macro();
17350960Sbostic 				(void) fclose(ifp);
17450960Sbostic 			}
17550960Sbostic                         argv++;
17650960Sbostic 		}
17738823Sbostic 
17838823Sbostic 
17938823Sbostic 	if (*m4wraps) { 		/* anything for rundown ??   */
18038823Sbostic 		ilevel = 0;		/* in case m4wrap includes.. */
181*51241Seric 		bufbase = bp = buf;	/* use the entire buffer   */
18238823Sbostic 		putback(EOF);		/* eof is a must !!	     */
18338823Sbostic 		pbstr(m4wraps); 	/* user-defined wrapup act   */
18438823Sbostic 		macro();		/* last will and testament   */
18538823Sbostic 	}
18638823Sbostic 
18739102Sbostic 	if (active != stdout)
18839102Sbostic 		active = stdout;	/* reset output just in case */
18939102Sbostic 	for (n = 1; n < MAXOUT; n++)	/* default wrap-up: undivert */
19039102Sbostic 		if (outfile[n] != NULL)
19139102Sbostic 			getdiv(n);
19238823Sbostic 					/* remove bitbucket if used  */
19338823Sbostic 	if (outfile[0] != NULL) {
19438823Sbostic 		(void) fclose(outfile[0]);
19538823Sbostic 		m4temp[UNIQUE] = '0';
19650960Sbostic #ifdef vms
19750960Sbostic 		(void) remove(m4temp);
19850960Sbostic #else
19938823Sbostic 		(void) unlink(m4temp);
20050960Sbostic #endif
20138823Sbostic 	}
20238823Sbostic 
20350960Sbostic 	return 0;
20438823Sbostic }
20538823Sbostic 
20650960Sbostic ndptr inspect();
20738823Sbostic 
20838823Sbostic /*
20938823Sbostic  * macro - the work horse..
21038823Sbostic  */
21150960Sbostic void
21238823Sbostic macro() {
21338823Sbostic 	char token[MAXTOK];
21438823Sbostic 	register char *s;
21538823Sbostic 	register int t, l;
21638823Sbostic 	register ndptr p;
21738823Sbostic 	register int  nlpar;
21838823Sbostic 
21938823Sbostic 	cycle {
22038823Sbostic 		if ((t = gpbc()) == '_' || isalpha(t)) {
22138823Sbostic 			putback(t);
22238823Sbostic 			if ((p = inspect(s = token)) == nil) {
22338823Sbostic 				if (sp < 0)
22438823Sbostic 					while (*s)
22538823Sbostic 						putc(*s++, active);
22638823Sbostic 				else
22738823Sbostic 					while (*s)
22838823Sbostic 						chrsave(*s++);
22938823Sbostic 			}
23038823Sbostic 			else {
23138823Sbostic 		/*
23238823Sbostic 		 * real thing.. First build a call frame:
23338823Sbostic 		 */
23438823Sbostic 				pushf(fp);	/* previous call frm */
23538823Sbostic 				pushf(p->type); /* type of the call  */
23638823Sbostic 				pushf(0);	/* parenthesis level */
23738823Sbostic 				fp = sp;	/* new frame pointer */
23838823Sbostic 		/*
23938823Sbostic 		 * now push the string arguments:
24038823Sbostic 		 */
24138823Sbostic 				pushs(p->defn);	      /* defn string */
24238823Sbostic 				pushs(p->name);	      /* macro name  */
24338823Sbostic 				pushs(ep);	      /* start next..*/
24438823Sbostic 
24538823Sbostic 				putback(l = gpbc());
24638823Sbostic 				if (l != LPAREN)  {   /* add bracks  */
24738823Sbostic 					putback(RPAREN);
24838823Sbostic 					putback(LPAREN);
24938823Sbostic 				}
25038823Sbostic 			}
25138823Sbostic 		}
25238823Sbostic 		else if (t == EOF) {
25338823Sbostic 			if (sp > -1)
25450960Sbostic 				oops("unexpected end of input", "");
25538823Sbostic 			if (--ilevel < 0)
25638823Sbostic 				break;			/* all done thanks.. */
25738823Sbostic 			(void) fclose(infile[ilevel+1]);
258*51241Seric 			bufbase = bbase[ilevel];
25938823Sbostic 			continue;
26038823Sbostic 		}
26138823Sbostic 	/*
26238823Sbostic 	 * non-alpha single-char token seen..
26350960Sbostic 	 * [the order of else if .. stmts is important.]
26438823Sbostic 	 */
26538823Sbostic 		else if (t == lquote) { 		/* strip quotes */
26638823Sbostic 			nlpar = 1;
26738823Sbostic 			do {
26838823Sbostic 				if ((l = gpbc()) == rquote)
26938823Sbostic 					nlpar--;
27038823Sbostic 				else if (l == lquote)
27138823Sbostic 					nlpar++;
27238823Sbostic 				else if (l == EOF)
27350960Sbostic 					oops("missing right quote", "");
27438823Sbostic 				if (nlpar > 0) {
27538823Sbostic 					if (sp < 0)
27638823Sbostic 						putc(l, active);
27738823Sbostic 					else
27838823Sbostic 						chrsave(l);
27938823Sbostic 				}
28038823Sbostic 			}
28138823Sbostic 			while (nlpar != 0);
28238823Sbostic 		}
28338823Sbostic 
28438823Sbostic 		else if (sp < 0) {		/* not in a macro at all */
28538823Sbostic 			if (t == scommt) {	/* comment handling here */
28638823Sbostic 				putc(t, active);
28738823Sbostic 				while ((t = gpbc()) != ecommt)
28838823Sbostic 					putc(t, active);
28938823Sbostic 			}
29038823Sbostic 			putc(t, active);	/* output directly..	 */
29138823Sbostic 		}
29238823Sbostic 
29338823Sbostic 		else switch(t) {
29438823Sbostic 
29538823Sbostic 		case LPAREN:
29638823Sbostic 			if (PARLEV > 0)
29738823Sbostic 				chrsave(t);
29838823Sbostic 			while (isspace(l = gpbc()))
29938823Sbostic 				;		/* skip blank, tab, nl.. */
30038823Sbostic 			putback(l);
30138823Sbostic 			PARLEV++;
30238823Sbostic 			break;
30338823Sbostic 
30438823Sbostic 		case RPAREN:
30538823Sbostic 			if (--PARLEV > 0)
30638823Sbostic 				chrsave(t);
30738823Sbostic 			else {			/* end of argument list */
30838823Sbostic 				chrsave(EOS);
30938823Sbostic 
31038823Sbostic 				if (sp == STACKMAX)
31150960Sbostic 					oops("internal stack overflow", "");
31238823Sbostic 
31338823Sbostic 				if (CALTYP == MACRTYPE)
31450960Sbostic 					expand((char **) mstack+fp+1, sp-fp);
31538823Sbostic 				else
31650960Sbostic 					eval((char **) mstack+fp+1, sp-fp, CALTYP);
31738823Sbostic 
31838823Sbostic 				ep = PREVEP;	/* flush strspace */
31938823Sbostic 				sp = PREVSP;	/* previous sp..  */
32038823Sbostic 				fp = PREVFP;	/* rewind stack...*/
32138823Sbostic 			}
32238823Sbostic 			break;
32338823Sbostic 
32438823Sbostic 		case COMMA:
32550960Sbostic 			if (PARLEV == 1) {
32638823Sbostic 				chrsave(EOS);		/* new argument   */
32738823Sbostic 				while (isspace(l = gpbc()))
32838823Sbostic 					;
32938823Sbostic 				putback(l);
33038823Sbostic 				pushs(ep);
33138823Sbostic 			}
33238823Sbostic 			break;
33338823Sbostic 		default:
33438823Sbostic 			chrsave(t);			/* stack the char */
33538823Sbostic 			break;
33638823Sbostic 		}
33738823Sbostic 	}
33838823Sbostic }
33938823Sbostic 
34038823Sbostic /*
34138823Sbostic  * build an input token..
34238823Sbostic  * consider only those starting with _ or A-Za-z. This is a
34338823Sbostic  * combo with lookup to speed things up.
34438823Sbostic  */
34538823Sbostic ndptr
34638823Sbostic inspect(tp)
34738823Sbostic register char *tp;
34838823Sbostic {
34938823Sbostic 	register char c;
35038823Sbostic 	register char *name = tp;
35138823Sbostic 	register char *etp = tp+MAXTOK;
35238823Sbostic 	register ndptr p;
35350960Sbostic 	register unsigned long h = 0;
35438823Sbostic 
35550960Sbostic 	while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
35650960Sbostic 		h = (h << 5) + h + (*tp++ = c);
35738823Sbostic 	putback(c);
35838823Sbostic 	if (tp == etp)
35950960Sbostic 		oops("token too long", "");
36050960Sbostic 
36138823Sbostic 	*tp = EOS;
36250960Sbostic 
36338823Sbostic 	for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
36450960Sbostic 		if (STREQ(name, p->name))
36538823Sbostic 			break;
36650960Sbostic 	return p;
36738823Sbostic }
36838823Sbostic 
36938823Sbostic /*
37038823Sbostic  * initkwds - initialise m4 keywords as fast as possible.
37138823Sbostic  * This very similar to install, but without certain overheads,
37238823Sbostic  * such as calling lookup. Malloc is not used for storing the
37338823Sbostic  * keyword strings, since we simply use the static  pointers
37450960Sbostic  * within keywrds block.
37538823Sbostic  */
37650960Sbostic void
37738823Sbostic initkwds() {
37838823Sbostic 	register int i;
37938823Sbostic 	register int h;
38038823Sbostic 	register ndptr p;
38138823Sbostic 
38238823Sbostic 	for (i = 0; i < MAXKEYS; i++) {
38338823Sbostic 		h = hash(keywrds[i].knam);
38450960Sbostic 		p = (ndptr) xalloc(sizeof(struct ndblock));
38538823Sbostic 		p->nxtptr = hashtab[h];
38638823Sbostic 		hashtab[h] = p;
38738823Sbostic 		p->name = keywrds[i].knam;
38838823Sbostic 		p->defn = null;
38938823Sbostic 		p->type = keywrds[i].ktyp | STATIC;
39038823Sbostic 	}
39138823Sbostic }
392