xref: /openbsd/usr.bin/m4/eval.c (revision d2d86e25)
1*d2d86e25Sbcallah /*	$OpenBSD: eval.c,v 1.75 2017/06/15 13:48:42 bcallah 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
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
1208e061d4bSespie expand_builtin(const char *argv[], int argc, int td)
121df930be7Sderaadt {
12253f6f6bfSespie 	int c, n;
123054026c0Sespie 	int ac;
124df930be7Sderaadt 	static int sysval = 0;
125df930be7Sderaadt 
126df930be7Sderaadt #ifdef DEBUG
127df930be7Sderaadt 	printf("argc = %d\n", argc);
128df930be7Sderaadt 	for (n = 0; n < argc; n++)
129df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
13028728804Sespie 	fflush(stdout);
131df930be7Sderaadt #endif
132718b194dSespie 
133df930be7Sderaadt  /*
134df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
135df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
136df930be7Sderaadt   * argc to avoid further checking..
137df930be7Sderaadt   */
138739ce124Sespie  /* we keep the initial value for those built-ins that differentiate
139739ce124Sespie   * between builtin() and builtin.
140739ce124Sespie   */
141054026c0Sespie 	ac = argc;
142054026c0Sespie 
14387a9001aSespie 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
144df930be7Sderaadt 		argc--;
145df930be7Sderaadt 
146718b194dSespie 	switch (td & TYPEMASK) {
147df930be7Sderaadt 
148df930be7Sderaadt 	case DEFITYPE:
149df930be7Sderaadt 		if (argc > 2)
150df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
151df930be7Sderaadt 		break;
152df930be7Sderaadt 
153df930be7Sderaadt 	case PUSDTYPE:
154df930be7Sderaadt 		if (argc > 2)
155df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
156df930be7Sderaadt 		break;
157df930be7Sderaadt 
158df930be7Sderaadt 	case DUMPTYPE:
159df930be7Sderaadt 		dodump(argv, argc);
160df930be7Sderaadt 		break;
161df930be7Sderaadt 
16234970243Sespie 	case TRACEONTYPE:
16334970243Sespie 		dotrace(argv, argc, 1);
16434970243Sespie 		break;
16534970243Sespie 
16634970243Sespie 	case TRACEOFFTYPE:
16734970243Sespie 		dotrace(argv, argc, 0);
16834970243Sespie 		break;
16934970243Sespie 
170df930be7Sderaadt 	case EXPRTYPE:
171df930be7Sderaadt 	/*
172df930be7Sderaadt 	 * doexpr - evaluate arithmetic
173df930be7Sderaadt 	 * expression
174df930be7Sderaadt 	 */
175e79fa687Sespie 	{
176e79fa687Sespie 		int base = 10;
177e79fa687Sespie 		int maxdigits = 0;
178e79fa687Sespie 		const char *errstr;
179e79fa687Sespie 
180e79fa687Sespie 		if (argc > 3) {
181e79fa687Sespie 			base = strtonum(argv[3], 2, 36, &errstr);
182e79fa687Sespie 			if (errstr) {
18375ebbed7Sespie 				m4errx(1, "expr: base %s invalid.", argv[3]);
184e79fa687Sespie 			}
185e79fa687Sespie 		}
186e79fa687Sespie 		if (argc > 4) {
187e79fa687Sespie 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
188e79fa687Sespie 			if (errstr) {
18975ebbed7Sespie 				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
190e79fa687Sespie 			}
191e79fa687Sespie 		}
192df930be7Sderaadt 		if (argc > 2)
193e79fa687Sespie 			pbnumbase(expr(argv[2]), base, maxdigits);
194df930be7Sderaadt 		break;
195e79fa687Sespie 	}
196df930be7Sderaadt 
197df930be7Sderaadt 	case IFELTYPE:
198df930be7Sderaadt 		if (argc > 4)
199df930be7Sderaadt 			doifelse(argv, argc);
200df930be7Sderaadt 		break;
201df930be7Sderaadt 
202df930be7Sderaadt 	case IFDFTYPE:
203df930be7Sderaadt 	/*
204df930be7Sderaadt 	 * doifdef - select one of two
205df930be7Sderaadt 	 * alternatives based on the existence of
206df930be7Sderaadt 	 * another definition
207df930be7Sderaadt 	 */
208df930be7Sderaadt 		if (argc > 3) {
2093509e8ffSespie 			if (lookup_macro_definition(argv[2]) != NULL)
210df930be7Sderaadt 				pbstr(argv[3]);
211df930be7Sderaadt 			else if (argc > 4)
212df930be7Sderaadt 				pbstr(argv[4]);
213df930be7Sderaadt 		}
214df930be7Sderaadt 		break;
215df930be7Sderaadt 
216df930be7Sderaadt 	case LENGTYPE:
217df930be7Sderaadt 	/*
218df930be7Sderaadt 	 * dolen - find the length of the
219df930be7Sderaadt 	 * argument
220df930be7Sderaadt 	 */
221df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
222df930be7Sderaadt 		break;
223df930be7Sderaadt 
224df930be7Sderaadt 	case INCRTYPE:
225df930be7Sderaadt 	/*
226df930be7Sderaadt 	 * doincr - increment the value of the
227df930be7Sderaadt 	 * argument
228df930be7Sderaadt 	 */
229df930be7Sderaadt 		if (argc > 2)
230df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
231df930be7Sderaadt 		break;
232df930be7Sderaadt 
233df930be7Sderaadt 	case DECRTYPE:
234df930be7Sderaadt 	/*
235df930be7Sderaadt 	 * dodecr - decrement the value of the
236df930be7Sderaadt 	 * argument
237df930be7Sderaadt 	 */
238df930be7Sderaadt 		if (argc > 2)
239df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
240df930be7Sderaadt 		break;
241df930be7Sderaadt 
242df930be7Sderaadt 	case SYSCTYPE:
243df930be7Sderaadt 	/*
244df930be7Sderaadt 	 * dosys - execute system command
245df930be7Sderaadt 	 */
246b3d09a36Srobert 		if (argc > 2) {
247b3d09a36Srobert 			fflush(stdout);
248df930be7Sderaadt 			sysval = system(argv[2]);
249b3d09a36Srobert 		}
250df930be7Sderaadt 		break;
251df930be7Sderaadt 
252df930be7Sderaadt 	case SYSVTYPE:
253df930be7Sderaadt 	/*
254df930be7Sderaadt 	 * dosysval - return value of the last
255df930be7Sderaadt 	 * system call.
256df930be7Sderaadt 	 *
257df930be7Sderaadt 	 */
258df930be7Sderaadt 		pbnum(sysval);
259df930be7Sderaadt 		break;
260df930be7Sderaadt 
261c91edbbbSespie 	case ESYSCMDTYPE:
262c91edbbbSespie 		if (argc > 2)
263c91edbbbSespie 			doesyscmd(argv[2]);
264c91edbbbSespie 		break;
265df930be7Sderaadt 	case INCLTYPE:
2662aa31d4aSderaadt 		if (argc > 2) {
2672aa31d4aSderaadt 			if (!doincl(argv[2])) {
268a45fdd0cSespie 				if (mimic_gnu) {
269a45fdd0cSespie 					warn("%s at line %lu: include(%s)",
270a45fdd0cSespie 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
271a45fdd0cSespie 					exit_code = 1;
272*d2d86e25Sbcallah 					if (fatal_warns) {
273*d2d86e25Sbcallah 						killdiv();
274*d2d86e25Sbcallah 						exit(exit_code);
275*d2d86e25Sbcallah 					}
276a45fdd0cSespie 				} else
2770d3ffe1dSespie 					err(1, "%s at line %lu: include(%s)",
2780d3ffe1dSespie 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2792aa31d4aSderaadt 			}
2802aa31d4aSderaadt 		}
281df930be7Sderaadt 		break;
282df930be7Sderaadt 
283df930be7Sderaadt 	case SINCTYPE:
284df930be7Sderaadt 		if (argc > 2)
285df930be7Sderaadt 			(void) doincl(argv[2]);
286df930be7Sderaadt 		break;
287df930be7Sderaadt #ifdef EXTENDED
288df930be7Sderaadt 	case PASTTYPE:
289df930be7Sderaadt 		if (argc > 2)
290df930be7Sderaadt 			if (!dopaste(argv[2]))
2910d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
2920d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
293df930be7Sderaadt 		break;
294df930be7Sderaadt 
295df930be7Sderaadt 	case SPASTYPE:
296df930be7Sderaadt 		if (argc > 2)
297df930be7Sderaadt 			(void) dopaste(argv[2]);
298df930be7Sderaadt 		break;
29909d1584fSespie 	case FORMATTYPE:
30009d1584fSespie 		doformat(argv, argc);
30109d1584fSespie 		break;
302df930be7Sderaadt #endif
303df930be7Sderaadt 	case CHNQTYPE:
304739ce124Sespie 		dochq(argv, ac);
305df930be7Sderaadt 		break;
306df930be7Sderaadt 
307df930be7Sderaadt 	case CHNCTYPE:
308df930be7Sderaadt 		dochc(argv, argc);
309df930be7Sderaadt 		break;
310df930be7Sderaadt 
311df930be7Sderaadt 	case SUBSTYPE:
312df930be7Sderaadt 	/*
313df930be7Sderaadt 	 * dosub - select substring
314df930be7Sderaadt 	 *
315df930be7Sderaadt 	 */
316df930be7Sderaadt 		if (argc > 3)
317df930be7Sderaadt 			dosub(argv, argc);
318df930be7Sderaadt 		break;
319df930be7Sderaadt 
320df930be7Sderaadt 	case SHIFTYPE:
321df930be7Sderaadt 	/*
322df930be7Sderaadt 	 * doshift - push back all arguments
323df930be7Sderaadt 	 * except the first one (i.e. skip
324df930be7Sderaadt 	 * argv[2])
325df930be7Sderaadt 	 */
326df930be7Sderaadt 		if (argc > 3) {
327df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
3283a73db8cSderaadt 				pbstr(rquote);
329df930be7Sderaadt 				pbstr(argv[n]);
3303a73db8cSderaadt 				pbstr(lquote);
331739ce124Sespie 				pushback(COMMA);
332df930be7Sderaadt 			}
3333a73db8cSderaadt 			pbstr(rquote);
334df930be7Sderaadt 			pbstr(argv[3]);
3353a73db8cSderaadt 			pbstr(lquote);
336df930be7Sderaadt 		}
337df930be7Sderaadt 		break;
338df930be7Sderaadt 
339df930be7Sderaadt 	case DIVRTYPE:
340df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
341df930be7Sderaadt 			dodiv(n);
342df930be7Sderaadt 		else {
343df930be7Sderaadt 			active = stdout;
344df930be7Sderaadt 			oindex = 0;
345df930be7Sderaadt 		}
346df930be7Sderaadt 		break;
347df930be7Sderaadt 
348df930be7Sderaadt 	case UNDVTYPE:
349df930be7Sderaadt 		doundiv(argv, argc);
350df930be7Sderaadt 		break;
351df930be7Sderaadt 
352df930be7Sderaadt 	case DIVNTYPE:
353df930be7Sderaadt 	/*
354df930be7Sderaadt 	 * dodivnum - return the number of
355df930be7Sderaadt 	 * current output diversion
356df930be7Sderaadt 	 */
357df930be7Sderaadt 		pbnum(oindex);
358df930be7Sderaadt 		break;
359df930be7Sderaadt 
360df930be7Sderaadt 	case UNDFTYPE:
361df930be7Sderaadt 	/*
362df930be7Sderaadt 	 * doundefine - undefine a previously
363df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
364df930be7Sderaadt 	 */
365df930be7Sderaadt 		if (argc > 2)
366df930be7Sderaadt 			for (n = 2; n < argc; n++)
3673509e8ffSespie 				macro_undefine(argv[n]);
368df930be7Sderaadt 		break;
369df930be7Sderaadt 
370df930be7Sderaadt 	case POPDTYPE:
371df930be7Sderaadt 	/*
372df930be7Sderaadt 	 * dopopdef - remove the topmost
373df930be7Sderaadt 	 * definitions of macro(s) or m4
374df930be7Sderaadt 	 * keyword(s).
375df930be7Sderaadt 	 */
376df930be7Sderaadt 		if (argc > 2)
377df930be7Sderaadt 			for (n = 2; n < argc; n++)
3783509e8ffSespie 				macro_popdef(argv[n]);
379df930be7Sderaadt 		break;
380df930be7Sderaadt 
381df930be7Sderaadt 	case MKTMTYPE:
382df930be7Sderaadt 	/*
383df930be7Sderaadt 	 * dotemp - create a temporary file
384df930be7Sderaadt 	 */
38501e71e69Sespie 		if (argc > 2) {
38601e71e69Sespie 			int fd;
387bb34cd6cSespie 			char *temp;
38801e71e69Sespie 
389bb34cd6cSespie 			temp = xstrdup(argv[2]);
390bb34cd6cSespie 
391bb34cd6cSespie 			fd = mkstemp(temp);
39201e71e69Sespie 			if (fd == -1)
3930d3ffe1dSespie 				err(1,
3940d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
3950d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
39601e71e69Sespie 			close(fd);
397bb34cd6cSespie 			pbstr(temp);
398bb34cd6cSespie 			free(temp);
39901e71e69Sespie 		}
400df930be7Sderaadt 		break;
401df930be7Sderaadt 
402df930be7Sderaadt 	case TRNLTYPE:
403df930be7Sderaadt 	/*
404df930be7Sderaadt 	 * dotranslit - replace all characters in
405df930be7Sderaadt 	 * the source string that appears in the
406df930be7Sderaadt 	 * "from" string with the corresponding
407df930be7Sderaadt 	 * characters in the "to" string.
408df930be7Sderaadt 	 */
409df930be7Sderaadt 		if (argc > 3) {
41028728804Sespie 			char *temp;
41128728804Sespie 
412f6169a2cSespie 			temp = xalloc(strlen(argv[2])+1, NULL);
413df930be7Sderaadt 			if (argc > 4)
414df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
415df930be7Sderaadt 			else
416df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
417df930be7Sderaadt 			pbstr(temp);
41828728804Sespie 			free(temp);
4197d3e0b6bSderaadt 		} else if (argc > 2)
420df930be7Sderaadt 			pbstr(argv[2]);
421df930be7Sderaadt 		break;
422df930be7Sderaadt 
423df930be7Sderaadt 	case INDXTYPE:
424df930be7Sderaadt 	/*
425df930be7Sderaadt 	 * doindex - find the index of the second
426df930be7Sderaadt 	 * argument string in the first argument
427df930be7Sderaadt 	 * string. -1 if not present.
428df930be7Sderaadt 	 */
429df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
430df930be7Sderaadt 		break;
431df930be7Sderaadt 
432df930be7Sderaadt 	case ERRPTYPE:
433df930be7Sderaadt 	/*
434df930be7Sderaadt 	 * doerrp - print the arguments to stderr
435df930be7Sderaadt 	 * file
436df930be7Sderaadt 	 */
437df930be7Sderaadt 		if (argc > 2) {
438df930be7Sderaadt 			for (n = 2; n < argc; n++)
439df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
440df930be7Sderaadt 			fprintf(stderr, "\n");
441df930be7Sderaadt 		}
442df930be7Sderaadt 		break;
443df930be7Sderaadt 
444df930be7Sderaadt 	case DNLNTYPE:
445df930be7Sderaadt 	/*
446df930be7Sderaadt 	 * dodnl - eat-up-to and including
447df930be7Sderaadt 	 * newline
448df930be7Sderaadt 	 */
449df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
450df930be7Sderaadt 			;
451df930be7Sderaadt 		break;
452df930be7Sderaadt 
453df930be7Sderaadt 	case M4WRTYPE:
454df930be7Sderaadt 	/*
455df930be7Sderaadt 	 * dom4wrap - set up for
456df930be7Sderaadt 	 * wrap-up/wind-down activity
457df930be7Sderaadt 	 */
458ad459a23Sespie 		if (argc > 2)
459ad459a23Sespie 			dom4wrap(argv[2]);
460df930be7Sderaadt 		break;
461df930be7Sderaadt 
462df930be7Sderaadt 	case EXITTYPE:
463df930be7Sderaadt 	/*
464df930be7Sderaadt 	 * doexit - immediate exit from m4.
465df930be7Sderaadt 	 */
466df930be7Sderaadt 		killdiv();
467df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
468df930be7Sderaadt 		break;
469df930be7Sderaadt 
470df930be7Sderaadt 	case DEFNTYPE:
471df930be7Sderaadt 		if (argc > 2)
472df930be7Sderaadt 			for (n = 2; n < argc; n++)
473df930be7Sderaadt 				dodefn(argv[n]);
474df930be7Sderaadt 		break;
475df930be7Sderaadt 
476b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
477b8161682Sespie 		if (argc > 2)
478b8161682Sespie 			doindir(argv, argc);
479b8161682Sespie 		break;
480b8161682Sespie 
481b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
482b8161682Sespie 		if (argc > 2)
483b8161682Sespie 			dobuiltin(argv, argc);
484b8161682Sespie 		break;
485b8161682Sespie 
486b8161682Sespie 	case PATSTYPE:
487b8161682Sespie 		if (argc > 2)
488b8161682Sespie 			dopatsubst(argv, argc);
489b8161682Sespie 		break;
490b8161682Sespie 	case REGEXPTYPE:
491b8161682Sespie 		if (argc > 2)
492b8161682Sespie 			doregexp(argv, argc);
493b8161682Sespie 		break;
494b8161682Sespie 	case LINETYPE:
495b8161682Sespie 		doprintlineno(infile+ilevel);
496b8161682Sespie 		break;
497b8161682Sespie 	case FILENAMETYPE:
498b8161682Sespie 		doprintfilename(infile+ilevel);
499b8161682Sespie 		break;
500423624b7Sespie 	case SELFTYPE:
501423624b7Sespie 		pbstr(rquote);
502423624b7Sespie 		pbstr(argv[1]);
503423624b7Sespie 		pbstr(lquote);
504423624b7Sespie 		break;
505df930be7Sderaadt 	default:
50675ebbed7Sespie 		m4errx(1, "eval: major botch.");
507df930be7Sderaadt 		break;
508df930be7Sderaadt 	}
509df930be7Sderaadt }
510df930be7Sderaadt 
511df930be7Sderaadt /*
51208f7f207Sespie  * expand_macro - user-defined macro expansion
513df930be7Sderaadt  */
514df930be7Sderaadt void
5158e061d4bSespie expand_macro(const char *argv[], int argc)
516df930be7Sderaadt {
517bb34cd6cSespie 	const char *t;
518bb34cd6cSespie 	const char *p;
51953f6f6bfSespie 	int n;
52053f6f6bfSespie 	int argno;
521df930be7Sderaadt 
522df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
523df930be7Sderaadt 	p = t;
524df930be7Sderaadt 	while (*p)
525df930be7Sderaadt 		p++;
526df930be7Sderaadt 	p--;			       /* last character of defn */
527df930be7Sderaadt 	while (p > t) {
528df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
529739ce124Sespie 			PUSHBACK(*p);
530df930be7Sderaadt 		else {
531df930be7Sderaadt 			switch (*p) {
532df930be7Sderaadt 
533df930be7Sderaadt 			case '#':
534df930be7Sderaadt 				pbnum(argc - 2);
535df930be7Sderaadt 				break;
536df930be7Sderaadt 			case '0':
537df930be7Sderaadt 			case '1':
538df930be7Sderaadt 			case '2':
539df930be7Sderaadt 			case '3':
540df930be7Sderaadt 			case '4':
541df930be7Sderaadt 			case '5':
542df930be7Sderaadt 			case '6':
543df930be7Sderaadt 			case '7':
544df930be7Sderaadt 			case '8':
545df930be7Sderaadt 			case '9':
546df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
547df930be7Sderaadt 					pbstr(argv[argno + 1]);
548df930be7Sderaadt 				break;
549df930be7Sderaadt 			case '*':
550faa30e49Sespie 				if (argc > 2) {
551df930be7Sderaadt 					for (n = argc - 1; n > 2; n--) {
552df930be7Sderaadt 						pbstr(argv[n]);
553739ce124Sespie 						pushback(COMMA);
554df930be7Sderaadt 					}
555df930be7Sderaadt 					pbstr(argv[2]);
556faa30e49Sespie 				}
557df930be7Sderaadt 				break;
558aa676ce1Smillert                         case '@':
559faa30e49Sespie 				if (argc > 2) {
560aa676ce1Smillert 					for (n = argc - 1; n > 2; n--) {
561aa676ce1Smillert 						pbstr(rquote);
562aa676ce1Smillert 						pbstr(argv[n]);
563aa676ce1Smillert 						pbstr(lquote);
564739ce124Sespie 						pushback(COMMA);
565aa676ce1Smillert 					}
566aa676ce1Smillert 					pbstr(rquote);
567aa676ce1Smillert 					pbstr(argv[2]);
568aa676ce1Smillert 					pbstr(lquote);
569faa30e49Sespie 				}
570aa676ce1Smillert                                 break;
571df930be7Sderaadt 			default:
572739ce124Sespie 				PUSHBACK(*p);
573739ce124Sespie 				PUSHBACK('$');
574df930be7Sderaadt 				break;
575df930be7Sderaadt 			}
576df930be7Sderaadt 			p--;
577df930be7Sderaadt 		}
578df930be7Sderaadt 		p--;
579df930be7Sderaadt 	}
580df930be7Sderaadt 	if (p == t)		       /* do last character */
581739ce124Sespie 		PUSHBACK(*p);
582df930be7Sderaadt }
583df930be7Sderaadt 
5845ddad5ccSespie 
585df930be7Sderaadt /*
5865ddad5ccSespie  * dodefine - install definition in the table
5875ddad5ccSespie  */
5885ddad5ccSespie void
5895ddad5ccSespie dodefine(const char *name, const char *defn)
5905ddad5ccSespie {
59187a9001aSespie 	if (!*name && !mimic_gnu)
59275ebbed7Sespie 		m4errx(1, "null definition.");
59387a9001aSespie 	else
5943509e8ffSespie 		macro_define(name, defn);
595df930be7Sderaadt }
596df930be7Sderaadt 
597df930be7Sderaadt /*
598df930be7Sderaadt  * dodefn - push back a quoted definition of
599df930be7Sderaadt  *      the given name.
600df930be7Sderaadt  */
601bb34cd6cSespie static void
6028e061d4bSespie dodefn(const char *name)
603df930be7Sderaadt {
6043509e8ffSespie 	struct macro_definition *p;
605df930be7Sderaadt 
6063509e8ffSespie 	if ((p = lookup_macro_definition(name)) != NULL) {
6075ddad5ccSespie 		if ((p->type & TYPEMASK) == MACRTYPE) {
6083a73db8cSderaadt 			pbstr(rquote);
609df930be7Sderaadt 			pbstr(p->defn);
6103a73db8cSderaadt 			pbstr(lquote);
6115ddad5ccSespie 		} else {
6125ddad5ccSespie 			pbstr(p->defn);
613f8b42d48Sespie 			pbstr(BUILTIN_MARKER);
614f8b42d48Sespie 		}
615df930be7Sderaadt 	}
616df930be7Sderaadt }
617df930be7Sderaadt 
618df930be7Sderaadt /*
619df930be7Sderaadt  * dopushdef - install a definition in the hash table
620df930be7Sderaadt  *      without removing a previous definition. Since
621df930be7Sderaadt  *      each new entry is entered in *front* of the
622df930be7Sderaadt  *      hash bucket, it hides a previous definition from
623df930be7Sderaadt  *      lookup.
624df930be7Sderaadt  */
625bb34cd6cSespie static void
6268e061d4bSespie dopushdef(const char *name, const char *defn)
627df930be7Sderaadt {
62887a9001aSespie 	if (!*name && !mimic_gnu)
62975ebbed7Sespie 		m4errx(1, "null definition.");
63087a9001aSespie 	else
6313509e8ffSespie 		macro_pushdef(name, defn);
632df930be7Sderaadt }
633df930be7Sderaadt 
634df930be7Sderaadt /*
635dd0682a2Sespie  * dump_one_def - dump the specified definition.
636dd0682a2Sespie  */
637dd0682a2Sespie static void
6383509e8ffSespie dump_one_def(const char *name, struct macro_definition *p)
639dd0682a2Sespie {
640ad93774eSespie 	if (!traceout)
641ad93774eSespie 		traceout = stderr;
6425191fa0aSespie 	if (mimic_gnu) {
6435191fa0aSespie 		if ((p->type & TYPEMASK) == MACRTYPE)
6443509e8ffSespie 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
6455191fa0aSespie 		else {
6463509e8ffSespie 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
6475191fa0aSespie 		}
6485191fa0aSespie 	} else
6493509e8ffSespie 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
650dd0682a2Sespie }
651dd0682a2Sespie 
652dd0682a2Sespie /*
653df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
654df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
655df930be7Sderaadt  *      hash table is dumped.
656df930be7Sderaadt  */
657bb34cd6cSespie static void
6588e061d4bSespie dodump(const char *argv[], int argc)
659df930be7Sderaadt {
66053f6f6bfSespie 	int n;
6613509e8ffSespie 	struct macro_definition *p;
662df930be7Sderaadt 
663df930be7Sderaadt 	if (argc > 2) {
664df930be7Sderaadt 		for (n = 2; n < argc; n++)
6653509e8ffSespie 			if ((p = lookup_macro_definition(argv[n])) != NULL)
6663509e8ffSespie 				dump_one_def(argv[n], p);
6673509e8ffSespie 	} else
6683509e8ffSespie 		macro_for_all(dump_one_def);
669df930be7Sderaadt }
670df930be7Sderaadt 
671df930be7Sderaadt /*
67234970243Sespie  * dotrace - mark some macros as traced/untraced depending upon on.
67334970243Sespie  */
67434970243Sespie static void
6758e061d4bSespie dotrace(const char *argv[], int argc, int on)
67634970243Sespie {
67734970243Sespie 	int n;
67834970243Sespie 
67934970243Sespie 	if (argc > 2) {
68034970243Sespie 		for (n = 2; n < argc; n++)
68134970243Sespie 			mark_traced(argv[n], on);
68234970243Sespie 	} else
68334970243Sespie 		mark_traced(NULL, on);
68434970243Sespie }
68534970243Sespie 
68634970243Sespie /*
687df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
688df930be7Sderaadt  */
689bb34cd6cSespie static void
6908e061d4bSespie doifelse(const char *argv[], int argc)
691df930be7Sderaadt {
692df930be7Sderaadt 	cycle {
693df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
694df930be7Sderaadt 			pbstr(argv[4]);
695df930be7Sderaadt 		else if (argc == 6)
696df930be7Sderaadt 			pbstr(argv[5]);
697df930be7Sderaadt 		else if (argc > 6) {
698df930be7Sderaadt 			argv += 3;
699df930be7Sderaadt 			argc -= 3;
700df930be7Sderaadt 			continue;
701df930be7Sderaadt 		}
702df930be7Sderaadt 		break;
703df930be7Sderaadt 	}
704df930be7Sderaadt }
705df930be7Sderaadt 
706df930be7Sderaadt /*
707df930be7Sderaadt  * doinclude - include a given file.
708df930be7Sderaadt  */
709bb34cd6cSespie static int
7108e061d4bSespie doincl(const char *ifile)
711df930be7Sderaadt {
712df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
71375ebbed7Sespie 		m4errx(1, "too many include files.");
7140d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
715df930be7Sderaadt 		ilevel++;
716df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
717df930be7Sderaadt 		return (1);
7187d3e0b6bSderaadt 	} else
719df930be7Sderaadt 		return (0);
720df930be7Sderaadt }
721df930be7Sderaadt 
722df930be7Sderaadt #ifdef EXTENDED
723df930be7Sderaadt /*
724df930be7Sderaadt  * dopaste - include a given file without any
725df930be7Sderaadt  *           macro processing.
726df930be7Sderaadt  */
727bb34cd6cSespie static int
7288e061d4bSespie dopaste(const char *pfile)
729df930be7Sderaadt {
730df930be7Sderaadt 	FILE *pf;
73153f6f6bfSespie 	int c;
732df930be7Sderaadt 
733df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
734aec72266Sespie 		if (synch_lines)
735aec72266Sespie 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
736df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
737df930be7Sderaadt 			putc(c, active);
738df930be7Sderaadt 		(void) fclose(pf);
739aec72266Sespie 		emit_synchline();
740df930be7Sderaadt 		return (1);
7417d3e0b6bSderaadt 	} else
742df930be7Sderaadt 		return (0);
743df930be7Sderaadt }
744df930be7Sderaadt #endif
745df930be7Sderaadt 
746df930be7Sderaadt /*
747df930be7Sderaadt  * dochq - change quote characters
748df930be7Sderaadt  */
749bb34cd6cSespie static void
750739ce124Sespie dochq(const char *argv[], int ac)
751df930be7Sderaadt {
752739ce124Sespie 	if (ac == 2) {
753739ce124Sespie 		lquote[0] = LQUOTE; lquote[1] = EOS;
754739ce124Sespie 		rquote[0] = RQUOTE; rquote[1] = EOS;
7557d3e0b6bSderaadt 	} else {
756739ce124Sespie 		strlcpy(lquote, argv[2], sizeof(lquote));
757739ce124Sespie 		if (ac > 3) {
758739ce124Sespie 			strlcpy(rquote, argv[3], sizeof(rquote));
759739ce124Sespie 		} else {
760739ce124Sespie 			rquote[0] = ECOMMT; rquote[1] = EOS;
761739ce124Sespie 		}
762df930be7Sderaadt 	}
763df930be7Sderaadt }
764df930be7Sderaadt 
765df930be7Sderaadt /*
766df930be7Sderaadt  * dochc - change comment characters
767df930be7Sderaadt  */
768bb34cd6cSespie static void
7698e061d4bSespie dochc(const char *argv[], int argc)
770df930be7Sderaadt {
771739ce124Sespie /* XXX Note that there is no difference between no argument and a single
772739ce124Sespie  * empty argument.
773739ce124Sespie  */
774739ce124Sespie 	if (argc == 2) {
775739ce124Sespie 		scommt[0] = EOS;
776739ce124Sespie 		ecommt[0] = EOS;
777739ce124Sespie 	} else {
778b81b15b2Sespie 		strlcpy(scommt, argv[2], sizeof(scommt));
779739ce124Sespie 		if (argc == 3) {
780739ce124Sespie 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
781739ce124Sespie 		} else {
782b81b15b2Sespie 			strlcpy(ecommt, argv[3], sizeof(ecommt));
783df930be7Sderaadt 		}
784df930be7Sderaadt 	}
785df930be7Sderaadt }
786df930be7Sderaadt 
787df930be7Sderaadt /*
788ad459a23Sespie  * dom4wrap - expand text at EOF
789ad459a23Sespie  */
790ad459a23Sespie static void
791ad459a23Sespie dom4wrap(const char *text)
792ad459a23Sespie {
793ad459a23Sespie 	if (wrapindex >= maxwraps) {
794ad459a23Sespie 		if (maxwraps == 0)
795ad459a23Sespie 			maxwraps = 16;
796ad459a23Sespie 		else
797ad459a23Sespie 			maxwraps *= 2;
798c608d5f4Sespie 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
799ad459a23Sespie 		   "too many m4wraps");
800ad459a23Sespie 	}
801ad459a23Sespie 	m4wraps[wrapindex++] = xstrdup(text);
802ad459a23Sespie }
803ad459a23Sespie 
804ad459a23Sespie /*
805df930be7Sderaadt  * dodivert - divert the output to a temporary file
806df930be7Sderaadt  */
807bb34cd6cSespie static void
8088e061d4bSespie dodiv(int n)
809df930be7Sderaadt {
810445b77f7Smillert 	int fd;
811445b77f7Smillert 
8127d3e0b6bSderaadt 	oindex = n;
81325afcddbSespie 	if (n >= maxout) {
81425afcddbSespie 		if (mimic_gnu)
81525afcddbSespie 			resizedivs(n + 10);
81625afcddbSespie 		else
81725afcddbSespie 			n = 0;		/* bitbucket */
81825afcddbSespie 	}
81925afcddbSespie 
82025afcddbSespie 	if (n < 0)
821df930be7Sderaadt 		n = 0;		       /* bitbucket */
822df930be7Sderaadt 	if (outfile[n] == NULL) {
8233f42598dSespie 		char fname[] = _PATH_DIVNAME;
8243f42598dSespie 
8253f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
826f5d2852fSespie 		    unlink(fname) == -1 ||
8273f42598dSespie 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
8283f42598dSespie 			err(1, "%s: cannot divert", fname);
829df930be7Sderaadt 	}
830df930be7Sderaadt 	active = outfile[n];
831df930be7Sderaadt }
832df930be7Sderaadt 
833df930be7Sderaadt /*
834df930be7Sderaadt  * doundivert - undivert a specified output, or all
835df930be7Sderaadt  *              other outputs, in numerical order.
836df930be7Sderaadt  */
837bb34cd6cSespie static void
8388e061d4bSespie doundiv(const char *argv[], int argc)
839df930be7Sderaadt {
84053f6f6bfSespie 	int ind;
84153f6f6bfSespie 	int n;
842df930be7Sderaadt 
843df930be7Sderaadt 	if (argc > 2) {
844df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
845e79fa687Sespie 			const char *errstr;
846e79fa687Sespie 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
847e79fa687Sespie 			if (errstr) {
848e79fa687Sespie 				if (errno == EINVAL && mimic_gnu)
849e79fa687Sespie 					getdivfile(argv[ind]);
850e79fa687Sespie 			} else {
851e79fa687Sespie 				if (n < maxout && outfile[n] != NULL)
852df930be7Sderaadt 					getdiv(n);
853e79fa687Sespie 			}
854df930be7Sderaadt 		}
855df930be7Sderaadt 	}
856df930be7Sderaadt 	else
85725afcddbSespie 		for (n = 1; n < maxout; n++)
858df930be7Sderaadt 			if (outfile[n] != NULL)
859df930be7Sderaadt 				getdiv(n);
860df930be7Sderaadt }
861df930be7Sderaadt 
862df930be7Sderaadt /*
863df930be7Sderaadt  * dosub - select substring
864df930be7Sderaadt  */
865bb34cd6cSespie static void
8668e061d4bSespie dosub(const char *argv[], int argc)
867df930be7Sderaadt {
868bb34cd6cSespie 	const char *ap, *fc, *k;
86953f6f6bfSespie 	int nc;
870df930be7Sderaadt 
871df930be7Sderaadt 	ap = argv[2];		       /* target string */
872df930be7Sderaadt #ifdef EXPR
873df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
874df930be7Sderaadt #else
875df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
876df930be7Sderaadt #endif
877bee8364eSespie 	nc = strlen(fc);
878bee8364eSespie 	if (argc >= 5)
879bee8364eSespie #ifdef EXPR
880bee8364eSespie 		nc = min(nc, expr(argv[4]));
881bee8364eSespie #else
882bee8364eSespie 		nc = min(nc, atoi(argv[4]));
883bee8364eSespie #endif
884df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
885bee8364eSespie 		for (k = fc + nc - 1; k >= fc; k--)
886739ce124Sespie 			pushback(*k);
887df930be7Sderaadt }
888df930be7Sderaadt 
889df930be7Sderaadt /*
890df930be7Sderaadt  * map:
891df930be7Sderaadt  * map every character of s1 that is specified in from
892df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
893df930be7Sderaadt  *
89487ab3cf4Sespie  * This is derived from the a standard implementation of map(s,from,to)
89587ab3cf4Sespie  * function of ICON language. Within mapvec, we replace every character
89687ab3cf4Sespie  * of "from" with the corresponding character in "to".
89787ab3cf4Sespie  * If "to" is shorter than "from", than the corresponding entries are null,
89887ab3cf4Sespie  * which means that those characters dissapear altogether.
899df930be7Sderaadt  */
900bb34cd6cSespie static void
9018e061d4bSespie map(char *dest, const char *src, const char *from, const char *to)
902df930be7Sderaadt {
903bb34cd6cSespie 	const char *tmp;
904ee3599c7Sespie 	unsigned char sch, dch;
90587c5c065Sespie 	static char frombis[257];
90687c5c065Sespie 	static char tobis[257];
90727e0c134Sespie 	int i;
90827e0c134Sespie 	char seen[256];
909ee3599c7Sespie 	static unsigned char mapvec[256] = {
910ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
911ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
912ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
913ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
914ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
915ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
916ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
917ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
918ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
919ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
920ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
921ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
922ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
923ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
924ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
925ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
926ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
927ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
928df930be7Sderaadt 	};
929df930be7Sderaadt 
930df930be7Sderaadt 	if (*src) {
93187c5c065Sespie 		if (mimic_gnu) {
93287c5c065Sespie 			/*
93387c5c065Sespie 			 * expand character ranges on the fly
93487c5c065Sespie 			 */
93587c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
93687c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
93787c5c065Sespie 		}
938df930be7Sderaadt 		tmp = from;
939df930be7Sderaadt 	/*
940df930be7Sderaadt 	 * create a mapping between "from" and
941df930be7Sderaadt 	 * "to"
942df930be7Sderaadt 	 */
94327e0c134Sespie 		for (i = 0; i < 256; i++)
94427e0c134Sespie 			seen[i] = 0;
94527e0c134Sespie 		while (*from) {
94627e0c134Sespie 			if (!seen[(unsigned char)(*from)]) {
94727e0c134Sespie 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
94827e0c134Sespie 				seen[(unsigned char)(*from)] = 1;
94927e0c134Sespie 			}
95027e0c134Sespie 			from++;
95127e0c134Sespie 			if (*to)
95227e0c134Sespie 				to++;
95327e0c134Sespie 		}
954df930be7Sderaadt 
955df930be7Sderaadt 		while (*src) {
956ee3599c7Sespie 			sch = (unsigned char)(*src++);
957df930be7Sderaadt 			dch = mapvec[sch];
958ee3599c7Sespie 			if ((*dest = (char)dch))
959df930be7Sderaadt 				dest++;
960df930be7Sderaadt 		}
961df930be7Sderaadt 	/*
962df930be7Sderaadt 	 * restore all the changed characters
963df930be7Sderaadt 	 */
964df930be7Sderaadt 		while (*tmp) {
965ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
966df930be7Sderaadt 			tmp++;
967df930be7Sderaadt 		}
968df930be7Sderaadt 	}
969ee3599c7Sespie 	*dest = '\0';
970df930be7Sderaadt }
97187c5c065Sespie 
97287c5c065Sespie 
97387c5c065Sespie /*
97487c5c065Sespie  * handledash:
97587c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
97687c5c065Sespie  * on the way.
97787c5c065Sespie  */
97887c5c065Sespie static const char *
9798e061d4bSespie handledash(char *buffer, char *end, const char *src)
98087c5c065Sespie {
98187c5c065Sespie 	char *p;
98287c5c065Sespie 
98387c5c065Sespie 	p = buffer;
98487c5c065Sespie 	while(*src) {
98587c5c065Sespie 		if (src[1] == '-' && src[2]) {
98687c5c065Sespie 			unsigned char i;
987e79fa687Sespie 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
98887c5c065Sespie 				for (i = (unsigned char)src[0];
98987c5c065Sespie 				    i <= (unsigned char)src[2]; i++) {
99087c5c065Sespie 					*p++ = i;
99187c5c065Sespie 					if (p == end) {
99287c5c065Sespie 						*p = '\0';
99387c5c065Sespie 						return buffer;
99487c5c065Sespie 					}
99587c5c065Sespie 				}
996e79fa687Sespie 			} else {
997e79fa687Sespie 				for (i = (unsigned char)src[0];
998e79fa687Sespie 				    i >= (unsigned char)src[2]; i--) {
999e79fa687Sespie 					*p++ = i;
1000e79fa687Sespie 					if (p == end) {
1001e79fa687Sespie 						*p = '\0';
1002e79fa687Sespie 						return buffer;
1003e79fa687Sespie 					}
1004e79fa687Sespie 				}
1005e79fa687Sespie 			}
100687c5c065Sespie 			src += 3;
100787c5c065Sespie 		} else
100887c5c065Sespie 			*p++ = *src++;
100987c5c065Sespie 		if (p == end)
101087c5c065Sespie 			break;
101187c5c065Sespie 	}
101287c5c065Sespie 	*p = '\0';
101387c5c065Sespie 	return buffer;
101487c5c065Sespie }
1015