xref: /original-bsd/usr.bin/m4/m4.c (revision 972e762a)
10859a5e0Ssam #ifndef lint
2*972e762aSbostic static char sccsid[] = "@(#)m4.c	1.5 (Berkeley) 05/10/89";
30859a5e0Ssam #endif
40859a5e0Ssam 
59a34925cSclemc #include <stdio.h>
69a34925cSclemc #include <signal.h>
7*972e762aSbostic #include "pathnames.h"
89a34925cSclemc 
99a34925cSclemc #define ERROR NULL
109a34925cSclemc #define	READ	"r"
119a34925cSclemc #define	WRITE	"w"
129a34925cSclemc 
139a34925cSclemc #define	EOS	0
149a34925cSclemc int	lpar	= '(';
159a34925cSclemc #define	LPAR	lpar
169a34925cSclemc #define	RPAR	')'
179a34925cSclemc #define	COMMA	','
189a34925cSclemc #define	GRAVE	'`'
199a34925cSclemc #define	ACUTE	'\''
209a34925cSclemc #define LBRAK	'['
219a34925cSclemc #define RBRAK	']'
229a34925cSclemc #ifdef  M4
239a34925cSclemc char	lquote	LBRAK;
249a34925cSclemc char	rquote	RBRAK;
259a34925cSclemc #endif
269a34925cSclemc #ifndef M4
279a34925cSclemc char	lquote	= GRAVE;
289a34925cSclemc char	rquote	= ACUTE;
299a34925cSclemc #endif
309a34925cSclemc #define	COMMENT	'#'
319a34925cSclemc #define	ALPH	1
329a34925cSclemc #define	DIG	2
339a34925cSclemc 
349a34925cSclemc #define	HSHSIZ	199	/* prime */
359a34925cSclemc #define	STACKS	50
369a34925cSclemc #define	SAVS	4096
379a34925cSclemc #define	TOKS	128
389a34925cSclemc 
399a34925cSclemc #define	putbak(c)	*ip++ = c;
409a34925cSclemc #define	getchr()	(ip>cur_ip?*--ip: getc(infile[infptr]))
419a34925cSclemc #define	putchr(c)	if (cp==NULL) {if (curfile)putc(c,curfile);} else *op++ = c
429a34925cSclemc char	type[] = {
439a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
449a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
459a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
469a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
479a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
489a34925cSclemc 	0,	0,	0,	0,	0,	0,	0,	0,
499a34925cSclemc 	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,
509a34925cSclemc 	DIG,	DIG,	0,	0,	0,	0,	0,	0,
519a34925cSclemc 	0,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
529a34925cSclemc 	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
539a34925cSclemc 	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
549a34925cSclemc 	ALPH,	ALPH,	ALPH,	0,	0,	0,	0,	ALPH,
559a34925cSclemc 	0,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
569a34925cSclemc 	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
579a34925cSclemc 	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,	ALPH,
589a34925cSclemc 	ALPH,	ALPH,	ALPH,	0,	0,	0,	0,	0,
599a34925cSclemc };
609a34925cSclemc 
619a34925cSclemc char	token[TOKS];
629a34925cSclemc char	eoa[]	= "\0";
63733d808dSclemc 
64733d808dSclemc #define	RESERVED	01	/* This is a reserved word with side action */
659a34925cSclemc struct	nlist {
669a34925cSclemc 	char	*name;
679a34925cSclemc 	char	*def;
68733d808dSclemc 	char	flag;
699a34925cSclemc 	struct	nlist *next;
709a34925cSclemc };
719a34925cSclemc 
729a34925cSclemc struct	nlist	*hshtab[HSHSIZ];
739a34925cSclemc char	ibuf[SAVS+TOKS];
749a34925cSclemc char	obuf[SAVS+TOKS];
759a34925cSclemc char	*op	= obuf;
769a34925cSclemc char	*ip	= ibuf;
779a34925cSclemc char *ip_stk[10] = {ibuf};
789a34925cSclemc char *cur_ip = ibuf;
799a34925cSclemc struct call {
809a34925cSclemc 	char	**argp;
819a34925cSclemc 	int	plev;
829a34925cSclemc };
839a34925cSclemc struct	call	*cp = NULL;
849a34925cSclemc 
859a34925cSclemc char	*makeloc;
869a34925cSclemc char	*ifdefloc;
879a34925cSclemc char	*lenloc;
889a34925cSclemc char	*undefloc;
899a34925cSclemc char	*shiftloc;
909a34925cSclemc char	*cqloc;
919a34925cSclemc char	*defloc;
929a34925cSclemc char	*evaloc;
939a34925cSclemc char	*incrloc;
949a34925cSclemc char	*substrloc;
959a34925cSclemc char	*indexloc;
969a34925cSclemc char	*transloc;
979a34925cSclemc char	*ifloc;
989a34925cSclemc char	*divloc;
999a34925cSclemc char	*divnumloc;
1009a34925cSclemc char	*undivloc;
1019a34925cSclemc char	*dnlloc;
1029a34925cSclemc char	*inclloc;
1039a34925cSclemc char	*sinclloc;
1049a34925cSclemc char	*syscmdloc;
1059a34925cSclemc char	*dumploc;
1069a34925cSclemc char	*errploc;
1079a34925cSclemc 
108*972e762aSbostic char	tempname[] = _PATH_TMP;
1099a34925cSclemc struct nlist	*lookup();
1109a34925cSclemc char	*install();
1119a34925cSclemc char	*malloc();
1129a34925cSclemc char	*mktemp();
1139a34925cSclemc char	*copy();
1149a34925cSclemc long	ctol();
1159a34925cSclemc int	hshval;
1169a34925cSclemc FILE	*olist[11] = { stdout };
1179a34925cSclemc int	okret;
1189a34925cSclemc int	curout	= 0;
1199a34925cSclemc FILE	*curfile = { stdout };
1209a34925cSclemc FILE	*infile[10] = { stdin };
1219a34925cSclemc int	infptr	= 0;
1229a34925cSclemc 
main(argc,argv)1239a34925cSclemc main(argc, argv)
1249a34925cSclemc char **argv;
1259a34925cSclemc {
1269a34925cSclemc 	char *argstk[STACKS+10];
1279a34925cSclemc 	struct call callst[STACKS];
1289a34925cSclemc 	register char *tp, **ap;
1299a34925cSclemc 	int delexit(), catchsig();
1309a34925cSclemc 	register t;
1319a34925cSclemc 	int i;
1329a34925cSclemc 
1339a34925cSclemc #ifdef gcos
1349a34925cSclemc #ifdef M4
135733d808dSclemc 	install("GCOS", eoa, 0);
1369a34925cSclemc #endif
1379a34925cSclemc #ifndef M4
138733d808dSclemc 	install("gcos", eoa, 0);
1399a34925cSclemc #endif
1409a34925cSclemc #endif
1419a34925cSclemc #ifdef unix
1429a34925cSclemc #ifdef M4
143733d808dSclemc 	install("UNIX", eoa, 0);
1449a34925cSclemc #endif
1459a34925cSclemc #ifndef M4
146733d808dSclemc 	install("unix", eoa, 0);
1479a34925cSclemc #endif
1489a34925cSclemc #endif
1499a34925cSclemc 
1509a34925cSclemc #ifdef M4
151733d808dSclemc 	makeloc = install("MAKETEMP", eoa, RESERVED);
152733d808dSclemc 	ifdefloc = install("IFDEF", eoa, RESERVED);
153733d808dSclemc 	lenloc = install("LEN", eoa, RESERVED);
154733d808dSclemc 	undefloc = install("UNDEFINE", eoa, RESERVED);
155733d808dSclemc 	shiftloc = install("SHIFT", eoa, RESERVED);
156733d808dSclemc 	cqloc = install("CHANGEQUOTE", eoa, RESERVED);
157733d808dSclemc 	defloc = install("DEFINE", eoa, RESERVED);
158733d808dSclemc 	evaloc = install("EVAL", eoa, RESERVED);
159733d808dSclemc 	inclloc = install("INCLUDE", eoa, RESERVED);
160733d808dSclemc 	sinclloc = install("SINCLUDE", eoa, RESERVED);
161733d808dSclemc 	syscmdloc = install("SYSCMD", eoa, RESERVED);
162733d808dSclemc 	dumploc = install("DUMPDEF", eoa, RESERVED);
163733d808dSclemc 	errploc = install("ERRPRINT", eoa, RESERVED);
164733d808dSclemc 	incrloc = install("INCR", eoa, RESERVED);
165733d808dSclemc 	substrloc = install("SUBSTR", eoa, RESERVED);
166733d808dSclemc 	indexloc = install("INDEX", eoa, RESERVED);
167733d808dSclemc 	transloc = install("TRANSLIT", eoa, RESERVED);
168733d808dSclemc 	ifloc = install("IFELSE", eoa, RESERVED);
169733d808dSclemc 	divloc = install("DIVERT", eoa, RESERVED);
170733d808dSclemc 	divnumloc = install("DIVNUM", eoa, RESERVED);
171733d808dSclemc 	undivloc = install("UNDIVERT", eoa, RESERVED);
172733d808dSclemc 	dnlloc = install("DNL", eoa, RESERVED);
1739a34925cSclemc #endif
1749a34925cSclemc 
1759a34925cSclemc #ifndef M4
176733d808dSclemc 	makeloc = install("maketemp", eoa, RESERVED);
177733d808dSclemc 	ifdefloc = install("ifdef", eoa, RESERVED);
178733d808dSclemc 	lenloc = install("len", eoa, RESERVED);
179733d808dSclemc 	undefloc = install("undefine", eoa, RESERVED);
180733d808dSclemc 	shiftloc = install("shift", eoa, RESERVED);
181733d808dSclemc 	cqloc = install("changequote", eoa, RESERVED);
182733d808dSclemc 	defloc = install("define", eoa, RESERVED);
183733d808dSclemc 	evaloc = install("eval", eoa, RESERVED);
184733d808dSclemc 	inclloc = install("include", eoa, RESERVED);
185733d808dSclemc 	sinclloc = install("sinclude", eoa, RESERVED);
186733d808dSclemc 	syscmdloc = install("syscmd", eoa, RESERVED);
187733d808dSclemc 	dumploc = install("dumpdef", eoa, RESERVED);
188733d808dSclemc 	errploc = install("errprint", eoa, RESERVED);
189733d808dSclemc 	incrloc = install("incr", eoa, RESERVED);
190733d808dSclemc 	substrloc = install("substr", eoa, RESERVED);
191733d808dSclemc 	indexloc = install("index", eoa, RESERVED);
192733d808dSclemc 	transloc = install("translit", eoa, RESERVED);
193733d808dSclemc 	ifloc = install("ifelse", eoa, RESERVED);
194733d808dSclemc 	divloc = install("divert", eoa, RESERVED);
195733d808dSclemc 	divnumloc = install("divnum", eoa, RESERVED);
196733d808dSclemc 	undivloc = install("undivert", eoa, RESERVED);
197733d808dSclemc 	dnlloc = install("dnl", eoa, RESERVED);
1989a34925cSclemc #endif
1999a34925cSclemc 	ap = argstk;
2009a34925cSclemc #ifndef gcos
2019a34925cSclemc 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
2029a34925cSclemc 		signal(SIGHUP, catchsig);
2039a34925cSclemc 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2049a34925cSclemc 		signal(SIGINT, catchsig);
20501f249f8Sbostic 	mktemp(tempname);
2069a34925cSclemc 	close(creat(tempname, 0));
2079a34925cSclemc #endif
2089a34925cSclemc #ifdef gcos
2099a34925cSclemc 	tempname = "m4.tempa";
2109a34925cSclemc #endif
2119a34925cSclemc 	if (argc>1)
2129a34925cSclemc 		putbak(0);
2139a34925cSclemc 	for (;;) {
2149a34925cSclemc 		tp = token;
2159a34925cSclemc 		*tp++ = t = getchr();
2169a34925cSclemc 		*tp = EOS;
2179a34925cSclemc 		if (t<=0) {
2189a34925cSclemc 			if (infptr > 0) {
2199a34925cSclemc 				fclose(infile[infptr]);
2209a34925cSclemc 				infptr--;
2219a34925cSclemc 				cur_ip = ip_stk[infptr];
2229a34925cSclemc 				continue;
2239a34925cSclemc 			}
2249a34925cSclemc 			if (argc<=1)
2259a34925cSclemc 				break;
2269a34925cSclemc 			argc--;
2279a34925cSclemc 			argv++;
2289a34925cSclemc 			if (infile[infptr]!=stdin)
2299a34925cSclemc 				fclose(infile[infptr]);
2309a34925cSclemc 			if (**argv=='-')
2319a34925cSclemc 				infile[infptr] = stdin;
2329a34925cSclemc 			else if ((infile[infptr]=fopen(argv[0], READ))==ERROR) {
2339a34925cSclemc 				fprintf(stderr, "m4: file not found: %s\n", argv[0]);
2349a34925cSclemc 				delexit();
2359a34925cSclemc 			}
2369a34925cSclemc 			continue;
2379a34925cSclemc 		}
2389a34925cSclemc 		if (type[t]==ALPH) {
2399a34925cSclemc 			while ((t=type[*tp++=getchr()])==ALPH||t==DIG);
2409a34925cSclemc 			putbak(*--tp);
2419a34925cSclemc 			*tp = EOS;
2429a34925cSclemc 			if (*ap = lookup(token)->def) {
2439a34925cSclemc 				if (++ap >= &argstk[STACKS]) {
2449a34925cSclemc 					fprintf(stderr, "m4: arg stack overflow\n");
2459a34925cSclemc 					delexit();
2469a34925cSclemc 				}
2479a34925cSclemc 				if (cp==NULL)
2489a34925cSclemc 					cp = callst;
2499a34925cSclemc 				else if (++cp > &callst[STACKS]) {
2509a34925cSclemc 					fprintf(stderr, "m4: call stack overflow\n");
2519a34925cSclemc 					delexit();
2529a34925cSclemc 				}
2539a34925cSclemc 				cp->argp = ap;
2549a34925cSclemc 				*ap++ = op;
2559a34925cSclemc 				puttok();
2569a34925cSclemc 				*op++ = '\0';
2579a34925cSclemc 				t = getchr();
2589a34925cSclemc 				putbak(t);
2599a34925cSclemc 				if (t!=LPAR) {
2609a34925cSclemc 					/* if (t!=' ' && t!='\t') */
2619a34925cSclemc 						putbak(')');
2629a34925cSclemc 					putbak('(');
2639a34925cSclemc 				}
2649a34925cSclemc 				else	/* try to fix arg count */
2659a34925cSclemc 					*ap++ = op;
2669a34925cSclemc 				cp->plev = 0;
2679a34925cSclemc 			} else
2689a34925cSclemc 				puttok();
2699a34925cSclemc 		} else if (t==lquote) {
2709a34925cSclemc 			i = 1;
2719a34925cSclemc 			for (;;) {
2729a34925cSclemc 				t = getchr();
2739a34925cSclemc 				if (t==rquote) {
2749a34925cSclemc 					i--;
2759a34925cSclemc 					if (i==0)
2769a34925cSclemc 						break;
2779a34925cSclemc 				} else if (t==lquote)
2789a34925cSclemc 					i++;
2799a34925cSclemc 				else if (t<0) {
2809a34925cSclemc 					fprintf(stderr, "m4: EOF in string\n");
2819a34925cSclemc 					delexit();
2829a34925cSclemc 				}
2839a34925cSclemc 				putchr(t);
2849a34925cSclemc 			}
2859a34925cSclemc 		} else if (t==COMMENT) {
2869a34925cSclemc 			putbak(t);
2879a34925cSclemc 			while ((t = getchr())!='\n'&& t>=0)
2889a34925cSclemc 				if (cp==NULL)
2899a34925cSclemc 					putchr(t);
2909a34925cSclemc 			putbak(t);
2919a34925cSclemc 		} else if (cp==NULL) {
2929a34925cSclemc 			puttok();
2939a34925cSclemc 		} else if (t==LPAR) {
2949a34925cSclemc 			if (cp->plev)
2959a34925cSclemc 				*op++ = t;
2969a34925cSclemc 			cp->plev++;
2979a34925cSclemc 			while ( (t=getchr())==' ' || t=='\t' || t=='\n')
2989a34925cSclemc 				;	/* skip leading white space during arg collection */
2999a34925cSclemc 			putbak(t);
3009a34925cSclemc /*
3019a34925cSclemc 		} else if (t==' ' || t=='\t' || t=='\n') {
3029a34925cSclemc 			continue;
3039a34925cSclemc */
3049a34925cSclemc 		} else if (t==RPAR) {
3059a34925cSclemc 			cp->plev--;
3069a34925cSclemc 			if (cp->plev==0) {
3079a34925cSclemc 				*op++ = '\0';
3089a34925cSclemc 				expand(cp->argp, ap-cp->argp-1);
3099a34925cSclemc 				op = *cp->argp;
3109a34925cSclemc 				ap = cp->argp-1;
3119a34925cSclemc 				cp--;
3129a34925cSclemc 				if (cp < callst)
3139a34925cSclemc 					cp = NULL;
3149a34925cSclemc 			} else
3159a34925cSclemc 				*op++ = t;
3169a34925cSclemc 		} else if (t==COMMA && cp->plev<=1) {
3179a34925cSclemc 			*op++ = '\0';
3189a34925cSclemc 			*ap++ = op;
3199a34925cSclemc 			while ((t=getchr())==' ' || t=='\t' || t=='\n')
3209a34925cSclemc 				;	/* skip leading white space during arg collection */
3219a34925cSclemc 			putbak(t);
3229a34925cSclemc 		} else
3239a34925cSclemc 			*op++ = t;
3249a34925cSclemc 	}
3259a34925cSclemc 	if (cp!=NULL) {
3269a34925cSclemc 		fprintf(stderr, "m4: unexpected EOF\n");
3279a34925cSclemc 		delexit();
3289a34925cSclemc 	}
3299a34925cSclemc 	okret = 1;
3309a34925cSclemc 	delexit();
3319a34925cSclemc }
3329a34925cSclemc 
catchsig()3339a34925cSclemc catchsig()
3349a34925cSclemc {
3359a34925cSclemc 	okret = 0;
3369a34925cSclemc 	delexit();
3379a34925cSclemc }
3389a34925cSclemc 
delexit()3399a34925cSclemc delexit()
3409a34925cSclemc {
3419a34925cSclemc 	register FILE *fp;
3429a34925cSclemc 	register i, c;
3439a34925cSclemc 
3449a34925cSclemc 	if (!okret) {
3459a34925cSclemc 		signal(SIGHUP, SIG_IGN);
3469a34925cSclemc 		signal(SIGINT, SIG_IGN);
3479a34925cSclemc 	}
3489a34925cSclemc 	for (i=1; i<10; i++) {
3499a34925cSclemc 		if (olist[i]==NULL)
3509a34925cSclemc 			continue;
3519a34925cSclemc 		fclose(olist[i]);
3529a34925cSclemc 		tempname[7] = 'a'+i;
3539a34925cSclemc 		if (okret) {
3549a34925cSclemc 			fp = fopen(tempname, READ);
3559a34925cSclemc 			while ((c = getc(fp)) > 0)
3569a34925cSclemc 				putchar(c);
3579a34925cSclemc 			fclose(fp);
3589a34925cSclemc 		}
3599a34925cSclemc 		unlink(tempname);
3609a34925cSclemc 	}
3619a34925cSclemc 	tempname[7] = 'a';
3629a34925cSclemc 	unlink(tempname);
3639a34925cSclemc 	exit(1-okret);
3649a34925cSclemc }
3659a34925cSclemc 
puttok()3669a34925cSclemc puttok()
3679a34925cSclemc {
3689a34925cSclemc 	register char *tp;
3699a34925cSclemc 
3709a34925cSclemc 	tp = token;
3719a34925cSclemc 	if (cp) {
3729a34925cSclemc 		if (op >= &obuf[SAVS]) {
3739a34925cSclemc 			fprintf(stderr, "m4: argument overflow\n");
3749a34925cSclemc 			delexit();
3759a34925cSclemc 		}
3769a34925cSclemc 		while (*tp)
3779a34925cSclemc 			*op++ = *tp++;
3789a34925cSclemc 	} else if (curfile)
3799a34925cSclemc 		while (*tp)
3809a34925cSclemc 			putc(*tp++, curfile);
3819a34925cSclemc }
3829a34925cSclemc 
pbstr(str)3839a34925cSclemc pbstr(str)
3849a34925cSclemc register char *str;
3859a34925cSclemc {
3869a34925cSclemc 	register char *p;
3879a34925cSclemc 
3889a34925cSclemc 	p = str;
3899a34925cSclemc 	while (*p++);
3909a34925cSclemc 	--p;
3919a34925cSclemc 	if (ip >= &ibuf[SAVS]) {
3929a34925cSclemc 		fprintf(stderr, "m4: pushback overflow\n");
3939a34925cSclemc 		delexit();
3949a34925cSclemc 	}
3959a34925cSclemc 	while (p > str)
3969a34925cSclemc 		putbak(*--p);
3979a34925cSclemc }
3989a34925cSclemc 
expand(a1,c)3999a34925cSclemc expand(a1, c)
4009a34925cSclemc register char **a1;
4019a34925cSclemc {
4029a34925cSclemc 	register char *dp;
4039a34925cSclemc 	register n;
4049a34925cSclemc 
4059a34925cSclemc 	dp = a1[-1];
4069a34925cSclemc 	if (dp==defloc)
4079a34925cSclemc 		dodef(a1, c);
4089a34925cSclemc 	else if (dp==evaloc)
4099a34925cSclemc 		doeval(a1, c);
4109a34925cSclemc 	else if (dp==inclloc)
4119a34925cSclemc 		doincl(a1, c, 1);
4129a34925cSclemc 	else if (dp==sinclloc)
4139a34925cSclemc 		doincl(a1, c, 0);
4149a34925cSclemc 	else if (dp==makeloc)
4159a34925cSclemc 		domake(a1, c);
4169a34925cSclemc 	else if (dp==syscmdloc)
4179a34925cSclemc 		dosyscmd(a1, c);
4189a34925cSclemc 	else if (dp==incrloc)
4199a34925cSclemc 		doincr(a1, c);
4209a34925cSclemc 	else if (dp==substrloc)
4219a34925cSclemc 		dosubstr(a1, c);
4229a34925cSclemc 	else if (dp==indexloc)
4239a34925cSclemc 		doindex(a1, c);
4249a34925cSclemc 	else if (dp==transloc)
4259a34925cSclemc 		dotransl(a1, c);
4269a34925cSclemc 	else if (dp==ifloc)
4279a34925cSclemc 		doif(a1, c);
4289a34925cSclemc 	else if (dp==divloc)
4299a34925cSclemc 		dodiv(a1, c);
4309a34925cSclemc 	else if (dp==divnumloc)
4319a34925cSclemc 		dodivnum(a1, c);
4329a34925cSclemc 	else if (dp==undivloc)
4339a34925cSclemc 		doundiv(a1, c);
4349a34925cSclemc 	else if (dp==dnlloc)
4359a34925cSclemc 		dodnl(a1, c);
4369a34925cSclemc 	else if (dp==dumploc)
4379a34925cSclemc 		dodump(a1, c);
4389a34925cSclemc 	else if (dp==errploc)
4399a34925cSclemc 		doerrp(a1, c);
4409a34925cSclemc 	else if (dp==lenloc)
4419a34925cSclemc 		dolen(a1, c);
4429a34925cSclemc 	else if (dp==ifdefloc)
4439a34925cSclemc 		doifdef(a1, c);
4449a34925cSclemc 	else if (dp==undefloc)
4459a34925cSclemc 		doundef(a1, c);
4469a34925cSclemc 	else if (dp==shiftloc)
4479a34925cSclemc 		doshift(a1, c);
4489a34925cSclemc 	else if (dp==cqloc)
4499a34925cSclemc 		docq(a1, c);
4509a34925cSclemc 	else {
4519a34925cSclemc 		while (*dp++);
4529a34925cSclemc 		for (dp--; dp>a1[-1]; ) {
4539a34925cSclemc 			if (--dp>a1[-1] && dp[-1]=='$') {
4549a34925cSclemc 				n = *dp-'0';
4559a34925cSclemc 				if (n>=0 && n<=9) {
4569a34925cSclemc 					if (n <= c)
4579a34925cSclemc 						pbstr(a1[n]);
4589a34925cSclemc 					dp--;
4599a34925cSclemc 				} else
4609a34925cSclemc 					putbak(*dp);
4619a34925cSclemc 			} else
4629a34925cSclemc 				putbak(*dp);
4639a34925cSclemc 		}
4649a34925cSclemc 	}
4659a34925cSclemc }
4669a34925cSclemc 
lookup(str)4679a34925cSclemc struct nlist *lookup(str)
4689a34925cSclemc char *str;
4699a34925cSclemc {
4709a34925cSclemc 	register char *s1, *s2;
4719a34925cSclemc 	register struct nlist *np;
4729a34925cSclemc 	static struct nlist nodef;
4739a34925cSclemc 
4749a34925cSclemc 	s1 = str;
4759a34925cSclemc 	for (hshval = 0; *s1; )
4769a34925cSclemc 		hshval += *s1++;
4779a34925cSclemc 	hshval %= HSHSIZ;
4789a34925cSclemc 	for (np = hshtab[hshval]; np!=NULL; np = np->next) {
4799a34925cSclemc 		s1 = str;
4809a34925cSclemc 		s2 = np->name;
4819a34925cSclemc 		while (*s1++ == *s2)
4829a34925cSclemc 			if (*s2++ == EOS)
4839a34925cSclemc 				return(np);
4849a34925cSclemc 	}
4859a34925cSclemc 	return(&nodef);
4869a34925cSclemc }
4879a34925cSclemc 
install(nam,val,flag)488733d808dSclemc char *install(nam, val, flag)
4899a34925cSclemc char *nam, *val;
490733d808dSclemc char flag;
4919a34925cSclemc {
4929a34925cSclemc 	register struct nlist *np;
4939a34925cSclemc 
4949a34925cSclemc 	if ((np = lookup(nam))->name == NULL) {
4959a34925cSclemc 		np = (struct nlist *)malloc(sizeof(*np));
4969a34925cSclemc 		if (np == NULL) {
4979a34925cSclemc 			fprintf(stderr, "m4: no space for alloc\n");
4989a34925cSclemc 			exit(1);
4999a34925cSclemc 		}
5009a34925cSclemc 		np->name = copy(nam);
5019a34925cSclemc 		np->def = copy(val);
5029a34925cSclemc 		np->next = hshtab[hshval];
503733d808dSclemc 		np->flag = flag;
5049a34925cSclemc 		hshtab[hshval] = np;
5059a34925cSclemc 		return(np->def);
5069a34925cSclemc 	}
5079a34925cSclemc 	free(np->def);
508733d808dSclemc 	np->flag = flag;
5099a34925cSclemc 	np->def = copy(val);
5109a34925cSclemc 	return(np->def);
5119a34925cSclemc }
5129a34925cSclemc 
doundef(ap,c)5139a34925cSclemc doundef(ap, c)
5149a34925cSclemc char **ap;
5159a34925cSclemc {
5169a34925cSclemc 	register struct nlist *np, *tnp;
5179a34925cSclemc 
5189a34925cSclemc 	if (c < 1 || (np = lookup(ap[1]))->name == NULL)
5199a34925cSclemc 		return;
5209a34925cSclemc 	tnp = hshtab[hshval];	/* lookup sets hshval */
5219a34925cSclemc 	if (tnp == np)	/* it's in first place */
5229a34925cSclemc 		hshtab[hshval] = np->next;
5239a34925cSclemc 	else {
5249a34925cSclemc 		for ( ; tnp->next != np; tnp = tnp->next)
5259a34925cSclemc 			;
5269a34925cSclemc 		tnp->next = np->next;
5279a34925cSclemc 	}
528733d808dSclemc 	/*
529733d808dSclemc 	 * If this is a reserved word, it has been removed from the
530733d808dSclemc 	 * hastable.  We do not want to actually free the space because
531733d808dSclemc 	 * of the code in expand.  Expand wants to to pointer compairs
532733d808dSclemc 	 * to tell if this is a reserved word (e.g a special action
533733d808dSclemc 	 * needs to take place).  Thus if we do not free the space,
534733d808dSclemc 	 * expand will still work, but the name will never be found
535733d808dSclemc 	 * because it out of the symbol table!
536733d808dSclemc 	 */
537733d808dSclemc 	if (np->flag&RESERVED == 0) { /* If not reserved free it */
5389a34925cSclemc 		free(np->name);
5399a34925cSclemc 		free(np->def);
5409a34925cSclemc 		free((char *)np);
5419a34925cSclemc 	}
542733d808dSclemc }
5439a34925cSclemc 
copy(s)5449a34925cSclemc char *copy(s)
5459a34925cSclemc register char *s;
5469a34925cSclemc {
5479a34925cSclemc 	register char *p, *s1;
5489a34925cSclemc 
5499a34925cSclemc 	p = s1 = malloc((unsigned)strlen(s)+1);
5509a34925cSclemc 	if (p == NULL) {
5519a34925cSclemc 		fprintf(stderr, "m4: no space for alloc\n");
5529a34925cSclemc 		exit(1);
5539a34925cSclemc 	}
5549a34925cSclemc 	while (*s1++ = *s++);
5559a34925cSclemc 	return(p);
5569a34925cSclemc }
5579a34925cSclemc 
dodef(ap,c)5589a34925cSclemc dodef(ap, c)
5599a34925cSclemc char **ap;
5609a34925cSclemc {
5619a34925cSclemc 	if (c >= 2) {
5629a34925cSclemc 		if (strcmp(ap[1], ap[2]) == 0) {
5639a34925cSclemc 			fprintf(stderr, "m4: %s defined as itself\n", ap[1]);
5649a34925cSclemc 			delexit();
5659a34925cSclemc 		}
566733d808dSclemc 		install(ap[1], ap[2], 0);
5679a34925cSclemc 	}
5689a34925cSclemc 	else if (c == 1)
569733d808dSclemc 		install(ap[1], "", 0);
5709a34925cSclemc }
5719a34925cSclemc 
doifdef(ap,c)5729a34925cSclemc doifdef(ap, c)
5739a34925cSclemc char **ap;
5749a34925cSclemc {
5759a34925cSclemc 	register struct nlist *np;
5769a34925cSclemc 
5779a34925cSclemc 	if (c < 2)
5789a34925cSclemc 		return;
5799a34925cSclemc 	if (lookup(ap[1])->name != NULL)
5809a34925cSclemc 		pbstr(ap[2]);
5819a34925cSclemc 	else if (c >= 3)
5829a34925cSclemc 		pbstr(ap[3]);
5839a34925cSclemc }
5849a34925cSclemc 
dolen(ap,c)5859a34925cSclemc dolen(ap, c)
5869a34925cSclemc char **ap;
5879a34925cSclemc {
5889a34925cSclemc 	putnum((long) strlen(ap[1]));
5899a34925cSclemc }
5909a34925cSclemc 
docq(ap,c)5919a34925cSclemc docq(ap, c)
5929a34925cSclemc char **ap;
5939a34925cSclemc {
5949a34925cSclemc 	if (c > 1) {
5959a34925cSclemc 		lquote = *ap[1];
5969a34925cSclemc 		rquote = *ap[2];
5979a34925cSclemc 	} else if (c == 1) {
5989a34925cSclemc 		lquote = rquote = *ap[1];
5999a34925cSclemc 	} else {
6009a34925cSclemc #ifndef M4
6019a34925cSclemc 		lquote = GRAVE;
6029a34925cSclemc 		rquote = ACUTE;
6039a34925cSclemc #endif
6049a34925cSclemc #ifdef M4
6059a34925cSclemc 		lquote = LBRAK;
6069a34925cSclemc 		rquote = RBRAK;
6079a34925cSclemc #endif
6089a34925cSclemc 	}
6099a34925cSclemc }
6109a34925cSclemc 
doshift(ap,c)6119a34925cSclemc doshift(ap, c)
6129a34925cSclemc char **ap;
6139a34925cSclemc {
6149a34925cSclemc 	fprintf(stderr, "m4: shift not yet implemented\n");
6159a34925cSclemc }
6169a34925cSclemc 
dodump(ap,c)6179a34925cSclemc dodump(ap, c)
6189a34925cSclemc char **ap;
6199a34925cSclemc {
6209a34925cSclemc 	int i;
6219a34925cSclemc 	register struct nlist *np;
6229a34925cSclemc 
6239a34925cSclemc 	if (c > 0)
6249a34925cSclemc 		while (c--) {
6259a34925cSclemc 			if ((np = lookup(*++ap))->name != NULL)
6269a34925cSclemc 				fprintf(stderr, "`%s'	`%s'\n", np->name, np->def);
6279a34925cSclemc 		}
6289a34925cSclemc 	else
6299a34925cSclemc 		for (i=0; i<HSHSIZ; i++)
6309a34925cSclemc 			for (np=hshtab[i]; np!=NULL; np=np->next)
6319a34925cSclemc 				fprintf(stderr, "`%s'	`%s'\n", np->name, np->def);
6329a34925cSclemc }
6339a34925cSclemc 
doerrp(ap,c)6349a34925cSclemc doerrp(ap, c)
6359a34925cSclemc char **ap;
6369a34925cSclemc {
6379a34925cSclemc 	if (c > 0) {
6389a34925cSclemc 		fprintf(stderr, ap[1], ap[2], ap[3], ap[4], ap[5], ap[6]);
6399a34925cSclemc 		fprintf(stderr, "\n");
6409a34925cSclemc 	}
6419a34925cSclemc }
6429a34925cSclemc 
6439a34925cSclemc 
6449a34925cSclemc long	evalval;	/* return value from yacc stuff */
6459a34925cSclemc char	*pe;	/* used by grammar */
6469a34925cSclemc 
doeval(ap,c)6479a34925cSclemc doeval(ap, c)
6489a34925cSclemc char **ap;
6499a34925cSclemc {
6509a34925cSclemc 
6519a34925cSclemc 	if (c > 0) {
6529a34925cSclemc 		pe = ap[1];
6539a34925cSclemc 		if (yyparse() == 0)
6549a34925cSclemc 			putnum(evalval);
6559a34925cSclemc 		else
6569a34925cSclemc 			fprintf(stderr, "m4: invalid expression in eval: %s\n", ap[1]);
6579a34925cSclemc 	}
6589a34925cSclemc }
6599a34925cSclemc 
doincl(ap,c,noisy)6609a34925cSclemc doincl(ap, c, noisy)
6619a34925cSclemc char **ap;
6629a34925cSclemc {
6639a34925cSclemc 	if (c > 0 && strlen(ap[1]) > 0) {
6649a34925cSclemc 		infptr++;
6659a34925cSclemc 		ip_stk[infptr] = cur_ip = ip;
6669a34925cSclemc 		if ((infile[infptr] = fopen(ap[1], READ))==ERROR) {
6679a34925cSclemc 			if (noisy) {
6689a34925cSclemc 				fprintf(stderr, "m4: file not found: %s\n", ap[1]);
6699a34925cSclemc 				delexit();
6709a34925cSclemc 			}
6719a34925cSclemc 			else
6729a34925cSclemc 				infptr--;
6739a34925cSclemc 		}
6749a34925cSclemc 	}
6759a34925cSclemc }
6769a34925cSclemc 
dosyscmd(ap,c)6779a34925cSclemc dosyscmd(ap, c)
6789a34925cSclemc char **ap;
6799a34925cSclemc {
6809a34925cSclemc 	if (c > 0)
6819a34925cSclemc 		system(ap[1]);
6829a34925cSclemc }
6839a34925cSclemc 
domake(ap,c)6849a34925cSclemc domake(ap, c)
6859a34925cSclemc char **ap;
6869a34925cSclemc {
6879a34925cSclemc 	if (c > 0)
6889a34925cSclemc 		pbstr(mktemp(ap[1]));
6899a34925cSclemc }
6909a34925cSclemc 
doincr(ap,c)6919a34925cSclemc doincr(ap, c)
6929a34925cSclemc char **ap;
6939a34925cSclemc {
6949a34925cSclemc 	if (c >= 1)
6959a34925cSclemc 		putnum(ctol(ap[1])+1);
6969a34925cSclemc }
6979a34925cSclemc 
putnum(num)6989a34925cSclemc putnum(num)
6999a34925cSclemc long num;
7009a34925cSclemc {
7019a34925cSclemc 	register sign;
7029a34925cSclemc 
7039a34925cSclemc 	sign = (num < 0) ? '-' : '\0';
7049a34925cSclemc 	if (num < 0)
7059a34925cSclemc 		num = -num;
7069a34925cSclemc 	do {
7079a34925cSclemc 		putbak(num%10+'0');
7089a34925cSclemc 		num = num/10;
7099a34925cSclemc 	} while (num!=0);
7109a34925cSclemc 	if (sign == '-')
7119a34925cSclemc 		putbak('-');
7129a34925cSclemc }
7139a34925cSclemc 
dosubstr(ap,c)7149a34925cSclemc dosubstr(ap, c)
7159a34925cSclemc char **ap;
7169a34925cSclemc {
7179a34925cSclemc 	int nc;
7189a34925cSclemc 	register char *sp, *fc;
7199a34925cSclemc 
7209a34925cSclemc 	if (c<2)
7219a34925cSclemc 		return;
7229a34925cSclemc 	if (c<3)
7239a34925cSclemc 		nc = TOKS;
7249a34925cSclemc 	else
7259a34925cSclemc 		nc = ctoi(ap[3]);
7269a34925cSclemc 	fc = ap[1] + max(0, min(ctoi(ap[2]), strlen(ap[1])));
7279a34925cSclemc 	sp = fc + min(nc, strlen(fc));
7289a34925cSclemc 	while (sp > fc)
7299a34925cSclemc 		putbak(*--sp);
7309a34925cSclemc }
7319a34925cSclemc 
doindex(ap,c)7329a34925cSclemc doindex(ap, c)
7339a34925cSclemc char **ap;
7349a34925cSclemc {
7359a34925cSclemc 	if (c >= 2)
7369a34925cSclemc 		putnum((long) strindex(ap[1], ap[2]));
7379a34925cSclemc }
7389a34925cSclemc 
strindex(p1,p2)7399a34925cSclemc strindex(p1, p2)
7409a34925cSclemc char *p1, *p2;
7419a34925cSclemc {
7429a34925cSclemc 	register m;
7439a34925cSclemc 	register char *s, *t, *p;
7449a34925cSclemc 
7459a34925cSclemc 	for (p=p1; *p; p++) {
7469a34925cSclemc 		s = p;
7479a34925cSclemc 		m = 1;
7489a34925cSclemc 		for (t=p2; *t; )
7499a34925cSclemc 			if (*t++ != *s++)
7509a34925cSclemc 				m = 0;
7519a34925cSclemc 		if (m == 1)
7529a34925cSclemc 			return(p-p1);
7539a34925cSclemc 	}
7549a34925cSclemc 	return(-1);
7559a34925cSclemc }
7569a34925cSclemc 
dotransl(ap,c)7579a34925cSclemc dotransl(ap, c)
7589a34925cSclemc char **ap;
7599a34925cSclemc {
7609a34925cSclemc 	register char *s, *fr, *to;
7619a34925cSclemc 
7629a34925cSclemc 	if (c <= 1) return;
7639a34925cSclemc 
7649a34925cSclemc 	if (c == 2) {
7659a34925cSclemc 		register int i;
7669a34925cSclemc 		to = ap[1];
7679a34925cSclemc 		for (s = ap[1]; *s; s++) {
7689a34925cSclemc 			i = 0;
7699a34925cSclemc 			for (fr = ap[2]; *fr; fr++)
7709a34925cSclemc 				if (*s == *fr) {
7719a34925cSclemc 					i++;
7729a34925cSclemc 					break;
7739a34925cSclemc 				}
7749a34925cSclemc 			if (i == 0)
7759a34925cSclemc 				*to++ = *s;
7769a34925cSclemc 		}
7779a34925cSclemc 		*to = '\0';
7789a34925cSclemc 	}
7799a34925cSclemc 
7809a34925cSclemc 	if (c >= 3) {
7819a34925cSclemc 		for (s = ap[1]; *s; s++)
7829a34925cSclemc 			for (fr = ap[2], to = ap[3]; *fr && *to; fr++, to++)
7839a34925cSclemc 				if (*s == *fr)
7849a34925cSclemc 					*s = *to;
7859a34925cSclemc 	}
7869a34925cSclemc 
7879a34925cSclemc 	pbstr(ap[1]);
7889a34925cSclemc }
7899a34925cSclemc 
doif(ap,c)7909a34925cSclemc doif(ap, c)
7919a34925cSclemc register char **ap;
7929a34925cSclemc {
7939a34925cSclemc 	if (c < 3)
7949a34925cSclemc 		return;
7959a34925cSclemc 	while (c >= 3) {
7969a34925cSclemc 		if (strcmp(ap[1], ap[2]) == 0) {
7979a34925cSclemc 			pbstr(ap[3]);
7989a34925cSclemc 			return;
7999a34925cSclemc 		}
8009a34925cSclemc 		c -= 3;
8019a34925cSclemc 		ap += 3;
8029a34925cSclemc 	}
8039a34925cSclemc 	if (c > 0)
8049a34925cSclemc 		pbstr(ap[1]);
8059a34925cSclemc }
8069a34925cSclemc 
dodiv(ap,c)8079a34925cSclemc dodiv(ap, c)
8089a34925cSclemc register char **ap;
8099a34925cSclemc {
8109a34925cSclemc 	register int f;
8119a34925cSclemc 
8129a34925cSclemc 	if (c<1)
8139a34925cSclemc 		f = 0;
8149a34925cSclemc 	else
8159a34925cSclemc 		f = ctoi(ap[1]);
8169a34925cSclemc 	if (f>=10 || f<0) {
8179a34925cSclemc 		curfile = NULL;
8189a34925cSclemc 		return;
8199a34925cSclemc 	}
8209a34925cSclemc 	tempname[7] = 'a' + f;
8219a34925cSclemc 	if (olist[f] || (olist[f]=fopen(tempname, WRITE))) {
8229a34925cSclemc 		curout = f;
8239a34925cSclemc 		curfile = olist[f];
8249a34925cSclemc 	}
8259a34925cSclemc }
8269a34925cSclemc 
doundiv(ap,c)8279a34925cSclemc doundiv(ap, c)
8289a34925cSclemc char **ap;
8299a34925cSclemc {
8309a34925cSclemc 	register FILE *fp;
8319a34925cSclemc 	register int i, ch;
8329a34925cSclemc 	int j;
8339a34925cSclemc 
8349a34925cSclemc 	if (c == 0) {
8359a34925cSclemc 		for (i=1; i<10; i++) {
8369a34925cSclemc 			if (i==curout || olist[i]==NULL)
8379a34925cSclemc 				continue;
8389a34925cSclemc 			fclose(olist[i]);
8399a34925cSclemc 			tempname[7] = 'a'+i;
8409a34925cSclemc 			fp = fopen(tempname, READ);
8419a34925cSclemc 			if (curfile != NULL)
8429a34925cSclemc 				while ((ch = getc(fp)) > 0)
8439a34925cSclemc 					putc(ch, curfile);
8449a34925cSclemc 			fclose(fp);
8459a34925cSclemc 			unlink(tempname);
8469a34925cSclemc 			olist[i] = NULL;
8479a34925cSclemc 		}
8489a34925cSclemc 
8499a34925cSclemc 	}
8509a34925cSclemc 	else {
8519a34925cSclemc 		for (j = 1; j <= c; j++) {
8529a34925cSclemc 			i = ctoi(*++ap);
8539a34925cSclemc 			if (i<1 || i>9 || i==curout || olist[i]==NULL)
8549a34925cSclemc 				continue;
8559a34925cSclemc 			fclose(olist[i]);
8569a34925cSclemc 			tempname[7] = 'a'+i;
8579a34925cSclemc 			fp = fopen(tempname, READ);
8589a34925cSclemc 			if (curfile != NULL)
8599a34925cSclemc 				while ((ch = getc(fp)) > 0)
8609a34925cSclemc 					putc(ch, curfile);
8619a34925cSclemc 			fclose(fp);
8629a34925cSclemc 			unlink(tempname);
8639a34925cSclemc 			olist[i] = NULL;
8649a34925cSclemc 		}
8659a34925cSclemc 	}
8669a34925cSclemc }
8679a34925cSclemc 
dodivnum(ap,c)8689a34925cSclemc dodivnum(ap, c)
8699a34925cSclemc char **ap;
8709a34925cSclemc {
8719a34925cSclemc 	putnum((long) curout);
8729a34925cSclemc }
8739a34925cSclemc 
dodnl(ap,c)8749a34925cSclemc dodnl(ap, c)
8759a34925cSclemc char **ap;
8769a34925cSclemc {
8779a34925cSclemc 	register t;
8789a34925cSclemc 
8799a34925cSclemc 	while ((t=getchr())!='\n' && t>=0)
8809a34925cSclemc 		;
8819a34925cSclemc }
8829a34925cSclemc 
ctol(str)8839a34925cSclemc long ctol(str)
8849a34925cSclemc register char *str;
8859a34925cSclemc {
8869a34925cSclemc 	register sign;
8879a34925cSclemc 	long num;
8889a34925cSclemc 
8899a34925cSclemc 	while (*str==' ' || *str=='\t' || *str=='\n')
8909a34925cSclemc 		str++;
8919a34925cSclemc 	num = 0;
8929a34925cSclemc 	if (*str == '-') {
8939a34925cSclemc 		sign = -1;
8949a34925cSclemc 		str++;
8959a34925cSclemc 	}
8969a34925cSclemc 	else
8979a34925cSclemc 		sign = 1;
8989a34925cSclemc 	while (*str>='0' && *str<='9')
8999a34925cSclemc 		num = num*10 + *str++ - '0';
9009a34925cSclemc 	return(sign * num);
9019a34925cSclemc }
9029a34925cSclemc 
ctoi(s)9039a34925cSclemc ctoi(s)
9049a34925cSclemc char *s;
9059a34925cSclemc {
9069a34925cSclemc 	return(ctol(s));
9079a34925cSclemc }
9089a34925cSclemc 
min(a,b)9099a34925cSclemc min(a, b)
9109a34925cSclemc {
9119a34925cSclemc 	if (a>b)
9129a34925cSclemc 		return(b);
9139a34925cSclemc 	return(a);
9149a34925cSclemc }
9159a34925cSclemc 
max(a,b)9169a34925cSclemc max(a, b)
9179a34925cSclemc {
9189a34925cSclemc 	if (a>b)
9199a34925cSclemc 		return(a);
9209a34925cSclemc 	return(b);
9219a34925cSclemc }
922