eval.c revision 24901
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Ozan Yigit at York University.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 3. All advertising materials mentioning features or use of this software
171590Srgrimes *    must display the following acknowledgement:
181590Srgrimes *	This product includes software developed by the University of
191590Srgrimes *	California, Berkeley and its contributors.
201590Srgrimes * 4. Neither the name of the University nor the names of its contributors
211590Srgrimes *    may be used to endorse or promote products derived from this software
221590Srgrimes *    without specific prior written permission.
231590Srgrimes *
241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341590Srgrimes * SUCH DAMAGE.
351590Srgrimes */
361590Srgrimes
371590Srgrimes#ifndef lint
381590Srgrimesstatic char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 6/6/93";
391590Srgrimes#endif /* not lint */
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * eval.c
431590Srgrimes * Facility: m4 macro processor
441590Srgrimes * by: oz
451590Srgrimes */
461590Srgrimes
471590Srgrimes#include <sys/types.h>
481590Srgrimes#include <errno.h>
491590Srgrimes#include <unistd.h>
501590Srgrimes#include <stdio.h>
511590Srgrimes#include <stdlib.h>
521590Srgrimes#include <string.h>
531590Srgrimes#include "mdef.h"
541590Srgrimes#include "stdd.h"
551590Srgrimes#include "extern.h"
561590Srgrimes#include "pathnames.h"
571590Srgrimes
581590Srgrimes/*
591590Srgrimes * eval - evaluate built-in macros.
601590Srgrimes *	  argc - number of elements in argv.
611590Srgrimes *	  argv - element vector :
621590Srgrimes *			argv[0] = definition of a user
631590Srgrimes *				  macro or nil if built-in.
641590Srgrimes *			argv[1] = name of the macro or
651590Srgrimes *				  built-in.
661590Srgrimes *			argv[2] = parameters to user-defined
671590Srgrimes *			   .	  macro or built-in.
681590Srgrimes *			   .
691590Srgrimes *
701590Srgrimes * Note that the minimum value for argc is 3. A call in the form
711590Srgrimes * of macro-or-builtin() will result in:
721590Srgrimes *			argv[0] = nullstr
731590Srgrimes *			argv[1] = macro-or-builtin
741590Srgrimes *			argv[2] = nullstr
751590Srgrimes */
761590Srgrimes
771590Srgrimesvoid
781590Srgrimeseval(argv, argc, td)
791590Srgrimesregister char *argv[];
801590Srgrimesregister int argc;
811590Srgrimesregister int td;
821590Srgrimes{
831590Srgrimes	register int c, n;
841590Srgrimes	static int sysval = 0;
851590Srgrimes
861590Srgrimes#ifdef DEBUG
871590Srgrimes	printf("argc = %d\n", argc);
881590Srgrimes	for (n = 0; n < argc; n++)
891590Srgrimes		printf("argv[%d] = %s\n", n, argv[n]);
901590Srgrimes#endif
911590Srgrimes /*
921590Srgrimes  * if argc == 3 and argv[2] is null, then we
931590Srgrimes  * have macro-or-builtin() type call. We adjust
941590Srgrimes  * argc to avoid further checking..
951590Srgrimes  */
961590Srgrimes	if (argc == 3 && !*(argv[2]))
971590Srgrimes		argc--;
981590Srgrimes
991590Srgrimes	switch (td & ~STATIC) {
1001590Srgrimes
1011590Srgrimes	case DEFITYPE:
1021590Srgrimes		if (argc > 2)
1031590Srgrimes			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1041590Srgrimes		break;
1051590Srgrimes
1061590Srgrimes	case PUSDTYPE:
1071590Srgrimes		if (argc > 2)
1081590Srgrimes			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1091590Srgrimes		break;
1101590Srgrimes
1111590Srgrimes	case DUMPTYPE:
1121590Srgrimes		dodump(argv, argc);
1131590Srgrimes		break;
1141590Srgrimes
1151590Srgrimes	case EXPRTYPE:
1161590Srgrimes	/*
1171590Srgrimes	 * doexpr - evaluate arithmetic
1181590Srgrimes	 * expression
1191590Srgrimes	 */
1201590Srgrimes		if (argc > 2)
1211590Srgrimes			pbnum(expr(argv[2]));
1221590Srgrimes		break;
1231590Srgrimes
1241590Srgrimes	case IFELTYPE:
1251590Srgrimes		if (argc > 4)
1261590Srgrimes			doifelse(argv, argc);
1271590Srgrimes		break;
1281590Srgrimes
1291590Srgrimes	case IFDFTYPE:
1301590Srgrimes	/*
1311590Srgrimes	 * doifdef - select one of two
1321590Srgrimes	 * alternatives based on the existence of
1331590Srgrimes	 * another definition
1341590Srgrimes	 */
1351590Srgrimes		if (argc > 3) {
1361590Srgrimes			if (lookup(argv[2]) != nil)
1371590Srgrimes				pbstr(argv[3]);
1381590Srgrimes			else if (argc > 4)
1391590Srgrimes				pbstr(argv[4]);
1401590Srgrimes		}
1411590Srgrimes		break;
1421590Srgrimes
1431590Srgrimes	case LENGTYPE:
1441590Srgrimes	/*
1451590Srgrimes	 * dolen - find the length of the
1461590Srgrimes	 * argument
1471590Srgrimes	 */
1481590Srgrimes		if (argc > 2)
1491590Srgrimes			pbnum((argc > 2) ? strlen(argv[2]) : 0);
1501590Srgrimes		break;
1511590Srgrimes
1521590Srgrimes	case INCRTYPE:
1531590Srgrimes	/*
1541590Srgrimes	 * doincr - increment the value of the
1551590Srgrimes	 * argument
1561590Srgrimes	 */
1571590Srgrimes		if (argc > 2)
1581590Srgrimes			pbnum(atoi(argv[2]) + 1);
1591590Srgrimes		break;
1601590Srgrimes
1611590Srgrimes	case DECRTYPE:
1621590Srgrimes	/*
1631590Srgrimes	 * dodecr - decrement the value of the
1641590Srgrimes	 * argument
1651590Srgrimes	 */
1661590Srgrimes		if (argc > 2)
1671590Srgrimes			pbnum(atoi(argv[2]) - 1);
1681590Srgrimes		break;
1691590Srgrimes
1701590Srgrimes	case SYSCTYPE:
1711590Srgrimes	/*
1721590Srgrimes	 * dosys - execute system command
1738874Srgrimes	 */
1748874Srgrimes		/* Make sure m4 output is NOT interrupted */
1758874Srgrimes		fflush(stdout);
1767004Sache		fflush(stderr);
1771590Srgrimes		if (argc > 2)
1781590Srgrimes			sysval = system(argv[2]);
1791590Srgrimes		break;
1801590Srgrimes
1811590Srgrimes	case SYSVTYPE:
1821590Srgrimes	/*
1831590Srgrimes	 * dosysval - return value of the last
1841590Srgrimes	 * system call.
1858874Srgrimes	 *
1861590Srgrimes	 */
1871590Srgrimes		pbnum(sysval);
1881590Srgrimes		break;
1891590Srgrimes
1901590Srgrimes	case INCLTYPE:
1911590Srgrimes		if (argc > 2)
1921590Srgrimes			if (!doincl(argv[2]))
1931590Srgrimes				oops("%s: %s", argv[2], strerror(errno));
1941590Srgrimes		break;
1951590Srgrimes
1961590Srgrimes	case SINCTYPE:
1971590Srgrimes		if (argc > 2)
1981590Srgrimes			(void) doincl(argv[2]);
1991590Srgrimes		break;
2001590Srgrimes#ifdef EXTENDED
2011590Srgrimes	case PASTTYPE:
2021590Srgrimes		if (argc > 2)
2031590Srgrimes			if (!dopaste(argv[2]))
2041590Srgrimes				oops("%s: %s", argv[2], strerror(errno));
2051590Srgrimes		break;
2061590Srgrimes
2071590Srgrimes	case SPASTYPE:
2081590Srgrimes		if (argc > 2)
2091590Srgrimes			(void) dopaste(argv[2]);
2101590Srgrimes		break;
2111590Srgrimes#endif
2121590Srgrimes	case CHNQTYPE:
2131590Srgrimes		dochq(argv, argc);
2141590Srgrimes		break;
2151590Srgrimes
2161590Srgrimes	case CHNCTYPE:
2171590Srgrimes		dochc(argv, argc);
2181590Srgrimes		break;
2191590Srgrimes
2201590Srgrimes	case SUBSTYPE:
2211590Srgrimes	/*
2221590Srgrimes	 * dosub - select substring
2238874Srgrimes	 *
2241590Srgrimes	 */
2251590Srgrimes		if (argc > 3)
2261590Srgrimes			dosub(argv, argc);
2271590Srgrimes		break;
2281590Srgrimes
2291590Srgrimes	case SHIFTYPE:
2301590Srgrimes	/*
2311590Srgrimes	 * doshift - push back all arguments
2321590Srgrimes	 * except the first one (i.e. skip
2331590Srgrimes	 * argv[2])
2341590Srgrimes	 */
2351590Srgrimes		if (argc > 3) {
2361590Srgrimes			for (n = argc - 1; n > 3; n--) {
2371590Srgrimes				putback(rquote);
2381590Srgrimes				pbstr(argv[n]);
2391590Srgrimes				putback(lquote);
2401590Srgrimes				putback(',');
2411590Srgrimes			}
2421590Srgrimes			putback(rquote);
2431590Srgrimes			pbstr(argv[3]);
2441590Srgrimes			putback(lquote);
2451590Srgrimes		}
2461590Srgrimes		break;
2471590Srgrimes
2481590Srgrimes	case DIVRTYPE:
2491590Srgrimes		if (argc > 2 && (n = atoi(argv[2])) != 0)
2501590Srgrimes			dodiv(n);
2511590Srgrimes		else {
2521590Srgrimes			active = stdout;
2531590Srgrimes			oindex = 0;
2541590Srgrimes		}
2551590Srgrimes		break;
2561590Srgrimes
2571590Srgrimes	case UNDVTYPE:
2581590Srgrimes		doundiv(argv, argc);
2591590Srgrimes		break;
2601590Srgrimes
2611590Srgrimes	case DIVNTYPE:
2621590Srgrimes	/*
2631590Srgrimes	 * dodivnum - return the number of
2641590Srgrimes	 * current output diversion
2651590Srgrimes	 */
2661590Srgrimes		pbnum(oindex);
2671590Srgrimes		break;
2681590Srgrimes
2691590Srgrimes	case UNDFTYPE:
2701590Srgrimes	/*
2711590Srgrimes	 * doundefine - undefine a previously
2721590Srgrimes	 * defined macro(s) or m4 keyword(s).
2731590Srgrimes	 */
2741590Srgrimes		if (argc > 2)
2751590Srgrimes			for (n = 2; n < argc; n++)
2761590Srgrimes				remhash(argv[n], ALL);
2771590Srgrimes		break;
2781590Srgrimes
2791590Srgrimes	case POPDTYPE:
2801590Srgrimes	/*
2811590Srgrimes	 * dopopdef - remove the topmost
2821590Srgrimes	 * definitions of macro(s) or m4
2831590Srgrimes	 * keyword(s).
2841590Srgrimes	 */
2851590Srgrimes		if (argc > 2)
2861590Srgrimes			for (n = 2; n < argc; n++)
2871590Srgrimes				remhash(argv[n], TOP);
2881590Srgrimes		break;
2891590Srgrimes
2901590Srgrimes	case MKTMTYPE:
2911590Srgrimes	/*
2921590Srgrimes	 * dotemp - create a temporary file
2931590Srgrimes	 */
2941590Srgrimes		if (argc > 2)
2951590Srgrimes			pbstr(mktemp(argv[2]));
2961590Srgrimes		break;
2971590Srgrimes
2981590Srgrimes	case TRNLTYPE:
2991590Srgrimes	/*
3001590Srgrimes	 * dotranslit - replace all characters in
3011590Srgrimes	 * the source string that appears in the
3021590Srgrimes	 * "from" string with the corresponding
3031590Srgrimes	 * characters in the "to" string.
3041590Srgrimes	 */
3051590Srgrimes		if (argc > 3) {
3061590Srgrimes			char temp[MAXTOK];
3071590Srgrimes			if (argc > 4)
3081590Srgrimes				map(temp, argv[2], argv[3], argv[4]);
3091590Srgrimes			else
3101590Srgrimes				map(temp, argv[2], argv[3], null);
3111590Srgrimes			pbstr(temp);
3121590Srgrimes		}
3131590Srgrimes		else if (argc > 2)
3141590Srgrimes			pbstr(argv[2]);
3151590Srgrimes		break;
3161590Srgrimes
3171590Srgrimes	case INDXTYPE:
3181590Srgrimes	/*
3191590Srgrimes	 * doindex - find the index of the second
3201590Srgrimes	 * argument string in the first argument
3211590Srgrimes	 * string. -1 if not present.
3221590Srgrimes	 */
3231590Srgrimes		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
3241590Srgrimes		break;
3251590Srgrimes
3261590Srgrimes	case ERRPTYPE:
3271590Srgrimes	/*
3281590Srgrimes	 * doerrp - print the arguments to stderr
3291590Srgrimes	 * file
3301590Srgrimes	 */
3311590Srgrimes		if (argc > 2) {
3321590Srgrimes			for (n = 2; n < argc; n++)
3331590Srgrimes				fprintf(stderr, "%s ", argv[n]);
3341590Srgrimes			fprintf(stderr, "\n");
3351590Srgrimes		}
3361590Srgrimes		break;
3371590Srgrimes
3381590Srgrimes	case DNLNTYPE:
3391590Srgrimes	/*
3401590Srgrimes	 * dodnl - eat-up-to and including
3411590Srgrimes	 * newline
3421590Srgrimes	 */
3431590Srgrimes		while ((c = gpbc()) != '\n' && c != EOF)
3441590Srgrimes			;
3451590Srgrimes		break;
3461590Srgrimes
3471590Srgrimes	case M4WRTYPE:
3481590Srgrimes	/*
3491590Srgrimes	 * dom4wrap - set up for
3501590Srgrimes	 * wrap-up/wind-down activity
3511590Srgrimes	 */
3521590Srgrimes		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
3531590Srgrimes		break;
3541590Srgrimes
3551590Srgrimes	case EXITTYPE:
3561590Srgrimes	/*
3571590Srgrimes	 * doexit - immediate exit from m4.
3581590Srgrimes	 */
3597896Sache		killdiv();
3601590Srgrimes		exit((argc > 2) ? atoi(argv[2]) : 0);
3611590Srgrimes		break;
3621590Srgrimes
3631590Srgrimes	case DEFNTYPE:
3641590Srgrimes		if (argc > 2)
3651590Srgrimes			for (n = 2; n < argc; n++)
3661590Srgrimes				dodefn(argv[n]);
3671590Srgrimes		break;
3681590Srgrimes
3691590Srgrimes	default:
3701590Srgrimes		oops("%s: major botch.", "eval");
3711590Srgrimes		break;
3721590Srgrimes	}
3731590Srgrimes}
3741590Srgrimes
3751590Srgrimeschar *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
3761590Srgrimes
3771590Srgrimes/*
3781590Srgrimes * expand - user-defined macro expansion
3791590Srgrimes */
3801590Srgrimesvoid
3811590Srgrimesexpand(argv, argc)
3821590Srgrimesregister char *argv[];
3831590Srgrimesregister int argc;
3841590Srgrimes{
3855165Sache	register unsigned char *t;
3865165Sache	register unsigned char *p;
3871590Srgrimes	register int n;
3881590Srgrimes	register int argno;
3891590Srgrimes
3901590Srgrimes	t = argv[0];		       /* defn string as a whole */
3911590Srgrimes	p = t;
3921590Srgrimes	while (*p)
3931590Srgrimes		p++;
3941590Srgrimes	p--;			       /* last character of defn */
3951590Srgrimes	while (p > t) {
3961590Srgrimes		if (*(p - 1) != ARGFLAG)
3971590Srgrimes			putback(*p);
3981590Srgrimes		else {
3991590Srgrimes			switch (*p) {
4001590Srgrimes
4011590Srgrimes			case '#':
4021590Srgrimes				pbnum(argc - 2);
4031590Srgrimes				break;
4041590Srgrimes			case '0':
4051590Srgrimes			case '1':
4061590Srgrimes			case '2':
4071590Srgrimes			case '3':
4081590Srgrimes			case '4':
4091590Srgrimes			case '5':
4101590Srgrimes			case '6':
4111590Srgrimes			case '7':
4121590Srgrimes			case '8':
4131590Srgrimes			case '9':
4141590Srgrimes				if ((argno = *p - '0') < argc - 1)
4151590Srgrimes					pbstr(argv[argno + 1]);
4161590Srgrimes				break;
4171590Srgrimes			case '*':
4181590Srgrimes				for (n = argc - 1; n > 2; n--) {
4191590Srgrimes					pbstr(argv[n]);
4201590Srgrimes					putback(',');
4211590Srgrimes				}
4221590Srgrimes				pbstr(argv[2]);
4231590Srgrimes				break;
42424901Sjoerg			case '@':
42524901Sjoerg				for( n = argc - 1; n >= 2; n-- )
42624901Sjoerg				{
42724901Sjoerg					putback(rquote);
42824901Sjoerg					pbstr(argv[n]);
42924901Sjoerg					putback(lquote);
43024901Sjoerg					if( n > 2 )
43124901Sjoerg						putback(',');
43224901Sjoerg				}
43324901Sjoerg				break;
4341590Srgrimes			default:
4351590Srgrimes				putback(*p);
4361590Srgrimes				putback('$');
4371590Srgrimes				break;
4381590Srgrimes			}
4391590Srgrimes			p--;
4401590Srgrimes		}
4411590Srgrimes		p--;
4421590Srgrimes	}
4431590Srgrimes	if (p == t)		       /* do last character */
4441590Srgrimes		putback(*p);
4451590Srgrimes}
4461590Srgrimes
4471590Srgrimes/*
4481590Srgrimes * dodefine - install definition in the table
4491590Srgrimes */
4501590Srgrimesvoid
4511590Srgrimesdodefine(name, defn)
4521590Srgrimesregister char *name;
4531590Srgrimesregister char *defn;
4541590Srgrimes{
4551590Srgrimes	register ndptr p;
4561590Srgrimes
4571590Srgrimes	if (!*name)
4581590Srgrimes		oops("null definition.");
4591590Srgrimes	if (STREQ(name, defn))
4601590Srgrimes		oops("%s: recursive definition.", name);
4611590Srgrimes	if ((p = lookup(name)) == nil)
4621590Srgrimes		p = addent(name);
4631590Srgrimes	else if (p->defn != null)
4641590Srgrimes		free((char *) p->defn);
4651590Srgrimes	if (!*defn)
4661590Srgrimes		p->defn = null;
4671590Srgrimes	else
4681590Srgrimes		p->defn = xstrdup(defn);
4691590Srgrimes	p->type = MACRTYPE;
4701590Srgrimes}
4711590Srgrimes
4721590Srgrimes/*
4731590Srgrimes * dodefn - push back a quoted definition of
4741590Srgrimes *      the given name.
4751590Srgrimes */
4761590Srgrimesvoid
4771590Srgrimesdodefn(name)
4781590Srgrimeschar *name;
4791590Srgrimes{
4801590Srgrimes	register ndptr p;
4811590Srgrimes
4821590Srgrimes	if ((p = lookup(name)) != nil && p->defn != null) {
4831590Srgrimes		putback(rquote);
4841590Srgrimes		pbstr(p->defn);
4851590Srgrimes		putback(lquote);
4861590Srgrimes	}
4871590Srgrimes}
4881590Srgrimes
4891590Srgrimes/*
4901590Srgrimes * dopushdef - install a definition in the hash table
4911590Srgrimes *      without removing a previous definition. Since
4921590Srgrimes *      each new entry is entered in *front* of the
4931590Srgrimes *      hash bucket, it hides a previous definition from
4941590Srgrimes *      lookup.
4951590Srgrimes */
4961590Srgrimesvoid
4971590Srgrimesdopushdef(name, defn)
4981590Srgrimesregister char *name;
4991590Srgrimesregister char *defn;
5001590Srgrimes{
5011590Srgrimes	register ndptr p;
5021590Srgrimes
5031590Srgrimes	if (!*name)
5041590Srgrimes		oops("null definition");
5051590Srgrimes	if (STREQ(name, defn))
5061590Srgrimes		oops("%s: recursive definition.", name);
5071590Srgrimes	p = addent(name);
5081590Srgrimes	if (!*defn)
5091590Srgrimes		p->defn = null;
5101590Srgrimes	else
5111590Srgrimes		p->defn = xstrdup(defn);
5121590Srgrimes	p->type = MACRTYPE;
5131590Srgrimes}
5141590Srgrimes
5151590Srgrimes/*
5161590Srgrimes * dodumpdef - dump the specified definitions in the hash
5171590Srgrimes *      table to stderr. If nothing is specified, the entire
5181590Srgrimes *      hash table is dumped.
5191590Srgrimes */
5201590Srgrimesvoid
5211590Srgrimesdodump(argv, argc)
5221590Srgrimesregister char *argv[];
5231590Srgrimesregister int argc;
5241590Srgrimes{
5251590Srgrimes	register int n;
5261590Srgrimes	ndptr p;
5271590Srgrimes
5281590Srgrimes	if (argc > 2) {
5291590Srgrimes		for (n = 2; n < argc; n++)
5301590Srgrimes			if ((p = lookup(argv[n])) != nil)
5311590Srgrimes				fprintf(stderr, dumpfmt, p->name,
5321590Srgrimes					p->defn);
5331590Srgrimes	}
5341590Srgrimes	else {
5351590Srgrimes		for (n = 0; n < HASHSIZE; n++)
5361590Srgrimes			for (p = hashtab[n]; p != nil; p = p->nxtptr)
5371590Srgrimes				fprintf(stderr, dumpfmt, p->name,
5381590Srgrimes					p->defn);
5391590Srgrimes	}
5401590Srgrimes}
5411590Srgrimes
5421590Srgrimes/*
5431590Srgrimes * doifelse - select one of two alternatives - loop.
5441590Srgrimes */
5451590Srgrimesvoid
5461590Srgrimesdoifelse(argv, argc)
5471590Srgrimesregister char *argv[];
5481590Srgrimesregister int argc;
5491590Srgrimes{
5501590Srgrimes	cycle {
5511590Srgrimes		if (STREQ(argv[2], argv[3]))
5521590Srgrimes			pbstr(argv[4]);
5531590Srgrimes		else if (argc == 6)
5541590Srgrimes			pbstr(argv[5]);
5551590Srgrimes		else if (argc > 6) {
5561590Srgrimes			argv += 3;
5571590Srgrimes			argc -= 3;
5581590Srgrimes			continue;
5591590Srgrimes		}
5601590Srgrimes		break;
5611590Srgrimes	}
5621590Srgrimes}
5631590Srgrimes
5641590Srgrimes/*
5651590Srgrimes * doinclude - include a given file.
5661590Srgrimes */
5671590Srgrimesint
5681590Srgrimesdoincl(ifile)
5691590Srgrimeschar *ifile;
5701590Srgrimes{
5711590Srgrimes	if (ilevel + 1 == MAXINP)
5721590Srgrimes		oops("too many include files.");
5731590Srgrimes	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
5741590Srgrimes		ilevel++;
5751590Srgrimes		bbase[ilevel] = bufbase = bp;
5761590Srgrimes		return (1);
5771590Srgrimes	}
5781590Srgrimes	else
5791590Srgrimes		return (0);
5801590Srgrimes}
5811590Srgrimes
5821590Srgrimes#ifdef EXTENDED
5831590Srgrimes/*
5841590Srgrimes * dopaste - include a given file without any
5851590Srgrimes *           macro processing.
5861590Srgrimes */
5871590Srgrimesint
5881590Srgrimesdopaste(pfile)
5891590Srgrimeschar *pfile;
5901590Srgrimes{
5911590Srgrimes	FILE *pf;
5921590Srgrimes	register int c;
5931590Srgrimes
5941590Srgrimes	if ((pf = fopen(pfile, "r")) != NULL) {
5951590Srgrimes		while ((c = getc(pf)) != EOF)
5961590Srgrimes			putc(c, active);
5971590Srgrimes		(void) fclose(pf);
5981590Srgrimes		return (1);
5991590Srgrimes	}
6001590Srgrimes	else
6011590Srgrimes		return (0);
6021590Srgrimes}
6031590Srgrimes#endif
6041590Srgrimes
6051590Srgrimes/*
6061590Srgrimes * dochq - change quote characters
6071590Srgrimes */
6081590Srgrimesvoid
6091590Srgrimesdochq(argv, argc)
6101590Srgrimesregister char *argv[];
6111590Srgrimesregister int argc;
6121590Srgrimes{
6131590Srgrimes	if (argc > 2) {
6141590Srgrimes		if (*argv[2])
6151590Srgrimes			lquote = *argv[2];
6161590Srgrimes		if (argc > 3) {
6171590Srgrimes			if (*argv[3])
6181590Srgrimes				rquote = *argv[3];
6191590Srgrimes		}
6201590Srgrimes		else
6211590Srgrimes			rquote = lquote;
6221590Srgrimes	}
6231590Srgrimes	else {
6241590Srgrimes		lquote = LQUOTE;
6251590Srgrimes		rquote = RQUOTE;
6261590Srgrimes	}
6271590Srgrimes}
6281590Srgrimes
6291590Srgrimes/*
6301590Srgrimes * dochc - change comment characters
6311590Srgrimes */
6321590Srgrimesvoid
6331590Srgrimesdochc(argv, argc)
6341590Srgrimesregister char *argv[];
6351590Srgrimesregister int argc;
6361590Srgrimes{
6371590Srgrimes	if (argc > 2) {
6381590Srgrimes		if (*argv[2])
6391590Srgrimes			scommt = *argv[2];
6401590Srgrimes		if (argc > 3) {
6411590Srgrimes			if (*argv[3])
6421590Srgrimes				ecommt = *argv[3];
6431590Srgrimes		}
6441590Srgrimes		else
6451590Srgrimes			ecommt = ECOMMT;
6461590Srgrimes	}
6471590Srgrimes	else {
6481590Srgrimes		scommt = SCOMMT;
6491590Srgrimes		ecommt = ECOMMT;
6501590Srgrimes	}
6511590Srgrimes}
6521590Srgrimes
6531590Srgrimes/*
6541590Srgrimes * dodivert - divert the output to a temporary file
6551590Srgrimes */
6561590Srgrimesvoid
6571590Srgrimesdodiv(n)
6581590Srgrimesregister int n;
6591590Srgrimes{
6601590Srgrimes	if (n < 0 || n >= MAXOUT)
6611590Srgrimes		n = 0;		       /* bitbucket */
6621590Srgrimes	if (outfile[n] == NULL) {
6631590Srgrimes		m4temp[UNIQUE] = n + '0';
6641590Srgrimes		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
6651590Srgrimes			oops("%s: cannot divert.", m4temp);
6661590Srgrimes	}
6671590Srgrimes	oindex = n;
6681590Srgrimes	active = outfile[n];
6691590Srgrimes}
6701590Srgrimes
6711590Srgrimes/*
6721590Srgrimes * doundivert - undivert a specified output, or all
6731590Srgrimes *              other outputs, in numerical order.
6741590Srgrimes */
6751590Srgrimesvoid
6761590Srgrimesdoundiv(argv, argc)
6771590Srgrimesregister char *argv[];
6781590Srgrimesregister int argc;
6791590Srgrimes{
6801590Srgrimes	register int ind;
6811590Srgrimes	register int n;
6821590Srgrimes
6831590Srgrimes	if (argc > 2) {
6841590Srgrimes		for (ind = 2; ind < argc; ind++) {
6851590Srgrimes			n = atoi(argv[ind]);
6861590Srgrimes			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
6871590Srgrimes				getdiv(n);
6881590Srgrimes
6891590Srgrimes		}
6901590Srgrimes	}
6911590Srgrimes	else
6921590Srgrimes		for (n = 1; n < MAXOUT; n++)
6931590Srgrimes			if (outfile[n] != NULL)
6941590Srgrimes				getdiv(n);
6951590Srgrimes}
6961590Srgrimes
6971590Srgrimes/*
6981590Srgrimes * dosub - select substring
6991590Srgrimes */
7001590Srgrimesvoid
7011590Srgrimesdosub(argv, argc)
7021590Srgrimesregister char *argv[];
7031590Srgrimesregister int argc;
7041590Srgrimes{
7055165Sache	register unsigned char *ap, *fc, *k;
7061590Srgrimes	register int nc;
7071590Srgrimes
7081590Srgrimes	if (argc < 5)
7091590Srgrimes		nc = MAXTOK;
7101590Srgrimes	else
7111590Srgrimes#ifdef EXPR
7121590Srgrimes		nc = expr(argv[4]);
7131590Srgrimes#else
7141590Srgrimes		nc = atoi(argv[4]);
7151590Srgrimes#endif
7161590Srgrimes	ap = argv[2];		       /* target string */
7171590Srgrimes#ifdef EXPR
7181590Srgrimes	fc = ap + expr(argv[3]);       /* first char */
7191590Srgrimes#else
7201590Srgrimes	fc = ap + atoi(argv[3]);       /* first char */
7211590Srgrimes#endif
7221590Srgrimes	if (fc >= ap && fc < ap + strlen(ap))
7231590Srgrimes		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
7241590Srgrimes			putback(*k);
7251590Srgrimes}
7261590Srgrimes
7271590Srgrimes/*
7281590Srgrimes * map:
7291590Srgrimes * map every character of s1 that is specified in from
7301590Srgrimes * into s3 and replace in s. (source s1 remains untouched)
7311590Srgrimes *
7321590Srgrimes * This is a standard implementation of map(s,from,to) function of ICON
7331590Srgrimes * language. Within mapvec, we replace every character of "from" with
7341590Srgrimes * the corresponding character in "to". If "to" is shorter than "from",
7351590Srgrimes * than the corresponding entries are null, which means that those
7361590Srgrimes * characters dissapear altogether. Furthermore, imagine
7371590Srgrimes * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
7381590Srgrimes * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
7391590Srgrimes * ultimately maps to `*'. In order to achieve this effect in an efficient
7401590Srgrimes * manner (i.e. without multiple passes over the destination string), we
7411590Srgrimes * loop over mapvec, starting with the initial source character. if the
7421590Srgrimes * character value (dch) in this location is different than the source
7431590Srgrimes * character (sch), sch becomes dch, once again to index into mapvec, until
7441590Srgrimes * the character value stabilizes (i.e. sch = dch, in other words
7451590Srgrimes * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
7461590Srgrimes * character, it will stabilize, since mapvec[0] == 0 at all times. At the
7471590Srgrimes * end, we restore mapvec* back to normal where mapvec[n] == n for
7481590Srgrimes * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
7491590Srgrimes * about 5 times faster than any algorithm that makes multiple passes over
7501590Srgrimes * destination string.
7511590Srgrimes */
7521590Srgrimesvoid
7531590Srgrimesmap(dest, src, from, to)
7541590Srgrimesregister char *dest;
7551590Srgrimesregister char *src;
7561590Srgrimesregister char *from;
7571590Srgrimesregister char *to;
7581590Srgrimes{
7591590Srgrimes	register char *tmp;
7601590Srgrimes	register char sch, dch;
7611590Srgrimes	static char mapvec[128] = {
7621590Srgrimes		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
7631590Srgrimes		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
7641590Srgrimes		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
7651590Srgrimes		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
7661590Srgrimes		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
7671590Srgrimes		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
7681590Srgrimes		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
7691590Srgrimes		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
7701590Srgrimes		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
7711590Srgrimes		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
7721590Srgrimes		120, 121, 122, 123, 124, 125, 126, 127
7731590Srgrimes	};
7741590Srgrimes
7751590Srgrimes	if (*src) {
7761590Srgrimes		tmp = from;
7771590Srgrimes	/*
7781590Srgrimes	 * create a mapping between "from" and
7791590Srgrimes	 * "to"
7801590Srgrimes	 */
7811590Srgrimes		while (*from)
7821590Srgrimes			mapvec[*from++] = (*to) ? *to++ : (char) 0;
7831590Srgrimes
7841590Srgrimes		while (*src) {
7851590Srgrimes			sch = *src++;
7861590Srgrimes			dch = mapvec[sch];
7871590Srgrimes			while (dch != sch) {
7881590Srgrimes				sch = dch;
7891590Srgrimes				dch = mapvec[sch];
7901590Srgrimes			}
7911590Srgrimes			if (*dest = dch)
7921590Srgrimes				dest++;
7931590Srgrimes		}
7941590Srgrimes	/*
7951590Srgrimes	 * restore all the changed characters
7961590Srgrimes	 */
7971590Srgrimes		while (*tmp) {
7981590Srgrimes			mapvec[*tmp] = *tmp;
7991590Srgrimes			tmp++;
8001590Srgrimes		}
8011590Srgrimes	}
8021590Srgrimes	*dest = (char) 0;
8031590Srgrimes}
804