xref: /openbsd/usr.bin/m4/eval.c (revision 87c5c065)
1*87c5c065Sespie /*	$OpenBSD: eval.c,v 1.26 2000/03/18 01:06:55 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*87c5c065Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.26 2000/03/18 01:06:55 espie Exp $";
45df930be7Sderaadt #endif
46df930be7Sderaadt #endif /* not lint */
47df930be7Sderaadt 
48df930be7Sderaadt /*
49df930be7Sderaadt  * eval.c
50df930be7Sderaadt  * Facility: m4 macro processor
51df930be7Sderaadt  * by: oz
52df930be7Sderaadt  */
53df930be7Sderaadt 
54df930be7Sderaadt #include <sys/types.h>
55df930be7Sderaadt #include <errno.h>
56df930be7Sderaadt #include <unistd.h>
57df930be7Sderaadt #include <stdio.h>
58df930be7Sderaadt #include <stdlib.h>
593f42598dSespie #include <stddef.h>
60df930be7Sderaadt #include <string.h>
61445b77f7Smillert #include <fcntl.h>
6281c2181eSespie #include <err.h>
63df930be7Sderaadt #include "mdef.h"
64df930be7Sderaadt #include "stdd.h"
65df930be7Sderaadt #include "extern.h"
66df930be7Sderaadt #include "pathnames.h"
67df930be7Sderaadt 
68bb34cd6cSespie static void	dodefn __P((const char *));
69bb34cd6cSespie static void	dopushdef __P((const char *, const char *));
70bb34cd6cSespie static void	dodump __P((const char *[], int));
71bb34cd6cSespie static void	doifelse __P((const char *[], int));
72bb34cd6cSespie static int	doincl __P((const char *));
73bb34cd6cSespie static int	dopaste __P((const char *));
74bb34cd6cSespie static void	dochq __P((const char *[], int));
75bb34cd6cSespie static void	dochc __P((const char *[], int));
76bb34cd6cSespie static void	dodiv __P((int));
77bb34cd6cSespie static void	doundiv __P((const char *[], int));
78bb34cd6cSespie static void	dosub __P((const char *[], int));
79bb34cd6cSespie static void	map __P((char *, const char *, const char *, const char *));
80*87c5c065Sespie static const char *handledash __P((char *, char *, const char *));
81df930be7Sderaadt /*
82df930be7Sderaadt  * eval - evaluate built-in macros.
83df930be7Sderaadt  *	  argc - number of elements in argv.
84df930be7Sderaadt  *	  argv - element vector :
85df930be7Sderaadt  *			argv[0] = definition of a user
86df930be7Sderaadt  *				  macro or nil if built-in.
87df930be7Sderaadt  *			argv[1] = name of the macro or
88df930be7Sderaadt  *				  built-in.
89df930be7Sderaadt  *			argv[2] = parameters to user-defined
90df930be7Sderaadt  *			   .	  macro or built-in.
91df930be7Sderaadt  *			   .
92df930be7Sderaadt  *
93df930be7Sderaadt  * Note that the minimum value for argc is 3. A call in the form
94df930be7Sderaadt  * of macro-or-builtin() will result in:
95df930be7Sderaadt  *			argv[0] = nullstr
96df930be7Sderaadt  *			argv[1] = macro-or-builtin
97df930be7Sderaadt  *			argv[2] = nullstr
98df930be7Sderaadt  */
99df930be7Sderaadt 
100df930be7Sderaadt void
101df930be7Sderaadt eval(argv, argc, td)
102bb34cd6cSespie 	const char *argv[];
10353f6f6bfSespie 	int argc;
10453f6f6bfSespie 	int td;
105df930be7Sderaadt {
10653f6f6bfSespie 	int c, n;
107df930be7Sderaadt 	static int sysval = 0;
108df930be7Sderaadt 
109df930be7Sderaadt #ifdef DEBUG
110df930be7Sderaadt 	printf("argc = %d\n", argc);
111df930be7Sderaadt 	for (n = 0; n < argc; n++)
112df930be7Sderaadt 		printf("argv[%d] = %s\n", n, argv[n]);
113df930be7Sderaadt #endif
114718b194dSespie 
115718b194dSespie 	if (td & RECDEF)
1160d3ffe1dSespie 		errx(1, "%s at line %lu: expanding recursive definition for %s",
1170d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE, argv[1]);
118df930be7Sderaadt  /*
119df930be7Sderaadt   * if argc == 3 and argv[2] is null, then we
120df930be7Sderaadt   * have macro-or-builtin() type call. We adjust
121df930be7Sderaadt   * argc to avoid further checking..
122df930be7Sderaadt   */
123df930be7Sderaadt 	if (argc == 3 && !*(argv[2]))
124df930be7Sderaadt 		argc--;
125df930be7Sderaadt 
126718b194dSespie 	switch (td & TYPEMASK) {
127df930be7Sderaadt 
128df930be7Sderaadt 	case DEFITYPE:
129df930be7Sderaadt 		if (argc > 2)
130df930be7Sderaadt 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
131df930be7Sderaadt 		break;
132df930be7Sderaadt 
133df930be7Sderaadt 	case PUSDTYPE:
134df930be7Sderaadt 		if (argc > 2)
135df930be7Sderaadt 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
136df930be7Sderaadt 		break;
137df930be7Sderaadt 
138df930be7Sderaadt 	case DUMPTYPE:
139df930be7Sderaadt 		dodump(argv, argc);
140df930be7Sderaadt 		break;
141df930be7Sderaadt 
142df930be7Sderaadt 	case EXPRTYPE:
143df930be7Sderaadt 	/*
144df930be7Sderaadt 	 * doexpr - evaluate arithmetic
145df930be7Sderaadt 	 * expression
146df930be7Sderaadt 	 */
147df930be7Sderaadt 		if (argc > 2)
148df930be7Sderaadt 			pbnum(expr(argv[2]));
149df930be7Sderaadt 		break;
150df930be7Sderaadt 
151df930be7Sderaadt 	case IFELTYPE:
152df930be7Sderaadt 		if (argc > 4)
153df930be7Sderaadt 			doifelse(argv, argc);
154df930be7Sderaadt 		break;
155df930be7Sderaadt 
156df930be7Sderaadt 	case IFDFTYPE:
157df930be7Sderaadt 	/*
158df930be7Sderaadt 	 * doifdef - select one of two
159df930be7Sderaadt 	 * alternatives based on the existence of
160df930be7Sderaadt 	 * another definition
161df930be7Sderaadt 	 */
162df930be7Sderaadt 		if (argc > 3) {
163df930be7Sderaadt 			if (lookup(argv[2]) != nil)
164df930be7Sderaadt 				pbstr(argv[3]);
165df930be7Sderaadt 			else if (argc > 4)
166df930be7Sderaadt 				pbstr(argv[4]);
167df930be7Sderaadt 		}
168df930be7Sderaadt 		break;
169df930be7Sderaadt 
170df930be7Sderaadt 	case LENGTYPE:
171df930be7Sderaadt 	/*
172df930be7Sderaadt 	 * dolen - find the length of the
173df930be7Sderaadt 	 * argument
174df930be7Sderaadt 	 */
175df930be7Sderaadt 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
176df930be7Sderaadt 		break;
177df930be7Sderaadt 
178df930be7Sderaadt 	case INCRTYPE:
179df930be7Sderaadt 	/*
180df930be7Sderaadt 	 * doincr - increment the value of the
181df930be7Sderaadt 	 * argument
182df930be7Sderaadt 	 */
183df930be7Sderaadt 		if (argc > 2)
184df930be7Sderaadt 			pbnum(atoi(argv[2]) + 1);
185df930be7Sderaadt 		break;
186df930be7Sderaadt 
187df930be7Sderaadt 	case DECRTYPE:
188df930be7Sderaadt 	/*
189df930be7Sderaadt 	 * dodecr - decrement the value of the
190df930be7Sderaadt 	 * argument
191df930be7Sderaadt 	 */
192df930be7Sderaadt 		if (argc > 2)
193df930be7Sderaadt 			pbnum(atoi(argv[2]) - 1);
194df930be7Sderaadt 		break;
195df930be7Sderaadt 
196df930be7Sderaadt 	case SYSCTYPE:
197df930be7Sderaadt 	/*
198df930be7Sderaadt 	 * dosys - execute system command
199df930be7Sderaadt 	 */
200df930be7Sderaadt 		if (argc > 2)
201df930be7Sderaadt 			sysval = system(argv[2]);
202df930be7Sderaadt 		break;
203df930be7Sderaadt 
204df930be7Sderaadt 	case SYSVTYPE:
205df930be7Sderaadt 	/*
206df930be7Sderaadt 	 * dosysval - return value of the last
207df930be7Sderaadt 	 * system call.
208df930be7Sderaadt 	 *
209df930be7Sderaadt 	 */
210df930be7Sderaadt 		pbnum(sysval);
211df930be7Sderaadt 		break;
212df930be7Sderaadt 
213df930be7Sderaadt 	case INCLTYPE:
214df930be7Sderaadt 		if (argc > 2)
215df930be7Sderaadt 			if (!doincl(argv[2]))
2160d3ffe1dSespie 				err(1, "%s at line %lu: include(%s)",
2170d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
218df930be7Sderaadt 		break;
219df930be7Sderaadt 
220df930be7Sderaadt 	case SINCTYPE:
221df930be7Sderaadt 		if (argc > 2)
222df930be7Sderaadt 			(void) doincl(argv[2]);
223df930be7Sderaadt 		break;
224df930be7Sderaadt #ifdef EXTENDED
225df930be7Sderaadt 	case PASTTYPE:
226df930be7Sderaadt 		if (argc > 2)
227df930be7Sderaadt 			if (!dopaste(argv[2]))
2280d3ffe1dSespie 				err(1, "%s at line %lu: paste(%s)",
2290d3ffe1dSespie 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
230df930be7Sderaadt 		break;
231df930be7Sderaadt 
232df930be7Sderaadt 	case SPASTYPE:
233df930be7Sderaadt 		if (argc > 2)
234df930be7Sderaadt 			(void) dopaste(argv[2]);
235df930be7Sderaadt 		break;
236df930be7Sderaadt #endif
237df930be7Sderaadt 	case CHNQTYPE:
238df930be7Sderaadt 		dochq(argv, argc);
239df930be7Sderaadt 		break;
240df930be7Sderaadt 
241df930be7Sderaadt 	case CHNCTYPE:
242df930be7Sderaadt 		dochc(argv, argc);
243df930be7Sderaadt 		break;
244df930be7Sderaadt 
245df930be7Sderaadt 	case SUBSTYPE:
246df930be7Sderaadt 	/*
247df930be7Sderaadt 	 * dosub - select substring
248df930be7Sderaadt 	 *
249df930be7Sderaadt 	 */
250df930be7Sderaadt 		if (argc > 3)
251df930be7Sderaadt 			dosub(argv, argc);
252df930be7Sderaadt 		break;
253df930be7Sderaadt 
254df930be7Sderaadt 	case SHIFTYPE:
255df930be7Sderaadt 	/*
256df930be7Sderaadt 	 * doshift - push back all arguments
257df930be7Sderaadt 	 * except the first one (i.e. skip
258df930be7Sderaadt 	 * argv[2])
259df930be7Sderaadt 	 */
260df930be7Sderaadt 		if (argc > 3) {
261df930be7Sderaadt 			for (n = argc - 1; n > 3; n--) {
2623a73db8cSderaadt 				pbstr(rquote);
263df930be7Sderaadt 				pbstr(argv[n]);
2643a73db8cSderaadt 				pbstr(lquote);
265aa676ce1Smillert 				putback(COMMA);
266df930be7Sderaadt 			}
2673a73db8cSderaadt 			pbstr(rquote);
268df930be7Sderaadt 			pbstr(argv[3]);
2693a73db8cSderaadt 			pbstr(lquote);
270df930be7Sderaadt 		}
271df930be7Sderaadt 		break;
272df930be7Sderaadt 
273df930be7Sderaadt 	case DIVRTYPE:
274df930be7Sderaadt 		if (argc > 2 && (n = atoi(argv[2])) != 0)
275df930be7Sderaadt 			dodiv(n);
276df930be7Sderaadt 		else {
277df930be7Sderaadt 			active = stdout;
278df930be7Sderaadt 			oindex = 0;
279df930be7Sderaadt 		}
280df930be7Sderaadt 		break;
281df930be7Sderaadt 
282df930be7Sderaadt 	case UNDVTYPE:
283df930be7Sderaadt 		doundiv(argv, argc);
284df930be7Sderaadt 		break;
285df930be7Sderaadt 
286df930be7Sderaadt 	case DIVNTYPE:
287df930be7Sderaadt 	/*
288df930be7Sderaadt 	 * dodivnum - return the number of
289df930be7Sderaadt 	 * current output diversion
290df930be7Sderaadt 	 */
291df930be7Sderaadt 		pbnum(oindex);
292df930be7Sderaadt 		break;
293df930be7Sderaadt 
294df930be7Sderaadt 	case UNDFTYPE:
295df930be7Sderaadt 	/*
296df930be7Sderaadt 	 * doundefine - undefine a previously
297df930be7Sderaadt 	 * defined macro(s) or m4 keyword(s).
298df930be7Sderaadt 	 */
299df930be7Sderaadt 		if (argc > 2)
300df930be7Sderaadt 			for (n = 2; n < argc; n++)
301df930be7Sderaadt 				remhash(argv[n], ALL);
302df930be7Sderaadt 		break;
303df930be7Sderaadt 
304df930be7Sderaadt 	case POPDTYPE:
305df930be7Sderaadt 	/*
306df930be7Sderaadt 	 * dopopdef - remove the topmost
307df930be7Sderaadt 	 * definitions of macro(s) or m4
308df930be7Sderaadt 	 * keyword(s).
309df930be7Sderaadt 	 */
310df930be7Sderaadt 		if (argc > 2)
311df930be7Sderaadt 			for (n = 2; n < argc; n++)
312df930be7Sderaadt 				remhash(argv[n], TOP);
313df930be7Sderaadt 		break;
314df930be7Sderaadt 
315df930be7Sderaadt 	case MKTMTYPE:
316df930be7Sderaadt 	/*
317df930be7Sderaadt 	 * dotemp - create a temporary file
318df930be7Sderaadt 	 */
31901e71e69Sespie 		if (argc > 2) {
32001e71e69Sespie 			int fd;
321bb34cd6cSespie 			char *temp;
32201e71e69Sespie 
323bb34cd6cSespie 			temp = xstrdup(argv[2]);
324bb34cd6cSespie 
325bb34cd6cSespie 			fd = mkstemp(temp);
32601e71e69Sespie 			if (fd == -1)
3270d3ffe1dSespie 				err(1,
3280d3ffe1dSespie 	    "%s at line %lu: couldn't make temp file %s",
3290d3ffe1dSespie 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
33001e71e69Sespie 			close(fd);
331bb34cd6cSespie 			pbstr(temp);
332bb34cd6cSespie 			free(temp);
33301e71e69Sespie 		}
334df930be7Sderaadt 		break;
335df930be7Sderaadt 
336df930be7Sderaadt 	case TRNLTYPE:
337df930be7Sderaadt 	/*
338df930be7Sderaadt 	 * dotranslit - replace all characters in
339df930be7Sderaadt 	 * the source string that appears in the
340df930be7Sderaadt 	 * "from" string with the corresponding
341df930be7Sderaadt 	 * characters in the "to" string.
342df930be7Sderaadt 	 */
343df930be7Sderaadt 		if (argc > 3) {
3447d3e0b6bSderaadt 			char temp[STRSPMAX+1];
345df930be7Sderaadt 			if (argc > 4)
346df930be7Sderaadt 				map(temp, argv[2], argv[3], argv[4]);
347df930be7Sderaadt 			else
348df930be7Sderaadt 				map(temp, argv[2], argv[3], null);
349df930be7Sderaadt 			pbstr(temp);
3507d3e0b6bSderaadt 		} else if (argc > 2)
351df930be7Sderaadt 			pbstr(argv[2]);
352df930be7Sderaadt 		break;
353df930be7Sderaadt 
354df930be7Sderaadt 	case INDXTYPE:
355df930be7Sderaadt 	/*
356df930be7Sderaadt 	 * doindex - find the index of the second
357df930be7Sderaadt 	 * argument string in the first argument
358df930be7Sderaadt 	 * string. -1 if not present.
359df930be7Sderaadt 	 */
360df930be7Sderaadt 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
361df930be7Sderaadt 		break;
362df930be7Sderaadt 
363df930be7Sderaadt 	case ERRPTYPE:
364df930be7Sderaadt 	/*
365df930be7Sderaadt 	 * doerrp - print the arguments to stderr
366df930be7Sderaadt 	 * file
367df930be7Sderaadt 	 */
368df930be7Sderaadt 		if (argc > 2) {
369df930be7Sderaadt 			for (n = 2; n < argc; n++)
370df930be7Sderaadt 				fprintf(stderr, "%s ", argv[n]);
371df930be7Sderaadt 			fprintf(stderr, "\n");
372df930be7Sderaadt 		}
373df930be7Sderaadt 		break;
374df930be7Sderaadt 
375df930be7Sderaadt 	case DNLNTYPE:
376df930be7Sderaadt 	/*
377df930be7Sderaadt 	 * dodnl - eat-up-to and including
378df930be7Sderaadt 	 * newline
379df930be7Sderaadt 	 */
380df930be7Sderaadt 		while ((c = gpbc()) != '\n' && c != EOF)
381df930be7Sderaadt 			;
382df930be7Sderaadt 		break;
383df930be7Sderaadt 
384df930be7Sderaadt 	case M4WRTYPE:
385df930be7Sderaadt 	/*
386df930be7Sderaadt 	 * dom4wrap - set up for
387df930be7Sderaadt 	 * wrap-up/wind-down activity
388df930be7Sderaadt 	 */
389df930be7Sderaadt 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
390df930be7Sderaadt 		break;
391df930be7Sderaadt 
392df930be7Sderaadt 	case EXITTYPE:
393df930be7Sderaadt 	/*
394df930be7Sderaadt 	 * doexit - immediate exit from m4.
395df930be7Sderaadt 	 */
396df930be7Sderaadt 		killdiv();
397df930be7Sderaadt 		exit((argc > 2) ? atoi(argv[2]) : 0);
398df930be7Sderaadt 		break;
399df930be7Sderaadt 
400df930be7Sderaadt 	case DEFNTYPE:
401df930be7Sderaadt 		if (argc > 2)
402df930be7Sderaadt 			for (n = 2; n < argc; n++)
403df930be7Sderaadt 				dodefn(argv[n]);
404df930be7Sderaadt 		break;
405df930be7Sderaadt 
406b8161682Sespie 	case INDIRTYPE:	/* Indirect call */
407b8161682Sespie 		if (argc > 2)
408b8161682Sespie 			doindir(argv, argc);
409b8161682Sespie 		break;
410b8161682Sespie 
411b8161682Sespie 	case BUILTINTYPE: /* Builtins only */
412b8161682Sespie 		if (argc > 2)
413b8161682Sespie 			dobuiltin(argv, argc);
414b8161682Sespie 		break;
415b8161682Sespie 
416b8161682Sespie 	case PATSTYPE:
417b8161682Sespie 		if (argc > 2)
418b8161682Sespie 			dopatsubst(argv, argc);
419b8161682Sespie 		break;
420b8161682Sespie 	case REGEXPTYPE:
421b8161682Sespie 		if (argc > 2)
422b8161682Sespie 			doregexp(argv, argc);
423b8161682Sespie 		break;
424b8161682Sespie 	case LINETYPE:
425b8161682Sespie 		doprintlineno(infile+ilevel);
426b8161682Sespie 		break;
427b8161682Sespie 	case FILENAMETYPE:
428b8161682Sespie 		doprintfilename(infile+ilevel);
429b8161682Sespie 		break;
430423624b7Sespie 	case SELFTYPE:
431423624b7Sespie 		pbstr(rquote);
432423624b7Sespie 		pbstr(argv[1]);
433423624b7Sespie 		pbstr(lquote);
434423624b7Sespie 		break;
435df930be7Sderaadt 	default:
4360d3ffe1dSespie 		errx(1, "%s at line %lu: eval: major botch.",
4370d3ffe1dSespie 			CURRENT_NAME, CURRENT_LINE);
438df930be7Sderaadt 		break;
439df930be7Sderaadt 	}
440df930be7Sderaadt }
441df930be7Sderaadt 
442df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
443df930be7Sderaadt 
444df930be7Sderaadt /*
445df930be7Sderaadt  * expand - user-defined macro expansion
446df930be7Sderaadt  */
447df930be7Sderaadt void
448df930be7Sderaadt expand(argv, argc)
449bb34cd6cSespie 	const char *argv[];
45053f6f6bfSespie 	int argc;
451df930be7Sderaadt {
452bb34cd6cSespie 	const char *t;
453bb34cd6cSespie 	const char *p;
45453f6f6bfSespie 	int n;
45553f6f6bfSespie 	int argno;
456df930be7Sderaadt 
457df930be7Sderaadt 	t = argv[0];		       /* defn string as a whole */
458df930be7Sderaadt 	p = t;
459df930be7Sderaadt 	while (*p)
460df930be7Sderaadt 		p++;
461df930be7Sderaadt 	p--;			       /* last character of defn */
462df930be7Sderaadt 	while (p > t) {
463df930be7Sderaadt 		if (*(p - 1) != ARGFLAG)
464df930be7Sderaadt 			putback(*p);
465df930be7Sderaadt 		else {
466df930be7Sderaadt 			switch (*p) {
467df930be7Sderaadt 
468df930be7Sderaadt 			case '#':
469df930be7Sderaadt 				pbnum(argc - 2);
470df930be7Sderaadt 				break;
471df930be7Sderaadt 			case '0':
472df930be7Sderaadt 			case '1':
473df930be7Sderaadt 			case '2':
474df930be7Sderaadt 			case '3':
475df930be7Sderaadt 			case '4':
476df930be7Sderaadt 			case '5':
477df930be7Sderaadt 			case '6':
478df930be7Sderaadt 			case '7':
479df930be7Sderaadt 			case '8':
480df930be7Sderaadt 			case '9':
481df930be7Sderaadt 				if ((argno = *p - '0') < argc - 1)
482df930be7Sderaadt 					pbstr(argv[argno + 1]);
483df930be7Sderaadt 				break;
484df930be7Sderaadt 			case '*':
485df930be7Sderaadt 				for (n = argc - 1; n > 2; n--) {
486df930be7Sderaadt 					pbstr(argv[n]);
487aa676ce1Smillert 					putback(COMMA);
488df930be7Sderaadt 				}
489df930be7Sderaadt 				pbstr(argv[2]);
490df930be7Sderaadt 				break;
491aa676ce1Smillert                         case '@':
492aa676ce1Smillert                                 for (n = argc - 1; n > 2; n--) {
493aa676ce1Smillert                                         pbstr(rquote);
494aa676ce1Smillert                                         pbstr(argv[n]);
495aa676ce1Smillert                                         pbstr(lquote);
496aa676ce1Smillert 					putback(COMMA);
497aa676ce1Smillert                                 }
498aa676ce1Smillert 				pbstr(rquote);
499aa676ce1Smillert                                 pbstr(argv[2]);
500aa676ce1Smillert 				pbstr(lquote);
501aa676ce1Smillert                                 break;
502df930be7Sderaadt 			default:
503df930be7Sderaadt 				putback(*p);
504df930be7Sderaadt 				putback('$');
505df930be7Sderaadt 				break;
506df930be7Sderaadt 			}
507df930be7Sderaadt 			p--;
508df930be7Sderaadt 		}
509df930be7Sderaadt 		p--;
510df930be7Sderaadt 	}
511df930be7Sderaadt 	if (p == t)		       /* do last character */
512df930be7Sderaadt 		putback(*p);
513df930be7Sderaadt }
514df930be7Sderaadt 
515df930be7Sderaadt /*
516df930be7Sderaadt  * dodefine - install definition in the table
517df930be7Sderaadt  */
518df930be7Sderaadt void
519df930be7Sderaadt dodefine(name, defn)
520bb34cd6cSespie 	const char *name;
521bb34cd6cSespie 	const char *defn;
522df930be7Sderaadt {
52353f6f6bfSespie 	ndptr p;
524df930be7Sderaadt 
525df930be7Sderaadt 	if (!*name)
5260d3ffe1dSespie 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
5270d3ffe1dSespie 		    CURRENT_LINE);
528df930be7Sderaadt 	if ((p = lookup(name)) == nil)
529df930be7Sderaadt 		p = addent(name);
530df930be7Sderaadt 	else if (p->defn != null)
531df930be7Sderaadt 		free((char *) p->defn);
532df930be7Sderaadt 	if (!*defn)
533df930be7Sderaadt 		p->defn = null;
534df930be7Sderaadt 	else
535df930be7Sderaadt 		p->defn = xstrdup(defn);
536df930be7Sderaadt 	p->type = MACRTYPE;
537718b194dSespie 	if (STREQ(name, defn))
538718b194dSespie 		p->type |= RECDEF;
539df930be7Sderaadt }
540df930be7Sderaadt 
541df930be7Sderaadt /*
542df930be7Sderaadt  * dodefn - push back a quoted definition of
543df930be7Sderaadt  *      the given name.
544df930be7Sderaadt  */
545bb34cd6cSespie static void
546df930be7Sderaadt dodefn(name)
547bb34cd6cSespie 	const char *name;
548df930be7Sderaadt {
54953f6f6bfSespie 	ndptr p;
550df930be7Sderaadt 
551df930be7Sderaadt 	if ((p = lookup(name)) != nil && p->defn != null) {
5523a73db8cSderaadt 		pbstr(rquote);
553df930be7Sderaadt 		pbstr(p->defn);
5543a73db8cSderaadt 		pbstr(lquote);
555df930be7Sderaadt 	}
556df930be7Sderaadt }
557df930be7Sderaadt 
558df930be7Sderaadt /*
559df930be7Sderaadt  * dopushdef - install a definition in the hash table
560df930be7Sderaadt  *      without removing a previous definition. Since
561df930be7Sderaadt  *      each new entry is entered in *front* of the
562df930be7Sderaadt  *      hash bucket, it hides a previous definition from
563df930be7Sderaadt  *      lookup.
564df930be7Sderaadt  */
565bb34cd6cSespie static void
566df930be7Sderaadt dopushdef(name, defn)
567bb34cd6cSespie 	const char *name;
568bb34cd6cSespie 	const char *defn;
569df930be7Sderaadt {
57053f6f6bfSespie 	ndptr p;
571df930be7Sderaadt 
572df930be7Sderaadt 	if (!*name)
5730d3ffe1dSespie 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
5740d3ffe1dSespie 		    CURRENT_LINE);
575df930be7Sderaadt 	p = addent(name);
576df930be7Sderaadt 	if (!*defn)
577df930be7Sderaadt 		p->defn = null;
578df930be7Sderaadt 	else
579df930be7Sderaadt 		p->defn = xstrdup(defn);
580df930be7Sderaadt 	p->type = MACRTYPE;
581718b194dSespie 	if (STREQ(name, defn))
582718b194dSespie 		p->type |= RECDEF;
583df930be7Sderaadt }
584df930be7Sderaadt 
585df930be7Sderaadt /*
586df930be7Sderaadt  * dodumpdef - dump the specified definitions in the hash
587df930be7Sderaadt  *      table to stderr. If nothing is specified, the entire
588df930be7Sderaadt  *      hash table is dumped.
589df930be7Sderaadt  */
590bb34cd6cSespie static void
591df930be7Sderaadt dodump(argv, argc)
592bb34cd6cSespie 	const char *argv[];
59353f6f6bfSespie 	int argc;
594df930be7Sderaadt {
59553f6f6bfSespie 	int n;
596df930be7Sderaadt 	ndptr p;
597df930be7Sderaadt 
598df930be7Sderaadt 	if (argc > 2) {
599df930be7Sderaadt 		for (n = 2; n < argc; n++)
600df930be7Sderaadt 			if ((p = lookup(argv[n])) != nil)
601df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
602df930be7Sderaadt 					p->defn);
6037d3e0b6bSderaadt 	} else {
604df930be7Sderaadt 		for (n = 0; n < HASHSIZE; n++)
605df930be7Sderaadt 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
606df930be7Sderaadt 				fprintf(stderr, dumpfmt, p->name,
607df930be7Sderaadt 					p->defn);
608df930be7Sderaadt 	}
609df930be7Sderaadt }
610df930be7Sderaadt 
611df930be7Sderaadt /*
612df930be7Sderaadt  * doifelse - select one of two alternatives - loop.
613df930be7Sderaadt  */
614bb34cd6cSespie static void
615df930be7Sderaadt doifelse(argv, argc)
616bb34cd6cSespie 	const char *argv[];
61753f6f6bfSespie 	int argc;
618df930be7Sderaadt {
619df930be7Sderaadt 	cycle {
620df930be7Sderaadt 		if (STREQ(argv[2], argv[3]))
621df930be7Sderaadt 			pbstr(argv[4]);
622df930be7Sderaadt 		else if (argc == 6)
623df930be7Sderaadt 			pbstr(argv[5]);
624df930be7Sderaadt 		else if (argc > 6) {
625df930be7Sderaadt 			argv += 3;
626df930be7Sderaadt 			argc -= 3;
627df930be7Sderaadt 			continue;
628df930be7Sderaadt 		}
629df930be7Sderaadt 		break;
630df930be7Sderaadt 	}
631df930be7Sderaadt }
632df930be7Sderaadt 
633df930be7Sderaadt /*
634df930be7Sderaadt  * doinclude - include a given file.
635df930be7Sderaadt  */
636bb34cd6cSespie static int
637df930be7Sderaadt doincl(ifile)
638bb34cd6cSespie 	const char *ifile;
639df930be7Sderaadt {
640df930be7Sderaadt 	if (ilevel + 1 == MAXINP)
6410d3ffe1dSespie 		errx(1, "%s at line %lu: too many include files.",
6420d3ffe1dSespie 		    CURRENT_NAME, CURRENT_LINE);
6430d3ffe1dSespie 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
644df930be7Sderaadt 		ilevel++;
645df930be7Sderaadt 		bbase[ilevel] = bufbase = bp;
646df930be7Sderaadt 		return (1);
6477d3e0b6bSderaadt 	} else
648df930be7Sderaadt 		return (0);
649df930be7Sderaadt }
650df930be7Sderaadt 
651df930be7Sderaadt #ifdef EXTENDED
652df930be7Sderaadt /*
653df930be7Sderaadt  * dopaste - include a given file without any
654df930be7Sderaadt  *           macro processing.
655df930be7Sderaadt  */
656bb34cd6cSespie static int
657df930be7Sderaadt dopaste(pfile)
658bb34cd6cSespie 	const char *pfile;
659df930be7Sderaadt {
660df930be7Sderaadt 	FILE *pf;
66153f6f6bfSespie 	int c;
662df930be7Sderaadt 
663df930be7Sderaadt 	if ((pf = fopen(pfile, "r")) != NULL) {
664df930be7Sderaadt 		while ((c = getc(pf)) != EOF)
665df930be7Sderaadt 			putc(c, active);
666df930be7Sderaadt 		(void) fclose(pf);
667df930be7Sderaadt 		return (1);
6687d3e0b6bSderaadt 	} else
669df930be7Sderaadt 		return (0);
670df930be7Sderaadt }
671df930be7Sderaadt #endif
672df930be7Sderaadt 
673df930be7Sderaadt /*
674df930be7Sderaadt  * dochq - change quote characters
675df930be7Sderaadt  */
676bb34cd6cSespie static void
677df930be7Sderaadt dochq(argv, argc)
678bb34cd6cSespie 	const char *argv[];
67953f6f6bfSespie 	int argc;
680df930be7Sderaadt {
681*87c5c065Sespie 	/* In gnu-m4 mode, having two empty arguments means no quotes at
682*87c5c065Sespie 	 * all.  */
683*87c5c065Sespie 	if (mimic_gnu) {
684*87c5c065Sespie 		if (argc > 3 && !*argv[2] && !*argv[3]) {
685*87c5c065Sespie 			lquote[0] = EOS;
686*87c5c065Sespie 			rquote[0] = EOS;
687*87c5c065Sespie 			return;
688*87c5c065Sespie 		}
689*87c5c065Sespie 	}
690df930be7Sderaadt 	if (argc > 2) {
69118a1973bSderaadt 		if (*argv[2])
692b81b15b2Sespie 			strlcpy(lquote, argv[2], sizeof(lquote));
69318a1973bSderaadt 		else {
69418a1973bSderaadt 			lquote[0] = LQUOTE;
695f0484631Sespie 			lquote[1] = EOS;
69618a1973bSderaadt 		}
697df930be7Sderaadt 		if (argc > 3) {
698df930be7Sderaadt 			if (*argv[3])
699b81b15b2Sespie 				strlcpy(rquote, argv[3], sizeof(rquote));
7007d3e0b6bSderaadt 		} else
70129a0bfdcSderaadt 			strcpy(rquote, lquote);
7027d3e0b6bSderaadt 	} else {
703f0484631Sespie 		lquote[0] = LQUOTE, lquote[1] = EOS;
704f0484631Sespie 		rquote[0] = RQUOTE, rquote[1] = EOS;
705df930be7Sderaadt 	}
706df930be7Sderaadt }
707df930be7Sderaadt 
708df930be7Sderaadt /*
709df930be7Sderaadt  * dochc - change comment characters
710df930be7Sderaadt  */
711bb34cd6cSespie static void
712df930be7Sderaadt dochc(argv, argc)
713bb34cd6cSespie 	const char *argv[];
71453f6f6bfSespie 	int argc;
715df930be7Sderaadt {
716df930be7Sderaadt 	if (argc > 2) {
717df930be7Sderaadt 		if (*argv[2])
718b81b15b2Sespie 			strlcpy(scommt, argv[2], sizeof(scommt));
719df930be7Sderaadt 		if (argc > 3) {
720df930be7Sderaadt 			if (*argv[3])
721b81b15b2Sespie 				strlcpy(ecommt, argv[3], sizeof(ecommt));
722df930be7Sderaadt 		}
723df930be7Sderaadt 		else
724f0484631Sespie 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
725df930be7Sderaadt 	}
726df930be7Sderaadt 	else {
727f0484631Sespie 		scommt[0] = SCOMMT, scommt[1] = EOS;
728f0484631Sespie 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
729df930be7Sderaadt 	}
730df930be7Sderaadt }
731df930be7Sderaadt 
732df930be7Sderaadt /*
733df930be7Sderaadt  * dodivert - divert the output to a temporary file
734df930be7Sderaadt  */
735bb34cd6cSespie static void
736df930be7Sderaadt dodiv(n)
73753f6f6bfSespie 	int n;
738df930be7Sderaadt {
739445b77f7Smillert 	int fd;
740445b77f7Smillert 
7417d3e0b6bSderaadt 	oindex = n;
742df930be7Sderaadt 	if (n < 0 || n >= MAXOUT)
743df930be7Sderaadt 		n = 0;		       /* bitbucket */
744df930be7Sderaadt 	if (outfile[n] == NULL) {
7453f42598dSespie 		char fname[] = _PATH_DIVNAME;
7463f42598dSespie 
7473f42598dSespie 		if ((fd = mkstemp(fname)) < 0 ||
7483f42598dSespie 			(outfile[n] = fdopen(fd, "w+")) == NULL)
7493f42598dSespie 				err(1, "%s: cannot divert", fname);
7503f42598dSespie 		if (unlink(fname) == -1)
7513f42598dSespie 			err(1, "%s: cannot unlink", fname);
752df930be7Sderaadt 	}
753df930be7Sderaadt 	active = outfile[n];
754df930be7Sderaadt }
755df930be7Sderaadt 
756df930be7Sderaadt /*
757df930be7Sderaadt  * doundivert - undivert a specified output, or all
758df930be7Sderaadt  *              other outputs, in numerical order.
759df930be7Sderaadt  */
760bb34cd6cSespie static void
761df930be7Sderaadt doundiv(argv, argc)
762bb34cd6cSespie 	const char *argv[];
76353f6f6bfSespie 	int argc;
764df930be7Sderaadt {
76553f6f6bfSespie 	int ind;
76653f6f6bfSespie 	int n;
767df930be7Sderaadt 
768df930be7Sderaadt 	if (argc > 2) {
769df930be7Sderaadt 		for (ind = 2; ind < argc; ind++) {
770df930be7Sderaadt 			n = atoi(argv[ind]);
771df930be7Sderaadt 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
772df930be7Sderaadt 				getdiv(n);
773df930be7Sderaadt 
774df930be7Sderaadt 		}
775df930be7Sderaadt 	}
776df930be7Sderaadt 	else
777df930be7Sderaadt 		for (n = 1; n < MAXOUT; n++)
778df930be7Sderaadt 			if (outfile[n] != NULL)
779df930be7Sderaadt 				getdiv(n);
780df930be7Sderaadt }
781df930be7Sderaadt 
782df930be7Sderaadt /*
783df930be7Sderaadt  * dosub - select substring
784df930be7Sderaadt  */
785bb34cd6cSespie static void
786df930be7Sderaadt dosub(argv, argc)
787bb34cd6cSespie 	const char *argv[];
78853f6f6bfSespie 	int argc;
789df930be7Sderaadt {
790bb34cd6cSespie 	const char *ap, *fc, *k;
79153f6f6bfSespie 	int nc;
792df930be7Sderaadt 
793df930be7Sderaadt 	if (argc < 5)
794df930be7Sderaadt 		nc = MAXTOK;
795df930be7Sderaadt 	else
796df930be7Sderaadt #ifdef EXPR
797df930be7Sderaadt 		nc = expr(argv[4]);
798df930be7Sderaadt #else
799df930be7Sderaadt 		nc = atoi(argv[4]);
800df930be7Sderaadt #endif
801df930be7Sderaadt 	ap = argv[2];		       /* target string */
802df930be7Sderaadt #ifdef EXPR
803df930be7Sderaadt 	fc = ap + expr(argv[3]);       /* first char */
804df930be7Sderaadt #else
805df930be7Sderaadt 	fc = ap + atoi(argv[3]);       /* first char */
806df930be7Sderaadt #endif
807df930be7Sderaadt 	if (fc >= ap && fc < ap + strlen(ap))
808df930be7Sderaadt 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
809df930be7Sderaadt 			putback(*k);
810df930be7Sderaadt }
811df930be7Sderaadt 
812df930be7Sderaadt /*
813df930be7Sderaadt  * map:
814df930be7Sderaadt  * map every character of s1 that is specified in from
815df930be7Sderaadt  * into s3 and replace in s. (source s1 remains untouched)
816df930be7Sderaadt  *
817df930be7Sderaadt  * This is a standard implementation of map(s,from,to) function of ICON
818df930be7Sderaadt  * language. Within mapvec, we replace every character of "from" with
819df930be7Sderaadt  * the corresponding character in "to". If "to" is shorter than "from",
820df930be7Sderaadt  * than the corresponding entries are null, which means that those
821df930be7Sderaadt  * characters dissapear altogether. Furthermore, imagine
822df930be7Sderaadt  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
823df930be7Sderaadt  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
824df930be7Sderaadt  * ultimately maps to `*'. In order to achieve this effect in an efficient
825df930be7Sderaadt  * manner (i.e. without multiple passes over the destination string), we
826df930be7Sderaadt  * loop over mapvec, starting with the initial source character. if the
827df930be7Sderaadt  * character value (dch) in this location is different than the source
828df930be7Sderaadt  * character (sch), sch becomes dch, once again to index into mapvec, until
829df930be7Sderaadt  * the character value stabilizes (i.e. sch = dch, in other words
830df930be7Sderaadt  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
831df930be7Sderaadt  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
832df930be7Sderaadt  * end, we restore mapvec* back to normal where mapvec[n] == n for
833df930be7Sderaadt  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
834df930be7Sderaadt  * about 5 times faster than any algorithm that makes multiple passes over
835df930be7Sderaadt  * destination string.
836df930be7Sderaadt  */
837bb34cd6cSespie static void
838df930be7Sderaadt map(dest, src, from, to)
83953f6f6bfSespie 	char *dest;
840bb34cd6cSespie 	const char *src;
841bb34cd6cSespie 	const char *from;
842bb34cd6cSespie 	const char *to;
843df930be7Sderaadt {
844bb34cd6cSespie 	const char *tmp;
845ee3599c7Sespie 	unsigned char sch, dch;
846*87c5c065Sespie 	static char frombis[257];
847*87c5c065Sespie 	static char tobis[257];
848ee3599c7Sespie 	static unsigned char mapvec[256] = {
849ee3599c7Sespie 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
850ee3599c7Sespie 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
851ee3599c7Sespie 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
852ee3599c7Sespie 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
853ee3599c7Sespie 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
854ee3599c7Sespie 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
855ee3599c7Sespie 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
856ee3599c7Sespie 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
857ee3599c7Sespie 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
858ee3599c7Sespie 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
859ee3599c7Sespie 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
860ee3599c7Sespie 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
861ee3599c7Sespie 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
862ee3599c7Sespie 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
863ee3599c7Sespie 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
864ee3599c7Sespie 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
865ee3599c7Sespie 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
866ee3599c7Sespie 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
867df930be7Sderaadt 	};
868df930be7Sderaadt 
869df930be7Sderaadt 	if (*src) {
870*87c5c065Sespie 		if (mimic_gnu) {
871*87c5c065Sespie 			/*
872*87c5c065Sespie 			 * expand character ranges on the fly
873*87c5c065Sespie 			 */
874*87c5c065Sespie 			from = handledash(frombis, frombis + 256, from);
875*87c5c065Sespie 			to = handledash(tobis, tobis + 256, to);
876*87c5c065Sespie 		}
877df930be7Sderaadt 		tmp = from;
878df930be7Sderaadt 	/*
879df930be7Sderaadt 	 * create a mapping between "from" and
880df930be7Sderaadt 	 * "to"
881df930be7Sderaadt 	 */
882df930be7Sderaadt 		while (*from)
883ee3599c7Sespie 			mapvec[(unsigned char)(*from++)] = (*to) ?
884ee3599c7Sespie 				(unsigned char)(*to++) : 0;
885df930be7Sderaadt 
886df930be7Sderaadt 		while (*src) {
887ee3599c7Sespie 			sch = (unsigned char)(*src++);
888df930be7Sderaadt 			dch = mapvec[sch];
889df930be7Sderaadt 			while (dch != sch) {
890df930be7Sderaadt 				sch = dch;
891df930be7Sderaadt 				dch = mapvec[sch];
892df930be7Sderaadt 			}
893ee3599c7Sespie 			if ((*dest = (char)dch))
894df930be7Sderaadt 				dest++;
895df930be7Sderaadt 		}
896df930be7Sderaadt 	/*
897df930be7Sderaadt 	 * restore all the changed characters
898df930be7Sderaadt 	 */
899df930be7Sderaadt 		while (*tmp) {
900ee3599c7Sespie 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
901df930be7Sderaadt 			tmp++;
902df930be7Sderaadt 		}
903df930be7Sderaadt 	}
904ee3599c7Sespie 	*dest = '\0';
905df930be7Sderaadt }
906*87c5c065Sespie 
907*87c5c065Sespie 
908*87c5c065Sespie /*
909*87c5c065Sespie  * handledash:
910*87c5c065Sespie  *  use buffer to copy the src string, expanding character ranges
911*87c5c065Sespie  * on the way.
912*87c5c065Sespie  */
913*87c5c065Sespie static const char *
914*87c5c065Sespie handledash(buffer, end, src)
915*87c5c065Sespie 	char *buffer;
916*87c5c065Sespie 	char *end;
917*87c5c065Sespie 	const char *src;
918*87c5c065Sespie {
919*87c5c065Sespie 	char *p;
920*87c5c065Sespie 
921*87c5c065Sespie 	p = buffer;
922*87c5c065Sespie 	while(*src) {
923*87c5c065Sespie 		if (src[1] == '-' && src[2]) {
924*87c5c065Sespie 			unsigned char i;
925*87c5c065Sespie 			for (i = (unsigned char)src[0];
926*87c5c065Sespie 			    i <= (unsigned char)src[2]; i++) {
927*87c5c065Sespie 				*p++ = i;
928*87c5c065Sespie 				if (p == end) {
929*87c5c065Sespie 					*p = '\0';
930*87c5c065Sespie 					return buffer;
931*87c5c065Sespie 				}
932*87c5c065Sespie 			}
933*87c5c065Sespie 			src += 3;
934*87c5c065Sespie 		} else
935*87c5c065Sespie 			*p++ = *src++;
936*87c5c065Sespie 		if (p == end)
937*87c5c065Sespie 			break;
938*87c5c065Sespie 	}
939*87c5c065Sespie 	*p = '\0';
940*87c5c065Sespie 	return buffer;
941*87c5c065Sespie }
942*87c5c065Sespie 
943