xref: /freebsd/usr.bin/m4/eval.c (revision 9b50d9027575220cb6dd09b3e62f03f511e908b8)
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 	 */
1749b50d902SRodney W. Grimes 		if (argc > 2)
1759b50d902SRodney W. Grimes 			sysval = system(argv[2]);
1769b50d902SRodney W. Grimes 		break;
1779b50d902SRodney W. Grimes 
1789b50d902SRodney W. Grimes 	case SYSVTYPE:
1799b50d902SRodney W. Grimes 	/*
1809b50d902SRodney W. Grimes 	 * dosysval - return value of the last
1819b50d902SRodney W. Grimes 	 * system call.
1829b50d902SRodney W. Grimes 	 *
1839b50d902SRodney W. Grimes 	 */
1849b50d902SRodney W. Grimes 		pbnum(sysval);
1859b50d902SRodney W. Grimes 		break;
1869b50d902SRodney W. Grimes 
1879b50d902SRodney W. Grimes 	case INCLTYPE:
1889b50d902SRodney W. Grimes 		if (argc > 2)
1899b50d902SRodney W. Grimes 			if (!doincl(argv[2]))
1909b50d902SRodney W. Grimes 				oops("%s: %s", argv[2], strerror(errno));
1919b50d902SRodney W. Grimes 		break;
1929b50d902SRodney W. Grimes 
1939b50d902SRodney W. Grimes 	case SINCTYPE:
1949b50d902SRodney W. Grimes 		if (argc > 2)
1959b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
1969b50d902SRodney W. Grimes 		break;
1979b50d902SRodney W. Grimes #ifdef EXTENDED
1989b50d902SRodney W. Grimes 	case PASTTYPE:
1999b50d902SRodney W. Grimes 		if (argc > 2)
2009b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
2019b50d902SRodney W. Grimes 				oops("%s: %s", argv[2], strerror(errno));
2029b50d902SRodney W. Grimes 		break;
2039b50d902SRodney W. Grimes 
2049b50d902SRodney W. Grimes 	case SPASTYPE:
2059b50d902SRodney W. Grimes 		if (argc > 2)
2069b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
2079b50d902SRodney W. Grimes 		break;
2089b50d902SRodney W. Grimes #endif
2099b50d902SRodney W. Grimes 	case CHNQTYPE:
2109b50d902SRodney W. Grimes 		dochq(argv, argc);
2119b50d902SRodney W. Grimes 		break;
2129b50d902SRodney W. Grimes 
2139b50d902SRodney W. Grimes 	case CHNCTYPE:
2149b50d902SRodney W. Grimes 		dochc(argv, argc);
2159b50d902SRodney W. Grimes 		break;
2169b50d902SRodney W. Grimes 
2179b50d902SRodney W. Grimes 	case SUBSTYPE:
2189b50d902SRodney W. Grimes 	/*
2199b50d902SRodney W. Grimes 	 * dosub - select substring
2209b50d902SRodney W. Grimes 	 *
2219b50d902SRodney W. Grimes 	 */
2229b50d902SRodney W. Grimes 		if (argc > 3)
2239b50d902SRodney W. Grimes 			dosub(argv, argc);
2249b50d902SRodney W. Grimes 		break;
2259b50d902SRodney W. Grimes 
2269b50d902SRodney W. Grimes 	case SHIFTYPE:
2279b50d902SRodney W. Grimes 	/*
2289b50d902SRodney W. Grimes 	 * doshift - push back all arguments
2299b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
2309b50d902SRodney W. Grimes 	 * argv[2])
2319b50d902SRodney W. Grimes 	 */
2329b50d902SRodney W. Grimes 		if (argc > 3) {
2339b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
2349b50d902SRodney W. Grimes 				putback(rquote);
2359b50d902SRodney W. Grimes 				pbstr(argv[n]);
2369b50d902SRodney W. Grimes 				putback(lquote);
2379b50d902SRodney W. Grimes 				putback(',');
2389b50d902SRodney W. Grimes 			}
2399b50d902SRodney W. Grimes 			putback(rquote);
2409b50d902SRodney W. Grimes 			pbstr(argv[3]);
2419b50d902SRodney W. Grimes 			putback(lquote);
2429b50d902SRodney W. Grimes 		}
2439b50d902SRodney W. Grimes 		break;
2449b50d902SRodney W. Grimes 
2459b50d902SRodney W. Grimes 	case DIVRTYPE:
2469b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
2479b50d902SRodney W. Grimes 			dodiv(n);
2489b50d902SRodney W. Grimes 		else {
2499b50d902SRodney W. Grimes 			active = stdout;
2509b50d902SRodney W. Grimes 			oindex = 0;
2519b50d902SRodney W. Grimes 		}
2529b50d902SRodney W. Grimes 		break;
2539b50d902SRodney W. Grimes 
2549b50d902SRodney W. Grimes 	case UNDVTYPE:
2559b50d902SRodney W. Grimes 		doundiv(argv, argc);
2569b50d902SRodney W. Grimes 		break;
2579b50d902SRodney W. Grimes 
2589b50d902SRodney W. Grimes 	case DIVNTYPE:
2599b50d902SRodney W. Grimes 	/*
2609b50d902SRodney W. Grimes 	 * dodivnum - return the number of
2619b50d902SRodney W. Grimes 	 * current output diversion
2629b50d902SRodney W. Grimes 	 */
2639b50d902SRodney W. Grimes 		pbnum(oindex);
2649b50d902SRodney W. Grimes 		break;
2659b50d902SRodney W. Grimes 
2669b50d902SRodney W. Grimes 	case UNDFTYPE:
2679b50d902SRodney W. Grimes 	/*
2689b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
2699b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
2709b50d902SRodney W. Grimes 	 */
2719b50d902SRodney W. Grimes 		if (argc > 2)
2729b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
2739b50d902SRodney W. Grimes 				remhash(argv[n], ALL);
2749b50d902SRodney W. Grimes 		break;
2759b50d902SRodney W. Grimes 
2769b50d902SRodney W. Grimes 	case POPDTYPE:
2779b50d902SRodney W. Grimes 	/*
2789b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
2799b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
2809b50d902SRodney W. Grimes 	 * keyword(s).
2819b50d902SRodney W. Grimes 	 */
2829b50d902SRodney W. Grimes 		if (argc > 2)
2839b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
2849b50d902SRodney W. Grimes 				remhash(argv[n], TOP);
2859b50d902SRodney W. Grimes 		break;
2869b50d902SRodney W. Grimes 
2879b50d902SRodney W. Grimes 	case MKTMTYPE:
2889b50d902SRodney W. Grimes 	/*
2899b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
2909b50d902SRodney W. Grimes 	 */
2919b50d902SRodney W. Grimes 		if (argc > 2)
2929b50d902SRodney W. Grimes 			pbstr(mktemp(argv[2]));
2939b50d902SRodney W. Grimes 		break;
2949b50d902SRodney W. Grimes 
2959b50d902SRodney W. Grimes 	case TRNLTYPE:
2969b50d902SRodney W. Grimes 	/*
2979b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
2989b50d902SRodney W. Grimes 	 * the source string that appears in the
2999b50d902SRodney W. Grimes 	 * "from" string with the corresponding
3009b50d902SRodney W. Grimes 	 * characters in the "to" string.
3019b50d902SRodney W. Grimes 	 */
3029b50d902SRodney W. Grimes 		if (argc > 3) {
3039b50d902SRodney W. Grimes 			char temp[MAXTOK];
3049b50d902SRodney W. Grimes 			if (argc > 4)
3059b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
3069b50d902SRodney W. Grimes 			else
3079b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
3089b50d902SRodney W. Grimes 			pbstr(temp);
3099b50d902SRodney W. Grimes 		}
3109b50d902SRodney W. Grimes 		else if (argc > 2)
3119b50d902SRodney W. Grimes 			pbstr(argv[2]);
3129b50d902SRodney W. Grimes 		break;
3139b50d902SRodney W. Grimes 
3149b50d902SRodney W. Grimes 	case INDXTYPE:
3159b50d902SRodney W. Grimes 	/*
3169b50d902SRodney W. Grimes 	 * doindex - find the index of the second
3179b50d902SRodney W. Grimes 	 * argument string in the first argument
3189b50d902SRodney W. Grimes 	 * string. -1 if not present.
3199b50d902SRodney W. Grimes 	 */
3209b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
3219b50d902SRodney W. Grimes 		break;
3229b50d902SRodney W. Grimes 
3239b50d902SRodney W. Grimes 	case ERRPTYPE:
3249b50d902SRodney W. Grimes 	/*
3259b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
3269b50d902SRodney W. Grimes 	 * file
3279b50d902SRodney W. Grimes 	 */
3289b50d902SRodney W. Grimes 		if (argc > 2) {
3299b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3309b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
3319b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
3329b50d902SRodney W. Grimes 		}
3339b50d902SRodney W. Grimes 		break;
3349b50d902SRodney W. Grimes 
3359b50d902SRodney W. Grimes 	case DNLNTYPE:
3369b50d902SRodney W. Grimes 	/*
3379b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
3389b50d902SRodney W. Grimes 	 * newline
3399b50d902SRodney W. Grimes 	 */
3409b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
3419b50d902SRodney W. Grimes 			;
3429b50d902SRodney W. Grimes 		break;
3439b50d902SRodney W. Grimes 
3449b50d902SRodney W. Grimes 	case M4WRTYPE:
3459b50d902SRodney W. Grimes 	/*
3469b50d902SRodney W. Grimes 	 * dom4wrap - set up for
3479b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
3489b50d902SRodney W. Grimes 	 */
3499b50d902SRodney W. Grimes 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
3509b50d902SRodney W. Grimes 		break;
3519b50d902SRodney W. Grimes 
3529b50d902SRodney W. Grimes 	case EXITTYPE:
3539b50d902SRodney W. Grimes 	/*
3549b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
3559b50d902SRodney W. Grimes 	 */
3569b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
3579b50d902SRodney W. Grimes 		break;
3589b50d902SRodney W. Grimes 
3599b50d902SRodney W. Grimes 	case DEFNTYPE:
3609b50d902SRodney W. Grimes 		if (argc > 2)
3619b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3629b50d902SRodney W. Grimes 				dodefn(argv[n]);
3639b50d902SRodney W. Grimes 		break;
3649b50d902SRodney W. Grimes 
3659b50d902SRodney W. Grimes 	default:
3669b50d902SRodney W. Grimes 		oops("%s: major botch.", "eval");
3679b50d902SRodney W. Grimes 		break;
3689b50d902SRodney W. Grimes 	}
3699b50d902SRodney W. Grimes }
3709b50d902SRodney W. Grimes 
3719b50d902SRodney W. Grimes char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
3729b50d902SRodney W. Grimes 
3739b50d902SRodney W. Grimes /*
3749b50d902SRodney W. Grimes  * expand - user-defined macro expansion
3759b50d902SRodney W. Grimes  */
3769b50d902SRodney W. Grimes void
3779b50d902SRodney W. Grimes expand(argv, argc)
3789b50d902SRodney W. Grimes register char *argv[];
3799b50d902SRodney W. Grimes register int argc;
3809b50d902SRodney W. Grimes {
3819b50d902SRodney W. Grimes 	register char *t;
3829b50d902SRodney W. Grimes 	register char *p;
3839b50d902SRodney W. Grimes 	register int n;
3849b50d902SRodney W. Grimes 	register int argno;
3859b50d902SRodney W. Grimes 
3869b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
3879b50d902SRodney W. Grimes 	p = t;
3889b50d902SRodney W. Grimes 	while (*p)
3899b50d902SRodney W. Grimes 		p++;
3909b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
3919b50d902SRodney W. Grimes 	while (p > t) {
3929b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
3939b50d902SRodney W. Grimes 			putback(*p);
3949b50d902SRodney W. Grimes 		else {
3959b50d902SRodney W. Grimes 			switch (*p) {
3969b50d902SRodney W. Grimes 
3979b50d902SRodney W. Grimes 			case '#':
3989b50d902SRodney W. Grimes 				pbnum(argc - 2);
3999b50d902SRodney W. Grimes 				break;
4009b50d902SRodney W. Grimes 			case '0':
4019b50d902SRodney W. Grimes 			case '1':
4029b50d902SRodney W. Grimes 			case '2':
4039b50d902SRodney W. Grimes 			case '3':
4049b50d902SRodney W. Grimes 			case '4':
4059b50d902SRodney W. Grimes 			case '5':
4069b50d902SRodney W. Grimes 			case '6':
4079b50d902SRodney W. Grimes 			case '7':
4089b50d902SRodney W. Grimes 			case '8':
4099b50d902SRodney W. Grimes 			case '9':
4109b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
4119b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
4129b50d902SRodney W. Grimes 				break;
4139b50d902SRodney W. Grimes 			case '*':
4149b50d902SRodney W. Grimes 				for (n = argc - 1; n > 2; n--) {
4159b50d902SRodney W. Grimes 					pbstr(argv[n]);
4169b50d902SRodney W. Grimes 					putback(',');
4179b50d902SRodney W. Grimes 				}
4189b50d902SRodney W. Grimes 				pbstr(argv[2]);
4199b50d902SRodney W. Grimes 				break;
4209b50d902SRodney W. Grimes 			default:
4219b50d902SRodney W. Grimes 				putback(*p);
4229b50d902SRodney W. Grimes 				putback('$');
4239b50d902SRodney W. Grimes 				break;
4249b50d902SRodney W. Grimes 			}
4259b50d902SRodney W. Grimes 			p--;
4269b50d902SRodney W. Grimes 		}
4279b50d902SRodney W. Grimes 		p--;
4289b50d902SRodney W. Grimes 	}
4299b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
4309b50d902SRodney W. Grimes 		putback(*p);
4319b50d902SRodney W. Grimes }
4329b50d902SRodney W. Grimes 
4339b50d902SRodney W. Grimes /*
4349b50d902SRodney W. Grimes  * dodefine - install definition in the table
4359b50d902SRodney W. Grimes  */
4369b50d902SRodney W. Grimes void
4379b50d902SRodney W. Grimes dodefine(name, defn)
4389b50d902SRodney W. Grimes register char *name;
4399b50d902SRodney W. Grimes register char *defn;
4409b50d902SRodney W. Grimes {
4419b50d902SRodney W. Grimes 	register ndptr p;
4429b50d902SRodney W. Grimes 
4439b50d902SRodney W. Grimes 	if (!*name)
4449b50d902SRodney W. Grimes 		oops("null definition.");
4459b50d902SRodney W. Grimes 	if (STREQ(name, defn))
4469b50d902SRodney W. Grimes 		oops("%s: recursive definition.", name);
4479b50d902SRodney W. Grimes 	if ((p = lookup(name)) == nil)
4489b50d902SRodney W. Grimes 		p = addent(name);
4499b50d902SRodney W. Grimes 	else if (p->defn != null)
4509b50d902SRodney W. Grimes 		free((char *) p->defn);
4519b50d902SRodney W. Grimes 	if (!*defn)
4529b50d902SRodney W. Grimes 		p->defn = null;
4539b50d902SRodney W. Grimes 	else
4549b50d902SRodney W. Grimes 		p->defn = xstrdup(defn);
4559b50d902SRodney W. Grimes 	p->type = MACRTYPE;
4569b50d902SRodney W. Grimes }
4579b50d902SRodney W. Grimes 
4589b50d902SRodney W. Grimes /*
4599b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
4609b50d902SRodney W. Grimes  *      the given name.
4619b50d902SRodney W. Grimes  */
4629b50d902SRodney W. Grimes void
4639b50d902SRodney W. Grimes dodefn(name)
4649b50d902SRodney W. Grimes char *name;
4659b50d902SRodney W. Grimes {
4669b50d902SRodney W. Grimes 	register ndptr p;
4679b50d902SRodney W. Grimes 
4689b50d902SRodney W. Grimes 	if ((p = lookup(name)) != nil && p->defn != null) {
4699b50d902SRodney W. Grimes 		putback(rquote);
4709b50d902SRodney W. Grimes 		pbstr(p->defn);
4719b50d902SRodney W. Grimes 		putback(lquote);
4729b50d902SRodney W. Grimes 	}
4739b50d902SRodney W. Grimes }
4749b50d902SRodney W. Grimes 
4759b50d902SRodney W. Grimes /*
4769b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
4779b50d902SRodney W. Grimes  *      without removing a previous definition. Since
4789b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
4799b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
4809b50d902SRodney W. Grimes  *      lookup.
4819b50d902SRodney W. Grimes  */
4829b50d902SRodney W. Grimes void
4839b50d902SRodney W. Grimes dopushdef(name, defn)
4849b50d902SRodney W. Grimes register char *name;
4859b50d902SRodney W. Grimes register char *defn;
4869b50d902SRodney W. Grimes {
4879b50d902SRodney W. Grimes 	register ndptr p;
4889b50d902SRodney W. Grimes 
4899b50d902SRodney W. Grimes 	if (!*name)
4909b50d902SRodney W. Grimes 		oops("null definition");
4919b50d902SRodney W. Grimes 	if (STREQ(name, defn))
4929b50d902SRodney W. Grimes 		oops("%s: recursive definition.", name);
4939b50d902SRodney W. Grimes 	p = addent(name);
4949b50d902SRodney W. Grimes 	if (!*defn)
4959b50d902SRodney W. Grimes 		p->defn = null;
4969b50d902SRodney W. Grimes 	else
4979b50d902SRodney W. Grimes 		p->defn = xstrdup(defn);
4989b50d902SRodney W. Grimes 	p->type = MACRTYPE;
4999b50d902SRodney W. Grimes }
5009b50d902SRodney W. Grimes 
5019b50d902SRodney W. Grimes /*
5029b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
5039b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
5049b50d902SRodney W. Grimes  *      hash table is dumped.
5059b50d902SRodney W. Grimes  */
5069b50d902SRodney W. Grimes void
5079b50d902SRodney W. Grimes dodump(argv, argc)
5089b50d902SRodney W. Grimes register char *argv[];
5099b50d902SRodney W. Grimes register int argc;
5109b50d902SRodney W. Grimes {
5119b50d902SRodney W. Grimes 	register int n;
5129b50d902SRodney W. Grimes 	ndptr p;
5139b50d902SRodney W. Grimes 
5149b50d902SRodney W. Grimes 	if (argc > 2) {
5159b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
5169b50d902SRodney W. Grimes 			if ((p = lookup(argv[n])) != nil)
5179b50d902SRodney W. Grimes 				fprintf(stderr, dumpfmt, p->name,
5189b50d902SRodney W. Grimes 					p->defn);
5199b50d902SRodney W. Grimes 	}
5209b50d902SRodney W. Grimes 	else {
5219b50d902SRodney W. Grimes 		for (n = 0; n < HASHSIZE; n++)
5229b50d902SRodney W. Grimes 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
5239b50d902SRodney W. Grimes 				fprintf(stderr, dumpfmt, p->name,
5249b50d902SRodney W. Grimes 					p->defn);
5259b50d902SRodney W. Grimes 	}
5269b50d902SRodney W. Grimes }
5279b50d902SRodney W. Grimes 
5289b50d902SRodney W. Grimes /*
5299b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
5309b50d902SRodney W. Grimes  */
5319b50d902SRodney W. Grimes void
5329b50d902SRodney W. Grimes doifelse(argv, argc)
5339b50d902SRodney W. Grimes register char *argv[];
5349b50d902SRodney W. Grimes register int argc;
5359b50d902SRodney W. Grimes {
5369b50d902SRodney W. Grimes 	cycle {
5379b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
5389b50d902SRodney W. Grimes 			pbstr(argv[4]);
5399b50d902SRodney W. Grimes 		else if (argc == 6)
5409b50d902SRodney W. Grimes 			pbstr(argv[5]);
5419b50d902SRodney W. Grimes 		else if (argc > 6) {
5429b50d902SRodney W. Grimes 			argv += 3;
5439b50d902SRodney W. Grimes 			argc -= 3;
5449b50d902SRodney W. Grimes 			continue;
5459b50d902SRodney W. Grimes 		}
5469b50d902SRodney W. Grimes 		break;
5479b50d902SRodney W. Grimes 	}
5489b50d902SRodney W. Grimes }
5499b50d902SRodney W. Grimes 
5509b50d902SRodney W. Grimes /*
5519b50d902SRodney W. Grimes  * doinclude - include a given file.
5529b50d902SRodney W. Grimes  */
5539b50d902SRodney W. Grimes int
5549b50d902SRodney W. Grimes doincl(ifile)
5559b50d902SRodney W. Grimes char *ifile;
5569b50d902SRodney W. Grimes {
5579b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
5589b50d902SRodney W. Grimes 		oops("too many include files.");
5599b50d902SRodney W. Grimes 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
5609b50d902SRodney W. Grimes 		ilevel++;
5619b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
5629b50d902SRodney W. Grimes 		return (1);
5639b50d902SRodney W. Grimes 	}
5649b50d902SRodney W. Grimes 	else
5659b50d902SRodney W. Grimes 		return (0);
5669b50d902SRodney W. Grimes }
5679b50d902SRodney W. Grimes 
5689b50d902SRodney W. Grimes #ifdef EXTENDED
5699b50d902SRodney W. Grimes /*
5709b50d902SRodney W. Grimes  * dopaste - include a given file without any
5719b50d902SRodney W. Grimes  *           macro processing.
5729b50d902SRodney W. Grimes  */
5739b50d902SRodney W. Grimes int
5749b50d902SRodney W. Grimes dopaste(pfile)
5759b50d902SRodney W. Grimes char *pfile;
5769b50d902SRodney W. Grimes {
5779b50d902SRodney W. Grimes 	FILE *pf;
5789b50d902SRodney W. Grimes 	register int c;
5799b50d902SRodney W. Grimes 
5809b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
5819b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
5829b50d902SRodney W. Grimes 			putc(c, active);
5839b50d902SRodney W. Grimes 		(void) fclose(pf);
5849b50d902SRodney W. Grimes 		return (1);
5859b50d902SRodney W. Grimes 	}
5869b50d902SRodney W. Grimes 	else
5879b50d902SRodney W. Grimes 		return (0);
5889b50d902SRodney W. Grimes }
5899b50d902SRodney W. Grimes #endif
5909b50d902SRodney W. Grimes 
5919b50d902SRodney W. Grimes /*
5929b50d902SRodney W. Grimes  * dochq - change quote characters
5939b50d902SRodney W. Grimes  */
5949b50d902SRodney W. Grimes void
5959b50d902SRodney W. Grimes dochq(argv, argc)
5969b50d902SRodney W. Grimes register char *argv[];
5979b50d902SRodney W. Grimes register int argc;
5989b50d902SRodney W. Grimes {
5999b50d902SRodney W. Grimes 	if (argc > 2) {
6009b50d902SRodney W. Grimes 		if (*argv[2])
6019b50d902SRodney W. Grimes 			lquote = *argv[2];
6029b50d902SRodney W. Grimes 		if (argc > 3) {
6039b50d902SRodney W. Grimes 			if (*argv[3])
6049b50d902SRodney W. Grimes 				rquote = *argv[3];
6059b50d902SRodney W. Grimes 		}
6069b50d902SRodney W. Grimes 		else
6079b50d902SRodney W. Grimes 			rquote = lquote;
6089b50d902SRodney W. Grimes 	}
6099b50d902SRodney W. Grimes 	else {
6109b50d902SRodney W. Grimes 		lquote = LQUOTE;
6119b50d902SRodney W. Grimes 		rquote = RQUOTE;
6129b50d902SRodney W. Grimes 	}
6139b50d902SRodney W. Grimes }
6149b50d902SRodney W. Grimes 
6159b50d902SRodney W. Grimes /*
6169b50d902SRodney W. Grimes  * dochc - change comment characters
6179b50d902SRodney W. Grimes  */
6189b50d902SRodney W. Grimes void
6199b50d902SRodney W. Grimes dochc(argv, argc)
6209b50d902SRodney W. Grimes register char *argv[];
6219b50d902SRodney W. Grimes register int argc;
6229b50d902SRodney W. Grimes {
6239b50d902SRodney W. Grimes 	if (argc > 2) {
6249b50d902SRodney W. Grimes 		if (*argv[2])
6259b50d902SRodney W. Grimes 			scommt = *argv[2];
6269b50d902SRodney W. Grimes 		if (argc > 3) {
6279b50d902SRodney W. Grimes 			if (*argv[3])
6289b50d902SRodney W. Grimes 				ecommt = *argv[3];
6299b50d902SRodney W. Grimes 		}
6309b50d902SRodney W. Grimes 		else
6319b50d902SRodney W. Grimes 			ecommt = ECOMMT;
6329b50d902SRodney W. Grimes 	}
6339b50d902SRodney W. Grimes 	else {
6349b50d902SRodney W. Grimes 		scommt = SCOMMT;
6359b50d902SRodney W. Grimes 		ecommt = ECOMMT;
6369b50d902SRodney W. Grimes 	}
6379b50d902SRodney W. Grimes }
6389b50d902SRodney W. Grimes 
6399b50d902SRodney W. Grimes /*
6409b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
6419b50d902SRodney W. Grimes  */
6429b50d902SRodney W. Grimes void
6439b50d902SRodney W. Grimes dodiv(n)
6449b50d902SRodney W. Grimes register int n;
6459b50d902SRodney W. Grimes {
6469b50d902SRodney W. Grimes 	if (n < 0 || n >= MAXOUT)
6479b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
6489b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
6499b50d902SRodney W. Grimes 		m4temp[UNIQUE] = n + '0';
6509b50d902SRodney W. Grimes 		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
6519b50d902SRodney W. Grimes 			oops("%s: cannot divert.", m4temp);
6529b50d902SRodney W. Grimes 	}
6539b50d902SRodney W. Grimes 	oindex = n;
6549b50d902SRodney W. Grimes 	active = outfile[n];
6559b50d902SRodney W. Grimes }
6569b50d902SRodney W. Grimes 
6579b50d902SRodney W. Grimes /*
6589b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
6599b50d902SRodney W. Grimes  *              other outputs, in numerical order.
6609b50d902SRodney W. Grimes  */
6619b50d902SRodney W. Grimes void
6629b50d902SRodney W. Grimes doundiv(argv, argc)
6639b50d902SRodney W. Grimes register char *argv[];
6649b50d902SRodney W. Grimes register int argc;
6659b50d902SRodney W. Grimes {
6669b50d902SRodney W. Grimes 	register int ind;
6679b50d902SRodney W. Grimes 	register int n;
6689b50d902SRodney W. Grimes 
6699b50d902SRodney W. Grimes 	if (argc > 2) {
6709b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
6719b50d902SRodney W. Grimes 			n = atoi(argv[ind]);
6729b50d902SRodney W. Grimes 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
6739b50d902SRodney W. Grimes 				getdiv(n);
6749b50d902SRodney W. Grimes 
6759b50d902SRodney W. Grimes 		}
6769b50d902SRodney W. Grimes 	}
6779b50d902SRodney W. Grimes 	else
6789b50d902SRodney W. Grimes 		for (n = 1; n < MAXOUT; n++)
6799b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
6809b50d902SRodney W. Grimes 				getdiv(n);
6819b50d902SRodney W. Grimes }
6829b50d902SRodney W. Grimes 
6839b50d902SRodney W. Grimes /*
6849b50d902SRodney W. Grimes  * dosub - select substring
6859b50d902SRodney W. Grimes  */
6869b50d902SRodney W. Grimes void
6879b50d902SRodney W. Grimes dosub(argv, argc)
6889b50d902SRodney W. Grimes register char *argv[];
6899b50d902SRodney W. Grimes register int argc;
6909b50d902SRodney W. Grimes {
6919b50d902SRodney W. Grimes 	register char *ap, *fc, *k;
6929b50d902SRodney W. Grimes 	register int nc;
6939b50d902SRodney W. Grimes 
6949b50d902SRodney W. Grimes 	if (argc < 5)
6959b50d902SRodney W. Grimes 		nc = MAXTOK;
6969b50d902SRodney W. Grimes 	else
6979b50d902SRodney W. Grimes #ifdef EXPR
6989b50d902SRodney W. Grimes 		nc = expr(argv[4]);
6999b50d902SRodney W. Grimes #else
7009b50d902SRodney W. Grimes 		nc = atoi(argv[4]);
7019b50d902SRodney W. Grimes #endif
7029b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
7039b50d902SRodney W. Grimes #ifdef EXPR
7049b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
7059b50d902SRodney W. Grimes #else
7069b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
7079b50d902SRodney W. Grimes #endif
7089b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
7099b50d902SRodney W. Grimes 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
7109b50d902SRodney W. Grimes 			putback(*k);
7119b50d902SRodney W. Grimes }
7129b50d902SRodney W. Grimes 
7139b50d902SRodney W. Grimes /*
7149b50d902SRodney W. Grimes  * map:
7159b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
7169b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
7179b50d902SRodney W. Grimes  *
7189b50d902SRodney W. Grimes  * This is a standard implementation of map(s,from,to) function of ICON
7199b50d902SRodney W. Grimes  * language. Within mapvec, we replace every character of "from" with
7209b50d902SRodney W. Grimes  * the corresponding character in "to". If "to" is shorter than "from",
7219b50d902SRodney W. Grimes  * than the corresponding entries are null, which means that those
7229b50d902SRodney W. Grimes  * characters dissapear altogether. Furthermore, imagine
7239b50d902SRodney W. Grimes  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
7249b50d902SRodney W. Grimes  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
7259b50d902SRodney W. Grimes  * ultimately maps to `*'. In order to achieve this effect in an efficient
7269b50d902SRodney W. Grimes  * manner (i.e. without multiple passes over the destination string), we
7279b50d902SRodney W. Grimes  * loop over mapvec, starting with the initial source character. if the
7289b50d902SRodney W. Grimes  * character value (dch) in this location is different than the source
7299b50d902SRodney W. Grimes  * character (sch), sch becomes dch, once again to index into mapvec, until
7309b50d902SRodney W. Grimes  * the character value stabilizes (i.e. sch = dch, in other words
7319b50d902SRodney W. Grimes  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
7329b50d902SRodney W. Grimes  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
7339b50d902SRodney W. Grimes  * end, we restore mapvec* back to normal where mapvec[n] == n for
7349b50d902SRodney W. Grimes  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
7359b50d902SRodney W. Grimes  * about 5 times faster than any algorithm that makes multiple passes over
7369b50d902SRodney W. Grimes  * destination string.
7379b50d902SRodney W. Grimes  */
7389b50d902SRodney W. Grimes void
7399b50d902SRodney W. Grimes map(dest, src, from, to)
7409b50d902SRodney W. Grimes register char *dest;
7419b50d902SRodney W. Grimes register char *src;
7429b50d902SRodney W. Grimes register char *from;
7439b50d902SRodney W. Grimes register char *to;
7449b50d902SRodney W. Grimes {
7459b50d902SRodney W. Grimes 	register char *tmp;
7469b50d902SRodney W. Grimes 	register char sch, dch;
7479b50d902SRodney W. Grimes 	static char mapvec[128] = {
7489b50d902SRodney W. Grimes 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
7499b50d902SRodney W. Grimes 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
7509b50d902SRodney W. Grimes 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
7519b50d902SRodney W. Grimes 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
7529b50d902SRodney W. Grimes 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
7539b50d902SRodney W. Grimes 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
7549b50d902SRodney W. Grimes 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
7559b50d902SRodney W. Grimes 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
7569b50d902SRodney W. Grimes 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
7579b50d902SRodney W. Grimes 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
7589b50d902SRodney W. Grimes 		120, 121, 122, 123, 124, 125, 126, 127
7599b50d902SRodney W. Grimes 	};
7609b50d902SRodney W. Grimes 
7619b50d902SRodney W. Grimes 	if (*src) {
7629b50d902SRodney W. Grimes 		tmp = from;
7639b50d902SRodney W. Grimes 	/*
7649b50d902SRodney W. Grimes 	 * create a mapping between "from" and
7659b50d902SRodney W. Grimes 	 * "to"
7669b50d902SRodney W. Grimes 	 */
7679b50d902SRodney W. Grimes 		while (*from)
7689b50d902SRodney W. Grimes 			mapvec[*from++] = (*to) ? *to++ : (char) 0;
7699b50d902SRodney W. Grimes 
7709b50d902SRodney W. Grimes 		while (*src) {
7719b50d902SRodney W. Grimes 			sch = *src++;
7729b50d902SRodney W. Grimes 			dch = mapvec[sch];
7739b50d902SRodney W. Grimes 			while (dch != sch) {
7749b50d902SRodney W. Grimes 				sch = dch;
7759b50d902SRodney W. Grimes 				dch = mapvec[sch];
7769b50d902SRodney W. Grimes 			}
7779b50d902SRodney W. Grimes 			if (*dest = dch)
7789b50d902SRodney W. Grimes 				dest++;
7799b50d902SRodney W. Grimes 		}
7809b50d902SRodney W. Grimes 	/*
7819b50d902SRodney W. Grimes 	 * restore all the changed characters
7829b50d902SRodney W. Grimes 	 */
7839b50d902SRodney W. Grimes 		while (*tmp) {
7849b50d902SRodney W. Grimes 			mapvec[*tmp] = *tmp;
7859b50d902SRodney W. Grimes 			tmp++;
7869b50d902SRodney W. Grimes 		}
7879b50d902SRodney W. Grimes 	}
7889b50d902SRodney W. Grimes 	*dest = (char) 0;
7899b50d902SRodney W. Grimes }
790