xref: /openbsd/usr.bin/m4/eval.c (revision ad93774e)
1*ad93774eSespie /*	$OpenBSD: eval.c,v 1.53 2005/01/21 19:11:02 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.
19f75387cbSmillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36df930be7Sderaadt #ifndef lint
37df930be7Sderaadt #if 0
38df930be7Sderaadt static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
39df930be7Sderaadt #else
40*ad93774eSespie static char rcsid[] = "$OpenBSD: eval.c,v 1.53 2005/01/21 19:11:02 espie Exp $";
41df930be7Sderaadt #endif
42df930be7Sderaadt #endif /* not lint */
43df930be7Sderaadt 
44df930be7Sderaadt /*
45df930be7Sderaadt  * eval.c
46df930be7Sderaadt  * Facility: m4 macro processor
47df930be7Sderaadt  * by: oz
48df930be7Sderaadt  */
49df930be7Sderaadt 
50df930be7Sderaadt #include <sys/types.h>
51df930be7Sderaadt #include <errno.h>
52df930be7Sderaadt #include <unistd.h>
53df930be7Sderaadt #include <stdio.h>
54df930be7Sderaadt #include <stdlib.h>
553f42598dSespie #include <stddef.h>
56df930be7Sderaadt #include <string.h>
57445b77f7Smillert #include <fcntl.h>
5881c2181eSespie #include <err.h>
59df930be7Sderaadt #include "mdef.h"
60df930be7Sderaadt #include "stdd.h"
61df930be7Sderaadt #include "extern.h"
62df930be7Sderaadt #include "pathnames.h"
63df930be7Sderaadt 
64c72b5b24Smillert static void	dodefn(const char *);
65c72b5b24Smillert static void	dopushdef(const char *, const char *);
66c72b5b24Smillert static void	dodump(const char *[], int);
67c72b5b24Smillert static void	dotrace(const char *[], int, int);
68c72b5b24Smillert static void	doifelse(const char *[], int);
69c72b5b24Smillert static int	doincl(const char *);
70c72b5b24Smillert static int	dopaste(const char *);
71c72b5b24Smillert static void	gnu_dochq(const char *[], int);
72c72b5b24Smillert static void	dochq(const char *[], int);
73c72b5b24Smillert static void	gnu_dochc(const char *[], int);
74c72b5b24Smillert static void	dochc(const char *[], int);
75c72b5b24Smillert static void	dodiv(int);
76c72b5b24Smillert static void	doundiv(const char *[], int);
77c72b5b24Smillert static void	dosub(const char *[], int);
78c72b5b24Smillert static void	map(char *, const char *, const char *, const char *);
79c72b5b24Smillert static const char *handledash(char *, char *, const char *);
80c72b5b24Smillert static void	expand_builtin(const char *[], int, int);
81c72b5b24Smillert static void	expand_macro(const char *[], int);
823509e8ffSespie static void	dump_one_def(const char *, struct macro_definition *);
8308f7f207Sespie 
8499f77b33Sespie unsigned long	expansion_id;
8508f7f207Sespie 
86df930be7Sderaadt /*
8708f7f207Sespie  * eval - eval all macros and builtins calls
88054026c0Sespie  *	  argc - number of elements in argv.
89054026c0Sespie  *	  argv - element vector :
90054026c0Sespie  *			argv[0] = definition of a user
913509e8ffSespie  *				  macro or NULL if built-in.
92054026c0Sespie  *			argv[1] = name of the macro or
93054026c0Sespie  *				  built-in.
94054026c0Sespie  *			argv[2] = parameters to user-defined
95054026c0Sespie  *			   .	  macro or built-in.
96054026c0Sespie  *			   .
97054026c0Sespie  *
98054026c0Sespie  * A call in the form of macro-or-builtin() will result in:
99054026c0Sespie  *			argv[0] = nullstr
100054026c0Sespie  *			argv[1] = macro-or-builtin
101054026c0Sespie  *			argv[2] = nullstr
102054026c0Sespie  *
103054026c0Sespie  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
10408f7f207Sespie  */
10508f7f207Sespie void
106dde05c5fSespie eval(const char *argv[], int argc, int td, int is_traced)
10708f7f207Sespie {
1084dac505dSespie 	ssize_t mark = -1;
1094dac505dSespie 
11099f77b33Sespie 	expansion_id++;
11108f7f207Sespie 	if (td & RECDEF)
11208f7f207Sespie 		errx(1, "%s at line %lu: expanding recursive definition for %s",
11308f7f207Sespie 			CURRENT_NAME, CURRENT_LINE, argv[1]);
114dde05c5fSespie 	if (is_traced)
1154dac505dSespie 		mark = trace(argv, argc, infile+ilevel);
11608f7f207Sespie 	if (td == MACRTYPE)
11708f7f207Sespie 		expand_macro(argv, argc);
11808f7f207Sespie 	else
11908f7f207Sespie 		expand_builtin(argv, argc, td);
1204dac505dSespie     	if (mark != -1)
1214dac505dSespie 		finish_trace(mark);
12208f7f207Sespie }
12308f7f207Sespie 
12408f7f207Sespie /*
12508f7f207Sespie  * expand_builtin - evaluate built-in macros.
126df930be7Sderaadt  */
127df930be7Sderaadt void
1288e061d4bSespie expand_builtin(const char *argv[], int argc, int td)
129df930be7Sderaadt {
13053f6f6bfSespie 	int c, n;
131054026c0Sespie 	int ac;
132df930be7Sderaadt 	static int sysval = 0;
133df930be7Sderaadt 
134df930be7Sderaadt #ifdef DEBUG
135df930be7Sderaadt 	printf("argc = %d\n", argc);
136df930be7Sderaadt 	for (n = 0; n < argc; n++)
137df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
13828728804Sespie 	fflush(stdout);
139df930be7Sderaadt #endif
140718b194dSespie 
141df930be7Sderaadt  /*
142df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
143df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
144df930be7Sderaadt   * argc to avoid further checking..
145df930be7Sderaadt   */
146054026c0Sespie   	ac = argc;
147054026c0Sespie 
148df930be7Sderaadt 	if (argc == 3 && !*(argv[2]))
149df930be7Sderaadt 		argc--;
150df930be7Sderaadt 
151718b194dSespie 	switch (td & TYPEMASK) {
152df930be7Sderaadt 
153df930be7Sderaadt 	case DEFITYPE:
154df930be7Sderaadt 		if (argc > 2)
155df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
156df930be7Sderaadt 		break;
157df930be7Sderaadt 
158df930be7Sderaadt 	case PUSDTYPE:
159df930be7Sderaadt 		if (argc > 2)
160df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
161df930be7Sderaadt 		break;
162df930be7Sderaadt 
163df930be7Sderaadt 	case DUMPTYPE:
164df930be7Sderaadt 		dodump(argv, argc);
165df930be7Sderaadt 		break;
166df930be7Sderaadt 
16734970243Sespie 	case TRACEONTYPE:
16834970243Sespie 		dotrace(argv, argc, 1);
16934970243Sespie 		break;
17034970243Sespie 
17134970243Sespie 	case TRACEOFFTYPE:
17234970243Sespie 		dotrace(argv, argc, 0);
17334970243Sespie 		break;
17434970243Sespie 
175df930be7Sderaadt 	case EXPRTYPE:
176df930be7Sderaadt 	/*
177df930be7Sderaadt 	 * doexpr - evaluate arithmetic
178df930be7Sderaadt 	 * expression
179df930be7Sderaadt 	 */
180df930be7Sderaadt 		if (argc > 2)
181df930be7Sderaadt 			pbnum(expr(argv[2]));
182df930be7Sderaadt 		break;
183df930be7Sderaadt 
184df930be7Sderaadt 	case IFELTYPE:
185df930be7Sderaadt 		if (argc > 4)
186df930be7Sderaadt 			doifelse(argv, argc);
187df930be7Sderaadt 		break;
188df930be7Sderaadt 
189df930be7Sderaadt 	case IFDFTYPE:
190df930be7Sderaadt 	/*
191df930be7Sderaadt 	 * doifdef - select one of two
192df930be7Sderaadt 	 * alternatives based on the existence of
193df930be7Sderaadt 	 * another definition
194df930be7Sderaadt 	 */
195df930be7Sderaadt 		if (argc > 3) {
1963509e8ffSespie 			if (lookup_macro_definition(argv[2]) != NULL)
197df930be7Sderaadt 				pbstr(argv[3]);
198df930be7Sderaadt 			else if (argc > 4)
199df930be7Sderaadt 				pbstr(argv[4]);
200df930be7Sderaadt 		}
201df930be7Sderaadt 		break;
202df930be7Sderaadt 
203df930be7Sderaadt 	case LENGTYPE:
204df930be7Sderaadt 	/*
205df930be7Sderaadt 	 * dolen - find the length of the
206df930be7Sderaadt 	 * argument
207df930be7Sderaadt 	 */
208df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
209df930be7Sderaadt 		break;
210df930be7Sderaadt 
211df930be7Sderaadt 	case INCRTYPE:
212df930be7Sderaadt 	/*
213df930be7Sderaadt 	 * doincr - increment the value of the
214df930be7Sderaadt 	 * argument
215df930be7Sderaadt 	 */
216df930be7Sderaadt 		if (argc > 2)
217df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
218df930be7Sderaadt 		break;
219df930be7Sderaadt 
220df930be7Sderaadt 	case DECRTYPE:
221df930be7Sderaadt 	/*
222df930be7Sderaadt 	 * dodecr - decrement the value of the
223df930be7Sderaadt 	 * argument
224df930be7Sderaadt 	 */
225df930be7Sderaadt 		if (argc > 2)
226df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
227df930be7Sderaadt 		break;
228df930be7Sderaadt 
229df930be7Sderaadt 	case SYSCTYPE:
230df930be7Sderaadt 	/*
231df930be7Sderaadt 	 * dosys - execute system command
232df930be7Sderaadt 	 */
233df930be7Sderaadt 		if (argc > 2)
234df930be7Sderaadt 			sysval = system(argv[2]);
235df930be7Sderaadt 		break;
236df930be7Sderaadt 
237df930be7Sderaadt 	case SYSVTYPE:
238df930be7Sderaadt 	/*
239df930be7Sderaadt 	 * dosysval - return value of the last
240df930be7Sderaadt 	 * system call.
241df930be7Sderaadt 	 *
242df930be7Sderaadt 	 */
243df930be7Sderaadt 		pbnum(sysval);
244df930be7Sderaadt 		break;
245df930be7Sderaadt 
246c91edbbbSespie 	case ESYSCMDTYPE:
247c91edbbbSespie 		if (argc > 2)
248c91edbbbSespie 			doesyscmd(argv[2]);
249c91edbbbSespie 	    	break;
250df930be7Sderaadt 	case INCLTYPE:
251df930be7Sderaadt 		if (argc > 2)
252df930be7Sderaadt 			if (!doincl(argv[2]))
2530d3ffe1dSespie 				err(1, "%s at line %lu: include(%s)",
2540d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
255df930be7Sderaadt 		break;
256df930be7Sderaadt 
257df930be7Sderaadt 	case SINCTYPE:
258df930be7Sderaadt 		if (argc > 2)
259df930be7Sderaadt 			(void) doincl(argv[2]);
260df930be7Sderaadt 		break;
261df930be7Sderaadt #ifdef EXTENDED
262df930be7Sderaadt 	case PASTTYPE:
263df930be7Sderaadt 		if (argc > 2)
264df930be7Sderaadt 			if (!dopaste(argv[2]))
2650d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
2660d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
267df930be7Sderaadt 		break;
268df930be7Sderaadt 
269df930be7Sderaadt 	case SPASTYPE:
270df930be7Sderaadt 		if (argc > 2)
271df930be7Sderaadt 			(void) dopaste(argv[2]);
272df930be7Sderaadt 		break;
273df930be7Sderaadt #endif
274df930be7Sderaadt 	case CHNQTYPE:
275054026c0Sespie 		if (mimic_gnu)
276054026c0Sespie 			gnu_dochq(argv, ac);
277054026c0Sespie 		else
278df930be7Sderaadt 			dochq(argv, argc);
279df930be7Sderaadt 		break;
280df930be7Sderaadt 
281df930be7Sderaadt 	case CHNCTYPE:
282054026c0Sespie 		if (mimic_gnu)
283054026c0Sespie 			gnu_dochc(argv, ac);
284054026c0Sespie 		else
285df930be7Sderaadt 			dochc(argv, argc);
286df930be7Sderaadt 		break;
287df930be7Sderaadt 
288df930be7Sderaadt 	case SUBSTYPE:
289df930be7Sderaadt 	/*
290df930be7Sderaadt 	 * dosub - select substring
291df930be7Sderaadt 	 *
292df930be7Sderaadt 	 */
293df930be7Sderaadt 		if (argc > 3)
294df930be7Sderaadt 			dosub(argv, argc);
295df930be7Sderaadt 		break;
296df930be7Sderaadt 
297df930be7Sderaadt 	case SHIFTYPE:
298df930be7Sderaadt 	/*
299df930be7Sderaadt 	 * doshift - push back all arguments
300df930be7Sderaadt 	 * except the first one (i.e. skip
301df930be7Sderaadt 	 * argv[2])
302df930be7Sderaadt 	 */
303df930be7Sderaadt 		if (argc > 3) {
304df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
3053a73db8cSderaadt 				pbstr(rquote);
306df930be7Sderaadt 				pbstr(argv[n]);
3073a73db8cSderaadt 				pbstr(lquote);
308aa676ce1Smillert 				putback(COMMA);
309df930be7Sderaadt 			}
3103a73db8cSderaadt 			pbstr(rquote);
311df930be7Sderaadt 			pbstr(argv[3]);
3123a73db8cSderaadt 			pbstr(lquote);
313df930be7Sderaadt 		}
314df930be7Sderaadt 		break;
315df930be7Sderaadt 
316df930be7Sderaadt 	case DIVRTYPE:
317df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
318df930be7Sderaadt 			dodiv(n);
319df930be7Sderaadt 		else {
320df930be7Sderaadt 			active = stdout;
321df930be7Sderaadt 			oindex = 0;
322df930be7Sderaadt 		}
323df930be7Sderaadt 		break;
324df930be7Sderaadt 
325df930be7Sderaadt 	case UNDVTYPE:
326df930be7Sderaadt 		doundiv(argv, argc);
327df930be7Sderaadt 		break;
328df930be7Sderaadt 
329df930be7Sderaadt 	case DIVNTYPE:
330df930be7Sderaadt 	/*
331df930be7Sderaadt 	 * dodivnum - return the number of
332df930be7Sderaadt 	 * current output diversion
333df930be7Sderaadt 	 */
334df930be7Sderaadt 		pbnum(oindex);
335df930be7Sderaadt 		break;
336df930be7Sderaadt 
337df930be7Sderaadt 	case UNDFTYPE:
338df930be7Sderaadt 	/*
339df930be7Sderaadt 	 * doundefine - undefine a previously
340df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
341df930be7Sderaadt 	 */
342df930be7Sderaadt 		if (argc > 2)
343df930be7Sderaadt 			for (n = 2; n < argc; n++)
3443509e8ffSespie 				macro_undefine(argv[n]);
345df930be7Sderaadt 		break;
346df930be7Sderaadt 
347df930be7Sderaadt 	case POPDTYPE:
348df930be7Sderaadt 	/*
349df930be7Sderaadt 	 * dopopdef - remove the topmost
350df930be7Sderaadt 	 * definitions of macro(s) or m4
351df930be7Sderaadt 	 * keyword(s).
352df930be7Sderaadt 	 */
353df930be7Sderaadt 		if (argc > 2)
354df930be7Sderaadt 			for (n = 2; n < argc; n++)
3553509e8ffSespie 				macro_popdef(argv[n]);
356df930be7Sderaadt 		break;
357df930be7Sderaadt 
358df930be7Sderaadt 	case MKTMTYPE:
359df930be7Sderaadt 	/*
360df930be7Sderaadt 	 * dotemp - create a temporary file
361df930be7Sderaadt 	 */
36201e71e69Sespie 		if (argc > 2) {
36301e71e69Sespie 			int fd;
364bb34cd6cSespie 			char *temp;
36501e71e69Sespie 
366bb34cd6cSespie 			temp = xstrdup(argv[2]);
367bb34cd6cSespie 
368bb34cd6cSespie 			fd = mkstemp(temp);
36901e71e69Sespie 			if (fd == -1)
3700d3ffe1dSespie 				err(1,
3710d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
3720d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
37301e71e69Sespie 			close(fd);
374bb34cd6cSespie 			pbstr(temp);
375bb34cd6cSespie 			free(temp);
37601e71e69Sespie 		}
377df930be7Sderaadt 		break;
378df930be7Sderaadt 
379df930be7Sderaadt 	case TRNLTYPE:
380df930be7Sderaadt 	/*
381df930be7Sderaadt 	 * dotranslit - replace all characters in
382df930be7Sderaadt 	 * the source string that appears in the
383df930be7Sderaadt 	 * "from" string with the corresponding
384df930be7Sderaadt 	 * characters in the "to" string.
385df930be7Sderaadt 	 */
386df930be7Sderaadt 		if (argc > 3) {
38728728804Sespie 			char *temp;
38828728804Sespie 
389f6169a2cSespie 			temp = xalloc(strlen(argv[2])+1, NULL);
390df930be7Sderaadt 			if (argc > 4)
391df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
392df930be7Sderaadt 			else
393df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
394df930be7Sderaadt 			pbstr(temp);
39528728804Sespie 			free(temp);
3967d3e0b6bSderaadt 		} else if (argc > 2)
397df930be7Sderaadt 			pbstr(argv[2]);
398df930be7Sderaadt 		break;
399df930be7Sderaadt 
400df930be7Sderaadt 	case INDXTYPE:
401df930be7Sderaadt 	/*
402df930be7Sderaadt 	 * doindex - find the index of the second
403df930be7Sderaadt 	 * argument string in the first argument
404df930be7Sderaadt 	 * string. -1 if not present.
405df930be7Sderaadt 	 */
406df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
407df930be7Sderaadt 		break;
408df930be7Sderaadt 
409df930be7Sderaadt 	case ERRPTYPE:
410df930be7Sderaadt 	/*
411df930be7Sderaadt 	 * doerrp - print the arguments to stderr
412df930be7Sderaadt 	 * file
413df930be7Sderaadt 	 */
414df930be7Sderaadt 		if (argc > 2) {
415df930be7Sderaadt 			for (n = 2; n < argc; n++)
416df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
417df930be7Sderaadt 			fprintf(stderr, "\n");
418df930be7Sderaadt 		}
419df930be7Sderaadt 		break;
420df930be7Sderaadt 
421df930be7Sderaadt 	case DNLNTYPE:
422df930be7Sderaadt 	/*
423df930be7Sderaadt 	 * dodnl - eat-up-to and including
424df930be7Sderaadt 	 * newline
425df930be7Sderaadt 	 */
426df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
427df930be7Sderaadt 			;
428df930be7Sderaadt 		break;
429df930be7Sderaadt 
430df930be7Sderaadt 	case M4WRTYPE:
431df930be7Sderaadt 	/*
432df930be7Sderaadt 	 * dom4wrap - set up for
433df930be7Sderaadt 	 * wrap-up/wind-down activity
434df930be7Sderaadt 	 */
435df930be7Sderaadt 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
436df930be7Sderaadt 		break;
437df930be7Sderaadt 
438df930be7Sderaadt 	case EXITTYPE:
439df930be7Sderaadt 	/*
440df930be7Sderaadt 	 * doexit - immediate exit from m4.
441df930be7Sderaadt 	 */
442df930be7Sderaadt 		killdiv();
443df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
444df930be7Sderaadt 		break;
445df930be7Sderaadt 
446df930be7Sderaadt 	case DEFNTYPE:
447df930be7Sderaadt 		if (argc > 2)
448df930be7Sderaadt 			for (n = 2; n < argc; n++)
449df930be7Sderaadt 				dodefn(argv[n]);
450df930be7Sderaadt 		break;
451df930be7Sderaadt 
452b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
453b8161682Sespie 		if (argc > 2)
454b8161682Sespie 			doindir(argv, argc);
455b8161682Sespie 		break;
456b8161682Sespie 
457b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
458b8161682Sespie 		if (argc > 2)
459b8161682Sespie 			dobuiltin(argv, argc);
460b8161682Sespie 		break;
461b8161682Sespie 
462b8161682Sespie 	case PATSTYPE:
463b8161682Sespie 		if (argc > 2)
464b8161682Sespie 			dopatsubst(argv, argc);
465b8161682Sespie 		break;
466b8161682Sespie 	case REGEXPTYPE:
467b8161682Sespie 		if (argc > 2)
468b8161682Sespie 			doregexp(argv, argc);
469b8161682Sespie 		break;
470b8161682Sespie 	case LINETYPE:
471b8161682Sespie 		doprintlineno(infile+ilevel);
472b8161682Sespie 		break;
473b8161682Sespie 	case FILENAMETYPE:
474b8161682Sespie 		doprintfilename(infile+ilevel);
475b8161682Sespie 		break;
476423624b7Sespie 	case SELFTYPE:
477423624b7Sespie 		pbstr(rquote);
478423624b7Sespie 		pbstr(argv[1]);
479423624b7Sespie 		pbstr(lquote);
480423624b7Sespie 		break;
481df930be7Sderaadt 	default:
4820d3ffe1dSespie 		errx(1, "%s at line %lu: eval: major botch.",
4830d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE);
484df930be7Sderaadt 		break;
485df930be7Sderaadt 	}
486df930be7Sderaadt }
487df930be7Sderaadt 
488df930be7Sderaadt /*
48908f7f207Sespie  * expand_macro - user-defined macro expansion
490df930be7Sderaadt  */
491df930be7Sderaadt void
4928e061d4bSespie expand_macro(const char *argv[], int argc)
493df930be7Sderaadt {
494bb34cd6cSespie 	const char *t;
495bb34cd6cSespie 	const char *p;
49653f6f6bfSespie 	int n;
49753f6f6bfSespie 	int argno;
498df930be7Sderaadt 
499df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
500df930be7Sderaadt 	p = t;
501df930be7Sderaadt 	while (*p)
502df930be7Sderaadt 		p++;
503df930be7Sderaadt 	p--;			       /* last character of defn */
504df930be7Sderaadt 	while (p > t) {
505df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
506dd84b4a6Sespie 			PUTBACK(*p);
507df930be7Sderaadt 		else {
508df930be7Sderaadt 			switch (*p) {
509df930be7Sderaadt 
510df930be7Sderaadt 			case '#':
511df930be7Sderaadt 				pbnum(argc - 2);
512df930be7Sderaadt 				break;
513df930be7Sderaadt 			case '0':
514df930be7Sderaadt 			case '1':
515df930be7Sderaadt 			case '2':
516df930be7Sderaadt 			case '3':
517df930be7Sderaadt 			case '4':
518df930be7Sderaadt 			case '5':
519df930be7Sderaadt 			case '6':
520df930be7Sderaadt 			case '7':
521df930be7Sderaadt 			case '8':
522df930be7Sderaadt 			case '9':
523df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
524df930be7Sderaadt 					pbstr(argv[argno + 1]);
525df930be7Sderaadt 				break;
526df930be7Sderaadt 			case '*':
527faa30e49Sespie 				if (argc > 2) {
528df930be7Sderaadt 					for (n = argc - 1; n > 2; n--) {
529df930be7Sderaadt 						pbstr(argv[n]);
530aa676ce1Smillert 						putback(COMMA);
531df930be7Sderaadt 					}
532df930be7Sderaadt 					pbstr(argv[2]);
533faa30e49Sespie 			    	}
534df930be7Sderaadt 				break;
535aa676ce1Smillert                         case '@':
536faa30e49Sespie 				if (argc > 2) {
537aa676ce1Smillert 					for (n = argc - 1; n > 2; n--) {
538aa676ce1Smillert 						pbstr(rquote);
539aa676ce1Smillert 						pbstr(argv[n]);
540aa676ce1Smillert 						pbstr(lquote);
541aa676ce1Smillert 						putback(COMMA);
542aa676ce1Smillert 					}
543aa676ce1Smillert 					pbstr(rquote);
544aa676ce1Smillert 					pbstr(argv[2]);
545aa676ce1Smillert 					pbstr(lquote);
546faa30e49Sespie 				}
547aa676ce1Smillert                                 break;
548df930be7Sderaadt 			default:
549dd84b4a6Sespie 				PUTBACK(*p);
550dd84b4a6Sespie 				PUTBACK('$');
551df930be7Sderaadt 				break;
552df930be7Sderaadt 			}
553df930be7Sderaadt 			p--;
554df930be7Sderaadt 		}
555df930be7Sderaadt 		p--;
556df930be7Sderaadt 	}
557df930be7Sderaadt 	if (p == t)		       /* do last character */
558dd84b4a6Sespie 		PUTBACK(*p);
559df930be7Sderaadt }
560df930be7Sderaadt 
5615ddad5ccSespie 
562df930be7Sderaadt /*
5635ddad5ccSespie  * dodefine - install definition in the table
5645ddad5ccSespie  */
5655ddad5ccSespie void
5665ddad5ccSespie dodefine(const char *name, const char *defn)
5675ddad5ccSespie {
5685ddad5ccSespie 	if (!*name)
5695ddad5ccSespie 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
5705ddad5ccSespie 		    CURRENT_LINE);
5713509e8ffSespie 	macro_define(name, defn);
572df930be7Sderaadt }
573df930be7Sderaadt 
574df930be7Sderaadt /*
575df930be7Sderaadt  * dodefn - push back a quoted definition of
576df930be7Sderaadt  *      the given name.
577df930be7Sderaadt  */
578bb34cd6cSespie static void
5798e061d4bSespie dodefn(const char *name)
580df930be7Sderaadt {
5813509e8ffSespie 	struct macro_definition *p;
582df930be7Sderaadt 
5833509e8ffSespie 	if ((p = lookup_macro_definition(name)) != NULL) {
5845ddad5ccSespie 		if ((p->type & TYPEMASK) == MACRTYPE) {
5853a73db8cSderaadt 			pbstr(rquote);
586df930be7Sderaadt 			pbstr(p->defn);
5873a73db8cSderaadt 			pbstr(lquote);
5885ddad5ccSespie 		} else {
5895ddad5ccSespie 			pbstr(p->defn);
590f8b42d48Sespie 			pbstr(BUILTIN_MARKER);
591f8b42d48Sespie 		}
592df930be7Sderaadt 	}
593df930be7Sderaadt }
594df930be7Sderaadt 
595df930be7Sderaadt /*
596df930be7Sderaadt  * dopushdef - install a definition in the hash table
597df930be7Sderaadt  *      without removing a previous definition. Since
598df930be7Sderaadt  *      each new entry is entered in *front* of the
599df930be7Sderaadt  *      hash bucket, it hides a previous definition from
600df930be7Sderaadt  *      lookup.
601df930be7Sderaadt  */
602bb34cd6cSespie static void
6038e061d4bSespie dopushdef(const char *name, const char *defn)
604df930be7Sderaadt {
605df930be7Sderaadt 	if (!*name)
6060d3ffe1dSespie 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
6070d3ffe1dSespie 		    CURRENT_LINE);
6083509e8ffSespie 	macro_pushdef(name, defn);
609df930be7Sderaadt }
610df930be7Sderaadt 
611df930be7Sderaadt /*
612dd0682a2Sespie  * dump_one_def - dump the specified definition.
613dd0682a2Sespie  */
614dd0682a2Sespie static void
6153509e8ffSespie dump_one_def(const char *name, struct macro_definition *p)
616dd0682a2Sespie {
617*ad93774eSespie 	if (!traceout)
618*ad93774eSespie 		traceout = stderr;
6195191fa0aSespie 	if (mimic_gnu) {
6205191fa0aSespie 		if ((p->type & TYPEMASK) == MACRTYPE)
6213509e8ffSespie 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
6225191fa0aSespie 		else {
6233509e8ffSespie 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
6245191fa0aSespie 	    	}
6255191fa0aSespie 	} else
6263509e8ffSespie 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
627dd0682a2Sespie }
628dd0682a2Sespie 
629dd0682a2Sespie /*
630df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
631df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
632df930be7Sderaadt  *      hash table is dumped.
633df930be7Sderaadt  */
634bb34cd6cSespie static void
6358e061d4bSespie dodump(const char *argv[], int argc)
636df930be7Sderaadt {
63753f6f6bfSespie 	int n;
6383509e8ffSespie 	struct macro_definition *p;
639df930be7Sderaadt 
640df930be7Sderaadt 	if (argc > 2) {
641df930be7Sderaadt 		for (n = 2; n < argc; n++)
6423509e8ffSespie 			if ((p = lookup_macro_definition(argv[n])) != NULL)
6433509e8ffSespie 				dump_one_def(argv[n], p);
6443509e8ffSespie 	} else
6453509e8ffSespie 		macro_for_all(dump_one_def);
646df930be7Sderaadt }
647df930be7Sderaadt 
648df930be7Sderaadt /*
64934970243Sespie  * dotrace - mark some macros as traced/untraced depending upon on.
65034970243Sespie  */
65134970243Sespie static void
6528e061d4bSespie dotrace(const char *argv[], int argc, int on)
65334970243Sespie {
65434970243Sespie 	int n;
65534970243Sespie 
65634970243Sespie 	if (argc > 2) {
65734970243Sespie 		for (n = 2; n < argc; n++)
65834970243Sespie 			mark_traced(argv[n], on);
65934970243Sespie 	} else
66034970243Sespie 		mark_traced(NULL, on);
66134970243Sespie }
66234970243Sespie 
66334970243Sespie /*
664df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
665df930be7Sderaadt  */
666bb34cd6cSespie static void
6678e061d4bSespie doifelse(const char *argv[], int argc)
668df930be7Sderaadt {
669df930be7Sderaadt 	cycle {
670df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
671df930be7Sderaadt 			pbstr(argv[4]);
672df930be7Sderaadt 		else if (argc == 6)
673df930be7Sderaadt 			pbstr(argv[5]);
674df930be7Sderaadt 		else if (argc > 6) {
675df930be7Sderaadt 			argv += 3;
676df930be7Sderaadt 			argc -= 3;
677df930be7Sderaadt 			continue;
678df930be7Sderaadt 		}
679df930be7Sderaadt 		break;
680df930be7Sderaadt 	}
681df930be7Sderaadt }
682df930be7Sderaadt 
683df930be7Sderaadt /*
684df930be7Sderaadt  * doinclude - include a given file.
685df930be7Sderaadt  */
686bb34cd6cSespie static int
6878e061d4bSespie doincl(const char *ifile)
688df930be7Sderaadt {
689df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
6900d3ffe1dSespie 		errx(1, "%s at line %lu: too many include files.",
6910d3ffe1dSespie 		    CURRENT_NAME, CURRENT_LINE);
6920d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
693df930be7Sderaadt 		ilevel++;
694df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
695df930be7Sderaadt 		return (1);
6967d3e0b6bSderaadt 	} else
697df930be7Sderaadt 		return (0);
698df930be7Sderaadt }
699df930be7Sderaadt 
700df930be7Sderaadt #ifdef EXTENDED
701df930be7Sderaadt /*
702df930be7Sderaadt  * dopaste - include a given file without any
703df930be7Sderaadt  *           macro processing.
704df930be7Sderaadt  */
705bb34cd6cSespie static int
7068e061d4bSespie dopaste(const char *pfile)
707df930be7Sderaadt {
708df930be7Sderaadt 	FILE *pf;
70953f6f6bfSespie 	int c;
710df930be7Sderaadt 
711df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
712aec72266Sespie 		if (synch_lines)
713aec72266Sespie 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
714df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
715df930be7Sderaadt 			putc(c, active);
716df930be7Sderaadt 		(void) fclose(pf);
717aec72266Sespie 		emit_synchline();
718df930be7Sderaadt 		return (1);
7197d3e0b6bSderaadt 	} else
720df930be7Sderaadt 		return (0);
721df930be7Sderaadt }
722df930be7Sderaadt #endif
723df930be7Sderaadt 
724054026c0Sespie static void
7258e061d4bSespie gnu_dochq(const char *argv[], int ac)
726054026c0Sespie {
727054026c0Sespie 	/* In gnu-m4 mode, the only way to restore quotes is to have no
728054026c0Sespie 	 * arguments at all. */
729054026c0Sespie 	if (ac == 2) {
730054026c0Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
731054026c0Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
732054026c0Sespie 	} else {
733054026c0Sespie 		strlcpy(lquote, argv[2], sizeof(lquote));
734054026c0Sespie 		if(ac > 3)
735054026c0Sespie 			strlcpy(rquote, argv[3], sizeof(rquote));
736054026c0Sespie 		else
737054026c0Sespie 			rquote[0] = EOS;
738054026c0Sespie 	}
739054026c0Sespie }
740054026c0Sespie 
741df930be7Sderaadt /*
742df930be7Sderaadt  * dochq - change quote characters
743df930be7Sderaadt  */
744bb34cd6cSespie static void
7458e061d4bSespie dochq(const char *argv[], int argc)
746df930be7Sderaadt {
747df930be7Sderaadt 	if (argc > 2) {
74818a1973bSderaadt 		if (*argv[2])
749b81b15b2Sespie 			strlcpy(lquote, argv[2], sizeof(lquote));
75018a1973bSderaadt 		else {
75118a1973bSderaadt 			lquote[0] = LQUOTE;
752f0484631Sespie 			lquote[1] = EOS;
75318a1973bSderaadt 		}
754df930be7Sderaadt 		if (argc > 3) {
755df930be7Sderaadt 			if (*argv[3])
756b81b15b2Sespie 				strlcpy(rquote, argv[3], sizeof(rquote));
7577d3e0b6bSderaadt 		} else
7583ffdcb07Sespie 			strlcpy(rquote, lquote, sizeof(rquote));
7597d3e0b6bSderaadt 	} else {
760f0484631Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
761f0484631Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
762df930be7Sderaadt 	}
763df930be7Sderaadt }
764df930be7Sderaadt 
765054026c0Sespie static void
7668e061d4bSespie gnu_dochc(const char *argv[], int ac)
767054026c0Sespie {
768054026c0Sespie 	/* In gnu-m4 mode, no arguments mean no comment
769054026c0Sespie 	 * arguments at all. */
770054026c0Sespie 	if (ac == 2) {
771054026c0Sespie 		scommt[0] = EOS;
772054026c0Sespie 		ecommt[0] = EOS;
773054026c0Sespie 	} else {
774054026c0Sespie 		if (*argv[2])
775054026c0Sespie 			strlcpy(scommt, argv[2], sizeof(scommt));
776054026c0Sespie 		else
777054026c0Sespie 			scommt[0] = SCOMMT, scommt[1] = EOS;
778054026c0Sespie 		if(ac > 3 && *argv[3])
779054026c0Sespie 			strlcpy(ecommt, argv[3], sizeof(ecommt));
780054026c0Sespie 		else
781054026c0Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
782054026c0Sespie 	}
783054026c0Sespie }
784df930be7Sderaadt /*
785df930be7Sderaadt  * dochc - change comment characters
786df930be7Sderaadt  */
787bb34cd6cSespie static void
7888e061d4bSespie dochc(const char *argv[], int argc)
789df930be7Sderaadt {
790df930be7Sderaadt 	if (argc > 2) {
791df930be7Sderaadt 		if (*argv[2])
792b81b15b2Sespie 			strlcpy(scommt, argv[2], sizeof(scommt));
793df930be7Sderaadt 		if (argc > 3) {
794df930be7Sderaadt 			if (*argv[3])
795b81b15b2Sespie 				strlcpy(ecommt, argv[3], sizeof(ecommt));
796df930be7Sderaadt 		}
797df930be7Sderaadt 		else
798f0484631Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
799df930be7Sderaadt 	}
800df930be7Sderaadt 	else {
801f0484631Sespie 		scommt[0] = SCOMMT, scommt[1] = EOS;
802f0484631Sespie 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
803df930be7Sderaadt 	}
804df930be7Sderaadt }
805df930be7Sderaadt 
806df930be7Sderaadt /*
807df930be7Sderaadt  * dodivert - divert the output to a temporary file
808df930be7Sderaadt  */
809bb34cd6cSespie static void
8108e061d4bSespie dodiv(int n)
811df930be7Sderaadt {
812445b77f7Smillert 	int fd;
813445b77f7Smillert 
8147d3e0b6bSderaadt 	oindex = n;
81525afcddbSespie 	if (n >= maxout) {
81625afcddbSespie 		if (mimic_gnu)
81725afcddbSespie 			resizedivs(n + 10);
81825afcddbSespie 		else
81925afcddbSespie 			n = 0;		/* bitbucket */
82025afcddbSespie     	}
82125afcddbSespie 
82225afcddbSespie 	if (n < 0)
823df930be7Sderaadt 		n = 0;		       /* bitbucket */
824df930be7Sderaadt 	if (outfile[n] == NULL) {
8253f42598dSespie 		char fname[] = _PATH_DIVNAME;
8263f42598dSespie 
8273f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
8283f42598dSespie 			(outfile[n] = fdopen(fd, "w+")) == NULL)
8293f42598dSespie 				err(1, "%s: cannot divert", fname);
8303f42598dSespie 		if (unlink(fname) == -1)
8313f42598dSespie 			err(1, "%s: cannot unlink", fname);
832df930be7Sderaadt 	}
833df930be7Sderaadt 	active = outfile[n];
834df930be7Sderaadt }
835df930be7Sderaadt 
836df930be7Sderaadt /*
837df930be7Sderaadt  * doundivert - undivert a specified output, or all
838df930be7Sderaadt  *              other outputs, in numerical order.
839df930be7Sderaadt  */
840bb34cd6cSespie static void
8418e061d4bSespie doundiv(const char *argv[], int argc)
842df930be7Sderaadt {
84353f6f6bfSespie 	int ind;
84453f6f6bfSespie 	int n;
845df930be7Sderaadt 
846df930be7Sderaadt 	if (argc > 2) {
847df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
848df930be7Sderaadt 			n = atoi(argv[ind]);
84925afcddbSespie 			if (n > 0 && n < maxout && outfile[n] != NULL)
850df930be7Sderaadt 				getdiv(n);
851df930be7Sderaadt 
852df930be7Sderaadt 		}
853df930be7Sderaadt 	}
854df930be7Sderaadt 	else
85525afcddbSespie 		for (n = 1; n < maxout; n++)
856df930be7Sderaadt 			if (outfile[n] != NULL)
857df930be7Sderaadt 				getdiv(n);
858df930be7Sderaadt }
859df930be7Sderaadt 
860df930be7Sderaadt /*
861df930be7Sderaadt  * dosub - select substring
862df930be7Sderaadt  */
863bb34cd6cSespie static void
8648e061d4bSespie dosub(const char *argv[], int argc)
865df930be7Sderaadt {
866bb34cd6cSespie 	const char *ap, *fc, *k;
86753f6f6bfSespie 	int nc;
868df930be7Sderaadt 
869df930be7Sderaadt 	ap = argv[2];		       /* target string */
870df930be7Sderaadt #ifdef EXPR
871df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
872df930be7Sderaadt #else
873df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
874df930be7Sderaadt #endif
875bee8364eSespie 	nc = strlen(fc);
876bee8364eSespie 	if (argc >= 5)
877bee8364eSespie #ifdef EXPR
878bee8364eSespie 		nc = min(nc, expr(argv[4]));
879bee8364eSespie #else
880bee8364eSespie 		nc = min(nc, atoi(argv[4]));
881bee8364eSespie #endif
882df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
883bee8364eSespie 		for (k = fc + nc - 1; k >= fc; k--)
884df930be7Sderaadt 			putback(*k);
885df930be7Sderaadt }
886df930be7Sderaadt 
887df930be7Sderaadt /*
888df930be7Sderaadt  * map:
889df930be7Sderaadt  * map every character of s1 that is specified in from
890df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
891df930be7Sderaadt  *
892df930be7Sderaadt  * This is a standard implementation of map(s,from,to) function of ICON
893df930be7Sderaadt  * language. Within mapvec, we replace every character of "from" with
894df930be7Sderaadt  * the corresponding character in "to". If "to" is shorter than "from",
895df930be7Sderaadt  * than the corresponding entries are null, which means that those
896df930be7Sderaadt  * characters dissapear altogether. Furthermore, imagine
897df930be7Sderaadt  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
898df930be7Sderaadt  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
899df930be7Sderaadt  * ultimately maps to `*'. In order to achieve this effect in an efficient
900df930be7Sderaadt  * manner (i.e. without multiple passes over the destination string), we
901df930be7Sderaadt  * loop over mapvec, starting with the initial source character. if the
902df930be7Sderaadt  * character value (dch) in this location is different than the source
903df930be7Sderaadt  * character (sch), sch becomes dch, once again to index into mapvec, until
904df930be7Sderaadt  * the character value stabilizes (i.e. sch = dch, in other words
905df930be7Sderaadt  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
906df930be7Sderaadt  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
907df930be7Sderaadt  * end, we restore mapvec* back to normal where mapvec[n] == n for
908df930be7Sderaadt  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
909df930be7Sderaadt  * about 5 times faster than any algorithm that makes multiple passes over
910df930be7Sderaadt  * destination string.
911df930be7Sderaadt  */
912bb34cd6cSespie static void
9138e061d4bSespie map(char *dest, const char *src, const char *from, const char *to)
914df930be7Sderaadt {
915bb34cd6cSespie 	const char *tmp;
916ee3599c7Sespie 	unsigned char sch, dch;
91787c5c065Sespie 	static char frombis[257];
91887c5c065Sespie 	static char tobis[257];
919ee3599c7Sespie 	static unsigned char mapvec[256] = {
920ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
921ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
922ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
923ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
924ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
925ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
926ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
927ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
928ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
929ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
930ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
931ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
932ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
933ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
934ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
935ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
936ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
937ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
938df930be7Sderaadt 	};
939df930be7Sderaadt 
940df930be7Sderaadt 	if (*src) {
94187c5c065Sespie 		if (mimic_gnu) {
94287c5c065Sespie 			/*
94387c5c065Sespie 			 * expand character ranges on the fly
94487c5c065Sespie 			 */
94587c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
94687c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
94787c5c065Sespie 		}
948df930be7Sderaadt 		tmp = from;
949df930be7Sderaadt 	/*
950df930be7Sderaadt 	 * create a mapping between "from" and
951df930be7Sderaadt 	 * "to"
952df930be7Sderaadt 	 */
953df930be7Sderaadt 		while (*from)
954ee3599c7Sespie 			mapvec[(unsigned char)(*from++)] = (*to) ?
955ee3599c7Sespie 				(unsigned char)(*to++) : 0;
956df930be7Sderaadt 
957df930be7Sderaadt 		while (*src) {
958ee3599c7Sespie 			sch = (unsigned char)(*src++);
959df930be7Sderaadt 			dch = mapvec[sch];
960df930be7Sderaadt 			while (dch != sch) {
961df930be7Sderaadt 				sch = dch;
962df930be7Sderaadt 				dch = mapvec[sch];
963df930be7Sderaadt 			}
964ee3599c7Sespie 			if ((*dest = (char)dch))
965df930be7Sderaadt 				dest++;
966df930be7Sderaadt 		}
967df930be7Sderaadt 	/*
968df930be7Sderaadt 	 * restore all the changed characters
969df930be7Sderaadt 	 */
970df930be7Sderaadt 		while (*tmp) {
971ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
972df930be7Sderaadt 			tmp++;
973df930be7Sderaadt 		}
974df930be7Sderaadt 	}
975ee3599c7Sespie 	*dest = '\0';
976df930be7Sderaadt }
97787c5c065Sespie 
97887c5c065Sespie 
97987c5c065Sespie /*
98087c5c065Sespie  * handledash:
98187c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
98287c5c065Sespie  * on the way.
98387c5c065Sespie  */
98487c5c065Sespie static const char *
9858e061d4bSespie handledash(char *buffer, char *end, const char *src)
98687c5c065Sespie {
98787c5c065Sespie 	char *p;
98887c5c065Sespie 
98987c5c065Sespie 	p = buffer;
99087c5c065Sespie 	while(*src) {
99187c5c065Sespie 		if (src[1] == '-' && src[2]) {
99287c5c065Sespie 			unsigned char i;
99387c5c065Sespie 			for (i = (unsigned char)src[0];
99487c5c065Sespie 			    i <= (unsigned char)src[2]; i++) {
99587c5c065Sespie 				*p++ = i;
99687c5c065Sespie 				if (p == end) {
99787c5c065Sespie 					*p = '\0';
99887c5c065Sespie 					return buffer;
99987c5c065Sespie 				}
100087c5c065Sespie 			}
100187c5c065Sespie 			src += 3;
100287c5c065Sespie 		} else
100387c5c065Sespie 			*p++ = *src++;
100487c5c065Sespie 		if (p == end)
100587c5c065Sespie 			break;
100687c5c065Sespie 	}
100787c5c065Sespie 	*p = '\0';
100887c5c065Sespie 	return buffer;
100987c5c065Sespie }
1010