xref: /freebsd/usr.bin/m4/eval.c (revision 232eaee62a8539a4b6c85c0d555ed14ba0f05fd2)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
69b50d902SRodney W. Grimes  * Ozan Yigit at York University.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes  * are met:
119b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
169b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
179b50d902SRodney W. Grimes  *    must display the following acknowledgement:
189b50d902SRodney W. Grimes  *	This product includes software developed by the University of
199b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
209b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
219b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
229b50d902SRodney W. Grimes  *    without specific prior written permission.
239b50d902SRodney W. Grimes  *
249b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
259b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
269b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
279b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
289b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
299b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
309b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
319b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
329b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
339b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
349b50d902SRodney W. Grimes  * SUCH DAMAGE.
359b50d902SRodney W. Grimes  */
369b50d902SRodney W. Grimes 
379b50d902SRodney W. Grimes #ifndef lint
389b50d902SRodney W. Grimes static char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 6/6/93";
399b50d902SRodney W. Grimes #endif /* not lint */
409b50d902SRodney W. Grimes 
419b50d902SRodney W. Grimes /*
429b50d902SRodney W. Grimes  * eval.c
439b50d902SRodney W. Grimes  * Facility: m4 macro processor
449b50d902SRodney W. Grimes  * by: oz
459b50d902SRodney W. Grimes  */
469b50d902SRodney W. Grimes 
479b50d902SRodney W. Grimes #include <sys/types.h>
489b50d902SRodney W. Grimes #include <errno.h>
499b50d902SRodney W. Grimes #include <unistd.h>
509b50d902SRodney W. Grimes #include <stdio.h>
519b50d902SRodney W. Grimes #include <stdlib.h>
529b50d902SRodney W. Grimes #include <string.h>
539b50d902SRodney W. Grimes #include "mdef.h"
549b50d902SRodney W. Grimes #include "stdd.h"
559b50d902SRodney W. Grimes #include "extern.h"
569b50d902SRodney W. Grimes #include "pathnames.h"
579b50d902SRodney W. Grimes 
589b50d902SRodney W. Grimes /*
599b50d902SRodney W. Grimes  * eval - evaluate built-in macros.
609b50d902SRodney W. Grimes  *	  argc - number of elements in argv.
619b50d902SRodney W. Grimes  *	  argv - element vector :
629b50d902SRodney W. Grimes  *			argv[0] = definition of a user
639b50d902SRodney W. Grimes  *				  macro or nil if built-in.
649b50d902SRodney W. Grimes  *			argv[1] = name of the macro or
659b50d902SRodney W. Grimes  *				  built-in.
669b50d902SRodney W. Grimes  *			argv[2] = parameters to user-defined
679b50d902SRodney W. Grimes  *			   .	  macro or built-in.
689b50d902SRodney W. Grimes  *			   .
699b50d902SRodney W. Grimes  *
709b50d902SRodney W. Grimes  * Note that the minimum value for argc is 3. A call in the form
719b50d902SRodney W. Grimes  * of macro-or-builtin() will result in:
729b50d902SRodney W. Grimes  *			argv[0] = nullstr
739b50d902SRodney W. Grimes  *			argv[1] = macro-or-builtin
749b50d902SRodney W. Grimes  *			argv[2] = nullstr
759b50d902SRodney W. Grimes  */
769b50d902SRodney W. Grimes 
779b50d902SRodney W. Grimes void
789b50d902SRodney W. Grimes eval(argv, argc, td)
799b50d902SRodney W. Grimes register char *argv[];
809b50d902SRodney W. Grimes register int argc;
819b50d902SRodney W. Grimes register int td;
829b50d902SRodney W. Grimes {
839b50d902SRodney W. Grimes 	register int c, n;
849b50d902SRodney W. Grimes 	static int sysval = 0;
859b50d902SRodney W. Grimes 
869b50d902SRodney W. Grimes #ifdef DEBUG
879b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
889b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
899b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
909b50d902SRodney W. Grimes #endif
919b50d902SRodney W. Grimes  /*
929b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
939b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
949b50d902SRodney W. Grimes   * argc to avoid further checking..
959b50d902SRodney W. Grimes   */
969b50d902SRodney W. Grimes 	if (argc == 3 && !*(argv[2]))
979b50d902SRodney W. Grimes 		argc--;
989b50d902SRodney W. Grimes 
999b50d902SRodney W. Grimes 	switch (td & ~STATIC) {
1009b50d902SRodney W. Grimes 
1019b50d902SRodney W. Grimes 	case DEFITYPE:
1029b50d902SRodney W. Grimes 		if (argc > 2)
1039b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1049b50d902SRodney W. Grimes 		break;
1059b50d902SRodney W. Grimes 
1069b50d902SRodney W. Grimes 	case PUSDTYPE:
1079b50d902SRodney W. Grimes 		if (argc > 2)
1089b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1099b50d902SRodney W. Grimes 		break;
1109b50d902SRodney W. Grimes 
1119b50d902SRodney W. Grimes 	case DUMPTYPE:
1129b50d902SRodney W. Grimes 		dodump(argv, argc);
1139b50d902SRodney W. Grimes 		break;
1149b50d902SRodney W. Grimes 
1159b50d902SRodney W. Grimes 	case EXPRTYPE:
1169b50d902SRodney W. Grimes 	/*
1179b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1189b50d902SRodney W. Grimes 	 * expression
1199b50d902SRodney W. Grimes 	 */
1209b50d902SRodney W. Grimes 		if (argc > 2)
1219b50d902SRodney W. Grimes 			pbnum(expr(argv[2]));
1229b50d902SRodney W. Grimes 		break;
1239b50d902SRodney W. Grimes 
1249b50d902SRodney W. Grimes 	case IFELTYPE:
1259b50d902SRodney W. Grimes 		if (argc > 4)
1269b50d902SRodney W. Grimes 			doifelse(argv, argc);
1279b50d902SRodney W. Grimes 		break;
1289b50d902SRodney W. Grimes 
1299b50d902SRodney W. Grimes 	case IFDFTYPE:
1309b50d902SRodney W. Grimes 	/*
1319b50d902SRodney W. Grimes 	 * doifdef - select one of two
1329b50d902SRodney W. Grimes 	 * alternatives based on the existence of
1339b50d902SRodney W. Grimes 	 * another definition
1349b50d902SRodney W. Grimes 	 */
1359b50d902SRodney W. Grimes 		if (argc > 3) {
1369b50d902SRodney W. Grimes 			if (lookup(argv[2]) != nil)
1379b50d902SRodney W. Grimes 				pbstr(argv[3]);
1389b50d902SRodney W. Grimes 			else if (argc > 4)
1399b50d902SRodney W. Grimes 				pbstr(argv[4]);
1409b50d902SRodney W. Grimes 		}
1419b50d902SRodney W. Grimes 		break;
1429b50d902SRodney W. Grimes 
1439b50d902SRodney W. Grimes 	case LENGTYPE:
1449b50d902SRodney W. Grimes 	/*
1459b50d902SRodney W. Grimes 	 * dolen - find the length of the
1469b50d902SRodney W. Grimes 	 * argument
1479b50d902SRodney W. Grimes 	 */
1489b50d902SRodney W. Grimes 		if (argc > 2)
1499b50d902SRodney W. Grimes 			pbnum((argc > 2) ? strlen(argv[2]) : 0);
1509b50d902SRodney W. Grimes 		break;
1519b50d902SRodney W. Grimes 
1529b50d902SRodney W. Grimes 	case INCRTYPE:
1539b50d902SRodney W. Grimes 	/*
1549b50d902SRodney W. Grimes 	 * doincr - increment the value of the
1559b50d902SRodney W. Grimes 	 * argument
1569b50d902SRodney W. Grimes 	 */
1579b50d902SRodney W. Grimes 		if (argc > 2)
1589b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) + 1);
1599b50d902SRodney W. Grimes 		break;
1609b50d902SRodney W. Grimes 
1619b50d902SRodney W. Grimes 	case DECRTYPE:
1629b50d902SRodney W. Grimes 	/*
1639b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
1649b50d902SRodney W. Grimes 	 * argument
1659b50d902SRodney W. Grimes 	 */
1669b50d902SRodney W. Grimes 		if (argc > 2)
1679b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) - 1);
1689b50d902SRodney W. Grimes 		break;
1699b50d902SRodney W. Grimes 
1709b50d902SRodney W. Grimes 	case SYSCTYPE:
1719b50d902SRodney W. Grimes 	/*
1729b50d902SRodney W. Grimes 	 * dosys - execute system command
1739b50d902SRodney W. Grimes 	 */
1743ee80812SAndrey A. Chernov 		/* Make sure m4 output is NOT interrupted */
1753ee80812SAndrey A. Chernov 		fflush(stdout);
1763ee80812SAndrey A. Chernov 		fflush(stderr);
1779b50d902SRodney W. Grimes 		if (argc > 2)
1789b50d902SRodney W. Grimes 			sysval = system(argv[2]);
1799b50d902SRodney W. Grimes 		break;
1809b50d902SRodney W. Grimes 
1819b50d902SRodney W. Grimes 	case SYSVTYPE:
1829b50d902SRodney W. Grimes 	/*
1839b50d902SRodney W. Grimes 	 * dosysval - return value of the last
1849b50d902SRodney W. Grimes 	 * system call.
1859b50d902SRodney W. Grimes 	 *
1869b50d902SRodney W. Grimes 	 */
1879b50d902SRodney W. Grimes 		pbnum(sysval);
1889b50d902SRodney W. Grimes 		break;
1899b50d902SRodney W. Grimes 
1909b50d902SRodney W. Grimes 	case INCLTYPE:
1919b50d902SRodney W. Grimes 		if (argc > 2)
1929b50d902SRodney W. Grimes 			if (!doincl(argv[2]))
1939b50d902SRodney W. Grimes 				oops("%s: %s", argv[2], strerror(errno));
1949b50d902SRodney W. Grimes 		break;
1959b50d902SRodney W. Grimes 
1969b50d902SRodney W. Grimes 	case SINCTYPE:
1979b50d902SRodney W. Grimes 		if (argc > 2)
1989b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
1999b50d902SRodney W. Grimes 		break;
2009b50d902SRodney W. Grimes #ifdef EXTENDED
2019b50d902SRodney W. Grimes 	case PASTTYPE:
2029b50d902SRodney W. Grimes 		if (argc > 2)
2039b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
2049b50d902SRodney W. Grimes 				oops("%s: %s", argv[2], strerror(errno));
2059b50d902SRodney W. Grimes 		break;
2069b50d902SRodney W. Grimes 
2079b50d902SRodney W. Grimes 	case SPASTYPE:
2089b50d902SRodney W. Grimes 		if (argc > 2)
2099b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
2109b50d902SRodney W. Grimes 		break;
2119b50d902SRodney W. Grimes #endif
2129b50d902SRodney W. Grimes 	case CHNQTYPE:
2139b50d902SRodney W. Grimes 		dochq(argv, argc);
2149b50d902SRodney W. Grimes 		break;
2159b50d902SRodney W. Grimes 
2169b50d902SRodney W. Grimes 	case CHNCTYPE:
2179b50d902SRodney W. Grimes 		dochc(argv, argc);
2189b50d902SRodney W. Grimes 		break;
2199b50d902SRodney W. Grimes 
2209b50d902SRodney W. Grimes 	case SUBSTYPE:
2219b50d902SRodney W. Grimes 	/*
2229b50d902SRodney W. Grimes 	 * dosub - select substring
2239b50d902SRodney W. Grimes 	 *
2249b50d902SRodney W. Grimes 	 */
2259b50d902SRodney W. Grimes 		if (argc > 3)
2269b50d902SRodney W. Grimes 			dosub(argv, argc);
2279b50d902SRodney W. Grimes 		break;
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes 	case SHIFTYPE:
2309b50d902SRodney W. Grimes 	/*
2319b50d902SRodney W. Grimes 	 * doshift - push back all arguments
2329b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
2339b50d902SRodney W. Grimes 	 * argv[2])
2349b50d902SRodney W. Grimes 	 */
2359b50d902SRodney W. Grimes 		if (argc > 3) {
2369b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
2379b50d902SRodney W. Grimes 				putback(rquote);
2389b50d902SRodney W. Grimes 				pbstr(argv[n]);
2399b50d902SRodney W. Grimes 				putback(lquote);
2409b50d902SRodney W. Grimes 				putback(',');
2419b50d902SRodney W. Grimes 			}
2429b50d902SRodney W. Grimes 			putback(rquote);
2439b50d902SRodney W. Grimes 			pbstr(argv[3]);
2449b50d902SRodney W. Grimes 			putback(lquote);
2459b50d902SRodney W. Grimes 		}
2469b50d902SRodney W. Grimes 		break;
2479b50d902SRodney W. Grimes 
2489b50d902SRodney W. Grimes 	case DIVRTYPE:
2499b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
2509b50d902SRodney W. Grimes 			dodiv(n);
2519b50d902SRodney W. Grimes 		else {
2529b50d902SRodney W. Grimes 			active = stdout;
2539b50d902SRodney W. Grimes 			oindex = 0;
2549b50d902SRodney W. Grimes 		}
2559b50d902SRodney W. Grimes 		break;
2569b50d902SRodney W. Grimes 
2579b50d902SRodney W. Grimes 	case UNDVTYPE:
2589b50d902SRodney W. Grimes 		doundiv(argv, argc);
2599b50d902SRodney W. Grimes 		break;
2609b50d902SRodney W. Grimes 
2619b50d902SRodney W. Grimes 	case DIVNTYPE:
2629b50d902SRodney W. Grimes 	/*
2639b50d902SRodney W. Grimes 	 * dodivnum - return the number of
2649b50d902SRodney W. Grimes 	 * current output diversion
2659b50d902SRodney W. Grimes 	 */
2669b50d902SRodney W. Grimes 		pbnum(oindex);
2679b50d902SRodney W. Grimes 		break;
2689b50d902SRodney W. Grimes 
2699b50d902SRodney W. Grimes 	case UNDFTYPE:
2709b50d902SRodney W. Grimes 	/*
2719b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
2729b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
2739b50d902SRodney W. Grimes 	 */
2749b50d902SRodney W. Grimes 		if (argc > 2)
2759b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
2769b50d902SRodney W. Grimes 				remhash(argv[n], ALL);
2779b50d902SRodney W. Grimes 		break;
2789b50d902SRodney W. Grimes 
2799b50d902SRodney W. Grimes 	case POPDTYPE:
2809b50d902SRodney W. Grimes 	/*
2819b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
2829b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
2839b50d902SRodney W. Grimes 	 * keyword(s).
2849b50d902SRodney W. Grimes 	 */
2859b50d902SRodney W. Grimes 		if (argc > 2)
2869b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
2879b50d902SRodney W. Grimes 				remhash(argv[n], TOP);
2889b50d902SRodney W. Grimes 		break;
2899b50d902SRodney W. Grimes 
2909b50d902SRodney W. Grimes 	case MKTMTYPE:
2919b50d902SRodney W. Grimes 	/*
2929b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
2939b50d902SRodney W. Grimes 	 */
2949b50d902SRodney W. Grimes 		if (argc > 2)
2959b50d902SRodney W. Grimes 			pbstr(mktemp(argv[2]));
2969b50d902SRodney W. Grimes 		break;
2979b50d902SRodney W. Grimes 
2989b50d902SRodney W. Grimes 	case TRNLTYPE:
2999b50d902SRodney W. Grimes 	/*
3009b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
3019b50d902SRodney W. Grimes 	 * the source string that appears in the
3029b50d902SRodney W. Grimes 	 * "from" string with the corresponding
3039b50d902SRodney W. Grimes 	 * characters in the "to" string.
3049b50d902SRodney W. Grimes 	 */
3059b50d902SRodney W. Grimes 		if (argc > 3) {
3069b50d902SRodney W. Grimes 			char temp[MAXTOK];
3079b50d902SRodney W. Grimes 			if (argc > 4)
3089b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
3099b50d902SRodney W. Grimes 			else
3109b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
3119b50d902SRodney W. Grimes 			pbstr(temp);
3129b50d902SRodney W. Grimes 		}
3139b50d902SRodney W. Grimes 		else if (argc > 2)
3149b50d902SRodney W. Grimes 			pbstr(argv[2]);
3159b50d902SRodney W. Grimes 		break;
3169b50d902SRodney W. Grimes 
3179b50d902SRodney W. Grimes 	case INDXTYPE:
3189b50d902SRodney W. Grimes 	/*
3199b50d902SRodney W. Grimes 	 * doindex - find the index of the second
3209b50d902SRodney W. Grimes 	 * argument string in the first argument
3219b50d902SRodney W. Grimes 	 * string. -1 if not present.
3229b50d902SRodney W. Grimes 	 */
3239b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
3249b50d902SRodney W. Grimes 		break;
3259b50d902SRodney W. Grimes 
3269b50d902SRodney W. Grimes 	case ERRPTYPE:
3279b50d902SRodney W. Grimes 	/*
3289b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
3299b50d902SRodney W. Grimes 	 * file
3309b50d902SRodney W. Grimes 	 */
3319b50d902SRodney W. Grimes 		if (argc > 2) {
3329b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3339b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
3349b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
3359b50d902SRodney W. Grimes 		}
3369b50d902SRodney W. Grimes 		break;
3379b50d902SRodney W. Grimes 
3389b50d902SRodney W. Grimes 	case DNLNTYPE:
3399b50d902SRodney W. Grimes 	/*
3409b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
3419b50d902SRodney W. Grimes 	 * newline
3429b50d902SRodney W. Grimes 	 */
3439b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
3449b50d902SRodney W. Grimes 			;
3459b50d902SRodney W. Grimes 		break;
3469b50d902SRodney W. Grimes 
3479b50d902SRodney W. Grimes 	case M4WRTYPE:
3489b50d902SRodney W. Grimes 	/*
3499b50d902SRodney W. Grimes 	 * dom4wrap - set up for
3509b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
3519b50d902SRodney W. Grimes 	 */
3529b50d902SRodney W. Grimes 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
3539b50d902SRodney W. Grimes 		break;
3549b50d902SRodney W. Grimes 
3559b50d902SRodney W. Grimes 	case EXITTYPE:
3569b50d902SRodney W. Grimes 	/*
3579b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
3589b50d902SRodney W. Grimes 	 */
359cac6992aSAndrey A. Chernov 		killdiv();
3609b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
3619b50d902SRodney W. Grimes 		break;
3629b50d902SRodney W. Grimes 
3639b50d902SRodney W. Grimes 	case DEFNTYPE:
3649b50d902SRodney W. Grimes 		if (argc > 2)
3659b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3669b50d902SRodney W. Grimes 				dodefn(argv[n]);
3679b50d902SRodney W. Grimes 		break;
3689b50d902SRodney W. Grimes 
3699b50d902SRodney W. Grimes 	default:
3709b50d902SRodney W. Grimes 		oops("%s: major botch.", "eval");
3719b50d902SRodney W. Grimes 		break;
3729b50d902SRodney W. Grimes 	}
3739b50d902SRodney W. Grimes }
3749b50d902SRodney W. Grimes 
3759b50d902SRodney W. Grimes char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
3769b50d902SRodney W. Grimes 
3779b50d902SRodney W. Grimes /*
3789b50d902SRodney W. Grimes  * expand - user-defined macro expansion
3799b50d902SRodney W. Grimes  */
3809b50d902SRodney W. Grimes void
3819b50d902SRodney W. Grimes expand(argv, argc)
3829b50d902SRodney W. Grimes register char *argv[];
3839b50d902SRodney W. Grimes register int argc;
3849b50d902SRodney W. Grimes {
3857c5eeb39SAndrey A. Chernov 	register unsigned char *t;
3867c5eeb39SAndrey A. Chernov 	register unsigned char *p;
3879b50d902SRodney W. Grimes 	register int n;
3889b50d902SRodney W. Grimes 	register int argno;
3899b50d902SRodney W. Grimes 
3909b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
3919b50d902SRodney W. Grimes 	p = t;
3929b50d902SRodney W. Grimes 	while (*p)
3939b50d902SRodney W. Grimes 		p++;
3949b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
3959b50d902SRodney W. Grimes 	while (p > t) {
3969b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
3979b50d902SRodney W. Grimes 			putback(*p);
3989b50d902SRodney W. Grimes 		else {
3999b50d902SRodney W. Grimes 			switch (*p) {
4009b50d902SRodney W. Grimes 
4019b50d902SRodney W. Grimes 			case '#':
4029b50d902SRodney W. Grimes 				pbnum(argc - 2);
4039b50d902SRodney W. Grimes 				break;
4049b50d902SRodney W. Grimes 			case '0':
4059b50d902SRodney W. Grimes 			case '1':
4069b50d902SRodney W. Grimes 			case '2':
4079b50d902SRodney W. Grimes 			case '3':
4089b50d902SRodney W. Grimes 			case '4':
4099b50d902SRodney W. Grimes 			case '5':
4109b50d902SRodney W. Grimes 			case '6':
4119b50d902SRodney W. Grimes 			case '7':
4129b50d902SRodney W. Grimes 			case '8':
4139b50d902SRodney W. Grimes 			case '9':
4149b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
4159b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
4169b50d902SRodney W. Grimes 				break;
4179b50d902SRodney W. Grimes 			case '*':
4189b50d902SRodney W. Grimes 				for (n = argc - 1; n > 2; n--) {
4199b50d902SRodney W. Grimes 					pbstr(argv[n]);
4209b50d902SRodney W. Grimes 					putback(',');
4219b50d902SRodney W. Grimes 				}
4229b50d902SRodney W. Grimes 				pbstr(argv[2]);
4239b50d902SRodney W. Grimes 				break;
424232eaee6SJoerg Wunsch 			case '@':
425232eaee6SJoerg Wunsch 				for( n = argc - 1; n >= 2; n-- )
426232eaee6SJoerg Wunsch 				{
427232eaee6SJoerg Wunsch 					putback(rquote);
428232eaee6SJoerg Wunsch 					pbstr(argv[n]);
429232eaee6SJoerg Wunsch 					putback(lquote);
430232eaee6SJoerg Wunsch 					if( n > 2 )
431232eaee6SJoerg Wunsch 						putback(',');
432232eaee6SJoerg Wunsch 				}
433232eaee6SJoerg Wunsch 				break;
4349b50d902SRodney W. Grimes 			default:
4359b50d902SRodney W. Grimes 				putback(*p);
4369b50d902SRodney W. Grimes 				putback('$');
4379b50d902SRodney W. Grimes 				break;
4389b50d902SRodney W. Grimes 			}
4399b50d902SRodney W. Grimes 			p--;
4409b50d902SRodney W. Grimes 		}
4419b50d902SRodney W. Grimes 		p--;
4429b50d902SRodney W. Grimes 	}
4439b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
4449b50d902SRodney W. Grimes 		putback(*p);
4459b50d902SRodney W. Grimes }
4469b50d902SRodney W. Grimes 
4479b50d902SRodney W. Grimes /*
4489b50d902SRodney W. Grimes  * dodefine - install definition in the table
4499b50d902SRodney W. Grimes  */
4509b50d902SRodney W. Grimes void
4519b50d902SRodney W. Grimes dodefine(name, defn)
4529b50d902SRodney W. Grimes register char *name;
4539b50d902SRodney W. Grimes register char *defn;
4549b50d902SRodney W. Grimes {
4559b50d902SRodney W. Grimes 	register ndptr p;
4569b50d902SRodney W. Grimes 
4579b50d902SRodney W. Grimes 	if (!*name)
4589b50d902SRodney W. Grimes 		oops("null definition.");
4599b50d902SRodney W. Grimes 	if (STREQ(name, defn))
4609b50d902SRodney W. Grimes 		oops("%s: recursive definition.", name);
4619b50d902SRodney W. Grimes 	if ((p = lookup(name)) == nil)
4629b50d902SRodney W. Grimes 		p = addent(name);
4639b50d902SRodney W. Grimes 	else if (p->defn != null)
4649b50d902SRodney W. Grimes 		free((char *) p->defn);
4659b50d902SRodney W. Grimes 	if (!*defn)
4669b50d902SRodney W. Grimes 		p->defn = null;
4679b50d902SRodney W. Grimes 	else
4689b50d902SRodney W. Grimes 		p->defn = xstrdup(defn);
4699b50d902SRodney W. Grimes 	p->type = MACRTYPE;
4709b50d902SRodney W. Grimes }
4719b50d902SRodney W. Grimes 
4729b50d902SRodney W. Grimes /*
4739b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
4749b50d902SRodney W. Grimes  *      the given name.
4759b50d902SRodney W. Grimes  */
4769b50d902SRodney W. Grimes void
4779b50d902SRodney W. Grimes dodefn(name)
4789b50d902SRodney W. Grimes char *name;
4799b50d902SRodney W. Grimes {
4809b50d902SRodney W. Grimes 	register ndptr p;
4819b50d902SRodney W. Grimes 
4829b50d902SRodney W. Grimes 	if ((p = lookup(name)) != nil && p->defn != null) {
4839b50d902SRodney W. Grimes 		putback(rquote);
4849b50d902SRodney W. Grimes 		pbstr(p->defn);
4859b50d902SRodney W. Grimes 		putback(lquote);
4869b50d902SRodney W. Grimes 	}
4879b50d902SRodney W. Grimes }
4889b50d902SRodney W. Grimes 
4899b50d902SRodney W. Grimes /*
4909b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
4919b50d902SRodney W. Grimes  *      without removing a previous definition. Since
4929b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
4939b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
4949b50d902SRodney W. Grimes  *      lookup.
4959b50d902SRodney W. Grimes  */
4969b50d902SRodney W. Grimes void
4979b50d902SRodney W. Grimes dopushdef(name, defn)
4989b50d902SRodney W. Grimes register char *name;
4999b50d902SRodney W. Grimes register char *defn;
5009b50d902SRodney W. Grimes {
5019b50d902SRodney W. Grimes 	register ndptr p;
5029b50d902SRodney W. Grimes 
5039b50d902SRodney W. Grimes 	if (!*name)
5049b50d902SRodney W. Grimes 		oops("null definition");
5059b50d902SRodney W. Grimes 	if (STREQ(name, defn))
5069b50d902SRodney W. Grimes 		oops("%s: recursive definition.", name);
5079b50d902SRodney W. Grimes 	p = addent(name);
5089b50d902SRodney W. Grimes 	if (!*defn)
5099b50d902SRodney W. Grimes 		p->defn = null;
5109b50d902SRodney W. Grimes 	else
5119b50d902SRodney W. Grimes 		p->defn = xstrdup(defn);
5129b50d902SRodney W. Grimes 	p->type = MACRTYPE;
5139b50d902SRodney W. Grimes }
5149b50d902SRodney W. Grimes 
5159b50d902SRodney W. Grimes /*
5169b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
5179b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
5189b50d902SRodney W. Grimes  *      hash table is dumped.
5199b50d902SRodney W. Grimes  */
5209b50d902SRodney W. Grimes void
5219b50d902SRodney W. Grimes dodump(argv, argc)
5229b50d902SRodney W. Grimes register char *argv[];
5239b50d902SRodney W. Grimes register int argc;
5249b50d902SRodney W. Grimes {
5259b50d902SRodney W. Grimes 	register int n;
5269b50d902SRodney W. Grimes 	ndptr p;
5279b50d902SRodney W. Grimes 
5289b50d902SRodney W. Grimes 	if (argc > 2) {
5299b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
5309b50d902SRodney W. Grimes 			if ((p = lookup(argv[n])) != nil)
5319b50d902SRodney W. Grimes 				fprintf(stderr, dumpfmt, p->name,
5329b50d902SRodney W. Grimes 					p->defn);
5339b50d902SRodney W. Grimes 	}
5349b50d902SRodney W. Grimes 	else {
5359b50d902SRodney W. Grimes 		for (n = 0; n < HASHSIZE; n++)
5369b50d902SRodney W. Grimes 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
5379b50d902SRodney W. Grimes 				fprintf(stderr, dumpfmt, p->name,
5389b50d902SRodney W. Grimes 					p->defn);
5399b50d902SRodney W. Grimes 	}
5409b50d902SRodney W. Grimes }
5419b50d902SRodney W. Grimes 
5429b50d902SRodney W. Grimes /*
5439b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
5449b50d902SRodney W. Grimes  */
5459b50d902SRodney W. Grimes void
5469b50d902SRodney W. Grimes doifelse(argv, argc)
5479b50d902SRodney W. Grimes register char *argv[];
5489b50d902SRodney W. Grimes register int argc;
5499b50d902SRodney W. Grimes {
5509b50d902SRodney W. Grimes 	cycle {
5519b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
5529b50d902SRodney W. Grimes 			pbstr(argv[4]);
5539b50d902SRodney W. Grimes 		else if (argc == 6)
5549b50d902SRodney W. Grimes 			pbstr(argv[5]);
5559b50d902SRodney W. Grimes 		else if (argc > 6) {
5569b50d902SRodney W. Grimes 			argv += 3;
5579b50d902SRodney W. Grimes 			argc -= 3;
5589b50d902SRodney W. Grimes 			continue;
5599b50d902SRodney W. Grimes 		}
5609b50d902SRodney W. Grimes 		break;
5619b50d902SRodney W. Grimes 	}
5629b50d902SRodney W. Grimes }
5639b50d902SRodney W. Grimes 
5649b50d902SRodney W. Grimes /*
5659b50d902SRodney W. Grimes  * doinclude - include a given file.
5669b50d902SRodney W. Grimes  */
5679b50d902SRodney W. Grimes int
5689b50d902SRodney W. Grimes doincl(ifile)
5699b50d902SRodney W. Grimes char *ifile;
5709b50d902SRodney W. Grimes {
5719b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
5729b50d902SRodney W. Grimes 		oops("too many include files.");
5739b50d902SRodney W. Grimes 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
5749b50d902SRodney W. Grimes 		ilevel++;
5759b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
5769b50d902SRodney W. Grimes 		return (1);
5779b50d902SRodney W. Grimes 	}
5789b50d902SRodney W. Grimes 	else
5799b50d902SRodney W. Grimes 		return (0);
5809b50d902SRodney W. Grimes }
5819b50d902SRodney W. Grimes 
5829b50d902SRodney W. Grimes #ifdef EXTENDED
5839b50d902SRodney W. Grimes /*
5849b50d902SRodney W. Grimes  * dopaste - include a given file without any
5859b50d902SRodney W. Grimes  *           macro processing.
5869b50d902SRodney W. Grimes  */
5879b50d902SRodney W. Grimes int
5889b50d902SRodney W. Grimes dopaste(pfile)
5899b50d902SRodney W. Grimes char *pfile;
5909b50d902SRodney W. Grimes {
5919b50d902SRodney W. Grimes 	FILE *pf;
5929b50d902SRodney W. Grimes 	register int c;
5939b50d902SRodney W. Grimes 
5949b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
5959b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
5969b50d902SRodney W. Grimes 			putc(c, active);
5979b50d902SRodney W. Grimes 		(void) fclose(pf);
5989b50d902SRodney W. Grimes 		return (1);
5999b50d902SRodney W. Grimes 	}
6009b50d902SRodney W. Grimes 	else
6019b50d902SRodney W. Grimes 		return (0);
6029b50d902SRodney W. Grimes }
6039b50d902SRodney W. Grimes #endif
6049b50d902SRodney W. Grimes 
6059b50d902SRodney W. Grimes /*
6069b50d902SRodney W. Grimes  * dochq - change quote characters
6079b50d902SRodney W. Grimes  */
6089b50d902SRodney W. Grimes void
6099b50d902SRodney W. Grimes dochq(argv, argc)
6109b50d902SRodney W. Grimes register char *argv[];
6119b50d902SRodney W. Grimes register int argc;
6129b50d902SRodney W. Grimes {
6139b50d902SRodney W. Grimes 	if (argc > 2) {
6149b50d902SRodney W. Grimes 		if (*argv[2])
6159b50d902SRodney W. Grimes 			lquote = *argv[2];
6169b50d902SRodney W. Grimes 		if (argc > 3) {
6179b50d902SRodney W. Grimes 			if (*argv[3])
6189b50d902SRodney W. Grimes 				rquote = *argv[3];
6199b50d902SRodney W. Grimes 		}
6209b50d902SRodney W. Grimes 		else
6219b50d902SRodney W. Grimes 			rquote = lquote;
6229b50d902SRodney W. Grimes 	}
6239b50d902SRodney W. Grimes 	else {
6249b50d902SRodney W. Grimes 		lquote = LQUOTE;
6259b50d902SRodney W. Grimes 		rquote = RQUOTE;
6269b50d902SRodney W. Grimes 	}
6279b50d902SRodney W. Grimes }
6289b50d902SRodney W. Grimes 
6299b50d902SRodney W. Grimes /*
6309b50d902SRodney W. Grimes  * dochc - change comment characters
6319b50d902SRodney W. Grimes  */
6329b50d902SRodney W. Grimes void
6339b50d902SRodney W. Grimes dochc(argv, argc)
6349b50d902SRodney W. Grimes register char *argv[];
6359b50d902SRodney W. Grimes register int argc;
6369b50d902SRodney W. Grimes {
6379b50d902SRodney W. Grimes 	if (argc > 2) {
6389b50d902SRodney W. Grimes 		if (*argv[2])
6399b50d902SRodney W. Grimes 			scommt = *argv[2];
6409b50d902SRodney W. Grimes 		if (argc > 3) {
6419b50d902SRodney W. Grimes 			if (*argv[3])
6429b50d902SRodney W. Grimes 				ecommt = *argv[3];
6439b50d902SRodney W. Grimes 		}
6449b50d902SRodney W. Grimes 		else
6459b50d902SRodney W. Grimes 			ecommt = ECOMMT;
6469b50d902SRodney W. Grimes 	}
6479b50d902SRodney W. Grimes 	else {
6489b50d902SRodney W. Grimes 		scommt = SCOMMT;
6499b50d902SRodney W. Grimes 		ecommt = ECOMMT;
6509b50d902SRodney W. Grimes 	}
6519b50d902SRodney W. Grimes }
6529b50d902SRodney W. Grimes 
6539b50d902SRodney W. Grimes /*
6549b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
6559b50d902SRodney W. Grimes  */
6569b50d902SRodney W. Grimes void
6579b50d902SRodney W. Grimes dodiv(n)
6589b50d902SRodney W. Grimes register int n;
6599b50d902SRodney W. Grimes {
6609b50d902SRodney W. Grimes 	if (n < 0 || n >= MAXOUT)
6619b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
6629b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
6639b50d902SRodney W. Grimes 		m4temp[UNIQUE] = n + '0';
6649b50d902SRodney W. Grimes 		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
6659b50d902SRodney W. Grimes 			oops("%s: cannot divert.", m4temp);
6669b50d902SRodney W. Grimes 	}
6679b50d902SRodney W. Grimes 	oindex = n;
6689b50d902SRodney W. Grimes 	active = outfile[n];
6699b50d902SRodney W. Grimes }
6709b50d902SRodney W. Grimes 
6719b50d902SRodney W. Grimes /*
6729b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
6739b50d902SRodney W. Grimes  *              other outputs, in numerical order.
6749b50d902SRodney W. Grimes  */
6759b50d902SRodney W. Grimes void
6769b50d902SRodney W. Grimes doundiv(argv, argc)
6779b50d902SRodney W. Grimes register char *argv[];
6789b50d902SRodney W. Grimes register int argc;
6799b50d902SRodney W. Grimes {
6809b50d902SRodney W. Grimes 	register int ind;
6819b50d902SRodney W. Grimes 	register int n;
6829b50d902SRodney W. Grimes 
6839b50d902SRodney W. Grimes 	if (argc > 2) {
6849b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
6859b50d902SRodney W. Grimes 			n = atoi(argv[ind]);
6869b50d902SRodney W. Grimes 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
6879b50d902SRodney W. Grimes 				getdiv(n);
6889b50d902SRodney W. Grimes 
6899b50d902SRodney W. Grimes 		}
6909b50d902SRodney W. Grimes 	}
6919b50d902SRodney W. Grimes 	else
6929b50d902SRodney W. Grimes 		for (n = 1; n < MAXOUT; n++)
6939b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
6949b50d902SRodney W. Grimes 				getdiv(n);
6959b50d902SRodney W. Grimes }
6969b50d902SRodney W. Grimes 
6979b50d902SRodney W. Grimes /*
6989b50d902SRodney W. Grimes  * dosub - select substring
6999b50d902SRodney W. Grimes  */
7009b50d902SRodney W. Grimes void
7019b50d902SRodney W. Grimes dosub(argv, argc)
7029b50d902SRodney W. Grimes register char *argv[];
7039b50d902SRodney W. Grimes register int argc;
7049b50d902SRodney W. Grimes {
7057c5eeb39SAndrey A. Chernov 	register unsigned char *ap, *fc, *k;
7069b50d902SRodney W. Grimes 	register int nc;
7079b50d902SRodney W. Grimes 
7089b50d902SRodney W. Grimes 	if (argc < 5)
7099b50d902SRodney W. Grimes 		nc = MAXTOK;
7109b50d902SRodney W. Grimes 	else
7119b50d902SRodney W. Grimes #ifdef EXPR
7129b50d902SRodney W. Grimes 		nc = expr(argv[4]);
7139b50d902SRodney W. Grimes #else
7149b50d902SRodney W. Grimes 		nc = atoi(argv[4]);
7159b50d902SRodney W. Grimes #endif
7169b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
7179b50d902SRodney W. Grimes #ifdef EXPR
7189b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
7199b50d902SRodney W. Grimes #else
7209b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
7219b50d902SRodney W. Grimes #endif
7229b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
7239b50d902SRodney W. Grimes 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
7249b50d902SRodney W. Grimes 			putback(*k);
7259b50d902SRodney W. Grimes }
7269b50d902SRodney W. Grimes 
7279b50d902SRodney W. Grimes /*
7289b50d902SRodney W. Grimes  * map:
7299b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
7309b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
7319b50d902SRodney W. Grimes  *
7329b50d902SRodney W. Grimes  * This is a standard implementation of map(s,from,to) function of ICON
7339b50d902SRodney W. Grimes  * language. Within mapvec, we replace every character of "from" with
7349b50d902SRodney W. Grimes  * the corresponding character in "to". If "to" is shorter than "from",
7359b50d902SRodney W. Grimes  * than the corresponding entries are null, which means that those
7369b50d902SRodney W. Grimes  * characters dissapear altogether. Furthermore, imagine
7379b50d902SRodney W. Grimes  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
7389b50d902SRodney W. Grimes  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
7399b50d902SRodney W. Grimes  * ultimately maps to `*'. In order to achieve this effect in an efficient
7409b50d902SRodney W. Grimes  * manner (i.e. without multiple passes over the destination string), we
7419b50d902SRodney W. Grimes  * loop over mapvec, starting with the initial source character. if the
7429b50d902SRodney W. Grimes  * character value (dch) in this location is different than the source
7439b50d902SRodney W. Grimes  * character (sch), sch becomes dch, once again to index into mapvec, until
7449b50d902SRodney W. Grimes  * the character value stabilizes (i.e. sch = dch, in other words
7459b50d902SRodney W. Grimes  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
7469b50d902SRodney W. Grimes  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
7479b50d902SRodney W. Grimes  * end, we restore mapvec* back to normal where mapvec[n] == n for
7489b50d902SRodney W. Grimes  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
7499b50d902SRodney W. Grimes  * about 5 times faster than any algorithm that makes multiple passes over
7509b50d902SRodney W. Grimes  * destination string.
7519b50d902SRodney W. Grimes  */
7529b50d902SRodney W. Grimes void
7539b50d902SRodney W. Grimes map(dest, src, from, to)
7549b50d902SRodney W. Grimes register char *dest;
7559b50d902SRodney W. Grimes register char *src;
7569b50d902SRodney W. Grimes register char *from;
7579b50d902SRodney W. Grimes register char *to;
7589b50d902SRodney W. Grimes {
7599b50d902SRodney W. Grimes 	register char *tmp;
7609b50d902SRodney W. Grimes 	register char sch, dch;
7619b50d902SRodney W. Grimes 	static char mapvec[128] = {
7629b50d902SRodney W. Grimes 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
7639b50d902SRodney W. Grimes 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
7649b50d902SRodney W. Grimes 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
7659b50d902SRodney W. Grimes 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
7669b50d902SRodney W. Grimes 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
7679b50d902SRodney W. Grimes 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
7689b50d902SRodney W. Grimes 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
7699b50d902SRodney W. Grimes 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
7709b50d902SRodney W. Grimes 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
7719b50d902SRodney W. Grimes 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
7729b50d902SRodney W. Grimes 		120, 121, 122, 123, 124, 125, 126, 127
7739b50d902SRodney W. Grimes 	};
7749b50d902SRodney W. Grimes 
7759b50d902SRodney W. Grimes 	if (*src) {
7769b50d902SRodney W. Grimes 		tmp = from;
7779b50d902SRodney W. Grimes 	/*
7789b50d902SRodney W. Grimes 	 * create a mapping between "from" and
7799b50d902SRodney W. Grimes 	 * "to"
7809b50d902SRodney W. Grimes 	 */
7819b50d902SRodney W. Grimes 		while (*from)
7829b50d902SRodney W. Grimes 			mapvec[*from++] = (*to) ? *to++ : (char) 0;
7839b50d902SRodney W. Grimes 
7849b50d902SRodney W. Grimes 		while (*src) {
7859b50d902SRodney W. Grimes 			sch = *src++;
7869b50d902SRodney W. Grimes 			dch = mapvec[sch];
7879b50d902SRodney W. Grimes 			while (dch != sch) {
7889b50d902SRodney W. Grimes 				sch = dch;
7899b50d902SRodney W. Grimes 				dch = mapvec[sch];
7909b50d902SRodney W. Grimes 			}
7919b50d902SRodney W. Grimes 			if (*dest = dch)
7929b50d902SRodney W. Grimes 				dest++;
7939b50d902SRodney W. Grimes 		}
7949b50d902SRodney W. Grimes 	/*
7959b50d902SRodney W. Grimes 	 * restore all the changed characters
7969b50d902SRodney W. Grimes 	 */
7979b50d902SRodney W. Grimes 		while (*tmp) {
7989b50d902SRodney W. Grimes 			mapvec[*tmp] = *tmp;
7999b50d902SRodney W. Grimes 			tmp++;
8009b50d902SRodney W. Grimes 		}
8019b50d902SRodney W. Grimes 	}
8029b50d902SRodney W. Grimes 	*dest = (char) 0;
8039b50d902SRodney W. Grimes }
804