xref: /openbsd/usr.bin/m4/eval.c (revision 25afcddb)
1*25afcddbSespie /*	$OpenBSD: eval.c,v 1.28 2000/07/27 17:44:32 espie Exp $	*/
2aa676ce1Smillert /*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1989, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Ozan Yigit at York University.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
19df930be7Sderaadt  * 3. All advertising materials mentioning features or use of this software
20df930be7Sderaadt  *    must display the following acknowledgement:
21df930be7Sderaadt  *	This product includes software developed by the University of
22df930be7Sderaadt  *	California, Berkeley and its contributors.
23df930be7Sderaadt  * 4. Neither the name of the University nor the names of its contributors
24df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
25df930be7Sderaadt  *    without specific prior written permission.
26df930be7Sderaadt  *
27df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df930be7Sderaadt  * SUCH DAMAGE.
38df930be7Sderaadt  */
39df930be7Sderaadt 
40df930be7Sderaadt #ifndef lint
41df930be7Sderaadt #if 0
42df930be7Sderaadt static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
43df930be7Sderaadt #else
44*25afcddbSespie static char rcsid[] = "$OpenBSD: eval.c,v 1.28 2000/07/27 17:44:32 espie Exp $";
45df930be7Sderaadt #endif
46df930be7Sderaadt #endif /* not lint */
47df930be7Sderaadt 
48df930be7Sderaadt /*
49df930be7Sderaadt  * eval.c
50df930be7Sderaadt  * Facility: m4 macro processor
51df930be7Sderaadt  * by: oz
52df930be7Sderaadt  */
53df930be7Sderaadt 
54df930be7Sderaadt #include <sys/types.h>
55df930be7Sderaadt #include <errno.h>
56df930be7Sderaadt #include <unistd.h>
57df930be7Sderaadt #include <stdio.h>
58df930be7Sderaadt #include <stdlib.h>
593f42598dSespie #include <stddef.h>
60df930be7Sderaadt #include <string.h>
61445b77f7Smillert #include <fcntl.h>
6281c2181eSespie #include <err.h>
63df930be7Sderaadt #include "mdef.h"
64df930be7Sderaadt #include "stdd.h"
65df930be7Sderaadt #include "extern.h"
66df930be7Sderaadt #include "pathnames.h"
67df930be7Sderaadt 
68bb34cd6cSespie static void	dodefn __P((const char *));
69bb34cd6cSespie static void	dopushdef __P((const char *, const char *));
70bb34cd6cSespie static void	dodump __P((const char *[], int));
71bb34cd6cSespie static void	doifelse __P((const char *[], int));
72bb34cd6cSespie static int	doincl __P((const char *));
73bb34cd6cSespie static int	dopaste __P((const char *));
74bb34cd6cSespie static void	dochq __P((const char *[], int));
75bb34cd6cSespie static void	dochc __P((const char *[], int));
76bb34cd6cSespie static void	dodiv __P((int));
77bb34cd6cSespie static void	doundiv __P((const char *[], int));
78bb34cd6cSespie static void	dosub __P((const char *[], int));
79bb34cd6cSespie static void	map __P((char *, const char *, const char *, const char *));
8087c5c065Sespie static const char *handledash __P((char *, char *, const char *));
81df930be7Sderaadt /*
82df930be7Sderaadt  * eval - evaluate built-in macros.
83df930be7Sderaadt  *	  argc - number of elements in argv.
84df930be7Sderaadt  *	  argv - element vector :
85df930be7Sderaadt  *			argv[0] = definition of a user
86df930be7Sderaadt  *				  macro or nil if built-in.
87df930be7Sderaadt  *			argv[1] = name of the macro or
88df930be7Sderaadt  *				  built-in.
89df930be7Sderaadt  *			argv[2] = parameters to user-defined
90df930be7Sderaadt  *			   .	  macro or built-in.
91df930be7Sderaadt  *			   .
92df930be7Sderaadt  *
93df930be7Sderaadt  * Note that the minimum value for argc is 3. A call in the form
94df930be7Sderaadt  * of macro-or-builtin() will result in:
95df930be7Sderaadt  *			argv[0] = nullstr
96df930be7Sderaadt  *			argv[1] = macro-or-builtin
97df930be7Sderaadt  *			argv[2] = nullstr
98df930be7Sderaadt  */
99df930be7Sderaadt 
100df930be7Sderaadt void
101df930be7Sderaadt eval(argv, argc, td)
102bb34cd6cSespie 	const char *argv[];
10353f6f6bfSespie 	int argc;
10453f6f6bfSespie 	int td;
105df930be7Sderaadt {
10653f6f6bfSespie 	int c, n;
107df930be7Sderaadt 	static int sysval = 0;
108df930be7Sderaadt 
109df930be7Sderaadt #ifdef DEBUG
110df930be7Sderaadt 	printf("argc = %d\n", argc);
111df930be7Sderaadt 	for (n = 0; n < argc; n++)
112df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
113df930be7Sderaadt #endif
114718b194dSespie 
115718b194dSespie 	if (td & RECDEF)
1160d3ffe1dSespie 		errx(1, "%s at line %lu: expanding recursive definition for %s",
1170d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE, argv[1]);
118df930be7Sderaadt  /*
119df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
120df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
121df930be7Sderaadt   * argc to avoid further checking..
122df930be7Sderaadt   */
123df930be7Sderaadt 	if (argc == 3 && !*(argv[2]))
124df930be7Sderaadt 		argc--;
125df930be7Sderaadt 
126718b194dSespie 	switch (td & TYPEMASK) {
127df930be7Sderaadt 
128df930be7Sderaadt 	case DEFITYPE:
129df930be7Sderaadt 		if (argc > 2)
130df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
131df930be7Sderaadt 		break;
132df930be7Sderaadt 
133df930be7Sderaadt 	case PUSDTYPE:
134df930be7Sderaadt 		if (argc > 2)
135df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
136df930be7Sderaadt 		break;
137df930be7Sderaadt 
138df930be7Sderaadt 	case DUMPTYPE:
139df930be7Sderaadt 		dodump(argv, argc);
140df930be7Sderaadt 		break;
141df930be7Sderaadt 
142df930be7Sderaadt 	case EXPRTYPE:
143df930be7Sderaadt 	/*
144df930be7Sderaadt 	 * doexpr - evaluate arithmetic
145df930be7Sderaadt 	 * expression
146df930be7Sderaadt 	 */
147df930be7Sderaadt 		if (argc > 2)
148df930be7Sderaadt 			pbnum(expr(argv[2]));
149df930be7Sderaadt 		break;
150df930be7Sderaadt 
151df930be7Sderaadt 	case IFELTYPE:
152df930be7Sderaadt 		if (argc > 4)
153df930be7Sderaadt 			doifelse(argv, argc);
154df930be7Sderaadt 		break;
155df930be7Sderaadt 
156df930be7Sderaadt 	case IFDFTYPE:
157df930be7Sderaadt 	/*
158df930be7Sderaadt 	 * doifdef - select one of two
159df930be7Sderaadt 	 * alternatives based on the existence of
160df930be7Sderaadt 	 * another definition
161df930be7Sderaadt 	 */
162df930be7Sderaadt 		if (argc > 3) {
163df930be7Sderaadt 			if (lookup(argv[2]) != nil)
164df930be7Sderaadt 				pbstr(argv[3]);
165df930be7Sderaadt 			else if (argc > 4)
166df930be7Sderaadt 				pbstr(argv[4]);
167df930be7Sderaadt 		}
168df930be7Sderaadt 		break;
169df930be7Sderaadt 
170df930be7Sderaadt 	case LENGTYPE:
171df930be7Sderaadt 	/*
172df930be7Sderaadt 	 * dolen - find the length of the
173df930be7Sderaadt 	 * argument
174df930be7Sderaadt 	 */
175df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
176df930be7Sderaadt 		break;
177df930be7Sderaadt 
178df930be7Sderaadt 	case INCRTYPE:
179df930be7Sderaadt 	/*
180df930be7Sderaadt 	 * doincr - increment the value of the
181df930be7Sderaadt 	 * argument
182df930be7Sderaadt 	 */
183df930be7Sderaadt 		if (argc > 2)
184df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
185df930be7Sderaadt 		break;
186df930be7Sderaadt 
187df930be7Sderaadt 	case DECRTYPE:
188df930be7Sderaadt 	/*
189df930be7Sderaadt 	 * dodecr - decrement the value of the
190df930be7Sderaadt 	 * argument
191df930be7Sderaadt 	 */
192df930be7Sderaadt 		if (argc > 2)
193df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
194df930be7Sderaadt 		break;
195df930be7Sderaadt 
196df930be7Sderaadt 	case SYSCTYPE:
197df930be7Sderaadt 	/*
198df930be7Sderaadt 	 * dosys - execute system command
199df930be7Sderaadt 	 */
200df930be7Sderaadt 		if (argc > 2)
201df930be7Sderaadt 			sysval = system(argv[2]);
202df930be7Sderaadt 		break;
203df930be7Sderaadt 
204df930be7Sderaadt 	case SYSVTYPE:
205df930be7Sderaadt 	/*
206df930be7Sderaadt 	 * dosysval - return value of the last
207df930be7Sderaadt 	 * system call.
208df930be7Sderaadt 	 *
209df930be7Sderaadt 	 */
210df930be7Sderaadt 		pbnum(sysval);
211df930be7Sderaadt 		break;
212df930be7Sderaadt 
213c91edbbbSespie 	case ESYSCMDTYPE:
214c91edbbbSespie 		if (argc > 2)
215c91edbbbSespie 			doesyscmd(argv[2]);
216c91edbbbSespie 	    	break;
217df930be7Sderaadt 	case INCLTYPE:
218df930be7Sderaadt 		if (argc > 2)
219df930be7Sderaadt 			if (!doincl(argv[2]))
2200d3ffe1dSespie 				err(1, "%s at line %lu: include(%s)",
2210d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
222df930be7Sderaadt 		break;
223df930be7Sderaadt 
224df930be7Sderaadt 	case SINCTYPE:
225df930be7Sderaadt 		if (argc > 2)
226df930be7Sderaadt 			(void) doincl(argv[2]);
227df930be7Sderaadt 		break;
228df930be7Sderaadt #ifdef EXTENDED
229df930be7Sderaadt 	case PASTTYPE:
230df930be7Sderaadt 		if (argc > 2)
231df930be7Sderaadt 			if (!dopaste(argv[2]))
2320d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
2330d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
234df930be7Sderaadt 		break;
235df930be7Sderaadt 
236df930be7Sderaadt 	case SPASTYPE:
237df930be7Sderaadt 		if (argc > 2)
238df930be7Sderaadt 			(void) dopaste(argv[2]);
239df930be7Sderaadt 		break;
240df930be7Sderaadt #endif
241df930be7Sderaadt 	case CHNQTYPE:
242df930be7Sderaadt 		dochq(argv, argc);
243df930be7Sderaadt 		break;
244df930be7Sderaadt 
245df930be7Sderaadt 	case CHNCTYPE:
246df930be7Sderaadt 		dochc(argv, argc);
247df930be7Sderaadt 		break;
248df930be7Sderaadt 
249df930be7Sderaadt 	case SUBSTYPE:
250df930be7Sderaadt 	/*
251df930be7Sderaadt 	 * dosub - select substring
252df930be7Sderaadt 	 *
253df930be7Sderaadt 	 */
254df930be7Sderaadt 		if (argc > 3)
255df930be7Sderaadt 			dosub(argv, argc);
256df930be7Sderaadt 		break;
257df930be7Sderaadt 
258df930be7Sderaadt 	case SHIFTYPE:
259df930be7Sderaadt 	/*
260df930be7Sderaadt 	 * doshift - push back all arguments
261df930be7Sderaadt 	 * except the first one (i.e. skip
262df930be7Sderaadt 	 * argv[2])
263df930be7Sderaadt 	 */
264df930be7Sderaadt 		if (argc > 3) {
265df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
2663a73db8cSderaadt 				pbstr(rquote);
267df930be7Sderaadt 				pbstr(argv[n]);
2683a73db8cSderaadt 				pbstr(lquote);
269aa676ce1Smillert 				putback(COMMA);
270df930be7Sderaadt 			}
2713a73db8cSderaadt 			pbstr(rquote);
272df930be7Sderaadt 			pbstr(argv[3]);
2733a73db8cSderaadt 			pbstr(lquote);
274df930be7Sderaadt 		}
275df930be7Sderaadt 		break;
276df930be7Sderaadt 
277df930be7Sderaadt 	case DIVRTYPE:
278df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
279df930be7Sderaadt 			dodiv(n);
280df930be7Sderaadt 		else {
281df930be7Sderaadt 			active = stdout;
282df930be7Sderaadt 			oindex = 0;
283df930be7Sderaadt 		}
284df930be7Sderaadt 		break;
285df930be7Sderaadt 
286df930be7Sderaadt 	case UNDVTYPE:
287df930be7Sderaadt 		doundiv(argv, argc);
288df930be7Sderaadt 		break;
289df930be7Sderaadt 
290df930be7Sderaadt 	case DIVNTYPE:
291df930be7Sderaadt 	/*
292df930be7Sderaadt 	 * dodivnum - return the number of
293df930be7Sderaadt 	 * current output diversion
294df930be7Sderaadt 	 */
295df930be7Sderaadt 		pbnum(oindex);
296df930be7Sderaadt 		break;
297df930be7Sderaadt 
298df930be7Sderaadt 	case UNDFTYPE:
299df930be7Sderaadt 	/*
300df930be7Sderaadt 	 * doundefine - undefine a previously
301df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
302df930be7Sderaadt 	 */
303df930be7Sderaadt 		if (argc > 2)
304df930be7Sderaadt 			for (n = 2; n < argc; n++)
305df930be7Sderaadt 				remhash(argv[n], ALL);
306df930be7Sderaadt 		break;
307df930be7Sderaadt 
308df930be7Sderaadt 	case POPDTYPE:
309df930be7Sderaadt 	/*
310df930be7Sderaadt 	 * dopopdef - remove the topmost
311df930be7Sderaadt 	 * definitions of macro(s) or m4
312df930be7Sderaadt 	 * keyword(s).
313df930be7Sderaadt 	 */
314df930be7Sderaadt 		if (argc > 2)
315df930be7Sderaadt 			for (n = 2; n < argc; n++)
316df930be7Sderaadt 				remhash(argv[n], TOP);
317df930be7Sderaadt 		break;
318df930be7Sderaadt 
319df930be7Sderaadt 	case MKTMTYPE:
320df930be7Sderaadt 	/*
321df930be7Sderaadt 	 * dotemp - create a temporary file
322df930be7Sderaadt 	 */
32301e71e69Sespie 		if (argc > 2) {
32401e71e69Sespie 			int fd;
325bb34cd6cSespie 			char *temp;
32601e71e69Sespie 
327bb34cd6cSespie 			temp = xstrdup(argv[2]);
328bb34cd6cSespie 
329bb34cd6cSespie 			fd = mkstemp(temp);
33001e71e69Sespie 			if (fd == -1)
3310d3ffe1dSespie 				err(1,
3320d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
3330d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
33401e71e69Sespie 			close(fd);
335bb34cd6cSespie 			pbstr(temp);
336bb34cd6cSespie 			free(temp);
33701e71e69Sespie 		}
338df930be7Sderaadt 		break;
339df930be7Sderaadt 
340df930be7Sderaadt 	case TRNLTYPE:
341df930be7Sderaadt 	/*
342df930be7Sderaadt 	 * dotranslit - replace all characters in
343df930be7Sderaadt 	 * the source string that appears in the
344df930be7Sderaadt 	 * "from" string with the corresponding
345df930be7Sderaadt 	 * characters in the "to" string.
346df930be7Sderaadt 	 */
347df930be7Sderaadt 		if (argc > 3) {
3487d3e0b6bSderaadt 			char temp[STRSPMAX+1];
349df930be7Sderaadt 			if (argc > 4)
350df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
351df930be7Sderaadt 			else
352df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
353df930be7Sderaadt 			pbstr(temp);
3547d3e0b6bSderaadt 		} else if (argc > 2)
355df930be7Sderaadt 			pbstr(argv[2]);
356df930be7Sderaadt 		break;
357df930be7Sderaadt 
358df930be7Sderaadt 	case INDXTYPE:
359df930be7Sderaadt 	/*
360df930be7Sderaadt 	 * doindex - find the index of the second
361df930be7Sderaadt 	 * argument string in the first argument
362df930be7Sderaadt 	 * string. -1 if not present.
363df930be7Sderaadt 	 */
364df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
365df930be7Sderaadt 		break;
366df930be7Sderaadt 
367df930be7Sderaadt 	case ERRPTYPE:
368df930be7Sderaadt 	/*
369df930be7Sderaadt 	 * doerrp - print the arguments to stderr
370df930be7Sderaadt 	 * file
371df930be7Sderaadt 	 */
372df930be7Sderaadt 		if (argc > 2) {
373df930be7Sderaadt 			for (n = 2; n < argc; n++)
374df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
375df930be7Sderaadt 			fprintf(stderr, "\n");
376df930be7Sderaadt 		}
377df930be7Sderaadt 		break;
378df930be7Sderaadt 
379df930be7Sderaadt 	case DNLNTYPE:
380df930be7Sderaadt 	/*
381df930be7Sderaadt 	 * dodnl - eat-up-to and including
382df930be7Sderaadt 	 * newline
383df930be7Sderaadt 	 */
384df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
385df930be7Sderaadt 			;
386df930be7Sderaadt 		break;
387df930be7Sderaadt 
388df930be7Sderaadt 	case M4WRTYPE:
389df930be7Sderaadt 	/*
390df930be7Sderaadt 	 * dom4wrap - set up for
391df930be7Sderaadt 	 * wrap-up/wind-down activity
392df930be7Sderaadt 	 */
393df930be7Sderaadt 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
394df930be7Sderaadt 		break;
395df930be7Sderaadt 
396df930be7Sderaadt 	case EXITTYPE:
397df930be7Sderaadt 	/*
398df930be7Sderaadt 	 * doexit - immediate exit from m4.
399df930be7Sderaadt 	 */
400df930be7Sderaadt 		killdiv();
401df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
402df930be7Sderaadt 		break;
403df930be7Sderaadt 
404df930be7Sderaadt 	case DEFNTYPE:
405df930be7Sderaadt 		if (argc > 2)
406df930be7Sderaadt 			for (n = 2; n < argc; n++)
407df930be7Sderaadt 				dodefn(argv[n]);
408df930be7Sderaadt 		break;
409df930be7Sderaadt 
410b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
411b8161682Sespie 		if (argc > 2)
412b8161682Sespie 			doindir(argv, argc);
413b8161682Sespie 		break;
414b8161682Sespie 
415b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
416b8161682Sespie 		if (argc > 2)
417b8161682Sespie 			dobuiltin(argv, argc);
418b8161682Sespie 		break;
419b8161682Sespie 
420b8161682Sespie 	case PATSTYPE:
421b8161682Sespie 		if (argc > 2)
422b8161682Sespie 			dopatsubst(argv, argc);
423b8161682Sespie 		break;
424b8161682Sespie 	case REGEXPTYPE:
425b8161682Sespie 		if (argc > 2)
426b8161682Sespie 			doregexp(argv, argc);
427b8161682Sespie 		break;
428b8161682Sespie 	case LINETYPE:
429b8161682Sespie 		doprintlineno(infile+ilevel);
430b8161682Sespie 		break;
431b8161682Sespie 	case FILENAMETYPE:
432b8161682Sespie 		doprintfilename(infile+ilevel);
433b8161682Sespie 		break;
434423624b7Sespie 	case SELFTYPE:
435423624b7Sespie 		pbstr(rquote);
436423624b7Sespie 		pbstr(argv[1]);
437423624b7Sespie 		pbstr(lquote);
438423624b7Sespie 		break;
439df930be7Sderaadt 	default:
4400d3ffe1dSespie 		errx(1, "%s at line %lu: eval: major botch.",
4410d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE);
442df930be7Sderaadt 		break;
443df930be7Sderaadt 	}
444df930be7Sderaadt }
445df930be7Sderaadt 
446df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
447df930be7Sderaadt 
448df930be7Sderaadt /*
449df930be7Sderaadt  * expand - user-defined macro expansion
450df930be7Sderaadt  */
451df930be7Sderaadt void
452df930be7Sderaadt expand(argv, argc)
453bb34cd6cSespie 	const char *argv[];
45453f6f6bfSespie 	int argc;
455df930be7Sderaadt {
456bb34cd6cSespie 	const char *t;
457bb34cd6cSespie 	const char *p;
45853f6f6bfSespie 	int n;
45953f6f6bfSespie 	int argno;
460df930be7Sderaadt 
461df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
462df930be7Sderaadt 	p = t;
463df930be7Sderaadt 	while (*p)
464df930be7Sderaadt 		p++;
465df930be7Sderaadt 	p--;			       /* last character of defn */
466df930be7Sderaadt 	while (p > t) {
467df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
468df930be7Sderaadt 			putback(*p);
469df930be7Sderaadt 		else {
470df930be7Sderaadt 			switch (*p) {
471df930be7Sderaadt 
472df930be7Sderaadt 			case '#':
473df930be7Sderaadt 				pbnum(argc - 2);
474df930be7Sderaadt 				break;
475df930be7Sderaadt 			case '0':
476df930be7Sderaadt 			case '1':
477df930be7Sderaadt 			case '2':
478df930be7Sderaadt 			case '3':
479df930be7Sderaadt 			case '4':
480df930be7Sderaadt 			case '5':
481df930be7Sderaadt 			case '6':
482df930be7Sderaadt 			case '7':
483df930be7Sderaadt 			case '8':
484df930be7Sderaadt 			case '9':
485df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
486df930be7Sderaadt 					pbstr(argv[argno + 1]);
487df930be7Sderaadt 				break;
488df930be7Sderaadt 			case '*':
489df930be7Sderaadt 				for (n = argc - 1; n > 2; n--) {
490df930be7Sderaadt 					pbstr(argv[n]);
491aa676ce1Smillert 					putback(COMMA);
492df930be7Sderaadt 				}
493df930be7Sderaadt 				pbstr(argv[2]);
494df930be7Sderaadt 				break;
495aa676ce1Smillert                         case '@':
496aa676ce1Smillert                                 for (n = argc - 1; n > 2; n--) {
497aa676ce1Smillert                                         pbstr(rquote);
498aa676ce1Smillert                                         pbstr(argv[n]);
499aa676ce1Smillert                                         pbstr(lquote);
500aa676ce1Smillert 					putback(COMMA);
501aa676ce1Smillert                                 }
502aa676ce1Smillert 				pbstr(rquote);
503aa676ce1Smillert                                 pbstr(argv[2]);
504aa676ce1Smillert 				pbstr(lquote);
505aa676ce1Smillert                                 break;
506df930be7Sderaadt 			default:
507df930be7Sderaadt 				putback(*p);
508df930be7Sderaadt 				putback('$');
509df930be7Sderaadt 				break;
510df930be7Sderaadt 			}
511df930be7Sderaadt 			p--;
512df930be7Sderaadt 		}
513df930be7Sderaadt 		p--;
514df930be7Sderaadt 	}
515df930be7Sderaadt 	if (p == t)		       /* do last character */
516df930be7Sderaadt 		putback(*p);
517df930be7Sderaadt }
518df930be7Sderaadt 
519df930be7Sderaadt /*
520df930be7Sderaadt  * dodefine - install definition in the table
521df930be7Sderaadt  */
522df930be7Sderaadt void
523df930be7Sderaadt dodefine(name, defn)
524bb34cd6cSespie 	const char *name;
525bb34cd6cSespie 	const char *defn;
526df930be7Sderaadt {
52753f6f6bfSespie 	ndptr p;
528df930be7Sderaadt 
529df930be7Sderaadt 	if (!*name)
5300d3ffe1dSespie 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
5310d3ffe1dSespie 		    CURRENT_LINE);
532df930be7Sderaadt 	if ((p = lookup(name)) == nil)
533df930be7Sderaadt 		p = addent(name);
534df930be7Sderaadt 	else if (p->defn != null)
535df930be7Sderaadt 		free((char *) p->defn);
536df930be7Sderaadt 	if (!*defn)
537df930be7Sderaadt 		p->defn = null;
538df930be7Sderaadt 	else
539df930be7Sderaadt 		p->defn = xstrdup(defn);
540df930be7Sderaadt 	p->type = MACRTYPE;
541718b194dSespie 	if (STREQ(name, defn))
542718b194dSespie 		p->type |= RECDEF;
543df930be7Sderaadt }
544df930be7Sderaadt 
545df930be7Sderaadt /*
546df930be7Sderaadt  * dodefn - push back a quoted definition of
547df930be7Sderaadt  *      the given name.
548df930be7Sderaadt  */
549bb34cd6cSespie static void
550df930be7Sderaadt dodefn(name)
551bb34cd6cSespie 	const char *name;
552df930be7Sderaadt {
55353f6f6bfSespie 	ndptr p;
554df930be7Sderaadt 
555df930be7Sderaadt 	if ((p = lookup(name)) != nil && p->defn != null) {
5563a73db8cSderaadt 		pbstr(rquote);
557df930be7Sderaadt 		pbstr(p->defn);
5583a73db8cSderaadt 		pbstr(lquote);
559df930be7Sderaadt 	}
560df930be7Sderaadt }
561df930be7Sderaadt 
562df930be7Sderaadt /*
563df930be7Sderaadt  * dopushdef - install a definition in the hash table
564df930be7Sderaadt  *      without removing a previous definition. Since
565df930be7Sderaadt  *      each new entry is entered in *front* of the
566df930be7Sderaadt  *      hash bucket, it hides a previous definition from
567df930be7Sderaadt  *      lookup.
568df930be7Sderaadt  */
569bb34cd6cSespie static void
570df930be7Sderaadt dopushdef(name, defn)
571bb34cd6cSespie 	const char *name;
572bb34cd6cSespie 	const char *defn;
573df930be7Sderaadt {
57453f6f6bfSespie 	ndptr p;
575df930be7Sderaadt 
576df930be7Sderaadt 	if (!*name)
5770d3ffe1dSespie 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
5780d3ffe1dSespie 		    CURRENT_LINE);
579df930be7Sderaadt 	p = addent(name);
580df930be7Sderaadt 	if (!*defn)
581df930be7Sderaadt 		p->defn = null;
582df930be7Sderaadt 	else
583df930be7Sderaadt 		p->defn = xstrdup(defn);
584df930be7Sderaadt 	p->type = MACRTYPE;
585718b194dSespie 	if (STREQ(name, defn))
586718b194dSespie 		p->type |= RECDEF;
587df930be7Sderaadt }
588df930be7Sderaadt 
589df930be7Sderaadt /*
590df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
591df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
592df930be7Sderaadt  *      hash table is dumped.
593df930be7Sderaadt  */
594bb34cd6cSespie static void
595df930be7Sderaadt dodump(argv, argc)
596bb34cd6cSespie 	const char *argv[];
59753f6f6bfSespie 	int argc;
598df930be7Sderaadt {
59953f6f6bfSespie 	int n;
600df930be7Sderaadt 	ndptr p;
601df930be7Sderaadt 
602df930be7Sderaadt 	if (argc > 2) {
603df930be7Sderaadt 		for (n = 2; n < argc; n++)
604df930be7Sderaadt 			if ((p = lookup(argv[n])) != nil)
605df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
606df930be7Sderaadt 					p->defn);
6077d3e0b6bSderaadt 	} else {
608df930be7Sderaadt 		for (n = 0; n < HASHSIZE; n++)
609df930be7Sderaadt 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
610df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
611df930be7Sderaadt 					p->defn);
612df930be7Sderaadt 	}
613df930be7Sderaadt }
614df930be7Sderaadt 
615df930be7Sderaadt /*
616df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
617df930be7Sderaadt  */
618bb34cd6cSespie static void
619df930be7Sderaadt doifelse(argv, argc)
620bb34cd6cSespie 	const char *argv[];
62153f6f6bfSespie 	int argc;
622df930be7Sderaadt {
623df930be7Sderaadt 	cycle {
624df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
625df930be7Sderaadt 			pbstr(argv[4]);
626df930be7Sderaadt 		else if (argc == 6)
627df930be7Sderaadt 			pbstr(argv[5]);
628df930be7Sderaadt 		else if (argc > 6) {
629df930be7Sderaadt 			argv += 3;
630df930be7Sderaadt 			argc -= 3;
631df930be7Sderaadt 			continue;
632df930be7Sderaadt 		}
633df930be7Sderaadt 		break;
634df930be7Sderaadt 	}
635df930be7Sderaadt }
636df930be7Sderaadt 
637df930be7Sderaadt /*
638df930be7Sderaadt  * doinclude - include a given file.
639df930be7Sderaadt  */
640bb34cd6cSespie static int
641df930be7Sderaadt doincl(ifile)
642bb34cd6cSespie 	const char *ifile;
643df930be7Sderaadt {
644df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
6450d3ffe1dSespie 		errx(1, "%s at line %lu: too many include files.",
6460d3ffe1dSespie 		    CURRENT_NAME, CURRENT_LINE);
6470d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
648df930be7Sderaadt 		ilevel++;
649df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
650df930be7Sderaadt 		return (1);
6517d3e0b6bSderaadt 	} else
652df930be7Sderaadt 		return (0);
653df930be7Sderaadt }
654df930be7Sderaadt 
655df930be7Sderaadt #ifdef EXTENDED
656df930be7Sderaadt /*
657df930be7Sderaadt  * dopaste - include a given file without any
658df930be7Sderaadt  *           macro processing.
659df930be7Sderaadt  */
660bb34cd6cSespie static int
661df930be7Sderaadt dopaste(pfile)
662bb34cd6cSespie 	const char *pfile;
663df930be7Sderaadt {
664df930be7Sderaadt 	FILE *pf;
66553f6f6bfSespie 	int c;
666df930be7Sderaadt 
667df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
668df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
669df930be7Sderaadt 			putc(c, active);
670df930be7Sderaadt 		(void) fclose(pf);
671df930be7Sderaadt 		return (1);
6727d3e0b6bSderaadt 	} else
673df930be7Sderaadt 		return (0);
674df930be7Sderaadt }
675df930be7Sderaadt #endif
676df930be7Sderaadt 
677df930be7Sderaadt /*
678df930be7Sderaadt  * dochq - change quote characters
679df930be7Sderaadt  */
680bb34cd6cSespie static void
681df930be7Sderaadt dochq(argv, argc)
682bb34cd6cSespie 	const char *argv[];
68353f6f6bfSespie 	int argc;
684df930be7Sderaadt {
68587c5c065Sespie 	/* In gnu-m4 mode, having two empty arguments means no quotes at
68687c5c065Sespie 	 * all.  */
68787c5c065Sespie 	if (mimic_gnu) {
68887c5c065Sespie 		if (argc > 3 && !*argv[2] && !*argv[3]) {
68987c5c065Sespie 			lquote[0] = EOS;
69087c5c065Sespie 			rquote[0] = EOS;
69187c5c065Sespie 			return;
69287c5c065Sespie 		}
69387c5c065Sespie 	}
694df930be7Sderaadt 	if (argc > 2) {
69518a1973bSderaadt 		if (*argv[2])
696b81b15b2Sespie 			strlcpy(lquote, argv[2], sizeof(lquote));
69718a1973bSderaadt 		else {
69818a1973bSderaadt 			lquote[0] = LQUOTE;
699f0484631Sespie 			lquote[1] = EOS;
70018a1973bSderaadt 		}
701df930be7Sderaadt 		if (argc > 3) {
702df930be7Sderaadt 			if (*argv[3])
703b81b15b2Sespie 				strlcpy(rquote, argv[3], sizeof(rquote));
7047d3e0b6bSderaadt 		} else
70529a0bfdcSderaadt 			strcpy(rquote, lquote);
7067d3e0b6bSderaadt 	} else {
707f0484631Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
708f0484631Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
709df930be7Sderaadt 	}
710df930be7Sderaadt }
711df930be7Sderaadt 
712df930be7Sderaadt /*
713df930be7Sderaadt  * dochc - change comment characters
714df930be7Sderaadt  */
715bb34cd6cSespie static void
716df930be7Sderaadt dochc(argv, argc)
717bb34cd6cSespie 	const char *argv[];
71853f6f6bfSespie 	int argc;
719df930be7Sderaadt {
720df930be7Sderaadt 	if (argc > 2) {
721df930be7Sderaadt 		if (*argv[2])
722b81b15b2Sespie 			strlcpy(scommt, argv[2], sizeof(scommt));
723df930be7Sderaadt 		if (argc > 3) {
724df930be7Sderaadt 			if (*argv[3])
725b81b15b2Sespie 				strlcpy(ecommt, argv[3], sizeof(ecommt));
726df930be7Sderaadt 		}
727df930be7Sderaadt 		else
728f0484631Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
729df930be7Sderaadt 	}
730df930be7Sderaadt 	else {
731f0484631Sespie 		scommt[0] = SCOMMT, scommt[1] = EOS;
732f0484631Sespie 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
733df930be7Sderaadt 	}
734df930be7Sderaadt }
735df930be7Sderaadt 
736df930be7Sderaadt /*
737df930be7Sderaadt  * dodivert - divert the output to a temporary file
738df930be7Sderaadt  */
739bb34cd6cSespie static void
740df930be7Sderaadt dodiv(n)
74153f6f6bfSespie 	int n;
742df930be7Sderaadt {
743445b77f7Smillert 	int fd;
744445b77f7Smillert 
7457d3e0b6bSderaadt 	oindex = n;
746*25afcddbSespie 	if (n >= maxout) {
747*25afcddbSespie 		if (mimic_gnu)
748*25afcddbSespie 			resizedivs(n + 10);
749*25afcddbSespie 		else
750*25afcddbSespie 			n = 0;		/* bitbucket */
751*25afcddbSespie     	}
752*25afcddbSespie 
753*25afcddbSespie 	if (n < 0)
754df930be7Sderaadt 		n = 0;		       /* bitbucket */
755df930be7Sderaadt 	if (outfile[n] == NULL) {
7563f42598dSespie 		char fname[] = _PATH_DIVNAME;
7573f42598dSespie 
7583f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
7593f42598dSespie 			(outfile[n] = fdopen(fd, "w+")) == NULL)
7603f42598dSespie 				err(1, "%s: cannot divert", fname);
7613f42598dSespie 		if (unlink(fname) == -1)
7623f42598dSespie 			err(1, "%s: cannot unlink", fname);
763df930be7Sderaadt 	}
764df930be7Sderaadt 	active = outfile[n];
765df930be7Sderaadt }
766df930be7Sderaadt 
767df930be7Sderaadt /*
768df930be7Sderaadt  * doundivert - undivert a specified output, or all
769df930be7Sderaadt  *              other outputs, in numerical order.
770df930be7Sderaadt  */
771bb34cd6cSespie static void
772df930be7Sderaadt doundiv(argv, argc)
773bb34cd6cSespie 	const char *argv[];
77453f6f6bfSespie 	int argc;
775df930be7Sderaadt {
77653f6f6bfSespie 	int ind;
77753f6f6bfSespie 	int n;
778df930be7Sderaadt 
779df930be7Sderaadt 	if (argc > 2) {
780df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
781df930be7Sderaadt 			n = atoi(argv[ind]);
782*25afcddbSespie 			if (n > 0 && n < maxout && outfile[n] != NULL)
783df930be7Sderaadt 				getdiv(n);
784df930be7Sderaadt 
785df930be7Sderaadt 		}
786df930be7Sderaadt 	}
787df930be7Sderaadt 	else
788*25afcddbSespie 		for (n = 1; n < maxout; n++)
789df930be7Sderaadt 			if (outfile[n] != NULL)
790df930be7Sderaadt 				getdiv(n);
791df930be7Sderaadt }
792df930be7Sderaadt 
793df930be7Sderaadt /*
794df930be7Sderaadt  * dosub - select substring
795df930be7Sderaadt  */
796bb34cd6cSespie static void
797df930be7Sderaadt dosub(argv, argc)
798bb34cd6cSespie 	const char *argv[];
79953f6f6bfSespie 	int argc;
800df930be7Sderaadt {
801bb34cd6cSespie 	const char *ap, *fc, *k;
80253f6f6bfSespie 	int nc;
803df930be7Sderaadt 
804df930be7Sderaadt 	if (argc < 5)
805df930be7Sderaadt 		nc = MAXTOK;
806df930be7Sderaadt 	else
807df930be7Sderaadt #ifdef EXPR
808df930be7Sderaadt 		nc = expr(argv[4]);
809df930be7Sderaadt #else
810df930be7Sderaadt 		nc = atoi(argv[4]);
811df930be7Sderaadt #endif
812df930be7Sderaadt 	ap = argv[2];		       /* target string */
813df930be7Sderaadt #ifdef EXPR
814df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
815df930be7Sderaadt #else
816df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
817df930be7Sderaadt #endif
818df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
819df930be7Sderaadt 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
820df930be7Sderaadt 			putback(*k);
821df930be7Sderaadt }
822df930be7Sderaadt 
823df930be7Sderaadt /*
824df930be7Sderaadt  * map:
825df930be7Sderaadt  * map every character of s1 that is specified in from
826df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
827df930be7Sderaadt  *
828df930be7Sderaadt  * This is a standard implementation of map(s,from,to) function of ICON
829df930be7Sderaadt  * language. Within mapvec, we replace every character of "from" with
830df930be7Sderaadt  * the corresponding character in "to". If "to" is shorter than "from",
831df930be7Sderaadt  * than the corresponding entries are null, which means that those
832df930be7Sderaadt  * characters dissapear altogether. Furthermore, imagine
833df930be7Sderaadt  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
834df930be7Sderaadt  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
835df930be7Sderaadt  * ultimately maps to `*'. In order to achieve this effect in an efficient
836df930be7Sderaadt  * manner (i.e. without multiple passes over the destination string), we
837df930be7Sderaadt  * loop over mapvec, starting with the initial source character. if the
838df930be7Sderaadt  * character value (dch) in this location is different than the source
839df930be7Sderaadt  * character (sch), sch becomes dch, once again to index into mapvec, until
840df930be7Sderaadt  * the character value stabilizes (i.e. sch = dch, in other words
841df930be7Sderaadt  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
842df930be7Sderaadt  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
843df930be7Sderaadt  * end, we restore mapvec* back to normal where mapvec[n] == n for
844df930be7Sderaadt  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
845df930be7Sderaadt  * about 5 times faster than any algorithm that makes multiple passes over
846df930be7Sderaadt  * destination string.
847df930be7Sderaadt  */
848bb34cd6cSespie static void
849df930be7Sderaadt map(dest, src, from, to)
85053f6f6bfSespie 	char *dest;
851bb34cd6cSespie 	const char *src;
852bb34cd6cSespie 	const char *from;
853bb34cd6cSespie 	const char *to;
854df930be7Sderaadt {
855bb34cd6cSespie 	const char *tmp;
856ee3599c7Sespie 	unsigned char sch, dch;
85787c5c065Sespie 	static char frombis[257];
85887c5c065Sespie 	static char tobis[257];
859ee3599c7Sespie 	static unsigned char mapvec[256] = {
860ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
861ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
862ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
863ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
864ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
865ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
866ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
867ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
868ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
869ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
870ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
871ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
872ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
873ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
874ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
875ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
876ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
877ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
878df930be7Sderaadt 	};
879df930be7Sderaadt 
880df930be7Sderaadt 	if (*src) {
88187c5c065Sespie 		if (mimic_gnu) {
88287c5c065Sespie 			/*
88387c5c065Sespie 			 * expand character ranges on the fly
88487c5c065Sespie 			 */
88587c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
88687c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
88787c5c065Sespie 		}
888df930be7Sderaadt 		tmp = from;
889df930be7Sderaadt 	/*
890df930be7Sderaadt 	 * create a mapping between "from" and
891df930be7Sderaadt 	 * "to"
892df930be7Sderaadt 	 */
893df930be7Sderaadt 		while (*from)
894ee3599c7Sespie 			mapvec[(unsigned char)(*from++)] = (*to) ?
895ee3599c7Sespie 				(unsigned char)(*to++) : 0;
896df930be7Sderaadt 
897df930be7Sderaadt 		while (*src) {
898ee3599c7Sespie 			sch = (unsigned char)(*src++);
899df930be7Sderaadt 			dch = mapvec[sch];
900df930be7Sderaadt 			while (dch != sch) {
901df930be7Sderaadt 				sch = dch;
902df930be7Sderaadt 				dch = mapvec[sch];
903df930be7Sderaadt 			}
904ee3599c7Sespie 			if ((*dest = (char)dch))
905df930be7Sderaadt 				dest++;
906df930be7Sderaadt 		}
907df930be7Sderaadt 	/*
908df930be7Sderaadt 	 * restore all the changed characters
909df930be7Sderaadt 	 */
910df930be7Sderaadt 		while (*tmp) {
911ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
912df930be7Sderaadt 			tmp++;
913df930be7Sderaadt 		}
914df930be7Sderaadt 	}
915ee3599c7Sespie 	*dest = '\0';
916df930be7Sderaadt }
91787c5c065Sespie 
91887c5c065Sespie 
91987c5c065Sespie /*
92087c5c065Sespie  * handledash:
92187c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
92287c5c065Sespie  * on the way.
92387c5c065Sespie  */
92487c5c065Sespie static const char *
92587c5c065Sespie handledash(buffer, end, src)
92687c5c065Sespie 	char *buffer;
92787c5c065Sespie 	char *end;
92887c5c065Sespie 	const char *src;
92987c5c065Sespie {
93087c5c065Sespie 	char *p;
93187c5c065Sespie 
93287c5c065Sespie 	p = buffer;
93387c5c065Sespie 	while(*src) {
93487c5c065Sespie 		if (src[1] == '-' && src[2]) {
93587c5c065Sespie 			unsigned char i;
93687c5c065Sespie 			for (i = (unsigned char)src[0];
93787c5c065Sespie 			    i <= (unsigned char)src[2]; i++) {
93887c5c065Sespie 				*p++ = i;
93987c5c065Sespie 				if (p == end) {
94087c5c065Sespie 					*p = '\0';
94187c5c065Sespie 					return buffer;
94287c5c065Sespie 				}
94387c5c065Sespie 			}
94487c5c065Sespie 			src += 3;
94587c5c065Sespie 		} else
94687c5c065Sespie 			*p++ = *src++;
94787c5c065Sespie 		if (p == end)
94887c5c065Sespie 			break;
94987c5c065Sespie 	}
95087c5c065Sespie 	*p = '\0';
95187c5c065Sespie 	return buffer;
95287c5c065Sespie }
95387c5c065Sespie 
954