xref: /freebsd/usr.bin/m4/eval.c (revision bd2bfb5846af9c8a5cb070d9df4972ac0ae4008e)
1bd2bfb58SJuli Mallett /*	$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $	*/
2acc9d408SJuli Mallett /*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3acc9d408SJuli Mallett 
49b50d902SRodney W. Grimes /*
59b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
69b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
99b50d902SRodney W. Grimes  * Ozan Yigit at York University.
109b50d902SRodney W. Grimes  *
119b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
129b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
139b50d902SRodney W. Grimes  * are met:
149b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
159b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
169b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
179b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
189b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
199b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
209b50d902SRodney W. Grimes  *    must display the following acknowledgement:
219b50d902SRodney W. Grimes  *	This product includes software developed by the University of
229b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
239b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
249b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
259b50d902SRodney W. Grimes  *    without specific prior written permission.
269b50d902SRodney W. Grimes  *
279b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
289b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
299b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
309b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
319b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
329b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
339b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
349b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
359b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
369b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
379b50d902SRodney W. Grimes  * SUCH DAMAGE.
389b50d902SRodney W. Grimes  */
399b50d902SRodney W. Grimes 
40acc9d408SJuli Mallett #include <sys/cdefs.h>
41acc9d408SJuli Mallett __SCCSID("@(#)eval.c	8.2 (Berkeley) 4/27/95");
42bd2bfb58SJuli Mallett __RCSID_SOURCE("$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $");
43acc9d408SJuli Mallett __FBSDID("$FreeBSD$");
449b50d902SRodney W. Grimes 
459b50d902SRodney W. Grimes /*
469b50d902SRodney W. Grimes  * eval.c
479b50d902SRodney W. Grimes  * Facility: m4 macro processor
489b50d902SRodney W. Grimes  * by: oz
499b50d902SRodney W. Grimes  */
509b50d902SRodney W. Grimes 
519b50d902SRodney W. Grimes #include <sys/types.h>
52acc9d408SJuli Mallett #include <errno.h>
53acc9d408SJuli Mallett #include <unistd.h>
549b50d902SRodney W. Grimes #include <stdio.h>
559b50d902SRodney W. Grimes #include <stdlib.h>
56acc9d408SJuli Mallett #include <stddef.h>
579b50d902SRodney W. Grimes #include <string.h>
58acc9d408SJuli Mallett #include <fcntl.h>
59acc9d408SJuli Mallett #include <err.h>
609b50d902SRodney W. Grimes #include "mdef.h"
619b50d902SRodney W. Grimes #include "stdd.h"
629b50d902SRodney W. Grimes #include "extern.h"
639b50d902SRodney W. Grimes #include "pathnames.h"
649b50d902SRodney W. Grimes 
65acc9d408SJuli Mallett #define BUILTIN_MARKER	"__builtin_"
66acc9d408SJuli Mallett 
67acc9d408SJuli Mallett static void	dodefn(const char *);
68acc9d408SJuli Mallett static void	dopushdef(const char *, const char *);
69acc9d408SJuli Mallett static void	dodump(const char *[], int);
70acc9d408SJuli Mallett static void	dotrace(const char *[], int, int);
71acc9d408SJuli Mallett static void	doifelse(const char *[], int);
72acc9d408SJuli Mallett static int	doincl(const char *);
73acc9d408SJuli Mallett static int	dopaste(const char *);
74acc9d408SJuli Mallett static void	gnu_dochq(const char *[], int);
75acc9d408SJuli Mallett static void	dochq(const char *[], int);
76acc9d408SJuli Mallett static void	gnu_dochc(const char *[], int);
77acc9d408SJuli Mallett static void	dochc(const char *[], int);
78acc9d408SJuli Mallett static void	dodiv(int);
79acc9d408SJuli Mallett static void	doundiv(const char *[], int);
80acc9d408SJuli Mallett static void	dosub(const char *[], int);
81acc9d408SJuli Mallett static void	map(char *, const char *, const char *, const char *);
82acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *);
83acc9d408SJuli Mallett static void	expand_builtin(const char *[], int, int);
84acc9d408SJuli Mallett static void	expand_macro(const char *[], int);
85acc9d408SJuli Mallett static void	dump_one_def(ndptr);
86acc9d408SJuli Mallett 
87acc9d408SJuli Mallett unsigned long	expansion_id;
88acc9d408SJuli Mallett 
899b50d902SRodney W. Grimes /*
90acc9d408SJuli Mallett  * eval - eval all macros and builtins calls
919b50d902SRodney W. Grimes  *	  argc - number of elements in argv.
929b50d902SRodney W. Grimes  *	  argv - element vector :
939b50d902SRodney W. Grimes  *			argv[0] = definition of a user
949b50d902SRodney W. Grimes  *				  macro or nil if built-in.
959b50d902SRodney W. Grimes  *			argv[1] = name of the macro or
969b50d902SRodney W. Grimes  *				  built-in.
979b50d902SRodney W. Grimes  *			argv[2] = parameters to user-defined
989b50d902SRodney W. Grimes  *			   .	  macro or built-in.
999b50d902SRodney W. Grimes  *			   .
1009b50d902SRodney W. Grimes  *
101acc9d408SJuli Mallett  * A call in the form of macro-or-builtin() will result in:
1029b50d902SRodney W. Grimes  *			argv[0] = nullstr
1039b50d902SRodney W. Grimes  *			argv[1] = macro-or-builtin
1049b50d902SRodney W. Grimes  *			argv[2] = nullstr
105acc9d408SJuli Mallett  *
106acc9d408SJuli Mallett  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1079b50d902SRodney W. Grimes  */
1089b50d902SRodney W. Grimes void
109bd2bfb58SJuli Mallett eval(const char *argv[], int argc, int td)
1109b50d902SRodney W. Grimes {
111acc9d408SJuli Mallett 	ssize_t mark = -1;
112acc9d408SJuli Mallett 
113acc9d408SJuli Mallett 	expansion_id++;
114acc9d408SJuli Mallett 	if (td & RECDEF)
115acc9d408SJuli Mallett 		errx(1, "%s at line %lu: expanding recursive definition for %s",
116acc9d408SJuli Mallett 			CURRENT_NAME, CURRENT_LINE, argv[1]);
117acc9d408SJuli Mallett 	if (traced_macros && is_traced(argv[1]))
118acc9d408SJuli Mallett 		mark = trace(argv, argc, infile+ilevel);
119acc9d408SJuli Mallett 	if (td == MACRTYPE)
120acc9d408SJuli Mallett 		expand_macro(argv, argc);
121acc9d408SJuli Mallett 	else
122acc9d408SJuli Mallett 		expand_builtin(argv, argc, td);
123acc9d408SJuli Mallett     	if (mark != -1)
124acc9d408SJuli Mallett 		finish_trace(mark);
125acc9d408SJuli Mallett }
126acc9d408SJuli Mallett 
127acc9d408SJuli Mallett /*
128acc9d408SJuli Mallett  * expand_builtin - evaluate built-in macros.
129acc9d408SJuli Mallett  */
130acc9d408SJuli Mallett void
131bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td)
132acc9d408SJuli Mallett {
133acc9d408SJuli Mallett 	int c, n;
134acc9d408SJuli Mallett 	int ac;
1359b50d902SRodney W. Grimes 	static int sysval = 0;
1369b50d902SRodney W. Grimes 
1379b50d902SRodney W. Grimes #ifdef DEBUG
1389b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
1399b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
1409b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
141acc9d408SJuli Mallett 	fflush(stdout);
1429b50d902SRodney W. Grimes #endif
143acc9d408SJuli Mallett 
1449b50d902SRodney W. Grimes  /*
1459b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
1469b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
1479b50d902SRodney W. Grimes   * argc to avoid further checking..
1489b50d902SRodney W. Grimes   */
149acc9d408SJuli Mallett   	ac = argc;
150acc9d408SJuli Mallett 
1519b50d902SRodney W. Grimes 	if (argc == 3 && !*(argv[2]))
1529b50d902SRodney W. Grimes 		argc--;
1539b50d902SRodney W. Grimes 
154acc9d408SJuli Mallett 	switch (td & TYPEMASK) {
1559b50d902SRodney W. Grimes 
1569b50d902SRodney W. Grimes 	case DEFITYPE:
1579b50d902SRodney W. Grimes 		if (argc > 2)
1589b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1599b50d902SRodney W. Grimes 		break;
1609b50d902SRodney W. Grimes 
1619b50d902SRodney W. Grimes 	case PUSDTYPE:
1629b50d902SRodney W. Grimes 		if (argc > 2)
1639b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1649b50d902SRodney W. Grimes 		break;
1659b50d902SRodney W. Grimes 
1669b50d902SRodney W. Grimes 	case DUMPTYPE:
1679b50d902SRodney W. Grimes 		dodump(argv, argc);
1689b50d902SRodney W. Grimes 		break;
1699b50d902SRodney W. Grimes 
170acc9d408SJuli Mallett 	case TRACEONTYPE:
171acc9d408SJuli Mallett 		dotrace(argv, argc, 1);
172acc9d408SJuli Mallett 		break;
173acc9d408SJuli Mallett 
174acc9d408SJuli Mallett 	case TRACEOFFTYPE:
175acc9d408SJuli Mallett 		dotrace(argv, argc, 0);
176acc9d408SJuli Mallett 		break;
177acc9d408SJuli Mallett 
1789b50d902SRodney W. Grimes 	case EXPRTYPE:
1799b50d902SRodney W. Grimes 	/*
1809b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1819b50d902SRodney W. Grimes 	 * expression
1829b50d902SRodney W. Grimes 	 */
1839b50d902SRodney W. Grimes 		if (argc > 2)
1849b50d902SRodney W. Grimes 			pbnum(expr(argv[2]));
1859b50d902SRodney W. Grimes 		break;
1869b50d902SRodney W. Grimes 
1879b50d902SRodney W. Grimes 	case IFELTYPE:
1889b50d902SRodney W. Grimes 		if (argc > 4)
1899b50d902SRodney W. Grimes 			doifelse(argv, argc);
1909b50d902SRodney W. Grimes 		break;
1919b50d902SRodney W. Grimes 
1929b50d902SRodney W. Grimes 	case IFDFTYPE:
1939b50d902SRodney W. Grimes 	/*
1949b50d902SRodney W. Grimes 	 * doifdef - select one of two
1959b50d902SRodney W. Grimes 	 * alternatives based on the existence of
1969b50d902SRodney W. Grimes 	 * another definition
1979b50d902SRodney W. Grimes 	 */
1989b50d902SRodney W. Grimes 		if (argc > 3) {
1999b50d902SRodney W. Grimes 			if (lookup(argv[2]) != nil)
2009b50d902SRodney W. Grimes 				pbstr(argv[3]);
2019b50d902SRodney W. Grimes 			else if (argc > 4)
2029b50d902SRodney W. Grimes 				pbstr(argv[4]);
2039b50d902SRodney W. Grimes 		}
2049b50d902SRodney W. Grimes 		break;
2059b50d902SRodney W. Grimes 
2069b50d902SRodney W. Grimes 	case LENGTYPE:
2079b50d902SRodney W. Grimes 	/*
2089b50d902SRodney W. Grimes 	 * dolen - find the length of the
2099b50d902SRodney W. Grimes 	 * argument
2109b50d902SRodney W. Grimes 	 */
2119b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2129b50d902SRodney W. Grimes 		break;
2139b50d902SRodney W. Grimes 
2149b50d902SRodney W. Grimes 	case INCRTYPE:
2159b50d902SRodney W. Grimes 	/*
2169b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2179b50d902SRodney W. Grimes 	 * argument
2189b50d902SRodney W. Grimes 	 */
2199b50d902SRodney W. Grimes 		if (argc > 2)
2209b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) + 1);
2219b50d902SRodney W. Grimes 		break;
2229b50d902SRodney W. Grimes 
2239b50d902SRodney W. Grimes 	case DECRTYPE:
2249b50d902SRodney W. Grimes 	/*
2259b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2269b50d902SRodney W. Grimes 	 * argument
2279b50d902SRodney W. Grimes 	 */
2289b50d902SRodney W. Grimes 		if (argc > 2)
2299b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) - 1);
2309b50d902SRodney W. Grimes 		break;
2319b50d902SRodney W. Grimes 
2329b50d902SRodney W. Grimes 	case SYSCTYPE:
2339b50d902SRodney W. Grimes 	/*
2349b50d902SRodney W. Grimes 	 * dosys - execute system command
2359b50d902SRodney W. Grimes 	 */
2369b50d902SRodney W. Grimes 		if (argc > 2)
2379b50d902SRodney W. Grimes 			sysval = system(argv[2]);
2389b50d902SRodney W. Grimes 		break;
2399b50d902SRodney W. Grimes 
2409b50d902SRodney W. Grimes 	case SYSVTYPE:
2419b50d902SRodney W. Grimes 	/*
2429b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2439b50d902SRodney W. Grimes 	 * system call.
2449b50d902SRodney W. Grimes 	 *
2459b50d902SRodney W. Grimes 	 */
2469b50d902SRodney W. Grimes 		pbnum(sysval);
2479b50d902SRodney W. Grimes 		break;
2489b50d902SRodney W. Grimes 
249acc9d408SJuli Mallett 	case ESYSCMDTYPE:
250acc9d408SJuli Mallett 		if (argc > 2)
251acc9d408SJuli Mallett 			doesyscmd(argv[2]);
252acc9d408SJuli Mallett 	    	break;
2539b50d902SRodney W. Grimes 	case INCLTYPE:
2549b50d902SRodney W. Grimes 		if (argc > 2)
2559b50d902SRodney W. Grimes 			if (!doincl(argv[2]))
256acc9d408SJuli Mallett 				err(1, "%s at line %lu: include(%s)",
257acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2589b50d902SRodney W. Grimes 		break;
2599b50d902SRodney W. Grimes 
2609b50d902SRodney W. Grimes 	case SINCTYPE:
2619b50d902SRodney W. Grimes 		if (argc > 2)
2629b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
2639b50d902SRodney W. Grimes 		break;
2649b50d902SRodney W. Grimes #ifdef EXTENDED
2659b50d902SRodney W. Grimes 	case PASTTYPE:
2669b50d902SRodney W. Grimes 		if (argc > 2)
2679b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
268acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
269acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2709b50d902SRodney W. Grimes 		break;
2719b50d902SRodney W. Grimes 
2729b50d902SRodney W. Grimes 	case SPASTYPE:
2739b50d902SRodney W. Grimes 		if (argc > 2)
2749b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
2759b50d902SRodney W. Grimes 		break;
2769b50d902SRodney W. Grimes #endif
2779b50d902SRodney W. Grimes 	case CHNQTYPE:
278acc9d408SJuli Mallett 		if (mimic_gnu)
279acc9d408SJuli Mallett 			gnu_dochq(argv, ac);
280acc9d408SJuli Mallett 		else
2819b50d902SRodney W. Grimes 			dochq(argv, argc);
2829b50d902SRodney W. Grimes 		break;
2839b50d902SRodney W. Grimes 
2849b50d902SRodney W. Grimes 	case CHNCTYPE:
285acc9d408SJuli Mallett 		if (mimic_gnu)
286acc9d408SJuli Mallett 			gnu_dochc(argv, ac);
287acc9d408SJuli Mallett 		else
2889b50d902SRodney W. Grimes 			dochc(argv, argc);
2899b50d902SRodney W. Grimes 		break;
2909b50d902SRodney W. Grimes 
2919b50d902SRodney W. Grimes 	case SUBSTYPE:
2929b50d902SRodney W. Grimes 	/*
2939b50d902SRodney W. Grimes 	 * dosub - select substring
2949b50d902SRodney W. Grimes 	 *
2959b50d902SRodney W. Grimes 	 */
2969b50d902SRodney W. Grimes 		if (argc > 3)
2979b50d902SRodney W. Grimes 			dosub(argv, argc);
2989b50d902SRodney W. Grimes 		break;
2999b50d902SRodney W. Grimes 
3009b50d902SRodney W. Grimes 	case SHIFTYPE:
3019b50d902SRodney W. Grimes 	/*
3029b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3039b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3049b50d902SRodney W. Grimes 	 * argv[2])
3059b50d902SRodney W. Grimes 	 */
3069b50d902SRodney W. Grimes 		if (argc > 3) {
3079b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
308acc9d408SJuli Mallett 				pbstr(rquote);
3099b50d902SRodney W. Grimes 				pbstr(argv[n]);
310acc9d408SJuli Mallett 				pbstr(lquote);
311acc9d408SJuli Mallett 				putback(COMMA);
3129b50d902SRodney W. Grimes 			}
313acc9d408SJuli Mallett 			pbstr(rquote);
3149b50d902SRodney W. Grimes 			pbstr(argv[3]);
315acc9d408SJuli Mallett 			pbstr(lquote);
3169b50d902SRodney W. Grimes 		}
3179b50d902SRodney W. Grimes 		break;
3189b50d902SRodney W. Grimes 
3199b50d902SRodney W. Grimes 	case DIVRTYPE:
3209b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
3219b50d902SRodney W. Grimes 			dodiv(n);
3229b50d902SRodney W. Grimes 		else {
3239b50d902SRodney W. Grimes 			active = stdout;
3249b50d902SRodney W. Grimes 			oindex = 0;
3259b50d902SRodney W. Grimes 		}
3269b50d902SRodney W. Grimes 		break;
3279b50d902SRodney W. Grimes 
3289b50d902SRodney W. Grimes 	case UNDVTYPE:
3299b50d902SRodney W. Grimes 		doundiv(argv, argc);
3309b50d902SRodney W. Grimes 		break;
3319b50d902SRodney W. Grimes 
3329b50d902SRodney W. Grimes 	case DIVNTYPE:
3339b50d902SRodney W. Grimes 	/*
3349b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3359b50d902SRodney W. Grimes 	 * current output diversion
3369b50d902SRodney W. Grimes 	 */
3379b50d902SRodney W. Grimes 		pbnum(oindex);
3389b50d902SRodney W. Grimes 		break;
3399b50d902SRodney W. Grimes 
3409b50d902SRodney W. Grimes 	case UNDFTYPE:
3419b50d902SRodney W. Grimes 	/*
3429b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3439b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3449b50d902SRodney W. Grimes 	 */
3459b50d902SRodney W. Grimes 		if (argc > 2)
3469b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3479b50d902SRodney W. Grimes 				remhash(argv[n], ALL);
3489b50d902SRodney W. Grimes 		break;
3499b50d902SRodney W. Grimes 
3509b50d902SRodney W. Grimes 	case POPDTYPE:
3519b50d902SRodney W. Grimes 	/*
3529b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3539b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3549b50d902SRodney W. Grimes 	 * keyword(s).
3559b50d902SRodney W. Grimes 	 */
3569b50d902SRodney W. Grimes 		if (argc > 2)
3579b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3589b50d902SRodney W. Grimes 				remhash(argv[n], TOP);
3599b50d902SRodney W. Grimes 		break;
3609b50d902SRodney W. Grimes 
3619b50d902SRodney W. Grimes 	case MKTMTYPE:
3629b50d902SRodney W. Grimes 	/*
3639b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
3649b50d902SRodney W. Grimes 	 */
365acc9d408SJuli Mallett 		if (argc > 2) {
366acc9d408SJuli Mallett 			int fd;
367acc9d408SJuli Mallett 			char *temp;
368acc9d408SJuli Mallett 
369acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
370acc9d408SJuli Mallett 
371acc9d408SJuli Mallett 			fd = mkstemp(temp);
372acc9d408SJuli Mallett 			if (fd == -1)
373acc9d408SJuli Mallett 				err(1,
374acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
375acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
376acc9d408SJuli Mallett 			close(fd);
377acc9d408SJuli Mallett 			pbstr(temp);
378acc9d408SJuli Mallett 			free(temp);
379acc9d408SJuli Mallett 		}
3809b50d902SRodney W. Grimes 		break;
3819b50d902SRodney W. Grimes 
3829b50d902SRodney W. Grimes 	case TRNLTYPE:
3839b50d902SRodney W. Grimes 	/*
3849b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
3859b50d902SRodney W. Grimes 	 * the source string that appears in the
3869b50d902SRodney W. Grimes 	 * "from" string with the corresponding
3879b50d902SRodney W. Grimes 	 * characters in the "to" string.
3889b50d902SRodney W. Grimes 	 */
3899b50d902SRodney W. Grimes 		if (argc > 3) {
390acc9d408SJuli Mallett 			char *temp;
391acc9d408SJuli Mallett 
392acc9d408SJuli Mallett 			temp = xalloc(strlen(argv[2])+1);
3939b50d902SRodney W. Grimes 			if (argc > 4)
3949b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
3959b50d902SRodney W. Grimes 			else
3969b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
3979b50d902SRodney W. Grimes 			pbstr(temp);
398acc9d408SJuli Mallett 			free(temp);
399acc9d408SJuli Mallett 		} else if (argc > 2)
4009b50d902SRodney W. Grimes 			pbstr(argv[2]);
4019b50d902SRodney W. Grimes 		break;
4029b50d902SRodney W. Grimes 
4039b50d902SRodney W. Grimes 	case INDXTYPE:
4049b50d902SRodney W. Grimes 	/*
4059b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4069b50d902SRodney W. Grimes 	 * argument string in the first argument
4079b50d902SRodney W. Grimes 	 * string. -1 if not present.
4089b50d902SRodney W. Grimes 	 */
4099b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4109b50d902SRodney W. Grimes 		break;
4119b50d902SRodney W. Grimes 
4129b50d902SRodney W. Grimes 	case ERRPTYPE:
4139b50d902SRodney W. Grimes 	/*
4149b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4159b50d902SRodney W. Grimes 	 * file
4169b50d902SRodney W. Grimes 	 */
4179b50d902SRodney W. Grimes 		if (argc > 2) {
4189b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4199b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4209b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4219b50d902SRodney W. Grimes 		}
4229b50d902SRodney W. Grimes 		break;
4239b50d902SRodney W. Grimes 
4249b50d902SRodney W. Grimes 	case DNLNTYPE:
4259b50d902SRodney W. Grimes 	/*
4269b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4279b50d902SRodney W. Grimes 	 * newline
4289b50d902SRodney W. Grimes 	 */
4299b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4309b50d902SRodney W. Grimes 			;
4319b50d902SRodney W. Grimes 		break;
4329b50d902SRodney W. Grimes 
4339b50d902SRodney W. Grimes 	case M4WRTYPE:
4349b50d902SRodney W. Grimes 	/*
4359b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4369b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4379b50d902SRodney W. Grimes 	 */
438acc9d408SJuli Mallett 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
4399b50d902SRodney W. Grimes 		break;
4409b50d902SRodney W. Grimes 
4419b50d902SRodney W. Grimes 	case EXITTYPE:
4429b50d902SRodney W. Grimes 	/*
4439b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4449b50d902SRodney W. Grimes 	 */
445cac6992aSAndrey A. Chernov 		killdiv();
4469b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4479b50d902SRodney W. Grimes 		break;
4489b50d902SRodney W. Grimes 
4499b50d902SRodney W. Grimes 	case DEFNTYPE:
4509b50d902SRodney W. Grimes 		if (argc > 2)
4519b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4529b50d902SRodney W. Grimes 				dodefn(argv[n]);
4539b50d902SRodney W. Grimes 		break;
4549b50d902SRodney W. Grimes 
455acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
456acc9d408SJuli Mallett 		if (argc > 2)
457acc9d408SJuli Mallett 			doindir(argv, argc);
458bbfd1447SSteve Price 		break;
459bbfd1447SSteve Price 
460acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
461acc9d408SJuli Mallett 		if (argc > 2)
462acc9d408SJuli Mallett 			dobuiltin(argv, argc);
463acc9d408SJuli Mallett 		break;
464acc9d408SJuli Mallett 
465acc9d408SJuli Mallett 	case PATSTYPE:
466acc9d408SJuli Mallett 		if (argc > 2)
467acc9d408SJuli Mallett 			dopatsubst(argv, argc);
468acc9d408SJuli Mallett 		break;
469acc9d408SJuli Mallett 	case REGEXPTYPE:
470acc9d408SJuli Mallett 		if (argc > 2)
471acc9d408SJuli Mallett 			doregexp(argv, argc);
472acc9d408SJuli Mallett 		break;
473acc9d408SJuli Mallett 	case LINETYPE:
474acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
475acc9d408SJuli Mallett 		break;
476acc9d408SJuli Mallett 	case FILENAMETYPE:
477acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
478acc9d408SJuli Mallett 		break;
479acc9d408SJuli Mallett 	case SELFTYPE:
480acc9d408SJuli Mallett 		pbstr(rquote);
481acc9d408SJuli Mallett 		pbstr(argv[1]);
482acc9d408SJuli Mallett 		pbstr(lquote);
483acc9d408SJuli Mallett 		break;
4849b50d902SRodney W. Grimes 	default:
485acc9d408SJuli Mallett 		errx(1, "%s at line %lu: eval: major botch.",
486acc9d408SJuli Mallett 			CURRENT_NAME, CURRENT_LINE);
4879b50d902SRodney W. Grimes 		break;
4889b50d902SRodney W. Grimes 	}
4899b50d902SRodney W. Grimes }
4909b50d902SRodney W. Grimes 
4919b50d902SRodney W. Grimes /*
492acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
4939b50d902SRodney W. Grimes  */
4949b50d902SRodney W. Grimes void
495bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc)
4969b50d902SRodney W. Grimes {
497acc9d408SJuli Mallett 	const char *t;
498acc9d408SJuli Mallett 	const char *p;
499acc9d408SJuli Mallett 	int n;
500acc9d408SJuli Mallett 	int argno;
5019b50d902SRodney W. Grimes 
5029b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5039b50d902SRodney W. Grimes 	p = t;
5049b50d902SRodney W. Grimes 	while (*p)
5059b50d902SRodney W. Grimes 		p++;
5069b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5079b50d902SRodney W. Grimes 	while (p > t) {
5089b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
509acc9d408SJuli Mallett 			PUTBACK(*p);
5109b50d902SRodney W. Grimes 		else {
5119b50d902SRodney W. Grimes 			switch (*p) {
5129b50d902SRodney W. Grimes 
5139b50d902SRodney W. Grimes 			case '#':
5149b50d902SRodney W. Grimes 				pbnum(argc - 2);
5159b50d902SRodney W. Grimes 				break;
5169b50d902SRodney W. Grimes 			case '0':
5179b50d902SRodney W. Grimes 			case '1':
5189b50d902SRodney W. Grimes 			case '2':
5199b50d902SRodney W. Grimes 			case '3':
5209b50d902SRodney W. Grimes 			case '4':
5219b50d902SRodney W. Grimes 			case '5':
5229b50d902SRodney W. Grimes 			case '6':
5239b50d902SRodney W. Grimes 			case '7':
5249b50d902SRodney W. Grimes 			case '8':
5259b50d902SRodney W. Grimes 			case '9':
5269b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5279b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5289b50d902SRodney W. Grimes 				break;
5299b50d902SRodney W. Grimes 			case '*':
530acc9d408SJuli Mallett 				if (argc > 2) {
5319b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5329b50d902SRodney W. Grimes 						pbstr(argv[n]);
533acc9d408SJuli Mallett 						putback(COMMA);
5349b50d902SRodney W. Grimes 					}
5359b50d902SRodney W. Grimes 					pbstr(argv[2]);
536acc9d408SJuli Mallett 			    	}
5379b50d902SRodney W. Grimes 				break;
538232eaee6SJoerg Wunsch                         case '@':
539acc9d408SJuli Mallett 				if (argc > 2) {
540acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
541acc9d408SJuli Mallett 						pbstr(rquote);
542232eaee6SJoerg Wunsch 						pbstr(argv[n]);
543acc9d408SJuli Mallett 						pbstr(lquote);
544acc9d408SJuli Mallett 						putback(COMMA);
545acc9d408SJuli Mallett 					}
546acc9d408SJuli Mallett 					pbstr(rquote);
547acc9d408SJuli Mallett 					pbstr(argv[2]);
548acc9d408SJuli Mallett 					pbstr(lquote);
549232eaee6SJoerg Wunsch 				}
550232eaee6SJoerg Wunsch                                 break;
5519b50d902SRodney W. Grimes 			default:
552acc9d408SJuli Mallett 				PUTBACK(*p);
553acc9d408SJuli Mallett 				PUTBACK('$');
5549b50d902SRodney W. Grimes 				break;
5559b50d902SRodney W. Grimes 			}
5569b50d902SRodney W. Grimes 			p--;
5579b50d902SRodney W. Grimes 		}
5589b50d902SRodney W. Grimes 		p--;
5599b50d902SRodney W. Grimes 	}
5609b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
561acc9d408SJuli Mallett 		PUTBACK(*p);
5629b50d902SRodney W. Grimes }
5639b50d902SRodney W. Grimes 
5649b50d902SRodney W. Grimes /*
5659b50d902SRodney W. Grimes  * dodefine - install definition in the table
5669b50d902SRodney W. Grimes  */
5679b50d902SRodney W. Grimes void
568bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn)
5699b50d902SRodney W. Grimes {
570acc9d408SJuli Mallett 	ndptr p;
571acc9d408SJuli Mallett 	int n;
5729b50d902SRodney W. Grimes 
5739b50d902SRodney W. Grimes 	if (!*name)
574acc9d408SJuli Mallett 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
575acc9d408SJuli Mallett 		    CURRENT_LINE);
5769b50d902SRodney W. Grimes 	if ((p = lookup(name)) == nil)
5779b50d902SRodney W. Grimes 		p = addent(name);
5789b50d902SRodney W. Grimes 	else if (p->defn != null)
5799b50d902SRodney W. Grimes 		free((char *) p->defn);
580acc9d408SJuli Mallett 	if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
581acc9d408SJuli Mallett 		n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
582acc9d408SJuli Mallett 		if (n != -1) {
583acc9d408SJuli Mallett 			p->type = n & TYPEMASK;
584acc9d408SJuli Mallett 			if ((n & NOARGS) == 0)
585acc9d408SJuli Mallett 				p->type |= NEEDARGS;
586ccc5b4e6SJuli Mallett 			p->defn = xstrdup(null);
587acc9d408SJuli Mallett 			return;
588acc9d408SJuli Mallett 		}
589acc9d408SJuli Mallett 	}
5909b50d902SRodney W. Grimes 	if (!*defn)
591ccc5b4e6SJuli Mallett 		p->defn = xstrdup(null);
5929b50d902SRodney W. Grimes 	else
593acc9d408SJuli Mallett 		p->defn = xstrdup(defn);
5949b50d902SRodney W. Grimes 	p->type = MACRTYPE;
595acc9d408SJuli Mallett 	if (STREQ(name, defn))
596acc9d408SJuli Mallett 		p->type |= RECDEF;
5979b50d902SRodney W. Grimes }
5989b50d902SRodney W. Grimes 
5999b50d902SRodney W. Grimes /*
6009b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
6019b50d902SRodney W. Grimes  *      the given name.
6029b50d902SRodney W. Grimes  */
603acc9d408SJuli Mallett static void
604bd2bfb58SJuli Mallett dodefn(const char *name)
6059b50d902SRodney W. Grimes {
606acc9d408SJuli Mallett 	ndptr p;
607ccc5b4e6SJuli Mallett 	const char *real;
6089b50d902SRodney W. Grimes 
609acc9d408SJuli Mallett 	if ((p = lookup(name)) != nil) {
610acc9d408SJuli Mallett 		if (p->defn != null) {
611acc9d408SJuli Mallett 			pbstr(rquote);
6129b50d902SRodney W. Grimes 			pbstr(p->defn);
613acc9d408SJuli Mallett 			pbstr(lquote);
614acc9d408SJuli Mallett 		} else if ((real = builtin_realname(p->type)) != NULL) {
615acc9d408SJuli Mallett 			pbstr(real);
616acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
617acc9d408SJuli Mallett 		}
6189b50d902SRodney W. Grimes 	}
6199b50d902SRodney W. Grimes }
6209b50d902SRodney W. Grimes 
6219b50d902SRodney W. Grimes /*
6229b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6239b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6249b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6259b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6269b50d902SRodney W. Grimes  *      lookup.
6279b50d902SRodney W. Grimes  */
628acc9d408SJuli Mallett static void
629bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn)
6309b50d902SRodney W. Grimes {
631acc9d408SJuli Mallett 	ndptr p;
6329b50d902SRodney W. Grimes 
6339b50d902SRodney W. Grimes 	if (!*name)
634acc9d408SJuli Mallett 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
635acc9d408SJuli Mallett 		    CURRENT_LINE);
6369b50d902SRodney W. Grimes 	p = addent(name);
6379b50d902SRodney W. Grimes 	if (!*defn)
638ccc5b4e6SJuli Mallett 		p->defn = xstrdup(null);
6399b50d902SRodney W. Grimes 	else
640acc9d408SJuli Mallett 		p->defn = xstrdup(defn);
6419b50d902SRodney W. Grimes 	p->type = MACRTYPE;
642acc9d408SJuli Mallett 	if (STREQ(name, defn))
643acc9d408SJuli Mallett 		p->type |= RECDEF;
644acc9d408SJuli Mallett }
645acc9d408SJuli Mallett 
646acc9d408SJuli Mallett /*
647acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
648acc9d408SJuli Mallett  */
649acc9d408SJuli Mallett static void
650bd2bfb58SJuli Mallett dump_one_def(ndptr p)
651acc9d408SJuli Mallett {
652ccc5b4e6SJuli Mallett 	const char *real;
653acc9d408SJuli Mallett 
654acc9d408SJuli Mallett 	if (mimic_gnu) {
655acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
656acc9d408SJuli Mallett 			fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
657acc9d408SJuli Mallett 		else {
658acc9d408SJuli Mallett 			real = builtin_realname(p->type);
659acc9d408SJuli Mallett 			if (real == NULL)
660acc9d408SJuli Mallett 				real = null;
661acc9d408SJuli Mallett 			fprintf(traceout, "%s:\t<%s>\n", p->name, real);
662acc9d408SJuli Mallett 	    	}
663acc9d408SJuli Mallett 	} else
664acc9d408SJuli Mallett 		fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
6659b50d902SRodney W. Grimes }
6669b50d902SRodney W. Grimes 
6679b50d902SRodney W. Grimes /*
6689b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6699b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6709b50d902SRodney W. Grimes  *      hash table is dumped.
6719b50d902SRodney W. Grimes  */
672acc9d408SJuli Mallett static void
673bd2bfb58SJuli Mallett dodump(const char *argv[], int argc)
6749b50d902SRodney W. Grimes {
675acc9d408SJuli Mallett 	int n;
6769b50d902SRodney W. Grimes 	ndptr p;
6779b50d902SRodney W. Grimes 
6789b50d902SRodney W. Grimes 	if (argc > 2) {
6799b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
6809b50d902SRodney W. Grimes 			if ((p = lookup(argv[n])) != nil)
681acc9d408SJuli Mallett 				dump_one_def(p);
682acc9d408SJuli Mallett 	} else {
6839b50d902SRodney W. Grimes 		for (n = 0; n < HASHSIZE; n++)
6849b50d902SRodney W. Grimes 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
685acc9d408SJuli Mallett 				dump_one_def(p);
6869b50d902SRodney W. Grimes 	}
6879b50d902SRodney W. Grimes }
6889b50d902SRodney W. Grimes 
6899b50d902SRodney W. Grimes /*
690acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
691acc9d408SJuli Mallett  */
692acc9d408SJuli Mallett static void
693bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on)
694acc9d408SJuli Mallett {
695acc9d408SJuli Mallett 	int n;
696acc9d408SJuli Mallett 
697acc9d408SJuli Mallett 	if (argc > 2) {
698acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
699acc9d408SJuli Mallett 			mark_traced(argv[n], on);
700acc9d408SJuli Mallett 	} else
701acc9d408SJuli Mallett 		mark_traced(NULL, on);
702acc9d408SJuli Mallett }
703acc9d408SJuli Mallett 
704acc9d408SJuli Mallett /*
7059b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
7069b50d902SRodney W. Grimes  */
707acc9d408SJuli Mallett static void
708bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc)
7099b50d902SRodney W. Grimes {
7109b50d902SRodney W. Grimes 	cycle {
7119b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
7129b50d902SRodney W. Grimes 			pbstr(argv[4]);
7139b50d902SRodney W. Grimes 		else if (argc == 6)
7149b50d902SRodney W. Grimes 			pbstr(argv[5]);
7159b50d902SRodney W. Grimes 		else if (argc > 6) {
7169b50d902SRodney W. Grimes 			argv += 3;
7179b50d902SRodney W. Grimes 			argc -= 3;
7189b50d902SRodney W. Grimes 			continue;
7199b50d902SRodney W. Grimes 		}
7209b50d902SRodney W. Grimes 		break;
7219b50d902SRodney W. Grimes 	}
7229b50d902SRodney W. Grimes }
7239b50d902SRodney W. Grimes 
7249b50d902SRodney W. Grimes /*
7259b50d902SRodney W. Grimes  * doinclude - include a given file.
7269b50d902SRodney W. Grimes  */
727acc9d408SJuli Mallett static int
728bd2bfb58SJuli Mallett doincl(const char *ifile)
7299b50d902SRodney W. Grimes {
7309b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
731acc9d408SJuli Mallett 		errx(1, "%s at line %lu: too many include files.",
732acc9d408SJuli Mallett 		    CURRENT_NAME, CURRENT_LINE);
733acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7349b50d902SRodney W. Grimes 		ilevel++;
735b1ea3d46SJuli Mallett 		if ((inname[ilevel] = strdup(ifile)) == NULL)
736b1ea3d46SJuli Mallett 			err(1, NULL);
737b1ea3d46SJuli Mallett 		inlineno[ilevel] = 1;
7389b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
739b1ea3d46SJuli Mallett 		emitline();
7409b50d902SRodney W. Grimes 		return (1);
741acc9d408SJuli Mallett 	} else
7429b50d902SRodney W. Grimes 		return (0);
7439b50d902SRodney W. Grimes }
7449b50d902SRodney W. Grimes 
7459b50d902SRodney W. Grimes #ifdef EXTENDED
7469b50d902SRodney W. Grimes /*
7479b50d902SRodney W. Grimes  * dopaste - include a given file without any
7489b50d902SRodney W. Grimes  *           macro processing.
7499b50d902SRodney W. Grimes  */
750acc9d408SJuli Mallett static int
751bd2bfb58SJuli Mallett dopaste(const char *pfile)
7529b50d902SRodney W. Grimes {
7539b50d902SRodney W. Grimes 	FILE *pf;
754acc9d408SJuli Mallett 	int c;
7559b50d902SRodney W. Grimes 
7569b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
757b1ea3d46SJuli Mallett 		fprintf(active, "#line 1 \"%s\"\n", pfile);
7589b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7599b50d902SRodney W. Grimes 			putc(c, active);
7609b50d902SRodney W. Grimes 		(void) fclose(pf);
761b1ea3d46SJuli Mallett 		emitline();
7629b50d902SRodney W. Grimes 		return (1);
763acc9d408SJuli Mallett 	} else
7649b50d902SRodney W. Grimes 		return (0);
7659b50d902SRodney W. Grimes }
7669b50d902SRodney W. Grimes #endif
7679b50d902SRodney W. Grimes 
768acc9d408SJuli Mallett static void
769bd2bfb58SJuli Mallett gnu_dochq(const char *argv[], int ac)
7709b50d902SRodney W. Grimes {
771acc9d408SJuli Mallett 	/* In gnu-m4 mode, the only way to restore quotes is to have no
772acc9d408SJuli Mallett 	 * arguments at all. */
773acc9d408SJuli Mallett 	if (ac == 2) {
774acc9d408SJuli Mallett 		lquote[0] = LQUOTE, lquote[1] = EOS;
775acc9d408SJuli Mallett 		rquote[0] = RQUOTE, rquote[1] = EOS;
776acc9d408SJuli Mallett 	} else {
777acc9d408SJuli Mallett 		strlcpy(lquote, argv[2], sizeof(lquote));
778acc9d408SJuli Mallett 		if(ac > 3)
779acc9d408SJuli Mallett 			strlcpy(rquote, argv[3], sizeof(rquote));
780ef2cea81SJonathan Lemon 		else
781acc9d408SJuli Mallett 			rquote[0] = EOS;
7829b50d902SRodney W. Grimes 	}
7839b50d902SRodney W. Grimes }
7849b50d902SRodney W. Grimes 
7859b50d902SRodney W. Grimes /*
786acc9d408SJuli Mallett  * dochq - change quote characters
7879b50d902SRodney W. Grimes  */
788acc9d408SJuli Mallett static void
789bd2bfb58SJuli Mallett dochq(const char *argv[], int argc)
7909b50d902SRodney W. Grimes {
7919b50d902SRodney W. Grimes 	if (argc > 2) {
7929b50d902SRodney W. Grimes 		if (*argv[2])
793acc9d408SJuli Mallett 			strlcpy(lquote, argv[2], sizeof(lquote));
794acc9d408SJuli Mallett 		else {
795acc9d408SJuli Mallett 			lquote[0] = LQUOTE;
796acc9d408SJuli Mallett 			lquote[1] = EOS;
797acc9d408SJuli Mallett 		}
7989b50d902SRodney W. Grimes 		if (argc > 3) {
7999b50d902SRodney W. Grimes 			if (*argv[3])
800acc9d408SJuli Mallett 				strlcpy(rquote, argv[3], sizeof(rquote));
801acc9d408SJuli Mallett 		} else
802acc9d408SJuli Mallett 			strcpy(rquote, lquote);
803acc9d408SJuli Mallett 	} else {
804acc9d408SJuli Mallett 		lquote[0] = LQUOTE, lquote[1] = EOS;
805acc9d408SJuli Mallett 		rquote[0] = RQUOTE, rquote[1] = EOS;
806acc9d408SJuli Mallett 	}
807acc9d408SJuli Mallett }
808acc9d408SJuli Mallett 
809acc9d408SJuli Mallett static void
810bd2bfb58SJuli Mallett gnu_dochc(const char *argv[], int ac)
811acc9d408SJuli Mallett {
812acc9d408SJuli Mallett 	/* In gnu-m4 mode, no arguments mean no comment
813acc9d408SJuli Mallett 	 * arguments at all. */
814acc9d408SJuli Mallett 	if (ac == 2) {
815acc9d408SJuli Mallett 		scommt[0] = EOS;
816acc9d408SJuli Mallett 		ecommt[0] = EOS;
817acc9d408SJuli Mallett 	} else {
818acc9d408SJuli Mallett 		if (*argv[2])
819acc9d408SJuli Mallett 			strlcpy(scommt, argv[2], sizeof(scommt));
820acc9d408SJuli Mallett 		else
821acc9d408SJuli Mallett 			scommt[0] = SCOMMT, scommt[1] = EOS;
822acc9d408SJuli Mallett 		if(ac > 3 && *argv[3])
823acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
824acc9d408SJuli Mallett 		else
825acc9d408SJuli Mallett 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
826acc9d408SJuli Mallett 	}
827acc9d408SJuli Mallett }
828acc9d408SJuli Mallett /*
829acc9d408SJuli Mallett  * dochc - change comment characters
830acc9d408SJuli Mallett  */
831acc9d408SJuli Mallett static void
832bd2bfb58SJuli Mallett dochc(const char *argv[], int argc)
833acc9d408SJuli Mallett {
834acc9d408SJuli Mallett 	if (argc > 2) {
835acc9d408SJuli Mallett 		if (*argv[2])
836acc9d408SJuli Mallett 			strlcpy(scommt, argv[2], sizeof(scommt));
837acc9d408SJuli Mallett 		if (argc > 3) {
838acc9d408SJuli Mallett 			if (*argv[3])
839acc9d408SJuli Mallett 				strlcpy(ecommt, argv[3], sizeof(ecommt));
8409b50d902SRodney W. Grimes 		}
8419b50d902SRodney W. Grimes 		else
842acc9d408SJuli Mallett 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
8439b50d902SRodney W. Grimes 	}
8449b50d902SRodney W. Grimes 	else {
845acc9d408SJuli Mallett 		scommt[0] = SCOMMT, scommt[1] = EOS;
846acc9d408SJuli Mallett 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
8479b50d902SRodney W. Grimes 	}
8489b50d902SRodney W. Grimes }
8499b50d902SRodney W. Grimes 
8509b50d902SRodney W. Grimes /*
8519b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8529b50d902SRodney W. Grimes  */
853acc9d408SJuli Mallett static void
854bd2bfb58SJuli Mallett dodiv(int n)
8559b50d902SRodney W. Grimes {
856acc9d408SJuli Mallett 	int fd;
857acc9d408SJuli Mallett 
858ef2cea81SJonathan Lemon 	oindex = n;
859acc9d408SJuli Mallett 	if (n >= maxout) {
860acc9d408SJuli Mallett 		if (mimic_gnu)
861acc9d408SJuli Mallett 			resizedivs(n + 10);
862acc9d408SJuli Mallett 		else
863acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
864acc9d408SJuli Mallett     	}
865acc9d408SJuli Mallett 
866acc9d408SJuli Mallett 	if (n < 0)
8679b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
8689b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
869acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
870acc9d408SJuli Mallett 
871acc9d408SJuli Mallett 		if ((fd = mkstemp(fname)) < 0 ||
872acc9d408SJuli Mallett 			(outfile[n] = fdopen(fd, "w+")) == NULL)
873acc9d408SJuli Mallett 				err(1, "%s: cannot divert", fname);
874acc9d408SJuli Mallett 		if (unlink(fname) == -1)
875acc9d408SJuli Mallett 			err(1, "%s: cannot unlink", fname);
8769b50d902SRodney W. Grimes 	}
8779b50d902SRodney W. Grimes 	active = outfile[n];
8789b50d902SRodney W. Grimes }
8799b50d902SRodney W. Grimes 
8809b50d902SRodney W. Grimes /*
8819b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
8829b50d902SRodney W. Grimes  *              other outputs, in numerical order.
8839b50d902SRodney W. Grimes  */
884acc9d408SJuli Mallett static void
885bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc)
8869b50d902SRodney W. Grimes {
887acc9d408SJuli Mallett 	int ind;
888acc9d408SJuli Mallett 	int n;
8899b50d902SRodney W. Grimes 
8909b50d902SRodney W. Grimes 	if (argc > 2) {
8919b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
8929b50d902SRodney W. Grimes 			n = atoi(argv[ind]);
893acc9d408SJuli Mallett 			if (n > 0 && n < maxout && outfile[n] != NULL)
8949b50d902SRodney W. Grimes 				getdiv(n);
8959b50d902SRodney W. Grimes 
8969b50d902SRodney W. Grimes 		}
8979b50d902SRodney W. Grimes 	}
8989b50d902SRodney W. Grimes 	else
899acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
9009b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
9019b50d902SRodney W. Grimes 				getdiv(n);
9029b50d902SRodney W. Grimes }
9039b50d902SRodney W. Grimes 
9049b50d902SRodney W. Grimes /*
9059b50d902SRodney W. Grimes  * dosub - select substring
9069b50d902SRodney W. Grimes  */
907acc9d408SJuli Mallett static void
908bd2bfb58SJuli Mallett dosub(const char *argv[], int argc)
9099b50d902SRodney W. Grimes {
910acc9d408SJuli Mallett 	const char *ap, *fc, *k;
911acc9d408SJuli Mallett 	int nc;
9129b50d902SRodney W. Grimes 
9139b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
9149b50d902SRodney W. Grimes #ifdef EXPR
9159b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
9169b50d902SRodney W. Grimes #else
9179b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
9189b50d902SRodney W. Grimes #endif
9194ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
920acc9d408SJuli Mallett 	if (argc >= 5)
9214ba4d387SGregory Neil Shapiro #ifdef EXPR
922acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
9234ba4d387SGregory Neil Shapiro #else
924acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
9254ba4d387SGregory Neil Shapiro #endif
9269b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
9274ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
9289b50d902SRodney W. Grimes 			putback(*k);
9299b50d902SRodney W. Grimes }
9309b50d902SRodney W. Grimes 
9319b50d902SRodney W. Grimes /*
9329b50d902SRodney W. Grimes  * map:
9339b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
9349b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
9359b50d902SRodney W. Grimes  *
9369b50d902SRodney W. Grimes  * This is a standard implementation of map(s,from,to) function of ICON
9379b50d902SRodney W. Grimes  * language. Within mapvec, we replace every character of "from" with
9389b50d902SRodney W. Grimes  * the corresponding character in "to". If "to" is shorter than "from",
9399b50d902SRodney W. Grimes  * than the corresponding entries are null, which means that those
9409b50d902SRodney W. Grimes  * characters dissapear altogether. Furthermore, imagine
9419b50d902SRodney W. Grimes  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
9429b50d902SRodney W. Grimes  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
9439b50d902SRodney W. Grimes  * ultimately maps to `*'. In order to achieve this effect in an efficient
9449b50d902SRodney W. Grimes  * manner (i.e. without multiple passes over the destination string), we
9459b50d902SRodney W. Grimes  * loop over mapvec, starting with the initial source character. if the
9469b50d902SRodney W. Grimes  * character value (dch) in this location is different than the source
9479b50d902SRodney W. Grimes  * character (sch), sch becomes dch, once again to index into mapvec, until
9489b50d902SRodney W. Grimes  * the character value stabilizes (i.e. sch = dch, in other words
9499b50d902SRodney W. Grimes  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
9509b50d902SRodney W. Grimes  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
9519b50d902SRodney W. Grimes  * end, we restore mapvec* back to normal where mapvec[n] == n for
9529b50d902SRodney W. Grimes  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
9539b50d902SRodney W. Grimes  * about 5 times faster than any algorithm that makes multiple passes over
9549b50d902SRodney W. Grimes  * destination string.
9559b50d902SRodney W. Grimes  */
956acc9d408SJuli Mallett static void
957bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to)
9589b50d902SRodney W. Grimes {
959acc9d408SJuli Mallett 	const char *tmp;
960acc9d408SJuli Mallett 	unsigned char sch, dch;
961acc9d408SJuli Mallett 	static char frombis[257];
962acc9d408SJuli Mallett 	static char tobis[257];
963acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
964acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
965acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
966acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
967acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
968acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
969acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
970acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
971acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
972acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
973acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
974acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
975acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
976acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
977acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
978acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
979acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
980acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
981acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9829b50d902SRodney W. Grimes 	};
9839b50d902SRodney W. Grimes 
9849b50d902SRodney W. Grimes 	if (*src) {
985acc9d408SJuli Mallett 		if (mimic_gnu) {
986acc9d408SJuli Mallett 			/*
987acc9d408SJuli Mallett 			 * expand character ranges on the fly
988acc9d408SJuli Mallett 			 */
989acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
990acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
991acc9d408SJuli Mallett 		}
9929b50d902SRodney W. Grimes 		tmp = from;
9939b50d902SRodney W. Grimes 	/*
9949b50d902SRodney W. Grimes 	 * create a mapping between "from" and
9959b50d902SRodney W. Grimes 	 * "to"
9969b50d902SRodney W. Grimes 	 */
9979b50d902SRodney W. Grimes 		while (*from)
998acc9d408SJuli Mallett 			mapvec[(unsigned char)(*from++)] = (*to) ?
999acc9d408SJuli Mallett 				(unsigned char)(*to++) : 0;
10009b50d902SRodney W. Grimes 
10019b50d902SRodney W. Grimes 		while (*src) {
1002acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
10039b50d902SRodney W. Grimes 			dch = mapvec[sch];
10049b50d902SRodney W. Grimes 			while (dch != sch) {
10059b50d902SRodney W. Grimes 				sch = dch;
10069b50d902SRodney W. Grimes 				dch = mapvec[sch];
10079b50d902SRodney W. Grimes 			}
1008acc9d408SJuli Mallett 			if ((*dest = (char)dch))
10099b50d902SRodney W. Grimes 				dest++;
10109b50d902SRodney W. Grimes 		}
10119b50d902SRodney W. Grimes 	/*
10129b50d902SRodney W. Grimes 	 * restore all the changed characters
10139b50d902SRodney W. Grimes 	 */
10149b50d902SRodney W. Grimes 		while (*tmp) {
1015acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
10169b50d902SRodney W. Grimes 			tmp++;
10179b50d902SRodney W. Grimes 		}
10189b50d902SRodney W. Grimes 	}
1019acc9d408SJuli Mallett 	*dest = '\0';
10209b50d902SRodney W. Grimes }
1021acc9d408SJuli Mallett 
1022acc9d408SJuli Mallett 
1023acc9d408SJuli Mallett /*
1024acc9d408SJuli Mallett  * handledash:
1025acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
1026acc9d408SJuli Mallett  * on the way.
1027acc9d408SJuli Mallett  */
1028acc9d408SJuli Mallett static const char *
1029bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src)
1030acc9d408SJuli Mallett {
1031acc9d408SJuli Mallett 	char *p;
1032acc9d408SJuli Mallett 
1033acc9d408SJuli Mallett 	p = buffer;
1034acc9d408SJuli Mallett 	while(*src) {
1035acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
1036acc9d408SJuli Mallett 			unsigned char i;
1037acc9d408SJuli Mallett 			for (i = (unsigned char)src[0];
1038acc9d408SJuli Mallett 			    i <= (unsigned char)src[2]; i++) {
1039acc9d408SJuli Mallett 				*p++ = i;
1040acc9d408SJuli Mallett 				if (p == end) {
1041acc9d408SJuli Mallett 					*p = '\0';
1042acc9d408SJuli Mallett 					return buffer;
1043acc9d408SJuli Mallett 				}
1044acc9d408SJuli Mallett 			}
1045acc9d408SJuli Mallett 			src += 3;
1046acc9d408SJuli Mallett 		} else
1047acc9d408SJuli Mallett 			*p++ = *src++;
1048acc9d408SJuli Mallett 		if (p == end)
1049acc9d408SJuli Mallett 			break;
1050acc9d408SJuli Mallett 	}
1051acc9d408SJuli Mallett 	*p = '\0';
1052acc9d408SJuli Mallett 	return buffer;
1053acc9d408SJuli Mallett }
1054