xref: /original-bsd/usr.bin/m4/eval.c (revision b043d314)
143d6cbb6Sbostic /*
2494f5ecfSbostic  * Copyright (c) 1989, 1993
3494f5ecfSbostic  *	The Regents of the University of California.  All rights reserved.
443d6cbb6Sbostic  *
543d6cbb6Sbostic  * This code is derived from software contributed to Berkeley by
6a435ab37Sbostic  * Ozan Yigit at York University.
743d6cbb6Sbostic  *
8799620b5Sbostic  * %sccs.include.redist.c%
943d6cbb6Sbostic  */
1043d6cbb6Sbostic 
1143d6cbb6Sbostic #ifndef lint
12*b043d314Sbostic static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 04/27/95";
1343d6cbb6Sbostic #endif /* not lint */
1443d6cbb6Sbostic 
1543d6cbb6Sbostic /*
1643d6cbb6Sbostic  * eval.c
1743d6cbb6Sbostic  * Facility: m4 macro processor
1843d6cbb6Sbostic  * by: oz
1943d6cbb6Sbostic  */
2043d6cbb6Sbostic 
21d3eef09bSbostic #include <sys/types.h>
22d3eef09bSbostic #include <errno.h>
23935903d7Sbostic #include <unistd.h>
24935903d7Sbostic #include <stdio.h>
25935903d7Sbostic #include <stdlib.h>
26935903d7Sbostic #include <string.h>
2743d6cbb6Sbostic #include "mdef.h"
28d3eef09bSbostic #include "stdd.h"
29d3eef09bSbostic #include "extern.h"
30d3eef09bSbostic #include "pathnames.h"
3143d6cbb6Sbostic 
3243d6cbb6Sbostic /*
3343d6cbb6Sbostic  * eval - evaluate built-in macros.
3443d6cbb6Sbostic  *	  argc - number of elements in argv.
3543d6cbb6Sbostic  *	  argv - element vector :
3643d6cbb6Sbostic  *			argv[0] = definition of a user
3743d6cbb6Sbostic  *				  macro or nil if built-in.
3843d6cbb6Sbostic  *			argv[1] = name of the macro or
3943d6cbb6Sbostic  *				  built-in.
4043d6cbb6Sbostic  *			argv[2] = parameters to user-defined
4143d6cbb6Sbostic  *			   .	  macro or built-in.
4243d6cbb6Sbostic  *			   .
4343d6cbb6Sbostic  *
4443d6cbb6Sbostic  * Note that the minimum value for argc is 3. A call in the form
4543d6cbb6Sbostic  * of macro-or-builtin() will result in:
4643d6cbb6Sbostic  *			argv[0] = nullstr
4743d6cbb6Sbostic  *			argv[1] = macro-or-builtin
4843d6cbb6Sbostic  *			argv[2] = nullstr
4943d6cbb6Sbostic  */
5043d6cbb6Sbostic 
51d3eef09bSbostic void
eval(argv,argc,td)5243d6cbb6Sbostic eval(argv, argc, td)
5343d6cbb6Sbostic register char *argv[];
5443d6cbb6Sbostic register int argc;
5543d6cbb6Sbostic register int td;
5643d6cbb6Sbostic {
5743d6cbb6Sbostic 	register int c, n;
58d3eef09bSbostic 	static int sysval = 0;
5943d6cbb6Sbostic 
6043d6cbb6Sbostic #ifdef DEBUG
6143d6cbb6Sbostic 	printf("argc = %d\n", argc);
6243d6cbb6Sbostic 	for (n = 0; n < argc; n++)
6343d6cbb6Sbostic 		printf("argv[%d] = %s\n", n, argv[n]);
6443d6cbb6Sbostic #endif
6543d6cbb6Sbostic  /*
66d3eef09bSbostic   * if argc == 3 and argv[2] is null, then we
67d3eef09bSbostic   * have macro-or-builtin() type call. We adjust
68d3eef09bSbostic   * argc to avoid further checking..
6943d6cbb6Sbostic   */
7043d6cbb6Sbostic 	if (argc == 3 && !*(argv[2]))
7143d6cbb6Sbostic 		argc--;
7243d6cbb6Sbostic 
7343d6cbb6Sbostic 	switch (td & ~STATIC) {
7443d6cbb6Sbostic 
7543d6cbb6Sbostic 	case DEFITYPE:
7643d6cbb6Sbostic 		if (argc > 2)
7743d6cbb6Sbostic 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
7843d6cbb6Sbostic 		break;
7943d6cbb6Sbostic 
8043d6cbb6Sbostic 	case PUSDTYPE:
8143d6cbb6Sbostic 		if (argc > 2)
8243d6cbb6Sbostic 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
8343d6cbb6Sbostic 		break;
8443d6cbb6Sbostic 
8543d6cbb6Sbostic 	case DUMPTYPE:
8643d6cbb6Sbostic 		dodump(argv, argc);
8743d6cbb6Sbostic 		break;
8843d6cbb6Sbostic 
8943d6cbb6Sbostic 	case EXPRTYPE:
9043d6cbb6Sbostic 	/*
91d3eef09bSbostic 	 * doexpr - evaluate arithmetic
92d3eef09bSbostic 	 * expression
9343d6cbb6Sbostic 	 */
9443d6cbb6Sbostic 		if (argc > 2)
9543d6cbb6Sbostic 			pbnum(expr(argv[2]));
9643d6cbb6Sbostic 		break;
9743d6cbb6Sbostic 
9843d6cbb6Sbostic 	case IFELTYPE:
9943d6cbb6Sbostic 		if (argc > 4)
10043d6cbb6Sbostic 			doifelse(argv, argc);
10143d6cbb6Sbostic 		break;
10243d6cbb6Sbostic 
10343d6cbb6Sbostic 	case IFDFTYPE:
10443d6cbb6Sbostic 	/*
105d3eef09bSbostic 	 * doifdef - select one of two
106d3eef09bSbostic 	 * alternatives based on the existence of
107d3eef09bSbostic 	 * another definition
10843d6cbb6Sbostic 	 */
10943d6cbb6Sbostic 		if (argc > 3) {
11043d6cbb6Sbostic 			if (lookup(argv[2]) != nil)
11143d6cbb6Sbostic 				pbstr(argv[3]);
11243d6cbb6Sbostic 			else if (argc > 4)
11343d6cbb6Sbostic 				pbstr(argv[4]);
11443d6cbb6Sbostic 		}
11543d6cbb6Sbostic 		break;
11643d6cbb6Sbostic 
11743d6cbb6Sbostic 	case LENGTYPE:
11843d6cbb6Sbostic 	/*
119d3eef09bSbostic 	 * dolen - find the length of the
120d3eef09bSbostic 	 * argument
12143d6cbb6Sbostic 	 */
12243d6cbb6Sbostic 		if (argc > 2)
12343d6cbb6Sbostic 			pbnum((argc > 2) ? strlen(argv[2]) : 0);
12443d6cbb6Sbostic 		break;
12543d6cbb6Sbostic 
12643d6cbb6Sbostic 	case INCRTYPE:
12743d6cbb6Sbostic 	/*
128d3eef09bSbostic 	 * doincr - increment the value of the
129d3eef09bSbostic 	 * argument
13043d6cbb6Sbostic 	 */
13143d6cbb6Sbostic 		if (argc > 2)
13243d6cbb6Sbostic 			pbnum(atoi(argv[2]) + 1);
13343d6cbb6Sbostic 		break;
13443d6cbb6Sbostic 
13543d6cbb6Sbostic 	case DECRTYPE:
13643d6cbb6Sbostic 	/*
137d3eef09bSbostic 	 * dodecr - decrement the value of the
138d3eef09bSbostic 	 * argument
13943d6cbb6Sbostic 	 */
14043d6cbb6Sbostic 		if (argc > 2)
14143d6cbb6Sbostic 			pbnum(atoi(argv[2]) - 1);
14243d6cbb6Sbostic 		break;
14343d6cbb6Sbostic 
14443d6cbb6Sbostic 	case SYSCTYPE:
14543d6cbb6Sbostic 	/*
14643d6cbb6Sbostic 	 * dosys - execute system command
14743d6cbb6Sbostic 	 */
14843d6cbb6Sbostic 		if (argc > 2)
14943d6cbb6Sbostic 			sysval = system(argv[2]);
15043d6cbb6Sbostic 		break;
15143d6cbb6Sbostic 
15243d6cbb6Sbostic 	case SYSVTYPE:
15343d6cbb6Sbostic 	/*
154d3eef09bSbostic 	 * dosysval - return value of the last
155d3eef09bSbostic 	 * system call.
15643d6cbb6Sbostic 	 *
15743d6cbb6Sbostic 	 */
15843d6cbb6Sbostic 		pbnum(sysval);
15943d6cbb6Sbostic 		break;
16043d6cbb6Sbostic 
16143d6cbb6Sbostic 	case INCLTYPE:
16243d6cbb6Sbostic 		if (argc > 2)
163d3eef09bSbostic 			if (!doincl(argv[2]))
164d3eef09bSbostic 				oops("%s: %s", argv[2], strerror(errno));
16543d6cbb6Sbostic 		break;
16643d6cbb6Sbostic 
16743d6cbb6Sbostic 	case SINCTYPE:
16843d6cbb6Sbostic 		if (argc > 2)
16943d6cbb6Sbostic 			(void) doincl(argv[2]);
17043d6cbb6Sbostic 		break;
17143d6cbb6Sbostic #ifdef EXTENDED
17243d6cbb6Sbostic 	case PASTTYPE:
17343d6cbb6Sbostic 		if (argc > 2)
174d3eef09bSbostic 			if (!dopaste(argv[2]))
175d3eef09bSbostic 				oops("%s: %s", argv[2], strerror(errno));
17643d6cbb6Sbostic 		break;
17743d6cbb6Sbostic 
17843d6cbb6Sbostic 	case SPASTYPE:
17943d6cbb6Sbostic 		if (argc > 2)
18043d6cbb6Sbostic 			(void) dopaste(argv[2]);
18143d6cbb6Sbostic 		break;
18243d6cbb6Sbostic #endif
18343d6cbb6Sbostic 	case CHNQTYPE:
18443d6cbb6Sbostic 		dochq(argv, argc);
18543d6cbb6Sbostic 		break;
18643d6cbb6Sbostic 
18743d6cbb6Sbostic 	case CHNCTYPE:
18843d6cbb6Sbostic 		dochc(argv, argc);
18943d6cbb6Sbostic 		break;
19043d6cbb6Sbostic 
19143d6cbb6Sbostic 	case SUBSTYPE:
19243d6cbb6Sbostic 	/*
19343d6cbb6Sbostic 	 * dosub - select substring
19443d6cbb6Sbostic 	 *
19543d6cbb6Sbostic 	 */
19643d6cbb6Sbostic 		if (argc > 3)
19743d6cbb6Sbostic 			dosub(argv, argc);
19843d6cbb6Sbostic 		break;
19943d6cbb6Sbostic 
20043d6cbb6Sbostic 	case SHIFTYPE:
20143d6cbb6Sbostic 	/*
202d3eef09bSbostic 	 * doshift - push back all arguments
203d3eef09bSbostic 	 * except the first one (i.e. skip
204d3eef09bSbostic 	 * argv[2])
20543d6cbb6Sbostic 	 */
20643d6cbb6Sbostic 		if (argc > 3) {
20743d6cbb6Sbostic 			for (n = argc - 1; n > 3; n--) {
20843d6cbb6Sbostic 				putback(rquote);
20943d6cbb6Sbostic 				pbstr(argv[n]);
21043d6cbb6Sbostic 				putback(lquote);
21143d6cbb6Sbostic 				putback(',');
21243d6cbb6Sbostic 			}
21343d6cbb6Sbostic 			putback(rquote);
21443d6cbb6Sbostic 			pbstr(argv[3]);
21543d6cbb6Sbostic 			putback(lquote);
21643d6cbb6Sbostic 		}
21743d6cbb6Sbostic 		break;
21843d6cbb6Sbostic 
21943d6cbb6Sbostic 	case DIVRTYPE:
22043d6cbb6Sbostic 		if (argc > 2 && (n = atoi(argv[2])) != 0)
22143d6cbb6Sbostic 			dodiv(n);
22243d6cbb6Sbostic 		else {
22343d6cbb6Sbostic 			active = stdout;
22443d6cbb6Sbostic 			oindex = 0;
22543d6cbb6Sbostic 		}
22643d6cbb6Sbostic 		break;
22743d6cbb6Sbostic 
22843d6cbb6Sbostic 	case UNDVTYPE:
22943d6cbb6Sbostic 		doundiv(argv, argc);
23043d6cbb6Sbostic 		break;
23143d6cbb6Sbostic 
23243d6cbb6Sbostic 	case DIVNTYPE:
23343d6cbb6Sbostic 	/*
234d3eef09bSbostic 	 * dodivnum - return the number of
235d3eef09bSbostic 	 * current output diversion
23643d6cbb6Sbostic 	 */
23743d6cbb6Sbostic 		pbnum(oindex);
23843d6cbb6Sbostic 		break;
23943d6cbb6Sbostic 
24043d6cbb6Sbostic 	case UNDFTYPE:
24143d6cbb6Sbostic 	/*
242d3eef09bSbostic 	 * doundefine - undefine a previously
243d3eef09bSbostic 	 * defined macro(s) or m4 keyword(s).
24443d6cbb6Sbostic 	 */
24543d6cbb6Sbostic 		if (argc > 2)
24643d6cbb6Sbostic 			for (n = 2; n < argc; n++)
24743d6cbb6Sbostic 				remhash(argv[n], ALL);
24843d6cbb6Sbostic 		break;
24943d6cbb6Sbostic 
25043d6cbb6Sbostic 	case POPDTYPE:
25143d6cbb6Sbostic 	/*
252d3eef09bSbostic 	 * dopopdef - remove the topmost
253d3eef09bSbostic 	 * definitions of macro(s) or m4
254d3eef09bSbostic 	 * keyword(s).
25543d6cbb6Sbostic 	 */
25643d6cbb6Sbostic 		if (argc > 2)
25743d6cbb6Sbostic 			for (n = 2; n < argc; n++)
25843d6cbb6Sbostic 				remhash(argv[n], TOP);
25943d6cbb6Sbostic 		break;
26043d6cbb6Sbostic 
26143d6cbb6Sbostic 	case MKTMTYPE:
26243d6cbb6Sbostic 	/*
26343d6cbb6Sbostic 	 * dotemp - create a temporary file
26443d6cbb6Sbostic 	 */
26543d6cbb6Sbostic 		if (argc > 2)
26643d6cbb6Sbostic 			pbstr(mktemp(argv[2]));
26743d6cbb6Sbostic 		break;
26843d6cbb6Sbostic 
26943d6cbb6Sbostic 	case TRNLTYPE:
27043d6cbb6Sbostic 	/*
271d3eef09bSbostic 	 * dotranslit - replace all characters in
272d3eef09bSbostic 	 * the source string that appears in the
273d3eef09bSbostic 	 * "from" string with the corresponding
27443d6cbb6Sbostic 	 * characters in the "to" string.
27543d6cbb6Sbostic 	 */
27643d6cbb6Sbostic 		if (argc > 3) {
27743d6cbb6Sbostic 			char temp[MAXTOK];
27843d6cbb6Sbostic 			if (argc > 4)
27943d6cbb6Sbostic 				map(temp, argv[2], argv[3], argv[4]);
28043d6cbb6Sbostic 			else
28143d6cbb6Sbostic 				map(temp, argv[2], argv[3], null);
28243d6cbb6Sbostic 			pbstr(temp);
28343d6cbb6Sbostic 		}
284d3eef09bSbostic 		else if (argc > 2)
28543d6cbb6Sbostic 			pbstr(argv[2]);
28643d6cbb6Sbostic 		break;
28743d6cbb6Sbostic 
28843d6cbb6Sbostic 	case INDXTYPE:
28943d6cbb6Sbostic 	/*
290d3eef09bSbostic 	 * doindex - find the index of the second
291d3eef09bSbostic 	 * argument string in the first argument
292d3eef09bSbostic 	 * string. -1 if not present.
29343d6cbb6Sbostic 	 */
29443d6cbb6Sbostic 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
29543d6cbb6Sbostic 		break;
29643d6cbb6Sbostic 
29743d6cbb6Sbostic 	case ERRPTYPE:
29843d6cbb6Sbostic 	/*
299d3eef09bSbostic 	 * doerrp - print the arguments to stderr
300d3eef09bSbostic 	 * file
30143d6cbb6Sbostic 	 */
30243d6cbb6Sbostic 		if (argc > 2) {
30343d6cbb6Sbostic 			for (n = 2; n < argc; n++)
30443d6cbb6Sbostic 				fprintf(stderr, "%s ", argv[n]);
30543d6cbb6Sbostic 			fprintf(stderr, "\n");
30643d6cbb6Sbostic 		}
30743d6cbb6Sbostic 		break;
30843d6cbb6Sbostic 
30943d6cbb6Sbostic 	case DNLNTYPE:
31043d6cbb6Sbostic 	/*
311d3eef09bSbostic 	 * dodnl - eat-up-to and including
312d3eef09bSbostic 	 * newline
31343d6cbb6Sbostic 	 */
31443d6cbb6Sbostic 		while ((c = gpbc()) != '\n' && c != EOF)
31543d6cbb6Sbostic 			;
31643d6cbb6Sbostic 		break;
31743d6cbb6Sbostic 
31843d6cbb6Sbostic 	case M4WRTYPE:
31943d6cbb6Sbostic 	/*
320d3eef09bSbostic 	 * dom4wrap - set up for
321d3eef09bSbostic 	 * wrap-up/wind-down activity
32243d6cbb6Sbostic 	 */
323d3eef09bSbostic 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
32443d6cbb6Sbostic 		break;
32543d6cbb6Sbostic 
32643d6cbb6Sbostic 	case EXITTYPE:
32743d6cbb6Sbostic 	/*
32843d6cbb6Sbostic 	 * doexit - immediate exit from m4.
32943d6cbb6Sbostic 	 */
330*b043d314Sbostic 		killdiv();
33143d6cbb6Sbostic 		exit((argc > 2) ? atoi(argv[2]) : 0);
33243d6cbb6Sbostic 		break;
33343d6cbb6Sbostic 
33443d6cbb6Sbostic 	case DEFNTYPE:
33543d6cbb6Sbostic 		if (argc > 2)
33643d6cbb6Sbostic 			for (n = 2; n < argc; n++)
33743d6cbb6Sbostic 				dodefn(argv[n]);
33843d6cbb6Sbostic 		break;
33943d6cbb6Sbostic 
34043d6cbb6Sbostic 	default:
341d3eef09bSbostic 		oops("%s: major botch.", "eval");
34243d6cbb6Sbostic 		break;
34343d6cbb6Sbostic 	}
34443d6cbb6Sbostic }
345d3eef09bSbostic 
346d3eef09bSbostic char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
347d3eef09bSbostic 
348d3eef09bSbostic /*
349d3eef09bSbostic  * expand - user-defined macro expansion
350d3eef09bSbostic  */
351d3eef09bSbostic void
expand(argv,argc)352d3eef09bSbostic expand(argv, argc)
353d3eef09bSbostic register char *argv[];
354d3eef09bSbostic register int argc;
355d3eef09bSbostic {
356d3eef09bSbostic 	register char *t;
357d3eef09bSbostic 	register char *p;
358d3eef09bSbostic 	register int n;
359d3eef09bSbostic 	register int argno;
360d3eef09bSbostic 
361d3eef09bSbostic 	t = argv[0];		       /* defn string as a whole */
362d3eef09bSbostic 	p = t;
363d3eef09bSbostic 	while (*p)
364d3eef09bSbostic 		p++;
365d3eef09bSbostic 	p--;			       /* last character of defn */
366d3eef09bSbostic 	while (p > t) {
367d3eef09bSbostic 		if (*(p - 1) != ARGFLAG)
368d3eef09bSbostic 			putback(*p);
369d3eef09bSbostic 		else {
370d3eef09bSbostic 			switch (*p) {
371d3eef09bSbostic 
372d3eef09bSbostic 			case '#':
373d3eef09bSbostic 				pbnum(argc - 2);
374d3eef09bSbostic 				break;
375d3eef09bSbostic 			case '0':
376d3eef09bSbostic 			case '1':
377d3eef09bSbostic 			case '2':
378d3eef09bSbostic 			case '3':
379d3eef09bSbostic 			case '4':
380d3eef09bSbostic 			case '5':
381d3eef09bSbostic 			case '6':
382d3eef09bSbostic 			case '7':
383d3eef09bSbostic 			case '8':
384d3eef09bSbostic 			case '9':
385d3eef09bSbostic 				if ((argno = *p - '0') < argc - 1)
386d3eef09bSbostic 					pbstr(argv[argno + 1]);
387d3eef09bSbostic 				break;
388d3eef09bSbostic 			case '*':
389d3eef09bSbostic 				for (n = argc - 1; n > 2; n--) {
390d3eef09bSbostic 					pbstr(argv[n]);
391d3eef09bSbostic 					putback(',');
392d3eef09bSbostic 				}
393d3eef09bSbostic 				pbstr(argv[2]);
394d3eef09bSbostic 				break;
395d3eef09bSbostic 			default:
396d3eef09bSbostic 				putback(*p);
3978a657776Sbostic 				putback('$');
398d3eef09bSbostic 				break;
399d3eef09bSbostic 			}
400d3eef09bSbostic 			p--;
401d3eef09bSbostic 		}
402d3eef09bSbostic 		p--;
403d3eef09bSbostic 	}
404d3eef09bSbostic 	if (p == t)		       /* do last character */
405d3eef09bSbostic 		putback(*p);
406d3eef09bSbostic }
407d3eef09bSbostic 
408d3eef09bSbostic /*
409d3eef09bSbostic  * dodefine - install definition in the table
410d3eef09bSbostic  */
411d3eef09bSbostic void
dodefine(name,defn)412d3eef09bSbostic dodefine(name, defn)
413d3eef09bSbostic register char *name;
414d3eef09bSbostic register char *defn;
415d3eef09bSbostic {
416d3eef09bSbostic 	register ndptr p;
417d3eef09bSbostic 
418d3eef09bSbostic 	if (!*name)
419d3eef09bSbostic 		oops("null definition.");
420d3eef09bSbostic 	if (STREQ(name, defn))
421d3eef09bSbostic 		oops("%s: recursive definition.", name);
422d3eef09bSbostic 	if ((p = lookup(name)) == nil)
423d3eef09bSbostic 		p = addent(name);
424d3eef09bSbostic 	else if (p->defn != null)
425d3eef09bSbostic 		free((char *) p->defn);
426d3eef09bSbostic 	if (!*defn)
427d3eef09bSbostic 		p->defn = null;
428d3eef09bSbostic 	else
429d3eef09bSbostic 		p->defn = xstrdup(defn);
430d3eef09bSbostic 	p->type = MACRTYPE;
431d3eef09bSbostic }
432d3eef09bSbostic 
433d3eef09bSbostic /*
434d3eef09bSbostic  * dodefn - push back a quoted definition of
435d3eef09bSbostic  *      the given name.
436d3eef09bSbostic  */
437d3eef09bSbostic void
dodefn(name)438d3eef09bSbostic dodefn(name)
439d3eef09bSbostic char *name;
440d3eef09bSbostic {
441d3eef09bSbostic 	register ndptr p;
442d3eef09bSbostic 
443d3eef09bSbostic 	if ((p = lookup(name)) != nil && p->defn != null) {
444d3eef09bSbostic 		putback(rquote);
445d3eef09bSbostic 		pbstr(p->defn);
446d3eef09bSbostic 		putback(lquote);
447d3eef09bSbostic 	}
448d3eef09bSbostic }
449d3eef09bSbostic 
450d3eef09bSbostic /*
451d3eef09bSbostic  * dopushdef - install a definition in the hash table
452d3eef09bSbostic  *      without removing a previous definition. Since
453d3eef09bSbostic  *      each new entry is entered in *front* of the
454d3eef09bSbostic  *      hash bucket, it hides a previous definition from
455d3eef09bSbostic  *      lookup.
456d3eef09bSbostic  */
457d3eef09bSbostic void
dopushdef(name,defn)458d3eef09bSbostic dopushdef(name, defn)
459d3eef09bSbostic register char *name;
460d3eef09bSbostic register char *defn;
461d3eef09bSbostic {
462d3eef09bSbostic 	register ndptr p;
463d3eef09bSbostic 
464d3eef09bSbostic 	if (!*name)
465d3eef09bSbostic 		oops("null definition");
466d3eef09bSbostic 	if (STREQ(name, defn))
467d3eef09bSbostic 		oops("%s: recursive definition.", name);
468d3eef09bSbostic 	p = addent(name);
469d3eef09bSbostic 	if (!*defn)
470d3eef09bSbostic 		p->defn = null;
471d3eef09bSbostic 	else
472d3eef09bSbostic 		p->defn = xstrdup(defn);
473d3eef09bSbostic 	p->type = MACRTYPE;
474d3eef09bSbostic }
475d3eef09bSbostic 
476d3eef09bSbostic /*
477d3eef09bSbostic  * dodumpdef - dump the specified definitions in the hash
478d3eef09bSbostic  *      table to stderr. If nothing is specified, the entire
479d3eef09bSbostic  *      hash table is dumped.
480d3eef09bSbostic  */
481d3eef09bSbostic void
dodump(argv,argc)482d3eef09bSbostic dodump(argv, argc)
483d3eef09bSbostic register char *argv[];
484d3eef09bSbostic register int argc;
485d3eef09bSbostic {
486d3eef09bSbostic 	register int n;
487d3eef09bSbostic 	ndptr p;
488d3eef09bSbostic 
489d3eef09bSbostic 	if (argc > 2) {
490d3eef09bSbostic 		for (n = 2; n < argc; n++)
491d3eef09bSbostic 			if ((p = lookup(argv[n])) != nil)
492d3eef09bSbostic 				fprintf(stderr, dumpfmt, p->name,
493d3eef09bSbostic 					p->defn);
494d3eef09bSbostic 	}
495d3eef09bSbostic 	else {
496d3eef09bSbostic 		for (n = 0; n < HASHSIZE; n++)
497d3eef09bSbostic 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
498d3eef09bSbostic 				fprintf(stderr, dumpfmt, p->name,
499d3eef09bSbostic 					p->defn);
500d3eef09bSbostic 	}
501d3eef09bSbostic }
502d3eef09bSbostic 
503d3eef09bSbostic /*
504d3eef09bSbostic  * doifelse - select one of two alternatives - loop.
505d3eef09bSbostic  */
506d3eef09bSbostic void
doifelse(argv,argc)507d3eef09bSbostic doifelse(argv, argc)
508d3eef09bSbostic register char *argv[];
509d3eef09bSbostic register int argc;
510d3eef09bSbostic {
511d3eef09bSbostic 	cycle {
512d3eef09bSbostic 		if (STREQ(argv[2], argv[3]))
513d3eef09bSbostic 			pbstr(argv[4]);
514d3eef09bSbostic 		else if (argc == 6)
515d3eef09bSbostic 			pbstr(argv[5]);
516d3eef09bSbostic 		else if (argc > 6) {
517d3eef09bSbostic 			argv += 3;
518d3eef09bSbostic 			argc -= 3;
519d3eef09bSbostic 			continue;
520d3eef09bSbostic 		}
521d3eef09bSbostic 		break;
522d3eef09bSbostic 	}
523d3eef09bSbostic }
524d3eef09bSbostic 
525d3eef09bSbostic /*
526d3eef09bSbostic  * doinclude - include a given file.
527d3eef09bSbostic  */
528d3eef09bSbostic int
doincl(ifile)529d3eef09bSbostic doincl(ifile)
530d3eef09bSbostic char *ifile;
531d3eef09bSbostic {
532d3eef09bSbostic 	if (ilevel + 1 == MAXINP)
533d3eef09bSbostic 		oops("too many include files.");
534d3eef09bSbostic 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
535d3eef09bSbostic 		ilevel++;
536c22b2b5fSeric 		bbase[ilevel] = bufbase = bp;
537d3eef09bSbostic 		return (1);
538d3eef09bSbostic 	}
539d3eef09bSbostic 	else
540d3eef09bSbostic 		return (0);
541d3eef09bSbostic }
542d3eef09bSbostic 
543d3eef09bSbostic #ifdef EXTENDED
544d3eef09bSbostic /*
545d3eef09bSbostic  * dopaste - include a given file without any
546d3eef09bSbostic  *           macro processing.
547d3eef09bSbostic  */
548d3eef09bSbostic int
dopaste(pfile)549d3eef09bSbostic dopaste(pfile)
550d3eef09bSbostic char *pfile;
551d3eef09bSbostic {
552d3eef09bSbostic 	FILE *pf;
553d3eef09bSbostic 	register int c;
554d3eef09bSbostic 
555d3eef09bSbostic 	if ((pf = fopen(pfile, "r")) != NULL) {
556d3eef09bSbostic 		while ((c = getc(pf)) != EOF)
557d3eef09bSbostic 			putc(c, active);
558d3eef09bSbostic 		(void) fclose(pf);
559d3eef09bSbostic 		return (1);
560d3eef09bSbostic 	}
561d3eef09bSbostic 	else
562d3eef09bSbostic 		return (0);
563d3eef09bSbostic }
564d3eef09bSbostic #endif
565d3eef09bSbostic 
566d3eef09bSbostic /*
567d3eef09bSbostic  * dochq - change quote characters
568d3eef09bSbostic  */
569d3eef09bSbostic void
dochq(argv,argc)570d3eef09bSbostic dochq(argv, argc)
571d3eef09bSbostic register char *argv[];
572d3eef09bSbostic register int argc;
573d3eef09bSbostic {
574d3eef09bSbostic 	if (argc > 2) {
575d3eef09bSbostic 		if (*argv[2])
576d3eef09bSbostic 			lquote = *argv[2];
577d3eef09bSbostic 		if (argc > 3) {
578d3eef09bSbostic 			if (*argv[3])
579d3eef09bSbostic 				rquote = *argv[3];
580d3eef09bSbostic 		}
581d3eef09bSbostic 		else
582d3eef09bSbostic 			rquote = lquote;
583d3eef09bSbostic 	}
584d3eef09bSbostic 	else {
585d3eef09bSbostic 		lquote = LQUOTE;
586d3eef09bSbostic 		rquote = RQUOTE;
587d3eef09bSbostic 	}
588d3eef09bSbostic }
589d3eef09bSbostic 
590d3eef09bSbostic /*
591d3eef09bSbostic  * dochc - change comment characters
592d3eef09bSbostic  */
593d3eef09bSbostic void
dochc(argv,argc)594d3eef09bSbostic dochc(argv, argc)
595d3eef09bSbostic register char *argv[];
596d3eef09bSbostic register int argc;
597d3eef09bSbostic {
598d3eef09bSbostic 	if (argc > 2) {
599d3eef09bSbostic 		if (*argv[2])
600d3eef09bSbostic 			scommt = *argv[2];
601d3eef09bSbostic 		if (argc > 3) {
602d3eef09bSbostic 			if (*argv[3])
603d3eef09bSbostic 				ecommt = *argv[3];
604d3eef09bSbostic 		}
605d3eef09bSbostic 		else
606d3eef09bSbostic 			ecommt = ECOMMT;
607d3eef09bSbostic 	}
608d3eef09bSbostic 	else {
609d3eef09bSbostic 		scommt = SCOMMT;
610d3eef09bSbostic 		ecommt = ECOMMT;
611d3eef09bSbostic 	}
612d3eef09bSbostic }
613d3eef09bSbostic 
614d3eef09bSbostic /*
615d3eef09bSbostic  * dodivert - divert the output to a temporary file
616d3eef09bSbostic  */
617d3eef09bSbostic void
dodiv(n)618d3eef09bSbostic dodiv(n)
619d3eef09bSbostic register int n;
620d3eef09bSbostic {
621d3eef09bSbostic 	if (n < 0 || n >= MAXOUT)
622d3eef09bSbostic 		n = 0;		       /* bitbucket */
623d3eef09bSbostic 	if (outfile[n] == NULL) {
624d3eef09bSbostic 		m4temp[UNIQUE] = n + '0';
625d3eef09bSbostic 		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
626d3eef09bSbostic 			oops("%s: cannot divert.", m4temp);
627d3eef09bSbostic 	}
628d3eef09bSbostic 	oindex = n;
629d3eef09bSbostic 	active = outfile[n];
630d3eef09bSbostic }
631d3eef09bSbostic 
632d3eef09bSbostic /*
633d3eef09bSbostic  * doundivert - undivert a specified output, or all
634d3eef09bSbostic  *              other outputs, in numerical order.
635d3eef09bSbostic  */
636d3eef09bSbostic void
doundiv(argv,argc)637d3eef09bSbostic doundiv(argv, argc)
638d3eef09bSbostic register char *argv[];
639d3eef09bSbostic register int argc;
640d3eef09bSbostic {
641d3eef09bSbostic 	register int ind;
642d3eef09bSbostic 	register int n;
643d3eef09bSbostic 
644d3eef09bSbostic 	if (argc > 2) {
645d3eef09bSbostic 		for (ind = 2; ind < argc; ind++) {
646d3eef09bSbostic 			n = atoi(argv[ind]);
647d3eef09bSbostic 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
648d3eef09bSbostic 				getdiv(n);
649d3eef09bSbostic 
650d3eef09bSbostic 		}
651d3eef09bSbostic 	}
652d3eef09bSbostic 	else
653d3eef09bSbostic 		for (n = 1; n < MAXOUT; n++)
654d3eef09bSbostic 			if (outfile[n] != NULL)
655d3eef09bSbostic 				getdiv(n);
656d3eef09bSbostic }
657d3eef09bSbostic 
658d3eef09bSbostic /*
659d3eef09bSbostic  * dosub - select substring
660d3eef09bSbostic  */
661d3eef09bSbostic void
dosub(argv,argc)662d3eef09bSbostic dosub(argv, argc)
663d3eef09bSbostic register char *argv[];
664d3eef09bSbostic register int argc;
665d3eef09bSbostic {
666d3eef09bSbostic 	register char *ap, *fc, *k;
667d3eef09bSbostic 	register int nc;
668d3eef09bSbostic 
669d3eef09bSbostic 	if (argc < 5)
670d3eef09bSbostic 		nc = MAXTOK;
671d3eef09bSbostic 	else
672d3eef09bSbostic #ifdef EXPR
673d3eef09bSbostic 		nc = expr(argv[4]);
674d3eef09bSbostic #else
675d3eef09bSbostic 		nc = atoi(argv[4]);
676d3eef09bSbostic #endif
677d3eef09bSbostic 	ap = argv[2];		       /* target string */
678d3eef09bSbostic #ifdef EXPR
679d3eef09bSbostic 	fc = ap + expr(argv[3]);       /* first char */
680d3eef09bSbostic #else
681d3eef09bSbostic 	fc = ap + atoi(argv[3]);       /* first char */
682d3eef09bSbostic #endif
683d3eef09bSbostic 	if (fc >= ap && fc < ap + strlen(ap))
684d3eef09bSbostic 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
685d3eef09bSbostic 			putback(*k);
686d3eef09bSbostic }
687d3eef09bSbostic 
688d3eef09bSbostic /*
689d3eef09bSbostic  * map:
690d3eef09bSbostic  * map every character of s1 that is specified in from
691d3eef09bSbostic  * into s3 and replace in s. (source s1 remains untouched)
692d3eef09bSbostic  *
693d3eef09bSbostic  * This is a standard implementation of map(s,from,to) function of ICON
694d3eef09bSbostic  * language. Within mapvec, we replace every character of "from" with
695d3eef09bSbostic  * the corresponding character in "to". If "to" is shorter than "from",
696d3eef09bSbostic  * than the corresponding entries are null, which means that those
697d3eef09bSbostic  * characters dissapear altogether. Furthermore, imagine
698d3eef09bSbostic  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
699d3eef09bSbostic  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
700d3eef09bSbostic  * ultimately maps to `*'. In order to achieve this effect in an efficient
701d3eef09bSbostic  * manner (i.e. without multiple passes over the destination string), we
702d3eef09bSbostic  * loop over mapvec, starting with the initial source character. if the
703d3eef09bSbostic  * character value (dch) in this location is different than the source
704d3eef09bSbostic  * character (sch), sch becomes dch, once again to index into mapvec, until
705d3eef09bSbostic  * the character value stabilizes (i.e. sch = dch, in other words
706d3eef09bSbostic  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
707d3eef09bSbostic  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
708d3eef09bSbostic  * end, we restore mapvec* back to normal where mapvec[n] == n for
709d3eef09bSbostic  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
710d3eef09bSbostic  * about 5 times faster than any algorithm that makes multiple passes over
711d3eef09bSbostic  * destination string.
712d3eef09bSbostic  */
713d3eef09bSbostic void
map(dest,src,from,to)714d3eef09bSbostic map(dest, src, from, to)
715d3eef09bSbostic register char *dest;
716d3eef09bSbostic register char *src;
717d3eef09bSbostic register char *from;
718d3eef09bSbostic register char *to;
719d3eef09bSbostic {
720d3eef09bSbostic 	register char *tmp;
721d3eef09bSbostic 	register char sch, dch;
722d3eef09bSbostic 	static char mapvec[128] = {
723d3eef09bSbostic 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
724d3eef09bSbostic 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
725d3eef09bSbostic 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
726d3eef09bSbostic 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
727d3eef09bSbostic 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
728d3eef09bSbostic 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
729d3eef09bSbostic 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
730d3eef09bSbostic 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
731d3eef09bSbostic 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
732d3eef09bSbostic 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
733d3eef09bSbostic 		120, 121, 122, 123, 124, 125, 126, 127
734d3eef09bSbostic 	};
735d3eef09bSbostic 
736d3eef09bSbostic 	if (*src) {
737d3eef09bSbostic 		tmp = from;
738d3eef09bSbostic 	/*
739d3eef09bSbostic 	 * create a mapping between "from" and
740d3eef09bSbostic 	 * "to"
741d3eef09bSbostic 	 */
742d3eef09bSbostic 		while (*from)
743d3eef09bSbostic 			mapvec[*from++] = (*to) ? *to++ : (char) 0;
744d3eef09bSbostic 
745d3eef09bSbostic 		while (*src) {
746d3eef09bSbostic 			sch = *src++;
747d3eef09bSbostic 			dch = mapvec[sch];
748d3eef09bSbostic 			while (dch != sch) {
749d3eef09bSbostic 				sch = dch;
750d3eef09bSbostic 				dch = mapvec[sch];
751d3eef09bSbostic 			}
752d3eef09bSbostic 			if (*dest = dch)
753d3eef09bSbostic 				dest++;
754d3eef09bSbostic 		}
755d3eef09bSbostic 	/*
756d3eef09bSbostic 	 * restore all the changed characters
757d3eef09bSbostic 	 */
758d3eef09bSbostic 		while (*tmp) {
759d3eef09bSbostic 			mapvec[*tmp] = *tmp;
760d3eef09bSbostic 			tmp++;
761d3eef09bSbostic 		}
762d3eef09bSbostic 	}
763d3eef09bSbostic 	*dest = (char) 0;
764d3eef09bSbostic }
765