xref: /openbsd/usr.bin/m4/eval.c (revision d9a51c35)
1*d9a51c35Sjmc /*	$OpenBSD: eval.c,v 1.79 2022/12/26 19:16:01 jmc 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 /*
37df930be7Sderaadt  * eval.c
38df930be7Sderaadt  * Facility: m4 macro processor
39df930be7Sderaadt  * by: oz
40df930be7Sderaadt  */
41df930be7Sderaadt 
42df930be7Sderaadt #include <sys/types.h>
43df44a85aSespie #include <err.h>
44df930be7Sderaadt #include <errno.h>
45e79fa687Sespie #include <limits.h>
46df930be7Sderaadt #include <unistd.h>
47df930be7Sderaadt #include <stdio.h>
481357284aSmillert #include <stdint.h>
49df930be7Sderaadt #include <stdlib.h>
503f42598dSespie #include <stddef.h>
51df930be7Sderaadt #include <string.h>
52445b77f7Smillert #include <fcntl.h>
53df930be7Sderaadt #include "mdef.h"
54df930be7Sderaadt #include "stdd.h"
55df930be7Sderaadt #include "extern.h"
56df930be7Sderaadt #include "pathnames.h"
57df930be7Sderaadt 
58c72b5b24Smillert static void	dodefn(const char *);
59c72b5b24Smillert static void	dopushdef(const char *, const char *);
60c72b5b24Smillert static void	dodump(const char *[], int);
61c72b5b24Smillert static void	dotrace(const char *[], int, int);
62c72b5b24Smillert static void	doifelse(const char *[], int);
63c72b5b24Smillert static int	doincl(const char *);
64c72b5b24Smillert static int	dopaste(const char *);
65c72b5b24Smillert static void	dochq(const char *[], int);
66c72b5b24Smillert static void	dochc(const char *[], int);
67ad459a23Sespie static void	dom4wrap(const char *);
68c72b5b24Smillert static void	dodiv(int);
69c72b5b24Smillert static void	doundiv(const char *[], int);
70c72b5b24Smillert static void	dosub(const char *[], int);
71c72b5b24Smillert static void	map(char *, const char *, const char *, const char *);
72c72b5b24Smillert static const char *handledash(char *, char *, const char *);
73c72b5b24Smillert static void	expand_builtin(const char *[], int, int);
74c72b5b24Smillert static void	expand_macro(const char *[], int);
753509e8ffSespie static void	dump_one_def(const char *, struct macro_definition *);
7608f7f207Sespie 
7799f77b33Sespie unsigned long	expansion_id;
7808f7f207Sespie 
79df930be7Sderaadt /*
8008f7f207Sespie  * eval - eval all macros and builtins calls
81054026c0Sespie  *	  argc - number of elements in argv.
82054026c0Sespie  *	  argv - element vector :
83054026c0Sespie  *			argv[0] = definition of a user
843509e8ffSespie  *				  macro or NULL if built-in.
85054026c0Sespie  *			argv[1] = name of the macro or
86054026c0Sespie  *				  built-in.
87054026c0Sespie  *			argv[2] = parameters to user-defined
88054026c0Sespie  *			   .	  macro or built-in.
89054026c0Sespie  *			   .
90054026c0Sespie  *
91054026c0Sespie  * A call in the form of macro-or-builtin() will result in:
92054026c0Sespie  *			argv[0] = nullstr
93054026c0Sespie  *			argv[1] = macro-or-builtin
94054026c0Sespie  *			argv[2] = nullstr
95054026c0Sespie  *
96054026c0Sespie  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
9708f7f207Sespie  */
9808f7f207Sespie void
eval(const char * argv[],int argc,int td,int is_traced)99dde05c5fSespie eval(const char *argv[], int argc, int td, int is_traced)
10008f7f207Sespie {
1010b7a013eSespie 	size_t mark = SIZE_MAX;
1024dac505dSespie 
10399f77b33Sespie 	expansion_id++;
10408f7f207Sespie 	if (td & RECDEF)
10575ebbed7Sespie 		m4errx(1, "expanding recursive definition for %s.", argv[1]);
106dde05c5fSespie 	if (is_traced)
1074dac505dSespie 		mark = trace(argv, argc, infile+ilevel);
10808f7f207Sespie 	if (td == MACRTYPE)
10908f7f207Sespie 		expand_macro(argv, argc);
11008f7f207Sespie 	else
11108f7f207Sespie 		expand_builtin(argv, argc, td);
1120b7a013eSespie 	if (mark != SIZE_MAX)
1134dac505dSespie 		finish_trace(mark);
11408f7f207Sespie }
11508f7f207Sespie 
11608f7f207Sespie /*
11708f7f207Sespie  * expand_builtin - evaluate built-in macros.
118df930be7Sderaadt  */
119df930be7Sderaadt void
expand_builtin(const char * argv[],int argc,int td)1208e061d4bSespie expand_builtin(const char *argv[], int argc, int td)
121df930be7Sderaadt {
12253f6f6bfSespie 	int c, n;
1231818d080Sespie 	const char *errstr;
124054026c0Sespie 	int ac;
125df930be7Sderaadt 	static int sysval = 0;
126df930be7Sderaadt 
127df930be7Sderaadt #ifdef DEBUG
128df930be7Sderaadt 	printf("argc = %d\n", argc);
129df930be7Sderaadt 	for (n = 0; n < argc; n++)
130df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
13128728804Sespie 	fflush(stdout);
132df930be7Sderaadt #endif
133718b194dSespie 
134df930be7Sderaadt  /*
135df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
136df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
137df930be7Sderaadt   * argc to avoid further checking..
138df930be7Sderaadt   */
139739ce124Sespie  /* we keep the initial value for those built-ins that differentiate
140739ce124Sespie   * between builtin() and builtin.
141739ce124Sespie   */
142054026c0Sespie 	ac = argc;
143054026c0Sespie 
14487a9001aSespie 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
145df930be7Sderaadt 		argc--;
146df930be7Sderaadt 
147718b194dSespie 	switch (td & TYPEMASK) {
148df930be7Sderaadt 
149df930be7Sderaadt 	case DEFITYPE:
150df930be7Sderaadt 		if (argc > 2)
151df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
152df930be7Sderaadt 		break;
153df930be7Sderaadt 
154df930be7Sderaadt 	case PUSDTYPE:
155df930be7Sderaadt 		if (argc > 2)
156df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
157df930be7Sderaadt 		break;
158df930be7Sderaadt 
159df930be7Sderaadt 	case DUMPTYPE:
160df930be7Sderaadt 		dodump(argv, argc);
161df930be7Sderaadt 		break;
162df930be7Sderaadt 
16334970243Sespie 	case TRACEONTYPE:
16434970243Sespie 		dotrace(argv, argc, 1);
16534970243Sespie 		break;
16634970243Sespie 
16734970243Sespie 	case TRACEOFFTYPE:
16834970243Sespie 		dotrace(argv, argc, 0);
16934970243Sespie 		break;
17034970243Sespie 
171df930be7Sderaadt 	case EXPRTYPE:
172df930be7Sderaadt 	/*
173df930be7Sderaadt 	 * doexpr - evaluate arithmetic
174df930be7Sderaadt 	 * expression
175df930be7Sderaadt 	 */
176e79fa687Sespie 	{
177e79fa687Sespie 		int base = 10;
178e79fa687Sespie 		int maxdigits = 0;
179e79fa687Sespie 
180e79fa687Sespie 		if (argc > 3) {
181e79fa687Sespie 			base = strtonum(argv[3], 2, 36, &errstr);
182e79fa687Sespie 			if (errstr) {
1831818d080Sespie 				m4errx(1, "expr: base is %s: %s.",
1841818d080Sespie 				    errstr, argv[3]);
185e79fa687Sespie 			}
186e79fa687Sespie 		}
187e79fa687Sespie 		if (argc > 4) {
188e79fa687Sespie 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
189e79fa687Sespie 			if (errstr) {
1901818d080Sespie 				m4errx(1, "expr: maxdigits is %s: %s.",
1911818d080Sespie 				    errstr, argv[4]);
192e79fa687Sespie 			}
193e79fa687Sespie 		}
194df930be7Sderaadt 		if (argc > 2)
195e79fa687Sespie 			pbnumbase(expr(argv[2]), base, maxdigits);
196df930be7Sderaadt 		break;
197e79fa687Sespie 	}
198df930be7Sderaadt 
199df930be7Sderaadt 	case IFELTYPE:
200df930be7Sderaadt 		doifelse(argv, argc);
201df930be7Sderaadt 		break;
202df930be7Sderaadt 
203df930be7Sderaadt 	case IFDFTYPE:
204df930be7Sderaadt 	/*
205df930be7Sderaadt 	 * doifdef - select one of two
206df930be7Sderaadt 	 * alternatives based on the existence of
207df930be7Sderaadt 	 * another definition
208df930be7Sderaadt 	 */
209df930be7Sderaadt 		if (argc > 3) {
2103509e8ffSespie 			if (lookup_macro_definition(argv[2]) != NULL)
211df930be7Sderaadt 				pbstr(argv[3]);
212df930be7Sderaadt 			else if (argc > 4)
213df930be7Sderaadt 				pbstr(argv[4]);
214df930be7Sderaadt 		}
215df930be7Sderaadt 		break;
216df930be7Sderaadt 
217df930be7Sderaadt 	case LENGTYPE:
218df930be7Sderaadt 	/*
219df930be7Sderaadt 	 * dolen - find the length of the
220df930be7Sderaadt 	 * argument
221df930be7Sderaadt 	 */
222df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
223df930be7Sderaadt 		break;
224df930be7Sderaadt 
225df930be7Sderaadt 	case INCRTYPE:
226df930be7Sderaadt 	/*
227df930be7Sderaadt 	 * doincr - increment the value of the
228df930be7Sderaadt 	 * argument
229df930be7Sderaadt 	 */
2301818d080Sespie 		if (argc > 2) {
2311818d080Sespie 			n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr);
2321818d080Sespie 			if (errstr != NULL)
2331818d080Sespie 				m4errx(1, "incr: argument is %s: %s.",
2341818d080Sespie 				    errstr, argv[2]);
2351818d080Sespie 			pbnum(n + 1);
2361818d080Sespie 		}
237df930be7Sderaadt 		break;
238df930be7Sderaadt 
239df930be7Sderaadt 	case DECRTYPE:
240df930be7Sderaadt 	/*
241df930be7Sderaadt 	 * dodecr - decrement the value of the
242df930be7Sderaadt 	 * argument
243df930be7Sderaadt 	 */
2441818d080Sespie 		if (argc > 2) {
2451818d080Sespie 			n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr);
2461818d080Sespie 			if (errstr)
2471818d080Sespie 				m4errx(1, "decr: argument is %s: %s.",
2481818d080Sespie 				    errstr, argv[2]);
2491818d080Sespie 			pbnum(n - 1);
2501818d080Sespie 		}
251df930be7Sderaadt 		break;
252df930be7Sderaadt 
253df930be7Sderaadt 	case SYSCTYPE:
254df930be7Sderaadt 	/*
255df930be7Sderaadt 	 * dosys - execute system command
256df930be7Sderaadt 	 */
257b3d09a36Srobert 		if (argc > 2) {
258b3d09a36Srobert 			fflush(stdout);
259df930be7Sderaadt 			sysval = system(argv[2]);
260b3d09a36Srobert 		}
261df930be7Sderaadt 		break;
262df930be7Sderaadt 
263df930be7Sderaadt 	case SYSVTYPE:
264df930be7Sderaadt 	/*
265df930be7Sderaadt 	 * dosysval - return value of the last
266df930be7Sderaadt 	 * system call.
267df930be7Sderaadt 	 *
268df930be7Sderaadt 	 */
269df930be7Sderaadt 		pbnum(sysval);
270df930be7Sderaadt 		break;
271df930be7Sderaadt 
272c91edbbbSespie 	case ESYSCMDTYPE:
273c91edbbbSespie 		if (argc > 2)
274c91edbbbSespie 			doesyscmd(argv[2]);
275c91edbbbSespie 		break;
276df930be7Sderaadt 	case INCLTYPE:
2772aa31d4aSderaadt 		if (argc > 2) {
2782aa31d4aSderaadt 			if (!doincl(argv[2])) {
279a45fdd0cSespie 				if (mimic_gnu) {
280a45fdd0cSespie 					warn("%s at line %lu: include(%s)",
281a45fdd0cSespie 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
282a45fdd0cSespie 					exit_code = 1;
283d2d86e25Sbcallah 					if (fatal_warns) {
284d2d86e25Sbcallah 						killdiv();
285d2d86e25Sbcallah 						exit(exit_code);
286d2d86e25Sbcallah 					}
287a45fdd0cSespie 				} else
2880d3ffe1dSespie 					err(1, "%s at line %lu: include(%s)",
2890d3ffe1dSespie 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2902aa31d4aSderaadt 			}
2912aa31d4aSderaadt 		}
292df930be7Sderaadt 		break;
293df930be7Sderaadt 
294df930be7Sderaadt 	case SINCTYPE:
295df930be7Sderaadt 		if (argc > 2)
296df930be7Sderaadt 			(void) doincl(argv[2]);
297df930be7Sderaadt 		break;
298df930be7Sderaadt #ifdef EXTENDED
299df930be7Sderaadt 	case PASTTYPE:
300df930be7Sderaadt 		if (argc > 2)
301df930be7Sderaadt 			if (!dopaste(argv[2]))
3020d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
3030d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
304df930be7Sderaadt 		break;
305df930be7Sderaadt 
306df930be7Sderaadt 	case SPASTYPE:
307df930be7Sderaadt 		if (argc > 2)
308df930be7Sderaadt 			(void) dopaste(argv[2]);
309df930be7Sderaadt 		break;
31009d1584fSespie 	case FORMATTYPE:
31109d1584fSespie 		doformat(argv, argc);
31209d1584fSespie 		break;
313df930be7Sderaadt #endif
314df930be7Sderaadt 	case CHNQTYPE:
315739ce124Sespie 		dochq(argv, ac);
316df930be7Sderaadt 		break;
317df930be7Sderaadt 
318df930be7Sderaadt 	case CHNCTYPE:
319df930be7Sderaadt 		dochc(argv, argc);
320df930be7Sderaadt 		break;
321df930be7Sderaadt 
322df930be7Sderaadt 	case SUBSTYPE:
323df930be7Sderaadt 	/*
324df930be7Sderaadt 	 * dosub - select substring
325df930be7Sderaadt 	 *
326df930be7Sderaadt 	 */
327df930be7Sderaadt 		if (argc > 3)
328df930be7Sderaadt 			dosub(argv, argc);
329df930be7Sderaadt 		break;
330df930be7Sderaadt 
331df930be7Sderaadt 	case SHIFTYPE:
332df930be7Sderaadt 	/*
333df930be7Sderaadt 	 * doshift - push back all arguments
334df930be7Sderaadt 	 * except the first one (i.e. skip
335df930be7Sderaadt 	 * argv[2])
336df930be7Sderaadt 	 */
337df930be7Sderaadt 		if (argc > 3) {
338df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
3393a73db8cSderaadt 				pbstr(rquote);
340df930be7Sderaadt 				pbstr(argv[n]);
3413a73db8cSderaadt 				pbstr(lquote);
342739ce124Sespie 				pushback(COMMA);
343df930be7Sderaadt 			}
3443a73db8cSderaadt 			pbstr(rquote);
345df930be7Sderaadt 			pbstr(argv[3]);
3463a73db8cSderaadt 			pbstr(lquote);
347df930be7Sderaadt 		}
348df930be7Sderaadt 		break;
349df930be7Sderaadt 
350df930be7Sderaadt 	case DIVRTYPE:
3511818d080Sespie 		if (argc > 2) {
3521818d080Sespie 			n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr);
3531818d080Sespie 			if (errstr)
3541818d080Sespie 				m4errx(1, "divert: argument is %s: %s.",
3551818d080Sespie 				    errstr, argv[2]);
3561818d080Sespie 			if (n != 0) {
357df930be7Sderaadt 				dodiv(n);
3581818d080Sespie 				break;
3591818d080Sespie 			}
3601818d080Sespie 		}
361df930be7Sderaadt 		active = stdout;
362df930be7Sderaadt 		oindex = 0;
363df930be7Sderaadt 		break;
364df930be7Sderaadt 
365df930be7Sderaadt 	case UNDVTYPE:
366df930be7Sderaadt 		doundiv(argv, argc);
367df930be7Sderaadt 		break;
368df930be7Sderaadt 
369df930be7Sderaadt 	case DIVNTYPE:
370df930be7Sderaadt 	/*
371df930be7Sderaadt 	 * dodivnum - return the number of
372df930be7Sderaadt 	 * current output diversion
373df930be7Sderaadt 	 */
374df930be7Sderaadt 		pbnum(oindex);
375df930be7Sderaadt 		break;
376df930be7Sderaadt 
377df930be7Sderaadt 	case UNDFTYPE:
378df930be7Sderaadt 	/*
379df930be7Sderaadt 	 * doundefine - undefine a previously
380df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
381df930be7Sderaadt 	 */
382df930be7Sderaadt 		if (argc > 2)
383df930be7Sderaadt 			for (n = 2; n < argc; n++)
3843509e8ffSespie 				macro_undefine(argv[n]);
385df930be7Sderaadt 		break;
386df930be7Sderaadt 
387df930be7Sderaadt 	case POPDTYPE:
388df930be7Sderaadt 	/*
389df930be7Sderaadt 	 * dopopdef - remove the topmost
390df930be7Sderaadt 	 * definitions of macro(s) or m4
391df930be7Sderaadt 	 * keyword(s).
392df930be7Sderaadt 	 */
393df930be7Sderaadt 		if (argc > 2)
394df930be7Sderaadt 			for (n = 2; n < argc; n++)
3953509e8ffSespie 				macro_popdef(argv[n]);
396df930be7Sderaadt 		break;
397df930be7Sderaadt 
398df930be7Sderaadt 	case MKTMTYPE:
399df930be7Sderaadt 	/*
400df930be7Sderaadt 	 * dotemp - create a temporary file
401df930be7Sderaadt 	 */
40201e71e69Sespie 		if (argc > 2) {
40301e71e69Sespie 			int fd;
404bb34cd6cSespie 			char *temp;
40501e71e69Sespie 
406bb34cd6cSespie 			temp = xstrdup(argv[2]);
407bb34cd6cSespie 
408bb34cd6cSespie 			fd = mkstemp(temp);
40901e71e69Sespie 			if (fd == -1)
4100d3ffe1dSespie 				err(1,
4110d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
4120d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
41301e71e69Sespie 			close(fd);
414bb34cd6cSespie 			pbstr(temp);
415bb34cd6cSespie 			free(temp);
41601e71e69Sespie 		}
417df930be7Sderaadt 		break;
418df930be7Sderaadt 
419df930be7Sderaadt 	case TRNLTYPE:
420df930be7Sderaadt 	/*
421df930be7Sderaadt 	 * dotranslit - replace all characters in
422df930be7Sderaadt 	 * the source string that appears in the
423df930be7Sderaadt 	 * "from" string with the corresponding
424df930be7Sderaadt 	 * characters in the "to" string.
425df930be7Sderaadt 	 */
426df930be7Sderaadt 		if (argc > 3) {
42728728804Sespie 			char *temp;
42828728804Sespie 
429f6169a2cSespie 			temp = xalloc(strlen(argv[2])+1, NULL);
430df930be7Sderaadt 			if (argc > 4)
431df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
432df930be7Sderaadt 			else
433df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
434df930be7Sderaadt 			pbstr(temp);
43528728804Sespie 			free(temp);
4367d3e0b6bSderaadt 		} else if (argc > 2)
437df930be7Sderaadt 			pbstr(argv[2]);
438df930be7Sderaadt 		break;
439df930be7Sderaadt 
440df930be7Sderaadt 	case INDXTYPE:
441df930be7Sderaadt 	/*
442df930be7Sderaadt 	 * doindex - find the index of the second
443df930be7Sderaadt 	 * argument string in the first argument
444df930be7Sderaadt 	 * string. -1 if not present.
445df930be7Sderaadt 	 */
446df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
447df930be7Sderaadt 		break;
448df930be7Sderaadt 
449df930be7Sderaadt 	case ERRPTYPE:
450df930be7Sderaadt 	/*
451df930be7Sderaadt 	 * doerrp - print the arguments to stderr
452df930be7Sderaadt 	 * file
453df930be7Sderaadt 	 */
454df930be7Sderaadt 		if (argc > 2) {
455df930be7Sderaadt 			for (n = 2; n < argc; n++)
456df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
457df930be7Sderaadt 			fprintf(stderr, "\n");
458df930be7Sderaadt 		}
459df930be7Sderaadt 		break;
460df930be7Sderaadt 
461df930be7Sderaadt 	case DNLNTYPE:
462df930be7Sderaadt 	/*
463df930be7Sderaadt 	 * dodnl - eat-up-to and including
464df930be7Sderaadt 	 * newline
465df930be7Sderaadt 	 */
466df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
467df930be7Sderaadt 			;
468df930be7Sderaadt 		break;
469df930be7Sderaadt 
470df930be7Sderaadt 	case M4WRTYPE:
471df930be7Sderaadt 	/*
472df930be7Sderaadt 	 * dom4wrap - set up for
473df930be7Sderaadt 	 * wrap-up/wind-down activity
474df930be7Sderaadt 	 */
475ad459a23Sespie 		if (argc > 2)
476ad459a23Sespie 			dom4wrap(argv[2]);
477df930be7Sderaadt 		break;
478df930be7Sderaadt 
479df930be7Sderaadt 	case EXITTYPE:
480df930be7Sderaadt 	/*
481df930be7Sderaadt 	 * doexit - immediate exit from m4.
482df930be7Sderaadt 	 */
483df930be7Sderaadt 		killdiv();
484df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
485df930be7Sderaadt 		break;
486df930be7Sderaadt 
487df930be7Sderaadt 	case DEFNTYPE:
488df930be7Sderaadt 		if (argc > 2)
489df930be7Sderaadt 			for (n = 2; n < argc; n++)
490df930be7Sderaadt 				dodefn(argv[n]);
491df930be7Sderaadt 		break;
492df930be7Sderaadt 
493b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
494b8161682Sespie 		if (argc > 2)
495b8161682Sespie 			doindir(argv, argc);
496b8161682Sespie 		break;
497b8161682Sespie 
498b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
499b8161682Sespie 		if (argc > 2)
500b8161682Sespie 			dobuiltin(argv, argc);
501b8161682Sespie 		break;
502b8161682Sespie 
503b8161682Sespie 	case PATSTYPE:
504b8161682Sespie 		if (argc > 2)
505b8161682Sespie 			dopatsubst(argv, argc);
506b8161682Sespie 		break;
507b8161682Sespie 	case REGEXPTYPE:
508b8161682Sespie 		if (argc > 2)
509b8161682Sespie 			doregexp(argv, argc);
510b8161682Sespie 		break;
511b8161682Sespie 	case LINETYPE:
512b8161682Sespie 		doprintlineno(infile+ilevel);
513b8161682Sespie 		break;
514b8161682Sespie 	case FILENAMETYPE:
515b8161682Sespie 		doprintfilename(infile+ilevel);
516b8161682Sespie 		break;
517423624b7Sespie 	case SELFTYPE:
518423624b7Sespie 		pbstr(rquote);
519423624b7Sespie 		pbstr(argv[1]);
520423624b7Sespie 		pbstr(lquote);
521423624b7Sespie 		break;
522df930be7Sderaadt 	default:
52375ebbed7Sespie 		m4errx(1, "eval: major botch.");
524df930be7Sderaadt 		break;
525df930be7Sderaadt 	}
526df930be7Sderaadt }
527df930be7Sderaadt 
528df930be7Sderaadt /*
52908f7f207Sespie  * expand_macro - user-defined macro expansion
530df930be7Sderaadt  */
531df930be7Sderaadt void
expand_macro(const char * argv[],int argc)5328e061d4bSespie expand_macro(const char *argv[], int argc)
533df930be7Sderaadt {
534bb34cd6cSespie 	const char *t;
535bb34cd6cSespie 	const char *p;
53653f6f6bfSespie 	int n;
53753f6f6bfSespie 	int argno;
538df930be7Sderaadt 
539df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
540df930be7Sderaadt 	p = t;
541df930be7Sderaadt 	while (*p)
542df930be7Sderaadt 		p++;
543df930be7Sderaadt 	p--;			       /* last character of defn */
544df930be7Sderaadt 	while (p > t) {
545df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
546739ce124Sespie 			PUSHBACK(*p);
547df930be7Sderaadt 		else {
548df930be7Sderaadt 			switch (*p) {
549df930be7Sderaadt 
550df930be7Sderaadt 			case '#':
551df930be7Sderaadt 				pbnum(argc - 2);
552df930be7Sderaadt 				break;
553df930be7Sderaadt 			case '0':
554df930be7Sderaadt 			case '1':
555df930be7Sderaadt 			case '2':
556df930be7Sderaadt 			case '3':
557df930be7Sderaadt 			case '4':
558df930be7Sderaadt 			case '5':
559df930be7Sderaadt 			case '6':
560df930be7Sderaadt 			case '7':
561df930be7Sderaadt 			case '8':
562df930be7Sderaadt 			case '9':
563df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
564df930be7Sderaadt 					pbstr(argv[argno + 1]);
565df930be7Sderaadt 				break;
566df930be7Sderaadt 			case '*':
567faa30e49Sespie 				if (argc > 2) {
568df930be7Sderaadt 					for (n = argc - 1; n > 2; n--) {
569df930be7Sderaadt 						pbstr(argv[n]);
570739ce124Sespie 						pushback(COMMA);
571df930be7Sderaadt 					}
572df930be7Sderaadt 					pbstr(argv[2]);
573faa30e49Sespie 				}
574df930be7Sderaadt 				break;
575aa676ce1Smillert                         case '@':
576faa30e49Sespie 				if (argc > 2) {
577aa676ce1Smillert 					for (n = argc - 1; n > 2; n--) {
578aa676ce1Smillert 						pbstr(rquote);
579aa676ce1Smillert 						pbstr(argv[n]);
580aa676ce1Smillert 						pbstr(lquote);
581739ce124Sespie 						pushback(COMMA);
582aa676ce1Smillert 					}
583aa676ce1Smillert 					pbstr(rquote);
584aa676ce1Smillert 					pbstr(argv[2]);
585aa676ce1Smillert 					pbstr(lquote);
586faa30e49Sespie 				}
587aa676ce1Smillert                                 break;
588df930be7Sderaadt 			default:
589739ce124Sespie 				PUSHBACK(*p);
590739ce124Sespie 				PUSHBACK('$');
591df930be7Sderaadt 				break;
592df930be7Sderaadt 			}
593df930be7Sderaadt 			p--;
594df930be7Sderaadt 		}
595df930be7Sderaadt 		p--;
596df930be7Sderaadt 	}
597df930be7Sderaadt 	if (p == t)		       /* do last character */
598739ce124Sespie 		PUSHBACK(*p);
599df930be7Sderaadt }
600df930be7Sderaadt 
6015ddad5ccSespie 
602df930be7Sderaadt /*
6035ddad5ccSespie  * dodefine - install definition in the table
6045ddad5ccSespie  */
6055ddad5ccSespie void
dodefine(const char * name,const char * defn)6065ddad5ccSespie dodefine(const char *name, const char *defn)
6075ddad5ccSespie {
60887a9001aSespie 	if (!*name && !mimic_gnu)
60975ebbed7Sespie 		m4errx(1, "null definition.");
61087a9001aSespie 	else
6113509e8ffSespie 		macro_define(name, defn);
612df930be7Sderaadt }
613df930be7Sderaadt 
614df930be7Sderaadt /*
615df930be7Sderaadt  * dodefn - push back a quoted definition of
616df930be7Sderaadt  *      the given name.
617df930be7Sderaadt  */
618bb34cd6cSespie static void
dodefn(const char * name)6198e061d4bSespie dodefn(const char *name)
620df930be7Sderaadt {
6213509e8ffSespie 	struct macro_definition *p;
622df930be7Sderaadt 
6233509e8ffSespie 	if ((p = lookup_macro_definition(name)) != NULL) {
6245ddad5ccSespie 		if ((p->type & TYPEMASK) == MACRTYPE) {
6253a73db8cSderaadt 			pbstr(rquote);
626df930be7Sderaadt 			pbstr(p->defn);
6273a73db8cSderaadt 			pbstr(lquote);
6285ddad5ccSespie 		} else {
6295ddad5ccSespie 			pbstr(p->defn);
630f8b42d48Sespie 			pbstr(BUILTIN_MARKER);
631f8b42d48Sespie 		}
632df930be7Sderaadt 	}
633df930be7Sderaadt }
634df930be7Sderaadt 
635df930be7Sderaadt /*
636df930be7Sderaadt  * dopushdef - install a definition in the hash table
637df930be7Sderaadt  *      without removing a previous definition. Since
638df930be7Sderaadt  *      each new entry is entered in *front* of the
639df930be7Sderaadt  *      hash bucket, it hides a previous definition from
640df930be7Sderaadt  *      lookup.
641df930be7Sderaadt  */
642bb34cd6cSespie static void
dopushdef(const char * name,const char * defn)6438e061d4bSespie dopushdef(const char *name, const char *defn)
644df930be7Sderaadt {
64587a9001aSespie 	if (!*name && !mimic_gnu)
64675ebbed7Sespie 		m4errx(1, "null definition.");
64787a9001aSespie 	else
6483509e8ffSespie 		macro_pushdef(name, defn);
649df930be7Sderaadt }
650df930be7Sderaadt 
651df930be7Sderaadt /*
652dd0682a2Sespie  * dump_one_def - dump the specified definition.
653dd0682a2Sespie  */
654dd0682a2Sespie static void
dump_one_def(const char * name,struct macro_definition * p)6553509e8ffSespie dump_one_def(const char *name, struct macro_definition *p)
656dd0682a2Sespie {
657ad93774eSespie 	if (!traceout)
658ad93774eSespie 		traceout = stderr;
6595191fa0aSespie 	if (mimic_gnu) {
6605191fa0aSespie 		if ((p->type & TYPEMASK) == MACRTYPE)
6613509e8ffSespie 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
6625191fa0aSespie 		else {
6633509e8ffSespie 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
6645191fa0aSespie 		}
6655191fa0aSespie 	} else
6663509e8ffSespie 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
667dd0682a2Sespie }
668dd0682a2Sespie 
669dd0682a2Sespie /*
670df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
671df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
672df930be7Sderaadt  *      hash table is dumped.
673df930be7Sderaadt  */
674bb34cd6cSespie static void
dodump(const char * argv[],int argc)6758e061d4bSespie dodump(const char *argv[], int argc)
676df930be7Sderaadt {
67753f6f6bfSespie 	int n;
6783509e8ffSespie 	struct macro_definition *p;
679df930be7Sderaadt 
680df930be7Sderaadt 	if (argc > 2) {
681df930be7Sderaadt 		for (n = 2; n < argc; n++)
6823509e8ffSespie 			if ((p = lookup_macro_definition(argv[n])) != NULL)
6833509e8ffSespie 				dump_one_def(argv[n], p);
6843509e8ffSespie 	} else
6853509e8ffSespie 		macro_for_all(dump_one_def);
686df930be7Sderaadt }
687df930be7Sderaadt 
688df930be7Sderaadt /*
68934970243Sespie  * dotrace - mark some macros as traced/untraced depending upon on.
69034970243Sespie  */
69134970243Sespie static void
dotrace(const char * argv[],int argc,int on)6928e061d4bSespie dotrace(const char *argv[], int argc, int on)
69334970243Sespie {
69434970243Sespie 	int n;
69534970243Sespie 
69634970243Sespie 	if (argc > 2) {
69734970243Sespie 		for (n = 2; n < argc; n++)
69834970243Sespie 			mark_traced(argv[n], on);
69934970243Sespie 	} else
70034970243Sespie 		mark_traced(NULL, on);
70134970243Sespie }
70234970243Sespie 
70334970243Sespie /*
704df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
705df930be7Sderaadt  */
706bb34cd6cSespie static void
doifelse(const char * argv[],int argc)7078e061d4bSespie doifelse(const char *argv[], int argc)
708df930be7Sderaadt {
709b6ff91d1Sespie 	while (argc > 4) {
710b6ff91d1Sespie 		if (STREQ(argv[2], argv[3])) {
711df930be7Sderaadt 			pbstr(argv[4]);
712b6ff91d1Sespie 			break;
713b6ff91d1Sespie 		} else if (argc == 6) {
714df930be7Sderaadt 			pbstr(argv[5]);
715b6ff91d1Sespie 			break;
716b6ff91d1Sespie 		} else {
717df930be7Sderaadt 			argv += 3;
718df930be7Sderaadt 			argc -= 3;
719df930be7Sderaadt 		}
720df930be7Sderaadt 	}
721df930be7Sderaadt }
722df930be7Sderaadt 
723df930be7Sderaadt /*
724df930be7Sderaadt  * doinclude - include a given file.
725df930be7Sderaadt  */
726bb34cd6cSespie static int
doincl(const char * ifile)7278e061d4bSespie doincl(const char *ifile)
728df930be7Sderaadt {
729df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
73075ebbed7Sespie 		m4errx(1, "too many include files.");
7310d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
732df930be7Sderaadt 		ilevel++;
733df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
734df930be7Sderaadt 		return (1);
7357d3e0b6bSderaadt 	} else
736df930be7Sderaadt 		return (0);
737df930be7Sderaadt }
738df930be7Sderaadt 
739df930be7Sderaadt #ifdef EXTENDED
740df930be7Sderaadt /*
741df930be7Sderaadt  * dopaste - include a given file without any
742df930be7Sderaadt  *           macro processing.
743df930be7Sderaadt  */
744bb34cd6cSespie static int
dopaste(const char * pfile)7458e061d4bSespie dopaste(const char *pfile)
746df930be7Sderaadt {
747df930be7Sderaadt 	FILE *pf;
74853f6f6bfSespie 	int c;
749df930be7Sderaadt 
750df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
751aec72266Sespie 		if (synch_lines)
752aec72266Sespie 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
753df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
754df930be7Sderaadt 			putc(c, active);
755df930be7Sderaadt 		(void) fclose(pf);
756aec72266Sespie 		emit_synchline();
757df930be7Sderaadt 		return (1);
7587d3e0b6bSderaadt 	} else
759df930be7Sderaadt 		return (0);
760df930be7Sderaadt }
761df930be7Sderaadt #endif
762df930be7Sderaadt 
763df930be7Sderaadt /*
764df930be7Sderaadt  * dochq - change quote characters
765df930be7Sderaadt  */
766bb34cd6cSespie static void
dochq(const char * argv[],int ac)767739ce124Sespie dochq(const char *argv[], int ac)
768df930be7Sderaadt {
769739ce124Sespie 	if (ac == 2) {
770739ce124Sespie 		lquote[0] = LQUOTE; lquote[1] = EOS;
771739ce124Sespie 		rquote[0] = RQUOTE; rquote[1] = EOS;
7727d3e0b6bSderaadt 	} else {
773739ce124Sespie 		strlcpy(lquote, argv[2], sizeof(lquote));
774739ce124Sespie 		if (ac > 3) {
775739ce124Sespie 			strlcpy(rquote, argv[3], sizeof(rquote));
776739ce124Sespie 		} else {
777739ce124Sespie 			rquote[0] = ECOMMT; rquote[1] = EOS;
778739ce124Sespie 		}
779df930be7Sderaadt 	}
780df930be7Sderaadt }
781df930be7Sderaadt 
782df930be7Sderaadt /*
783df930be7Sderaadt  * dochc - change comment characters
784df930be7Sderaadt  */
785bb34cd6cSespie static void
dochc(const char * argv[],int argc)7868e061d4bSespie dochc(const char *argv[], int argc)
787df930be7Sderaadt {
788739ce124Sespie /* XXX Note that there is no difference between no argument and a single
789739ce124Sespie  * empty argument.
790739ce124Sespie  */
791739ce124Sespie 	if (argc == 2) {
792739ce124Sespie 		scommt[0] = EOS;
793739ce124Sespie 		ecommt[0] = EOS;
794739ce124Sespie 	} else {
795b81b15b2Sespie 		strlcpy(scommt, argv[2], sizeof(scommt));
796739ce124Sespie 		if (argc == 3) {
797739ce124Sespie 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
798739ce124Sespie 		} else {
799b81b15b2Sespie 			strlcpy(ecommt, argv[3], sizeof(ecommt));
800df930be7Sderaadt 		}
801df930be7Sderaadt 	}
802df930be7Sderaadt }
803df930be7Sderaadt 
804df930be7Sderaadt /*
805ad459a23Sespie  * dom4wrap - expand text at EOF
806ad459a23Sespie  */
807ad459a23Sespie static void
dom4wrap(const char * text)808ad459a23Sespie dom4wrap(const char *text)
809ad459a23Sespie {
810ad459a23Sespie 	if (wrapindex >= maxwraps) {
811ad459a23Sespie 		if (maxwraps == 0)
812ad459a23Sespie 			maxwraps = 16;
813ad459a23Sespie 		else
814ad459a23Sespie 			maxwraps *= 2;
815c608d5f4Sespie 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
816ad459a23Sespie 		   "too many m4wraps");
817ad459a23Sespie 	}
818ad459a23Sespie 	m4wraps[wrapindex++] = xstrdup(text);
819ad459a23Sespie }
820ad459a23Sespie 
821ad459a23Sespie /*
822df930be7Sderaadt  * dodivert - divert the output to a temporary file
823df930be7Sderaadt  */
824bb34cd6cSespie static void
dodiv(int n)8258e061d4bSespie dodiv(int n)
826df930be7Sderaadt {
827445b77f7Smillert 	int fd;
828445b77f7Smillert 
8297d3e0b6bSderaadt 	oindex = n;
83025afcddbSespie 	if (n >= maxout) {
83125afcddbSespie 		if (mimic_gnu)
83225afcddbSespie 			resizedivs(n + 10);
83325afcddbSespie 		else
83425afcddbSespie 			n = 0;		/* bitbucket */
83525afcddbSespie 	}
83625afcddbSespie 
83725afcddbSespie 	if (n < 0)
838df930be7Sderaadt 		n = 0;		       /* bitbucket */
839df930be7Sderaadt 	if (outfile[n] == NULL) {
8403f42598dSespie 		char fname[] = _PATH_DIVNAME;
8413f42598dSespie 
842c2d43ecaSderaadt 		if ((fd = mkstemp(fname)) == -1 ||
843f5d2852fSespie 		    unlink(fname) == -1 ||
8443f42598dSespie 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
8453f42598dSespie 			err(1, "%s: cannot divert", fname);
846df930be7Sderaadt 	}
847df930be7Sderaadt 	active = outfile[n];
848df930be7Sderaadt }
849df930be7Sderaadt 
850df930be7Sderaadt /*
851df930be7Sderaadt  * doundivert - undivert a specified output, or all
852df930be7Sderaadt  *              other outputs, in numerical order.
853df930be7Sderaadt  */
854bb34cd6cSespie static void
doundiv(const char * argv[],int argc)8558e061d4bSespie doundiv(const char *argv[], int argc)
856df930be7Sderaadt {
85753f6f6bfSespie 	int ind;
85853f6f6bfSespie 	int n;
859df930be7Sderaadt 
860df930be7Sderaadt 	if (argc > 2) {
861df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
862e79fa687Sespie 			const char *errstr;
863e79fa687Sespie 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
864e79fa687Sespie 			if (errstr) {
865e79fa687Sespie 				if (errno == EINVAL && mimic_gnu)
866e79fa687Sespie 					getdivfile(argv[ind]);
867e79fa687Sespie 			} else {
868e79fa687Sespie 				if (n < maxout && outfile[n] != NULL)
869df930be7Sderaadt 					getdiv(n);
870e79fa687Sespie 			}
871df930be7Sderaadt 		}
872df930be7Sderaadt 	}
873df930be7Sderaadt 	else
87425afcddbSespie 		for (n = 1; n < maxout; n++)
875df930be7Sderaadt 			if (outfile[n] != NULL)
876df930be7Sderaadt 				getdiv(n);
877df930be7Sderaadt }
878df930be7Sderaadt 
879df930be7Sderaadt /*
880df930be7Sderaadt  * dosub - select substring
881df930be7Sderaadt  */
882bb34cd6cSespie static void
dosub(const char * argv[],int argc)8838e061d4bSespie dosub(const char *argv[], int argc)
884df930be7Sderaadt {
885bb34cd6cSespie 	const char *ap, *fc, *k;
88653f6f6bfSespie 	int nc;
887df930be7Sderaadt 
888df930be7Sderaadt 	ap = argv[2];		       /* target string */
889df930be7Sderaadt #ifdef EXPR
890df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
891df930be7Sderaadt #else
892df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
893df930be7Sderaadt #endif
894bee8364eSespie 	nc = strlen(fc);
895bee8364eSespie 	if (argc >= 5)
896bee8364eSespie #ifdef EXPR
897bee8364eSespie 		nc = min(nc, expr(argv[4]));
898bee8364eSespie #else
899bee8364eSespie 		nc = min(nc, atoi(argv[4]));
900bee8364eSespie #endif
901df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
902bee8364eSespie 		for (k = fc + nc - 1; k >= fc; k--)
903739ce124Sespie 			pushback(*k);
904df930be7Sderaadt }
905df930be7Sderaadt 
906df930be7Sderaadt /*
907df930be7Sderaadt  * map:
908df930be7Sderaadt  * map every character of s1 that is specified in from
909df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
910df930be7Sderaadt  *
91187ab3cf4Sespie  * This is derived from the a standard implementation of map(s,from,to)
91287ab3cf4Sespie  * function of ICON language. Within mapvec, we replace every character
91387ab3cf4Sespie  * of "from" with the corresponding character in "to".
91487ab3cf4Sespie  * If "to" is shorter than "from", than the corresponding entries are null,
915*d9a51c35Sjmc  * which means that those characters disappear altogether.
916df930be7Sderaadt  */
917bb34cd6cSespie static void
map(char * dest,const char * src,const char * from,const char * to)9188e061d4bSespie map(char *dest, const char *src, const char *from, const char *to)
919df930be7Sderaadt {
920bb34cd6cSespie 	const char *tmp;
921ee3599c7Sespie 	unsigned char sch, dch;
92287c5c065Sespie 	static char frombis[257];
92387c5c065Sespie 	static char tobis[257];
92427e0c134Sespie 	int i;
92527e0c134Sespie 	char seen[256];
926ee3599c7Sespie 	static unsigned char mapvec[256] = {
927ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
928ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
929ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
930ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
931ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
932ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
933ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
934ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
935ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
936ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
937ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
938ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
939ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
940ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
941ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
942ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
943ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
944ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
945df930be7Sderaadt 	};
946df930be7Sderaadt 
947df930be7Sderaadt 	if (*src) {
94887c5c065Sespie 		if (mimic_gnu) {
94987c5c065Sespie 			/*
95087c5c065Sespie 			 * expand character ranges on the fly
95187c5c065Sespie 			 */
95287c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
95387c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
95487c5c065Sespie 		}
955df930be7Sderaadt 		tmp = from;
956df930be7Sderaadt 	/*
957df930be7Sderaadt 	 * create a mapping between "from" and
958df930be7Sderaadt 	 * "to"
959df930be7Sderaadt 	 */
96027e0c134Sespie 		for (i = 0; i < 256; i++)
96127e0c134Sespie 			seen[i] = 0;
96227e0c134Sespie 		while (*from) {
96327e0c134Sespie 			if (!seen[(unsigned char)(*from)]) {
96427e0c134Sespie 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
96527e0c134Sespie 				seen[(unsigned char)(*from)] = 1;
96627e0c134Sespie 			}
96727e0c134Sespie 			from++;
96827e0c134Sespie 			if (*to)
96927e0c134Sespie 				to++;
97027e0c134Sespie 		}
971df930be7Sderaadt 
972df930be7Sderaadt 		while (*src) {
973ee3599c7Sespie 			sch = (unsigned char)(*src++);
974df930be7Sderaadt 			dch = mapvec[sch];
975ee3599c7Sespie 			if ((*dest = (char)dch))
976df930be7Sderaadt 				dest++;
977df930be7Sderaadt 		}
978df930be7Sderaadt 	/*
979df930be7Sderaadt 	 * restore all the changed characters
980df930be7Sderaadt 	 */
981df930be7Sderaadt 		while (*tmp) {
982ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
983df930be7Sderaadt 			tmp++;
984df930be7Sderaadt 		}
985df930be7Sderaadt 	}
986ee3599c7Sespie 	*dest = '\0';
987df930be7Sderaadt }
98887c5c065Sespie 
98987c5c065Sespie 
99087c5c065Sespie /*
99187c5c065Sespie  * handledash:
99287c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
99387c5c065Sespie  * on the way.
99487c5c065Sespie  */
99587c5c065Sespie static const char *
handledash(char * buffer,char * end,const char * src)9968e061d4bSespie handledash(char *buffer, char *end, const char *src)
99787c5c065Sespie {
99887c5c065Sespie 	char *p;
99987c5c065Sespie 
100087c5c065Sespie 	p = buffer;
100187c5c065Sespie 	while(*src) {
100287c5c065Sespie 		if (src[1] == '-' && src[2]) {
100387c5c065Sespie 			unsigned char i;
1004e79fa687Sespie 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
100587c5c065Sespie 				for (i = (unsigned char)src[0];
100687c5c065Sespie 				    i <= (unsigned char)src[2]; i++) {
100787c5c065Sespie 					*p++ = i;
100887c5c065Sespie 					if (p == end) {
100987c5c065Sespie 						*p = '\0';
101087c5c065Sespie 						return buffer;
101187c5c065Sespie 					}
101287c5c065Sespie 				}
1013e79fa687Sespie 			} else {
1014e79fa687Sespie 				for (i = (unsigned char)src[0];
1015e79fa687Sespie 				    i >= (unsigned char)src[2]; i--) {
1016e79fa687Sespie 					*p++ = i;
1017e79fa687Sespie 					if (p == end) {
1018e79fa687Sespie 						*p = '\0';
1019e79fa687Sespie 						return buffer;
1020e79fa687Sespie 					}
1021e79fa687Sespie 				}
1022e79fa687Sespie 			}
102387c5c065Sespie 			src += 3;
102487c5c065Sespie 		} else
102587c5c065Sespie 			*p++ = *src++;
102687c5c065Sespie 		if (p == end)
102787c5c065Sespie 			break;
102887c5c065Sespie 	}
102987c5c065Sespie 	*p = '\0';
103087c5c065Sespie 	return buffer;
103187c5c065Sespie }
1032