xref: /openbsd/usr.bin/m4/eval.c (revision 99f77b33)
1*99f77b33Sespie /*	$OpenBSD: eval.c,v 1.34 2001/09/18 14:43:22 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*99f77b33Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.34 2001/09/18 14:43:22 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 
68f8b42d48Sespie #define BUILTIN_MARKER	"__builtin_"
69f8b42d48Sespie 
70bb34cd6cSespie static void	dodefn __P((const char *));
71bb34cd6cSespie static void	dopushdef __P((const char *, const char *));
72bb34cd6cSespie static void	dodump __P((const char *[], int));
73bb34cd6cSespie static void	doifelse __P((const char *[], int));
74bb34cd6cSespie static int	doincl __P((const char *));
75bb34cd6cSespie static int	dopaste __P((const char *));
76bb34cd6cSespie static void	dochq __P((const char *[], int));
77bb34cd6cSespie static void	dochc __P((const char *[], int));
78bb34cd6cSespie static void	dodiv __P((int));
79bb34cd6cSespie static void	doundiv __P((const char *[], int));
80bb34cd6cSespie static void	dosub __P((const char *[], int));
81bb34cd6cSespie static void	map __P((char *, const char *, const char *, const char *));
8287c5c065Sespie static const char *handledash __P((char *, char *, const char *));
8308f7f207Sespie static void	expand_builtin __P((const char *[], int, int));
8408f7f207Sespie static void	expand_macro __P((const char *[], int));
85dd0682a2Sespie static void	dump_one_def __P((ndptr));
8608f7f207Sespie 
87*99f77b33Sespie unsigned long	expansion_id;
8808f7f207Sespie 
89df930be7Sderaadt /*
9008f7f207Sespie  * eval - eval all macros and builtins calls
9108f7f207Sespie  */
9208f7f207Sespie void
9308f7f207Sespie eval(argv, argc, td)
9408f7f207Sespie 	const char *argv[];
9508f7f207Sespie 	int argc;
9608f7f207Sespie 	int td;
9708f7f207Sespie {
98*99f77b33Sespie 	expansion_id++;
9908f7f207Sespie 	if (td & RECDEF)
10008f7f207Sespie 		errx(1, "%s at line %lu: expanding recursive definition for %s",
10108f7f207Sespie 			CURRENT_NAME, CURRENT_LINE, argv[1]);
10208f7f207Sespie 	if (td == MACRTYPE)
10308f7f207Sespie 		expand_macro(argv, argc);
10408f7f207Sespie 	else
10508f7f207Sespie 		expand_builtin(argv, argc, td);
10608f7f207Sespie }
10708f7f207Sespie 
10808f7f207Sespie /*
10908f7f207Sespie  * expand_builtin - evaluate built-in macros.
110df930be7Sderaadt  *	  argc - number of elements in argv.
111df930be7Sderaadt  *	  argv - element vector :
112df930be7Sderaadt  *			argv[0] = definition of a user
113df930be7Sderaadt  *				  macro or nil if built-in.
114df930be7Sderaadt  *			argv[1] = name of the macro or
115df930be7Sderaadt  *				  built-in.
116df930be7Sderaadt  *			argv[2] = parameters to user-defined
117df930be7Sderaadt  *			   .	  macro or built-in.
118df930be7Sderaadt  *			   .
119df930be7Sderaadt  *
120df930be7Sderaadt  * Note that the minimum value for argc is 3. A call in the form
121df930be7Sderaadt  * of macro-or-builtin() will result in:
122df930be7Sderaadt  *			argv[0] = nullstr
123df930be7Sderaadt  *			argv[1] = macro-or-builtin
124df930be7Sderaadt  *			argv[2] = nullstr
125df930be7Sderaadt  */
126df930be7Sderaadt 
127df930be7Sderaadt void
12808f7f207Sespie expand_builtin(argv, argc, td)
129bb34cd6cSespie 	const char *argv[];
13053f6f6bfSespie 	int argc;
13153f6f6bfSespie 	int td;
132df930be7Sderaadt {
13353f6f6bfSespie 	int c, n;
134df930be7Sderaadt 	static int sysval = 0;
135df930be7Sderaadt 
136df930be7Sderaadt #ifdef DEBUG
137df930be7Sderaadt 	printf("argc = %d\n", argc);
138df930be7Sderaadt 	for (n = 0; n < argc; n++)
139df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
140df930be7Sderaadt #endif
141718b194dSespie 
142df930be7Sderaadt  /*
143df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
144df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
145df930be7Sderaadt   * argc to avoid further checking..
146df930be7Sderaadt   */
147df930be7Sderaadt 	if (argc == 3 && !*(argv[2]))
148df930be7Sderaadt 		argc--;
149df930be7Sderaadt 
150718b194dSespie 	switch (td & TYPEMASK) {
151df930be7Sderaadt 
152df930be7Sderaadt 	case DEFITYPE:
153df930be7Sderaadt 		if (argc > 2)
154df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
155df930be7Sderaadt 		break;
156df930be7Sderaadt 
157df930be7Sderaadt 	case PUSDTYPE:
158df930be7Sderaadt 		if (argc > 2)
159df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
160df930be7Sderaadt 		break;
161df930be7Sderaadt 
162df930be7Sderaadt 	case DUMPTYPE:
163df930be7Sderaadt 		dodump(argv, argc);
164df930be7Sderaadt 		break;
165df930be7Sderaadt 
166df930be7Sderaadt 	case EXPRTYPE:
167df930be7Sderaadt 	/*
168df930be7Sderaadt 	 * doexpr - evaluate arithmetic
169df930be7Sderaadt 	 * expression
170df930be7Sderaadt 	 */
171df930be7Sderaadt 		if (argc > 2)
172df930be7Sderaadt 			pbnum(expr(argv[2]));
173df930be7Sderaadt 		break;
174df930be7Sderaadt 
175df930be7Sderaadt 	case IFELTYPE:
176df930be7Sderaadt 		if (argc > 4)
177df930be7Sderaadt 			doifelse(argv, argc);
178df930be7Sderaadt 		break;
179df930be7Sderaadt 
180df930be7Sderaadt 	case IFDFTYPE:
181df930be7Sderaadt 	/*
182df930be7Sderaadt 	 * doifdef - select one of two
183df930be7Sderaadt 	 * alternatives based on the existence of
184df930be7Sderaadt 	 * another definition
185df930be7Sderaadt 	 */
186df930be7Sderaadt 		if (argc > 3) {
187df930be7Sderaadt 			if (lookup(argv[2]) != nil)
188df930be7Sderaadt 				pbstr(argv[3]);
189df930be7Sderaadt 			else if (argc > 4)
190df930be7Sderaadt 				pbstr(argv[4]);
191df930be7Sderaadt 		}
192df930be7Sderaadt 		break;
193df930be7Sderaadt 
194df930be7Sderaadt 	case LENGTYPE:
195df930be7Sderaadt 	/*
196df930be7Sderaadt 	 * dolen - find the length of the
197df930be7Sderaadt 	 * argument
198df930be7Sderaadt 	 */
199df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
200df930be7Sderaadt 		break;
201df930be7Sderaadt 
202df930be7Sderaadt 	case INCRTYPE:
203df930be7Sderaadt 	/*
204df930be7Sderaadt 	 * doincr - increment the value of the
205df930be7Sderaadt 	 * argument
206df930be7Sderaadt 	 */
207df930be7Sderaadt 		if (argc > 2)
208df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
209df930be7Sderaadt 		break;
210df930be7Sderaadt 
211df930be7Sderaadt 	case DECRTYPE:
212df930be7Sderaadt 	/*
213df930be7Sderaadt 	 * dodecr - decrement the value of the
214df930be7Sderaadt 	 * argument
215df930be7Sderaadt 	 */
216df930be7Sderaadt 		if (argc > 2)
217df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
218df930be7Sderaadt 		break;
219df930be7Sderaadt 
220df930be7Sderaadt 	case SYSCTYPE:
221df930be7Sderaadt 	/*
222df930be7Sderaadt 	 * dosys - execute system command
223df930be7Sderaadt 	 */
224df930be7Sderaadt 		if (argc > 2)
225df930be7Sderaadt 			sysval = system(argv[2]);
226df930be7Sderaadt 		break;
227df930be7Sderaadt 
228df930be7Sderaadt 	case SYSVTYPE:
229df930be7Sderaadt 	/*
230df930be7Sderaadt 	 * dosysval - return value of the last
231df930be7Sderaadt 	 * system call.
232df930be7Sderaadt 	 *
233df930be7Sderaadt 	 */
234df930be7Sderaadt 		pbnum(sysval);
235df930be7Sderaadt 		break;
236df930be7Sderaadt 
237c91edbbbSespie 	case ESYSCMDTYPE:
238c91edbbbSespie 		if (argc > 2)
239c91edbbbSespie 			doesyscmd(argv[2]);
240c91edbbbSespie 	    	break;
241df930be7Sderaadt 	case INCLTYPE:
242df930be7Sderaadt 		if (argc > 2)
243df930be7Sderaadt 			if (!doincl(argv[2]))
2440d3ffe1dSespie 				err(1, "%s at line %lu: include(%s)",
2450d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
246df930be7Sderaadt 		break;
247df930be7Sderaadt 
248df930be7Sderaadt 	case SINCTYPE:
249df930be7Sderaadt 		if (argc > 2)
250df930be7Sderaadt 			(void) doincl(argv[2]);
251df930be7Sderaadt 		break;
252df930be7Sderaadt #ifdef EXTENDED
253df930be7Sderaadt 	case PASTTYPE:
254df930be7Sderaadt 		if (argc > 2)
255df930be7Sderaadt 			if (!dopaste(argv[2]))
2560d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
2570d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
258df930be7Sderaadt 		break;
259df930be7Sderaadt 
260df930be7Sderaadt 	case SPASTYPE:
261df930be7Sderaadt 		if (argc > 2)
262df930be7Sderaadt 			(void) dopaste(argv[2]);
263df930be7Sderaadt 		break;
264df930be7Sderaadt #endif
265df930be7Sderaadt 	case CHNQTYPE:
266df930be7Sderaadt 		dochq(argv, argc);
267df930be7Sderaadt 		break;
268df930be7Sderaadt 
269df930be7Sderaadt 	case CHNCTYPE:
270df930be7Sderaadt 		dochc(argv, argc);
271df930be7Sderaadt 		break;
272df930be7Sderaadt 
273df930be7Sderaadt 	case SUBSTYPE:
274df930be7Sderaadt 	/*
275df930be7Sderaadt 	 * dosub - select substring
276df930be7Sderaadt 	 *
277df930be7Sderaadt 	 */
278df930be7Sderaadt 		if (argc > 3)
279df930be7Sderaadt 			dosub(argv, argc);
280df930be7Sderaadt 		break;
281df930be7Sderaadt 
282df930be7Sderaadt 	case SHIFTYPE:
283df930be7Sderaadt 	/*
284df930be7Sderaadt 	 * doshift - push back all arguments
285df930be7Sderaadt 	 * except the first one (i.e. skip
286df930be7Sderaadt 	 * argv[2])
287df930be7Sderaadt 	 */
288df930be7Sderaadt 		if (argc > 3) {
289df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
2903a73db8cSderaadt 				pbstr(rquote);
291df930be7Sderaadt 				pbstr(argv[n]);
2923a73db8cSderaadt 				pbstr(lquote);
293aa676ce1Smillert 				putback(COMMA);
294df930be7Sderaadt 			}
2953a73db8cSderaadt 			pbstr(rquote);
296df930be7Sderaadt 			pbstr(argv[3]);
2973a73db8cSderaadt 			pbstr(lquote);
298df930be7Sderaadt 		}
299df930be7Sderaadt 		break;
300df930be7Sderaadt 
301df930be7Sderaadt 	case DIVRTYPE:
302df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
303df930be7Sderaadt 			dodiv(n);
304df930be7Sderaadt 		else {
305df930be7Sderaadt 			active = stdout;
306df930be7Sderaadt 			oindex = 0;
307df930be7Sderaadt 		}
308df930be7Sderaadt 		break;
309df930be7Sderaadt 
310df930be7Sderaadt 	case UNDVTYPE:
311df930be7Sderaadt 		doundiv(argv, argc);
312df930be7Sderaadt 		break;
313df930be7Sderaadt 
314df930be7Sderaadt 	case DIVNTYPE:
315df930be7Sderaadt 	/*
316df930be7Sderaadt 	 * dodivnum - return the number of
317df930be7Sderaadt 	 * current output diversion
318df930be7Sderaadt 	 */
319df930be7Sderaadt 		pbnum(oindex);
320df930be7Sderaadt 		break;
321df930be7Sderaadt 
322df930be7Sderaadt 	case UNDFTYPE:
323df930be7Sderaadt 	/*
324df930be7Sderaadt 	 * doundefine - undefine a previously
325df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
326df930be7Sderaadt 	 */
327df930be7Sderaadt 		if (argc > 2)
328df930be7Sderaadt 			for (n = 2; n < argc; n++)
329df930be7Sderaadt 				remhash(argv[n], ALL);
330df930be7Sderaadt 		break;
331df930be7Sderaadt 
332df930be7Sderaadt 	case POPDTYPE:
333df930be7Sderaadt 	/*
334df930be7Sderaadt 	 * dopopdef - remove the topmost
335df930be7Sderaadt 	 * definitions of macro(s) or m4
336df930be7Sderaadt 	 * keyword(s).
337df930be7Sderaadt 	 */
338df930be7Sderaadt 		if (argc > 2)
339df930be7Sderaadt 			for (n = 2; n < argc; n++)
340df930be7Sderaadt 				remhash(argv[n], TOP);
341df930be7Sderaadt 		break;
342df930be7Sderaadt 
343df930be7Sderaadt 	case MKTMTYPE:
344df930be7Sderaadt 	/*
345df930be7Sderaadt 	 * dotemp - create a temporary file
346df930be7Sderaadt 	 */
34701e71e69Sespie 		if (argc > 2) {
34801e71e69Sespie 			int fd;
349bb34cd6cSespie 			char *temp;
35001e71e69Sespie 
351bb34cd6cSespie 			temp = xstrdup(argv[2]);
352bb34cd6cSespie 
353bb34cd6cSespie 			fd = mkstemp(temp);
35401e71e69Sespie 			if (fd == -1)
3550d3ffe1dSespie 				err(1,
3560d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
3570d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
35801e71e69Sespie 			close(fd);
359bb34cd6cSespie 			pbstr(temp);
360bb34cd6cSespie 			free(temp);
36101e71e69Sespie 		}
362df930be7Sderaadt 		break;
363df930be7Sderaadt 
364df930be7Sderaadt 	case TRNLTYPE:
365df930be7Sderaadt 	/*
366df930be7Sderaadt 	 * dotranslit - replace all characters in
367df930be7Sderaadt 	 * the source string that appears in the
368df930be7Sderaadt 	 * "from" string with the corresponding
369df930be7Sderaadt 	 * characters in the "to" string.
370df930be7Sderaadt 	 */
371df930be7Sderaadt 		if (argc > 3) {
3727d3e0b6bSderaadt 			char temp[STRSPMAX+1];
373df930be7Sderaadt 			if (argc > 4)
374df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
375df930be7Sderaadt 			else
376df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
377df930be7Sderaadt 			pbstr(temp);
3787d3e0b6bSderaadt 		} else if (argc > 2)
379df930be7Sderaadt 			pbstr(argv[2]);
380df930be7Sderaadt 		break;
381df930be7Sderaadt 
382df930be7Sderaadt 	case INDXTYPE:
383df930be7Sderaadt 	/*
384df930be7Sderaadt 	 * doindex - find the index of the second
385df930be7Sderaadt 	 * argument string in the first argument
386df930be7Sderaadt 	 * string. -1 if not present.
387df930be7Sderaadt 	 */
388df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
389df930be7Sderaadt 		break;
390df930be7Sderaadt 
391df930be7Sderaadt 	case ERRPTYPE:
392df930be7Sderaadt 	/*
393df930be7Sderaadt 	 * doerrp - print the arguments to stderr
394df930be7Sderaadt 	 * file
395df930be7Sderaadt 	 */
396df930be7Sderaadt 		if (argc > 2) {
397df930be7Sderaadt 			for (n = 2; n < argc; n++)
398df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
399df930be7Sderaadt 			fprintf(stderr, "\n");
400df930be7Sderaadt 		}
401df930be7Sderaadt 		break;
402df930be7Sderaadt 
403df930be7Sderaadt 	case DNLNTYPE:
404df930be7Sderaadt 	/*
405df930be7Sderaadt 	 * dodnl - eat-up-to and including
406df930be7Sderaadt 	 * newline
407df930be7Sderaadt 	 */
408df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
409df930be7Sderaadt 			;
410df930be7Sderaadt 		break;
411df930be7Sderaadt 
412df930be7Sderaadt 	case M4WRTYPE:
413df930be7Sderaadt 	/*
414df930be7Sderaadt 	 * dom4wrap - set up for
415df930be7Sderaadt 	 * wrap-up/wind-down activity
416df930be7Sderaadt 	 */
417df930be7Sderaadt 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
418df930be7Sderaadt 		break;
419df930be7Sderaadt 
420df930be7Sderaadt 	case EXITTYPE:
421df930be7Sderaadt 	/*
422df930be7Sderaadt 	 * doexit - immediate exit from m4.
423df930be7Sderaadt 	 */
424df930be7Sderaadt 		killdiv();
425df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
426df930be7Sderaadt 		break;
427df930be7Sderaadt 
428df930be7Sderaadt 	case DEFNTYPE:
429df930be7Sderaadt 		if (argc > 2)
430df930be7Sderaadt 			for (n = 2; n < argc; n++)
431df930be7Sderaadt 				dodefn(argv[n]);
432df930be7Sderaadt 		break;
433df930be7Sderaadt 
434b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
435b8161682Sespie 		if (argc > 2)
436b8161682Sespie 			doindir(argv, argc);
437b8161682Sespie 		break;
438b8161682Sespie 
439b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
440b8161682Sespie 		if (argc > 2)
441b8161682Sespie 			dobuiltin(argv, argc);
442b8161682Sespie 		break;
443b8161682Sespie 
444b8161682Sespie 	case PATSTYPE:
445b8161682Sespie 		if (argc > 2)
446b8161682Sespie 			dopatsubst(argv, argc);
447b8161682Sespie 		break;
448b8161682Sespie 	case REGEXPTYPE:
449b8161682Sespie 		if (argc > 2)
450b8161682Sespie 			doregexp(argv, argc);
451b8161682Sespie 		break;
452b8161682Sespie 	case LINETYPE:
453b8161682Sespie 		doprintlineno(infile+ilevel);
454b8161682Sespie 		break;
455b8161682Sespie 	case FILENAMETYPE:
456b8161682Sespie 		doprintfilename(infile+ilevel);
457b8161682Sespie 		break;
458423624b7Sespie 	case SELFTYPE:
459423624b7Sespie 		pbstr(rquote);
460423624b7Sespie 		pbstr(argv[1]);
461423624b7Sespie 		pbstr(lquote);
462423624b7Sespie 		break;
463df930be7Sderaadt 	default:
4640d3ffe1dSespie 		errx(1, "%s at line %lu: eval: major botch.",
4650d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE);
466df930be7Sderaadt 		break;
467df930be7Sderaadt 	}
468df930be7Sderaadt }
469df930be7Sderaadt 
470df930be7Sderaadt /*
47108f7f207Sespie  * expand_macro - user-defined macro expansion
472df930be7Sderaadt  */
473df930be7Sderaadt void
47408f7f207Sespie expand_macro(argv, argc)
475bb34cd6cSespie 	const char *argv[];
47653f6f6bfSespie 	int argc;
477df930be7Sderaadt {
478bb34cd6cSespie 	const char *t;
479bb34cd6cSespie 	const char *p;
48053f6f6bfSespie 	int n;
48153f6f6bfSespie 	int argno;
482df930be7Sderaadt 
483df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
484df930be7Sderaadt 	p = t;
485df930be7Sderaadt 	while (*p)
486df930be7Sderaadt 		p++;
487df930be7Sderaadt 	p--;			       /* last character of defn */
488df930be7Sderaadt 	while (p > t) {
489df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
490df930be7Sderaadt 			putback(*p);
491df930be7Sderaadt 		else {
492df930be7Sderaadt 			switch (*p) {
493df930be7Sderaadt 
494df930be7Sderaadt 			case '#':
495df930be7Sderaadt 				pbnum(argc - 2);
496df930be7Sderaadt 				break;
497df930be7Sderaadt 			case '0':
498df930be7Sderaadt 			case '1':
499df930be7Sderaadt 			case '2':
500df930be7Sderaadt 			case '3':
501df930be7Sderaadt 			case '4':
502df930be7Sderaadt 			case '5':
503df930be7Sderaadt 			case '6':
504df930be7Sderaadt 			case '7':
505df930be7Sderaadt 			case '8':
506df930be7Sderaadt 			case '9':
507df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
508df930be7Sderaadt 					pbstr(argv[argno + 1]);
509df930be7Sderaadt 				break;
510df930be7Sderaadt 			case '*':
511df930be7Sderaadt 				for (n = argc - 1; n > 2; n--) {
512df930be7Sderaadt 					pbstr(argv[n]);
513aa676ce1Smillert 					putback(COMMA);
514df930be7Sderaadt 				}
515df930be7Sderaadt 				pbstr(argv[2]);
516df930be7Sderaadt 				break;
517aa676ce1Smillert                         case '@':
518aa676ce1Smillert                                 for (n = argc - 1; n > 2; n--) {
519aa676ce1Smillert                                         pbstr(rquote);
520aa676ce1Smillert                                         pbstr(argv[n]);
521aa676ce1Smillert                                         pbstr(lquote);
522aa676ce1Smillert 					putback(COMMA);
523aa676ce1Smillert                                 }
524aa676ce1Smillert 				pbstr(rquote);
525aa676ce1Smillert                                 pbstr(argv[2]);
526aa676ce1Smillert 				pbstr(lquote);
527aa676ce1Smillert                                 break;
528df930be7Sderaadt 			default:
529df930be7Sderaadt 				putback(*p);
530df930be7Sderaadt 				putback('$');
531df930be7Sderaadt 				break;
532df930be7Sderaadt 			}
533df930be7Sderaadt 			p--;
534df930be7Sderaadt 		}
535df930be7Sderaadt 		p--;
536df930be7Sderaadt 	}
537df930be7Sderaadt 	if (p == t)		       /* do last character */
538df930be7Sderaadt 		putback(*p);
539df930be7Sderaadt }
540df930be7Sderaadt 
541df930be7Sderaadt /*
542df930be7Sderaadt  * dodefine - install definition in the table
543df930be7Sderaadt  */
544df930be7Sderaadt void
545df930be7Sderaadt dodefine(name, defn)
546bb34cd6cSespie 	const char *name;
547bb34cd6cSespie 	const char *defn;
548df930be7Sderaadt {
54953f6f6bfSespie 	ndptr p;
550f8b42d48Sespie 	int n;
551df930be7Sderaadt 
552df930be7Sderaadt 	if (!*name)
5530d3ffe1dSespie 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
5540d3ffe1dSespie 		    CURRENT_LINE);
555df930be7Sderaadt 	if ((p = lookup(name)) == nil)
556df930be7Sderaadt 		p = addent(name);
557df930be7Sderaadt 	else if (p->defn != null)
558df930be7Sderaadt 		free((char *) p->defn);
559f8b42d48Sespie 	if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
560f8b42d48Sespie 		n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
561f8b42d48Sespie 		if (n != -1) {
562f8b42d48Sespie 			p->type = n;
563f8b42d48Sespie 			p->defn = null;
564f8b42d48Sespie 			return;
565f8b42d48Sespie 		}
566f8b42d48Sespie 	}
567df930be7Sderaadt 	if (!*defn)
568df930be7Sderaadt 		p->defn = null;
569df930be7Sderaadt 	else
570df930be7Sderaadt 		p->defn = xstrdup(defn);
571df930be7Sderaadt 	p->type = MACRTYPE;
572718b194dSespie 	if (STREQ(name, defn))
573718b194dSespie 		p->type |= RECDEF;
574df930be7Sderaadt }
575df930be7Sderaadt 
576df930be7Sderaadt /*
577df930be7Sderaadt  * dodefn - push back a quoted definition of
578df930be7Sderaadt  *      the given name.
579df930be7Sderaadt  */
580bb34cd6cSespie static void
581df930be7Sderaadt dodefn(name)
582bb34cd6cSespie 	const char *name;
583df930be7Sderaadt {
58453f6f6bfSespie 	ndptr p;
585f8b42d48Sespie 	char *real;
586df930be7Sderaadt 
587f8b42d48Sespie 	if ((p = lookup(name)) != nil) {
588f8b42d48Sespie 		if (p->defn != null) {
5893a73db8cSderaadt 		pbstr(rquote);
590df930be7Sderaadt 		pbstr(p->defn);
5913a73db8cSderaadt 		pbstr(lquote);
592f8b42d48Sespie 		} else if ((real = builtin_realname(p->type)) != NULL) {
593f8b42d48Sespie 			pbstr(real);
594f8b42d48Sespie 			pbstr(BUILTIN_MARKER);
595f8b42d48Sespie 		}
596df930be7Sderaadt 	}
597df930be7Sderaadt }
598df930be7Sderaadt 
599df930be7Sderaadt /*
600df930be7Sderaadt  * dopushdef - install a definition in the hash table
601df930be7Sderaadt  *      without removing a previous definition. Since
602df930be7Sderaadt  *      each new entry is entered in *front* of the
603df930be7Sderaadt  *      hash bucket, it hides a previous definition from
604df930be7Sderaadt  *      lookup.
605df930be7Sderaadt  */
606bb34cd6cSespie static void
607df930be7Sderaadt dopushdef(name, defn)
608bb34cd6cSespie 	const char *name;
609bb34cd6cSespie 	const char *defn;
610df930be7Sderaadt {
61153f6f6bfSespie 	ndptr p;
612df930be7Sderaadt 
613df930be7Sderaadt 	if (!*name)
6140d3ffe1dSespie 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
6150d3ffe1dSespie 		    CURRENT_LINE);
616df930be7Sderaadt 	p = addent(name);
617df930be7Sderaadt 	if (!*defn)
618df930be7Sderaadt 		p->defn = null;
619df930be7Sderaadt 	else
620df930be7Sderaadt 		p->defn = xstrdup(defn);
621df930be7Sderaadt 	p->type = MACRTYPE;
622718b194dSespie 	if (STREQ(name, defn))
623718b194dSespie 		p->type |= RECDEF;
624df930be7Sderaadt }
625df930be7Sderaadt 
626df930be7Sderaadt /*
627dd0682a2Sespie  * dump_one_def - dump the specified definition.
628dd0682a2Sespie  */
629dd0682a2Sespie static void
630dd0682a2Sespie dump_one_def(p)
631dd0682a2Sespie 	ndptr p;
632dd0682a2Sespie {
6335191fa0aSespie 	char *real;
6345191fa0aSespie 
6355191fa0aSespie 	if (mimic_gnu) {
6365191fa0aSespie 		if ((p->type & TYPEMASK) == MACRTYPE)
6375191fa0aSespie 			fprintf(stderr, "%s:\t%s\n", p->name, p->defn);
6385191fa0aSespie 		else {
6395191fa0aSespie 			real = builtin_realname(p->type);
6405191fa0aSespie 			if (real == NULL)
6415191fa0aSespie 				real = null;
6425191fa0aSespie 			fprintf(stderr, "%s:\t<%s>\n", p->name, real);
6435191fa0aSespie 	    	}
6445191fa0aSespie 	} else
645dd0682a2Sespie 		fprintf(stderr, "`%s'\t`%s'\n", p->name, p->defn);
646dd0682a2Sespie }
647dd0682a2Sespie 
648dd0682a2Sespie /*
649df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
650df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
651df930be7Sderaadt  *      hash table is dumped.
652df930be7Sderaadt  */
653bb34cd6cSespie static void
654df930be7Sderaadt dodump(argv, argc)
655bb34cd6cSespie 	const char *argv[];
65653f6f6bfSespie 	int argc;
657df930be7Sderaadt {
65853f6f6bfSespie 	int n;
659df930be7Sderaadt 	ndptr p;
660df930be7Sderaadt 
661df930be7Sderaadt 	if (argc > 2) {
662df930be7Sderaadt 		for (n = 2; n < argc; n++)
663df930be7Sderaadt 			if ((p = lookup(argv[n])) != nil)
664dd0682a2Sespie 				dump_one_def(p);
6657d3e0b6bSderaadt 	} else {
666df930be7Sderaadt 		for (n = 0; n < HASHSIZE; n++)
667df930be7Sderaadt 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
668dd0682a2Sespie 				dump_one_def(p);
669df930be7Sderaadt 	}
670df930be7Sderaadt }
671df930be7Sderaadt 
672df930be7Sderaadt /*
673df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
674df930be7Sderaadt  */
675bb34cd6cSespie static void
676df930be7Sderaadt doifelse(argv, argc)
677bb34cd6cSespie 	const char *argv[];
67853f6f6bfSespie 	int argc;
679df930be7Sderaadt {
680df930be7Sderaadt 	cycle {
681df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
682df930be7Sderaadt 			pbstr(argv[4]);
683df930be7Sderaadt 		else if (argc == 6)
684df930be7Sderaadt 			pbstr(argv[5]);
685df930be7Sderaadt 		else if (argc > 6) {
686df930be7Sderaadt 			argv += 3;
687df930be7Sderaadt 			argc -= 3;
688df930be7Sderaadt 			continue;
689df930be7Sderaadt 		}
690df930be7Sderaadt 		break;
691df930be7Sderaadt 	}
692df930be7Sderaadt }
693df930be7Sderaadt 
694df930be7Sderaadt /*
695df930be7Sderaadt  * doinclude - include a given file.
696df930be7Sderaadt  */
697bb34cd6cSespie static int
698df930be7Sderaadt doincl(ifile)
699bb34cd6cSespie 	const char *ifile;
700df930be7Sderaadt {
701df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
7020d3ffe1dSespie 		errx(1, "%s at line %lu: too many include files.",
7030d3ffe1dSespie 		    CURRENT_NAME, CURRENT_LINE);
7040d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
705df930be7Sderaadt 		ilevel++;
706df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
707df930be7Sderaadt 		return (1);
7087d3e0b6bSderaadt 	} else
709df930be7Sderaadt 		return (0);
710df930be7Sderaadt }
711df930be7Sderaadt 
712df930be7Sderaadt #ifdef EXTENDED
713df930be7Sderaadt /*
714df930be7Sderaadt  * dopaste - include a given file without any
715df930be7Sderaadt  *           macro processing.
716df930be7Sderaadt  */
717bb34cd6cSespie static int
718df930be7Sderaadt dopaste(pfile)
719bb34cd6cSespie 	const char *pfile;
720df930be7Sderaadt {
721df930be7Sderaadt 	FILE *pf;
72253f6f6bfSespie 	int c;
723df930be7Sderaadt 
724df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
725df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
726df930be7Sderaadt 			putc(c, active);
727df930be7Sderaadt 		(void) fclose(pf);
728df930be7Sderaadt 		return (1);
7297d3e0b6bSderaadt 	} else
730df930be7Sderaadt 		return (0);
731df930be7Sderaadt }
732df930be7Sderaadt #endif
733df930be7Sderaadt 
734df930be7Sderaadt /*
735df930be7Sderaadt  * dochq - change quote characters
736df930be7Sderaadt  */
737bb34cd6cSespie static void
738df930be7Sderaadt dochq(argv, argc)
739bb34cd6cSespie 	const char *argv[];
74053f6f6bfSespie 	int argc;
741df930be7Sderaadt {
74287c5c065Sespie 	/* In gnu-m4 mode, having two empty arguments means no quotes at
74387c5c065Sespie 	 * all.  */
74487c5c065Sespie 	if (mimic_gnu) {
74587c5c065Sespie 		if (argc > 3 && !*argv[2] && !*argv[3]) {
74687c5c065Sespie 			lquote[0] = EOS;
74787c5c065Sespie 			rquote[0] = EOS;
74887c5c065Sespie 			return;
74987c5c065Sespie 		}
75087c5c065Sespie 	}
751df930be7Sderaadt 	if (argc > 2) {
75218a1973bSderaadt 		if (*argv[2])
753b81b15b2Sespie 			strlcpy(lquote, argv[2], sizeof(lquote));
75418a1973bSderaadt 		else {
75518a1973bSderaadt 			lquote[0] = LQUOTE;
756f0484631Sespie 			lquote[1] = EOS;
75718a1973bSderaadt 		}
758df930be7Sderaadt 		if (argc > 3) {
759df930be7Sderaadt 			if (*argv[3])
760b81b15b2Sespie 				strlcpy(rquote, argv[3], sizeof(rquote));
7617d3e0b6bSderaadt 		} else
76229a0bfdcSderaadt 			strcpy(rquote, lquote);
7637d3e0b6bSderaadt 	} else {
764f0484631Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
765f0484631Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
766df930be7Sderaadt 	}
767df930be7Sderaadt }
768df930be7Sderaadt 
769df930be7Sderaadt /*
770df930be7Sderaadt  * dochc - change comment characters
771df930be7Sderaadt  */
772bb34cd6cSespie static void
773df930be7Sderaadt dochc(argv, argc)
774bb34cd6cSespie 	const char *argv[];
77553f6f6bfSespie 	int argc;
776df930be7Sderaadt {
777df930be7Sderaadt 	if (argc > 2) {
778df930be7Sderaadt 		if (*argv[2])
779b81b15b2Sespie 			strlcpy(scommt, argv[2], sizeof(scommt));
780df930be7Sderaadt 		if (argc > 3) {
781df930be7Sderaadt 			if (*argv[3])
782b81b15b2Sespie 				strlcpy(ecommt, argv[3], sizeof(ecommt));
783df930be7Sderaadt 		}
784df930be7Sderaadt 		else
785f0484631Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
786df930be7Sderaadt 	}
787df930be7Sderaadt 	else {
788f0484631Sespie 		scommt[0] = SCOMMT, scommt[1] = EOS;
789f0484631Sespie 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
790df930be7Sderaadt 	}
791df930be7Sderaadt }
792df930be7Sderaadt 
793df930be7Sderaadt /*
794df930be7Sderaadt  * dodivert - divert the output to a temporary file
795df930be7Sderaadt  */
796bb34cd6cSespie static void
797df930be7Sderaadt dodiv(n)
79853f6f6bfSespie 	int n;
799df930be7Sderaadt {
800445b77f7Smillert 	int fd;
801445b77f7Smillert 
8027d3e0b6bSderaadt 	oindex = n;
80325afcddbSespie 	if (n >= maxout) {
80425afcddbSespie 		if (mimic_gnu)
80525afcddbSespie 			resizedivs(n + 10);
80625afcddbSespie 		else
80725afcddbSespie 			n = 0;		/* bitbucket */
80825afcddbSespie     	}
80925afcddbSespie 
81025afcddbSespie 	if (n < 0)
811df930be7Sderaadt 		n = 0;		       /* bitbucket */
812df930be7Sderaadt 	if (outfile[n] == NULL) {
8133f42598dSespie 		char fname[] = _PATH_DIVNAME;
8143f42598dSespie 
8153f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
8163f42598dSespie 			(outfile[n] = fdopen(fd, "w+")) == NULL)
8173f42598dSespie 				err(1, "%s: cannot divert", fname);
8183f42598dSespie 		if (unlink(fname) == -1)
8193f42598dSespie 			err(1, "%s: cannot unlink", fname);
820df930be7Sderaadt 	}
821df930be7Sderaadt 	active = outfile[n];
822df930be7Sderaadt }
823df930be7Sderaadt 
824df930be7Sderaadt /*
825df930be7Sderaadt  * doundivert - undivert a specified output, or all
826df930be7Sderaadt  *              other outputs, in numerical order.
827df930be7Sderaadt  */
828bb34cd6cSespie static void
829df930be7Sderaadt doundiv(argv, argc)
830bb34cd6cSespie 	const char *argv[];
83153f6f6bfSespie 	int argc;
832df930be7Sderaadt {
83353f6f6bfSespie 	int ind;
83453f6f6bfSespie 	int n;
835df930be7Sderaadt 
836df930be7Sderaadt 	if (argc > 2) {
837df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
838df930be7Sderaadt 			n = atoi(argv[ind]);
83925afcddbSespie 			if (n > 0 && n < maxout && outfile[n] != NULL)
840df930be7Sderaadt 				getdiv(n);
841df930be7Sderaadt 
842df930be7Sderaadt 		}
843df930be7Sderaadt 	}
844df930be7Sderaadt 	else
84525afcddbSespie 		for (n = 1; n < maxout; n++)
846df930be7Sderaadt 			if (outfile[n] != NULL)
847df930be7Sderaadt 				getdiv(n);
848df930be7Sderaadt }
849df930be7Sderaadt 
850df930be7Sderaadt /*
851df930be7Sderaadt  * dosub - select substring
852df930be7Sderaadt  */
853bb34cd6cSespie static void
854df930be7Sderaadt dosub(argv, argc)
855bb34cd6cSespie 	const char *argv[];
85653f6f6bfSespie 	int argc;
857df930be7Sderaadt {
858bb34cd6cSespie 	const char *ap, *fc, *k;
85953f6f6bfSespie 	int nc;
860df930be7Sderaadt 
861df930be7Sderaadt 	ap = argv[2];		       /* target string */
862df930be7Sderaadt #ifdef EXPR
863df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
864df930be7Sderaadt #else
865df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
866df930be7Sderaadt #endif
867bee8364eSespie 	nc = strlen(fc);
868bee8364eSespie 	if (argc >= 5)
869bee8364eSespie #ifdef EXPR
870bee8364eSespie 		nc = min(nc, expr(argv[4]));
871bee8364eSespie #else
872bee8364eSespie 		nc = min(nc, atoi(argv[4]));
873bee8364eSespie #endif
874df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
875bee8364eSespie 		for (k = fc + nc - 1; k >= fc; k--)
876df930be7Sderaadt 			putback(*k);
877df930be7Sderaadt }
878df930be7Sderaadt 
879df930be7Sderaadt /*
880df930be7Sderaadt  * map:
881df930be7Sderaadt  * map every character of s1 that is specified in from
882df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
883df930be7Sderaadt  *
884df930be7Sderaadt  * This is a standard implementation of map(s,from,to) function of ICON
885df930be7Sderaadt  * language. Within mapvec, we replace every character of "from" with
886df930be7Sderaadt  * the corresponding character in "to". If "to" is shorter than "from",
887df930be7Sderaadt  * than the corresponding entries are null, which means that those
888df930be7Sderaadt  * characters dissapear altogether. Furthermore, imagine
889df930be7Sderaadt  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
890df930be7Sderaadt  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
891df930be7Sderaadt  * ultimately maps to `*'. In order to achieve this effect in an efficient
892df930be7Sderaadt  * manner (i.e. without multiple passes over the destination string), we
893df930be7Sderaadt  * loop over mapvec, starting with the initial source character. if the
894df930be7Sderaadt  * character value (dch) in this location is different than the source
895df930be7Sderaadt  * character (sch), sch becomes dch, once again to index into mapvec, until
896df930be7Sderaadt  * the character value stabilizes (i.e. sch = dch, in other words
897df930be7Sderaadt  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
898df930be7Sderaadt  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
899df930be7Sderaadt  * end, we restore mapvec* back to normal where mapvec[n] == n for
900df930be7Sderaadt  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
901df930be7Sderaadt  * about 5 times faster than any algorithm that makes multiple passes over
902df930be7Sderaadt  * destination string.
903df930be7Sderaadt  */
904bb34cd6cSespie static void
905df930be7Sderaadt map(dest, src, from, to)
90653f6f6bfSespie 	char *dest;
907bb34cd6cSespie 	const char *src;
908bb34cd6cSespie 	const char *from;
909bb34cd6cSespie 	const char *to;
910df930be7Sderaadt {
911bb34cd6cSespie 	const char *tmp;
912ee3599c7Sespie 	unsigned char sch, dch;
91387c5c065Sespie 	static char frombis[257];
91487c5c065Sespie 	static char tobis[257];
915ee3599c7Sespie 	static unsigned char mapvec[256] = {
916ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
917ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
918ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
919ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
920ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
921ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
922ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
923ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
924ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
925ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
926ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
927ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
928ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
929ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
930ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
931ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
932ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
933ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
934df930be7Sderaadt 	};
935df930be7Sderaadt 
936df930be7Sderaadt 	if (*src) {
93787c5c065Sespie 		if (mimic_gnu) {
93887c5c065Sespie 			/*
93987c5c065Sespie 			 * expand character ranges on the fly
94087c5c065Sespie 			 */
94187c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
94287c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
94387c5c065Sespie 		}
944df930be7Sderaadt 		tmp = from;
945df930be7Sderaadt 	/*
946df930be7Sderaadt 	 * create a mapping between "from" and
947df930be7Sderaadt 	 * "to"
948df930be7Sderaadt 	 */
949df930be7Sderaadt 		while (*from)
950ee3599c7Sespie 			mapvec[(unsigned char)(*from++)] = (*to) ?
951ee3599c7Sespie 				(unsigned char)(*to++) : 0;
952df930be7Sderaadt 
953df930be7Sderaadt 		while (*src) {
954ee3599c7Sespie 			sch = (unsigned char)(*src++);
955df930be7Sderaadt 			dch = mapvec[sch];
956df930be7Sderaadt 			while (dch != sch) {
957df930be7Sderaadt 				sch = dch;
958df930be7Sderaadt 				dch = mapvec[sch];
959df930be7Sderaadt 			}
960ee3599c7Sespie 			if ((*dest = (char)dch))
961df930be7Sderaadt 				dest++;
962df930be7Sderaadt 		}
963df930be7Sderaadt 	/*
964df930be7Sderaadt 	 * restore all the changed characters
965df930be7Sderaadt 	 */
966df930be7Sderaadt 		while (*tmp) {
967ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
968df930be7Sderaadt 			tmp++;
969df930be7Sderaadt 		}
970df930be7Sderaadt 	}
971ee3599c7Sespie 	*dest = '\0';
972df930be7Sderaadt }
97387c5c065Sespie 
97487c5c065Sespie 
97587c5c065Sespie /*
97687c5c065Sespie  * handledash:
97787c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
97887c5c065Sespie  * on the way.
97987c5c065Sespie  */
98087c5c065Sespie static const char *
98187c5c065Sespie handledash(buffer, end, src)
98287c5c065Sespie 	char *buffer;
98387c5c065Sespie 	char *end;
98487c5c065Sespie 	const char *src;
98587c5c065Sespie {
98687c5c065Sespie 	char *p;
98787c5c065Sespie 
98887c5c065Sespie 	p = buffer;
98987c5c065Sespie 	while(*src) {
99087c5c065Sespie 		if (src[1] == '-' && src[2]) {
99187c5c065Sespie 			unsigned char i;
99287c5c065Sespie 			for (i = (unsigned char)src[0];
99387c5c065Sespie 			    i <= (unsigned char)src[2]; i++) {
99487c5c065Sespie 				*p++ = i;
99587c5c065Sespie 				if (p == end) {
99687c5c065Sespie 					*p = '\0';
99787c5c065Sespie 					return buffer;
99887c5c065Sespie 				}
99987c5c065Sespie 			}
100087c5c065Sespie 			src += 3;
100187c5c065Sespie 		} else
100287c5c065Sespie 			*p++ = *src++;
100387c5c065Sespie 		if (p == end)
100487c5c065Sespie 			break;
100587c5c065Sespie 	}
100687c5c065Sespie 	*p = '\0';
100787c5c065Sespie 	return buffer;
100887c5c065Sespie }
100987c5c065Sespie 
1010