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