xref: /freebsd/usr.bin/m4/eval.c (revision acc9d4083840bce63fb8b3ff7ee8195d8f67d49e)
1acc9d408SJuli Mallett /*	$OpenBSD: eval.c,v 1.43 2002/02/16 21:27:48 millert 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");
42acc9d408SJuli Mallett __RCSID_SOURCE("$OpenBSD: eval.c,v 1.43 2002/02/16 21:27:48 millert 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
1099b50d902SRodney W. Grimes eval(argv, argc, td)
110acc9d408SJuli Mallett 	const char *argv[];
111acc9d408SJuli Mallett 	int argc;
112acc9d408SJuli Mallett 	int td;
1139b50d902SRodney W. Grimes {
114acc9d408SJuli Mallett 	ssize_t mark = -1;
115acc9d408SJuli Mallett 
116acc9d408SJuli Mallett 	expansion_id++;
117acc9d408SJuli Mallett 	if (td & RECDEF)
118acc9d408SJuli Mallett 		errx(1, "%s at line %lu: expanding recursive definition for %s",
119acc9d408SJuli Mallett 			CURRENT_NAME, CURRENT_LINE, argv[1]);
120acc9d408SJuli Mallett 	if (traced_macros && is_traced(argv[1]))
121acc9d408SJuli Mallett 		mark = trace(argv, argc, infile+ilevel);
122acc9d408SJuli Mallett 	if (td == MACRTYPE)
123acc9d408SJuli Mallett 		expand_macro(argv, argc);
124acc9d408SJuli Mallett 	else
125acc9d408SJuli Mallett 		expand_builtin(argv, argc, td);
126acc9d408SJuli Mallett     	if (mark != -1)
127acc9d408SJuli Mallett 		finish_trace(mark);
128acc9d408SJuli Mallett }
129acc9d408SJuli Mallett 
130acc9d408SJuli Mallett /*
131acc9d408SJuli Mallett  * expand_builtin - evaluate built-in macros.
132acc9d408SJuli Mallett  */
133acc9d408SJuli Mallett void
134acc9d408SJuli Mallett expand_builtin(argv, argc, td)
135acc9d408SJuli Mallett 	const char *argv[];
136acc9d408SJuli Mallett 	int argc;
137acc9d408SJuli Mallett 	int td;
138acc9d408SJuli Mallett {
139acc9d408SJuli Mallett 	int c, n;
140acc9d408SJuli Mallett 	int ac;
1419b50d902SRodney W. Grimes 	static int sysval = 0;
1429b50d902SRodney W. Grimes 
1439b50d902SRodney W. Grimes #ifdef DEBUG
1449b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
1459b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
1469b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
147acc9d408SJuli Mallett 	fflush(stdout);
1489b50d902SRodney W. Grimes #endif
149acc9d408SJuli Mallett 
1509b50d902SRodney W. Grimes  /*
1519b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
1529b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
1539b50d902SRodney W. Grimes   * argc to avoid further checking..
1549b50d902SRodney W. Grimes   */
155acc9d408SJuli Mallett   	ac = argc;
156acc9d408SJuli Mallett 
1579b50d902SRodney W. Grimes 	if (argc == 3 && !*(argv[2]))
1589b50d902SRodney W. Grimes 		argc--;
1599b50d902SRodney W. Grimes 
160acc9d408SJuli Mallett 	switch (td & TYPEMASK) {
1619b50d902SRodney W. Grimes 
1629b50d902SRodney W. Grimes 	case DEFITYPE:
1639b50d902SRodney W. Grimes 		if (argc > 2)
1649b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1659b50d902SRodney W. Grimes 		break;
1669b50d902SRodney W. Grimes 
1679b50d902SRodney W. Grimes 	case PUSDTYPE:
1689b50d902SRodney W. Grimes 		if (argc > 2)
1699b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1709b50d902SRodney W. Grimes 		break;
1719b50d902SRodney W. Grimes 
1729b50d902SRodney W. Grimes 	case DUMPTYPE:
1739b50d902SRodney W. Grimes 		dodump(argv, argc);
1749b50d902SRodney W. Grimes 		break;
1759b50d902SRodney W. Grimes 
176acc9d408SJuli Mallett 	case TRACEONTYPE:
177acc9d408SJuli Mallett 		dotrace(argv, argc, 1);
178acc9d408SJuli Mallett 		break;
179acc9d408SJuli Mallett 
180acc9d408SJuli Mallett 	case TRACEOFFTYPE:
181acc9d408SJuli Mallett 		dotrace(argv, argc, 0);
182acc9d408SJuli Mallett 		break;
183acc9d408SJuli Mallett 
1849b50d902SRodney W. Grimes 	case EXPRTYPE:
1859b50d902SRodney W. Grimes 	/*
1869b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1879b50d902SRodney W. Grimes 	 * expression
1889b50d902SRodney W. Grimes 	 */
1899b50d902SRodney W. Grimes 		if (argc > 2)
1909b50d902SRodney W. Grimes 			pbnum(expr(argv[2]));
1919b50d902SRodney W. Grimes 		break;
1929b50d902SRodney W. Grimes 
1939b50d902SRodney W. Grimes 	case IFELTYPE:
1949b50d902SRodney W. Grimes 		if (argc > 4)
1959b50d902SRodney W. Grimes 			doifelse(argv, argc);
1969b50d902SRodney W. Grimes 		break;
1979b50d902SRodney W. Grimes 
1989b50d902SRodney W. Grimes 	case IFDFTYPE:
1999b50d902SRodney W. Grimes 	/*
2009b50d902SRodney W. Grimes 	 * doifdef - select one of two
2019b50d902SRodney W. Grimes 	 * alternatives based on the existence of
2029b50d902SRodney W. Grimes 	 * another definition
2039b50d902SRodney W. Grimes 	 */
2049b50d902SRodney W. Grimes 		if (argc > 3) {
2059b50d902SRodney W. Grimes 			if (lookup(argv[2]) != nil)
2069b50d902SRodney W. Grimes 				pbstr(argv[3]);
2079b50d902SRodney W. Grimes 			else if (argc > 4)
2089b50d902SRodney W. Grimes 				pbstr(argv[4]);
2099b50d902SRodney W. Grimes 		}
2109b50d902SRodney W. Grimes 		break;
2119b50d902SRodney W. Grimes 
2129b50d902SRodney W. Grimes 	case LENGTYPE:
2139b50d902SRodney W. Grimes 	/*
2149b50d902SRodney W. Grimes 	 * dolen - find the length of the
2159b50d902SRodney W. Grimes 	 * argument
2169b50d902SRodney W. Grimes 	 */
2179b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2189b50d902SRodney W. Grimes 		break;
2199b50d902SRodney W. Grimes 
2209b50d902SRodney W. Grimes 	case INCRTYPE:
2219b50d902SRodney W. Grimes 	/*
2229b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2239b50d902SRodney W. Grimes 	 * argument
2249b50d902SRodney W. Grimes 	 */
2259b50d902SRodney W. Grimes 		if (argc > 2)
2269b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) + 1);
2279b50d902SRodney W. Grimes 		break;
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes 	case DECRTYPE:
2309b50d902SRodney W. Grimes 	/*
2319b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2329b50d902SRodney W. Grimes 	 * argument
2339b50d902SRodney W. Grimes 	 */
2349b50d902SRodney W. Grimes 		if (argc > 2)
2359b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) - 1);
2369b50d902SRodney W. Grimes 		break;
2379b50d902SRodney W. Grimes 
2389b50d902SRodney W. Grimes 	case SYSCTYPE:
2399b50d902SRodney W. Grimes 	/*
2409b50d902SRodney W. Grimes 	 * dosys - execute system command
2419b50d902SRodney W. Grimes 	 */
2429b50d902SRodney W. Grimes 		if (argc > 2)
2439b50d902SRodney W. Grimes 			sysval = system(argv[2]);
2449b50d902SRodney W. Grimes 		break;
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 	case SYSVTYPE:
2479b50d902SRodney W. Grimes 	/*
2489b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2499b50d902SRodney W. Grimes 	 * system call.
2509b50d902SRodney W. Grimes 	 *
2519b50d902SRodney W. Grimes 	 */
2529b50d902SRodney W. Grimes 		pbnum(sysval);
2539b50d902SRodney W. Grimes 		break;
2549b50d902SRodney W. Grimes 
255acc9d408SJuli Mallett 	case ESYSCMDTYPE:
256acc9d408SJuli Mallett 		if (argc > 2)
257acc9d408SJuli Mallett 			doesyscmd(argv[2]);
258acc9d408SJuli Mallett 	    	break;
2599b50d902SRodney W. Grimes 	case INCLTYPE:
2609b50d902SRodney W. Grimes 		if (argc > 2)
2619b50d902SRodney W. Grimes 			if (!doincl(argv[2]))
262acc9d408SJuli Mallett 				err(1, "%s at line %lu: include(%s)",
263acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2649b50d902SRodney W. Grimes 		break;
2659b50d902SRodney W. Grimes 
2669b50d902SRodney W. Grimes 	case SINCTYPE:
2679b50d902SRodney W. Grimes 		if (argc > 2)
2689b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
2699b50d902SRodney W. Grimes 		break;
2709b50d902SRodney W. Grimes #ifdef EXTENDED
2719b50d902SRodney W. Grimes 	case PASTTYPE:
2729b50d902SRodney W. Grimes 		if (argc > 2)
2739b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
274acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
275acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2769b50d902SRodney W. Grimes 		break;
2779b50d902SRodney W. Grimes 
2789b50d902SRodney W. Grimes 	case SPASTYPE:
2799b50d902SRodney W. Grimes 		if (argc > 2)
2809b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
2819b50d902SRodney W. Grimes 		break;
2829b50d902SRodney W. Grimes #endif
2839b50d902SRodney W. Grimes 	case CHNQTYPE:
284acc9d408SJuli Mallett 		if (mimic_gnu)
285acc9d408SJuli Mallett 			gnu_dochq(argv, ac);
286acc9d408SJuli Mallett 		else
2879b50d902SRodney W. Grimes 			dochq(argv, argc);
2889b50d902SRodney W. Grimes 		break;
2899b50d902SRodney W. Grimes 
2909b50d902SRodney W. Grimes 	case CHNCTYPE:
291acc9d408SJuli Mallett 		if (mimic_gnu)
292acc9d408SJuli Mallett 			gnu_dochc(argv, ac);
293acc9d408SJuli Mallett 		else
2949b50d902SRodney W. Grimes 			dochc(argv, argc);
2959b50d902SRodney W. Grimes 		break;
2969b50d902SRodney W. Grimes 
2979b50d902SRodney W. Grimes 	case SUBSTYPE:
2989b50d902SRodney W. Grimes 	/*
2999b50d902SRodney W. Grimes 	 * dosub - select substring
3009b50d902SRodney W. Grimes 	 *
3019b50d902SRodney W. Grimes 	 */
3029b50d902SRodney W. Grimes 		if (argc > 3)
3039b50d902SRodney W. Grimes 			dosub(argv, argc);
3049b50d902SRodney W. Grimes 		break;
3059b50d902SRodney W. Grimes 
3069b50d902SRodney W. Grimes 	case SHIFTYPE:
3079b50d902SRodney W. Grimes 	/*
3089b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3099b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3109b50d902SRodney W. Grimes 	 * argv[2])
3119b50d902SRodney W. Grimes 	 */
3129b50d902SRodney W. Grimes 		if (argc > 3) {
3139b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
314acc9d408SJuli Mallett 				pbstr(rquote);
3159b50d902SRodney W. Grimes 				pbstr(argv[n]);
316acc9d408SJuli Mallett 				pbstr(lquote);
317acc9d408SJuli Mallett 				putback(COMMA);
3189b50d902SRodney W. Grimes 			}
319acc9d408SJuli Mallett 			pbstr(rquote);
3209b50d902SRodney W. Grimes 			pbstr(argv[3]);
321acc9d408SJuli Mallett 			pbstr(lquote);
3229b50d902SRodney W. Grimes 		}
3239b50d902SRodney W. Grimes 		break;
3249b50d902SRodney W. Grimes 
3259b50d902SRodney W. Grimes 	case DIVRTYPE:
3269b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
3279b50d902SRodney W. Grimes 			dodiv(n);
3289b50d902SRodney W. Grimes 		else {
3299b50d902SRodney W. Grimes 			active = stdout;
3309b50d902SRodney W. Grimes 			oindex = 0;
3319b50d902SRodney W. Grimes 		}
3329b50d902SRodney W. Grimes 		break;
3339b50d902SRodney W. Grimes 
3349b50d902SRodney W. Grimes 	case UNDVTYPE:
3359b50d902SRodney W. Grimes 		doundiv(argv, argc);
3369b50d902SRodney W. Grimes 		break;
3379b50d902SRodney W. Grimes 
3389b50d902SRodney W. Grimes 	case DIVNTYPE:
3399b50d902SRodney W. Grimes 	/*
3409b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3419b50d902SRodney W. Grimes 	 * current output diversion
3429b50d902SRodney W. Grimes 	 */
3439b50d902SRodney W. Grimes 		pbnum(oindex);
3449b50d902SRodney W. Grimes 		break;
3459b50d902SRodney W. Grimes 
3469b50d902SRodney W. Grimes 	case UNDFTYPE:
3479b50d902SRodney W. Grimes 	/*
3489b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3499b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3509b50d902SRodney W. Grimes 	 */
3519b50d902SRodney W. Grimes 		if (argc > 2)
3529b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3539b50d902SRodney W. Grimes 				remhash(argv[n], ALL);
3549b50d902SRodney W. Grimes 		break;
3559b50d902SRodney W. Grimes 
3569b50d902SRodney W. Grimes 	case POPDTYPE:
3579b50d902SRodney W. Grimes 	/*
3589b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3599b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3609b50d902SRodney W. Grimes 	 * keyword(s).
3619b50d902SRodney W. Grimes 	 */
3629b50d902SRodney W. Grimes 		if (argc > 2)
3639b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
3649b50d902SRodney W. Grimes 				remhash(argv[n], TOP);
3659b50d902SRodney W. Grimes 		break;
3669b50d902SRodney W. Grimes 
3679b50d902SRodney W. Grimes 	case MKTMTYPE:
3689b50d902SRodney W. Grimes 	/*
3699b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
3709b50d902SRodney W. Grimes 	 */
371acc9d408SJuli Mallett 		if (argc > 2) {
372acc9d408SJuli Mallett 			int fd;
373acc9d408SJuli Mallett 			char *temp;
374acc9d408SJuli Mallett 
375acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
376acc9d408SJuli Mallett 
377acc9d408SJuli Mallett 			fd = mkstemp(temp);
378acc9d408SJuli Mallett 			if (fd == -1)
379acc9d408SJuli Mallett 				err(1,
380acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
381acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
382acc9d408SJuli Mallett 			close(fd);
383acc9d408SJuli Mallett 			pbstr(temp);
384acc9d408SJuli Mallett 			free(temp);
385acc9d408SJuli Mallett 		}
3869b50d902SRodney W. Grimes 		break;
3879b50d902SRodney W. Grimes 
3889b50d902SRodney W. Grimes 	case TRNLTYPE:
3899b50d902SRodney W. Grimes 	/*
3909b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
3919b50d902SRodney W. Grimes 	 * the source string that appears in the
3929b50d902SRodney W. Grimes 	 * "from" string with the corresponding
3939b50d902SRodney W. Grimes 	 * characters in the "to" string.
3949b50d902SRodney W. Grimes 	 */
3959b50d902SRodney W. Grimes 		if (argc > 3) {
396acc9d408SJuli Mallett 			char *temp;
397acc9d408SJuli Mallett 
398acc9d408SJuli Mallett 			temp = xalloc(strlen(argv[2])+1);
3999b50d902SRodney W. Grimes 			if (argc > 4)
4009b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
4019b50d902SRodney W. Grimes 			else
4029b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
4039b50d902SRodney W. Grimes 			pbstr(temp);
404acc9d408SJuli Mallett 			free(temp);
405acc9d408SJuli Mallett 		} else if (argc > 2)
4069b50d902SRodney W. Grimes 			pbstr(argv[2]);
4079b50d902SRodney W. Grimes 		break;
4089b50d902SRodney W. Grimes 
4099b50d902SRodney W. Grimes 	case INDXTYPE:
4109b50d902SRodney W. Grimes 	/*
4119b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4129b50d902SRodney W. Grimes 	 * argument string in the first argument
4139b50d902SRodney W. Grimes 	 * string. -1 if not present.
4149b50d902SRodney W. Grimes 	 */
4159b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4169b50d902SRodney W. Grimes 		break;
4179b50d902SRodney W. Grimes 
4189b50d902SRodney W. Grimes 	case ERRPTYPE:
4199b50d902SRodney W. Grimes 	/*
4209b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4219b50d902SRodney W. Grimes 	 * file
4229b50d902SRodney W. Grimes 	 */
4239b50d902SRodney W. Grimes 		if (argc > 2) {
4249b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4259b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4269b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4279b50d902SRodney W. Grimes 		}
4289b50d902SRodney W. Grimes 		break;
4299b50d902SRodney W. Grimes 
4309b50d902SRodney W. Grimes 	case DNLNTYPE:
4319b50d902SRodney W. Grimes 	/*
4329b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4339b50d902SRodney W. Grimes 	 * newline
4349b50d902SRodney W. Grimes 	 */
4359b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4369b50d902SRodney W. Grimes 			;
4379b50d902SRodney W. Grimes 		break;
4389b50d902SRodney W. Grimes 
4399b50d902SRodney W. Grimes 	case M4WRTYPE:
4409b50d902SRodney W. Grimes 	/*
4419b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4429b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4439b50d902SRodney W. Grimes 	 */
444acc9d408SJuli Mallett 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
4459b50d902SRodney W. Grimes 		break;
4469b50d902SRodney W. Grimes 
4479b50d902SRodney W. Grimes 	case EXITTYPE:
4489b50d902SRodney W. Grimes 	/*
4499b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4509b50d902SRodney W. Grimes 	 */
451cac6992aSAndrey A. Chernov 		killdiv();
4529b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4539b50d902SRodney W. Grimes 		break;
4549b50d902SRodney W. Grimes 
4559b50d902SRodney W. Grimes 	case DEFNTYPE:
4569b50d902SRodney W. Grimes 		if (argc > 2)
4579b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4589b50d902SRodney W. Grimes 				dodefn(argv[n]);
4599b50d902SRodney W. Grimes 		break;
4609b50d902SRodney W. Grimes 
461acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
462acc9d408SJuli Mallett 		if (argc > 2)
463acc9d408SJuli Mallett 			doindir(argv, argc);
464bbfd1447SSteve Price 		break;
465bbfd1447SSteve Price 
466acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
467acc9d408SJuli Mallett 		if (argc > 2)
468acc9d408SJuli Mallett 			dobuiltin(argv, argc);
469acc9d408SJuli Mallett 		break;
470acc9d408SJuli Mallett 
471acc9d408SJuli Mallett 	case PATSTYPE:
472acc9d408SJuli Mallett 		if (argc > 2)
473acc9d408SJuli Mallett 			dopatsubst(argv, argc);
474acc9d408SJuli Mallett 		break;
475acc9d408SJuli Mallett 	case REGEXPTYPE:
476acc9d408SJuli Mallett 		if (argc > 2)
477acc9d408SJuli Mallett 			doregexp(argv, argc);
478acc9d408SJuli Mallett 		break;
479acc9d408SJuli Mallett 	case LINETYPE:
480acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
481acc9d408SJuli Mallett 		break;
482acc9d408SJuli Mallett 	case FILENAMETYPE:
483acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
484acc9d408SJuli Mallett 		break;
485acc9d408SJuli Mallett 	case SELFTYPE:
486acc9d408SJuli Mallett 		pbstr(rquote);
487acc9d408SJuli Mallett 		pbstr(argv[1]);
488acc9d408SJuli Mallett 		pbstr(lquote);
489acc9d408SJuli Mallett 		break;
4909b50d902SRodney W. Grimes 	default:
491acc9d408SJuli Mallett 		errx(1, "%s at line %lu: eval: major botch.",
492acc9d408SJuli Mallett 			CURRENT_NAME, CURRENT_LINE);
4939b50d902SRodney W. Grimes 		break;
4949b50d902SRodney W. Grimes 	}
4959b50d902SRodney W. Grimes }
4969b50d902SRodney W. Grimes 
4979b50d902SRodney W. Grimes /*
498acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
4999b50d902SRodney W. Grimes  */
5009b50d902SRodney W. Grimes void
501acc9d408SJuli Mallett expand_macro(argv, argc)
502acc9d408SJuli Mallett 	const char *argv[];
503acc9d408SJuli Mallett 	int argc;
5049b50d902SRodney W. Grimes {
505acc9d408SJuli Mallett 	const char *t;
506acc9d408SJuli Mallett 	const char *p;
507acc9d408SJuli Mallett 	int n;
508acc9d408SJuli Mallett 	int argno;
5099b50d902SRodney W. Grimes 
5109b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5119b50d902SRodney W. Grimes 	p = t;
5129b50d902SRodney W. Grimes 	while (*p)
5139b50d902SRodney W. Grimes 		p++;
5149b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5159b50d902SRodney W. Grimes 	while (p > t) {
5169b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
517acc9d408SJuli Mallett 			PUTBACK(*p);
5189b50d902SRodney W. Grimes 		else {
5199b50d902SRodney W. Grimes 			switch (*p) {
5209b50d902SRodney W. Grimes 
5219b50d902SRodney W. Grimes 			case '#':
5229b50d902SRodney W. Grimes 				pbnum(argc - 2);
5239b50d902SRodney W. Grimes 				break;
5249b50d902SRodney W. Grimes 			case '0':
5259b50d902SRodney W. Grimes 			case '1':
5269b50d902SRodney W. Grimes 			case '2':
5279b50d902SRodney W. Grimes 			case '3':
5289b50d902SRodney W. Grimes 			case '4':
5299b50d902SRodney W. Grimes 			case '5':
5309b50d902SRodney W. Grimes 			case '6':
5319b50d902SRodney W. Grimes 			case '7':
5329b50d902SRodney W. Grimes 			case '8':
5339b50d902SRodney W. Grimes 			case '9':
5349b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5359b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5369b50d902SRodney W. Grimes 				break;
5379b50d902SRodney W. Grimes 			case '*':
538acc9d408SJuli Mallett 				if (argc > 2) {
5399b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5409b50d902SRodney W. Grimes 						pbstr(argv[n]);
541acc9d408SJuli Mallett 						putback(COMMA);
5429b50d902SRodney W. Grimes 					}
5439b50d902SRodney W. Grimes 					pbstr(argv[2]);
544acc9d408SJuli Mallett 			    	}
5459b50d902SRodney W. Grimes 				break;
546232eaee6SJoerg Wunsch                         case '@':
547acc9d408SJuli Mallett 				if (argc > 2) {
548acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
549acc9d408SJuli Mallett 						pbstr(rquote);
550232eaee6SJoerg Wunsch 						pbstr(argv[n]);
551acc9d408SJuli Mallett 						pbstr(lquote);
552acc9d408SJuli Mallett 						putback(COMMA);
553acc9d408SJuli Mallett 					}
554acc9d408SJuli Mallett 					pbstr(rquote);
555acc9d408SJuli Mallett 					pbstr(argv[2]);
556acc9d408SJuli Mallett 					pbstr(lquote);
557232eaee6SJoerg Wunsch 				}
558232eaee6SJoerg Wunsch                                 break;
5599b50d902SRodney W. Grimes 			default:
560acc9d408SJuli Mallett 				PUTBACK(*p);
561acc9d408SJuli Mallett 				PUTBACK('$');
5629b50d902SRodney W. Grimes 				break;
5639b50d902SRodney W. Grimes 			}
5649b50d902SRodney W. Grimes 			p--;
5659b50d902SRodney W. Grimes 		}
5669b50d902SRodney W. Grimes 		p--;
5679b50d902SRodney W. Grimes 	}
5689b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
569acc9d408SJuli Mallett 		PUTBACK(*p);
5709b50d902SRodney W. Grimes }
5719b50d902SRodney W. Grimes 
5729b50d902SRodney W. Grimes /*
5739b50d902SRodney W. Grimes  * dodefine - install definition in the table
5749b50d902SRodney W. Grimes  */
5759b50d902SRodney W. Grimes void
5769b50d902SRodney W. Grimes dodefine(name, defn)
577acc9d408SJuli Mallett 	const char *name;
578acc9d408SJuli Mallett 	const char *defn;
5799b50d902SRodney W. Grimes {
580acc9d408SJuli Mallett 	ndptr p;
581acc9d408SJuli Mallett 	int n;
5829b50d902SRodney W. Grimes 
5839b50d902SRodney W. Grimes 	if (!*name)
584acc9d408SJuli Mallett 		errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
585acc9d408SJuli Mallett 		    CURRENT_LINE);
5869b50d902SRodney W. Grimes 	if ((p = lookup(name)) == nil)
5879b50d902SRodney W. Grimes 		p = addent(name);
5889b50d902SRodney W. Grimes 	else if (p->defn != null)
5899b50d902SRodney W. Grimes 		free((char *) p->defn);
590acc9d408SJuli Mallett 	if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
591acc9d408SJuli Mallett 		n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
592acc9d408SJuli Mallett 		if (n != -1) {
593acc9d408SJuli Mallett 			p->type = n & TYPEMASK;
594acc9d408SJuli Mallett 			if ((n & NOARGS) == 0)
595acc9d408SJuli Mallett 				p->type |= NEEDARGS;
596acc9d408SJuli Mallett 			p->defn = null;
597acc9d408SJuli Mallett 			return;
598acc9d408SJuli Mallett 		}
599acc9d408SJuli Mallett 	}
6009b50d902SRodney W. Grimes 	if (!*defn)
6019b50d902SRodney W. Grimes 		p->defn = null;
6029b50d902SRodney W. Grimes 	else
603acc9d408SJuli Mallett 		p->defn = xstrdup(defn);
6049b50d902SRodney W. Grimes 	p->type = MACRTYPE;
605acc9d408SJuli Mallett 	if (STREQ(name, defn))
606acc9d408SJuli Mallett 		p->type |= RECDEF;
6079b50d902SRodney W. Grimes }
6089b50d902SRodney W. Grimes 
6099b50d902SRodney W. Grimes /*
6109b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
6119b50d902SRodney W. Grimes  *      the given name.
6129b50d902SRodney W. Grimes  */
613acc9d408SJuli Mallett static void
6149b50d902SRodney W. Grimes dodefn(name)
615acc9d408SJuli Mallett 	const char *name;
6169b50d902SRodney W. Grimes {
617acc9d408SJuli Mallett 	ndptr p;
618acc9d408SJuli Mallett 	char *real;
6199b50d902SRodney W. Grimes 
620acc9d408SJuli Mallett 	if ((p = lookup(name)) != nil) {
621acc9d408SJuli Mallett 		if (p->defn != null) {
622acc9d408SJuli Mallett 			pbstr(rquote);
6239b50d902SRodney W. Grimes 			pbstr(p->defn);
624acc9d408SJuli Mallett 			pbstr(lquote);
625acc9d408SJuli Mallett 		} else if ((real = builtin_realname(p->type)) != NULL) {
626acc9d408SJuli Mallett 			pbstr(real);
627acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
628acc9d408SJuli Mallett 		}
6299b50d902SRodney W. Grimes 	}
6309b50d902SRodney W. Grimes }
6319b50d902SRodney W. Grimes 
6329b50d902SRodney W. Grimes /*
6339b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6349b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6359b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6369b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6379b50d902SRodney W. Grimes  *      lookup.
6389b50d902SRodney W. Grimes  */
639acc9d408SJuli Mallett static void
6409b50d902SRodney W. Grimes dopushdef(name, defn)
641acc9d408SJuli Mallett 	const char *name;
642acc9d408SJuli Mallett 	const char *defn;
6439b50d902SRodney W. Grimes {
644acc9d408SJuli Mallett 	ndptr p;
6459b50d902SRodney W. Grimes 
6469b50d902SRodney W. Grimes 	if (!*name)
647acc9d408SJuli Mallett 		errx(1, "%s at line %lu: null definition", CURRENT_NAME,
648acc9d408SJuli Mallett 		    CURRENT_LINE);
6499b50d902SRodney W. Grimes 	p = addent(name);
6509b50d902SRodney W. Grimes 	if (!*defn)
6519b50d902SRodney W. Grimes 		p->defn = null;
6529b50d902SRodney W. Grimes 	else
653acc9d408SJuli Mallett 		p->defn = xstrdup(defn);
6549b50d902SRodney W. Grimes 	p->type = MACRTYPE;
655acc9d408SJuli Mallett 	if (STREQ(name, defn))
656acc9d408SJuli Mallett 		p->type |= RECDEF;
657acc9d408SJuli Mallett }
658acc9d408SJuli Mallett 
659acc9d408SJuli Mallett /*
660acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
661acc9d408SJuli Mallett  */
662acc9d408SJuli Mallett static void
663acc9d408SJuli Mallett dump_one_def(p)
664acc9d408SJuli Mallett 	ndptr p;
665acc9d408SJuli Mallett {
666acc9d408SJuli Mallett 	char *real;
667acc9d408SJuli Mallett 
668acc9d408SJuli Mallett 	if (mimic_gnu) {
669acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
670acc9d408SJuli Mallett 			fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
671acc9d408SJuli Mallett 		else {
672acc9d408SJuli Mallett 			real = builtin_realname(p->type);
673acc9d408SJuli Mallett 			if (real == NULL)
674acc9d408SJuli Mallett 				real = null;
675acc9d408SJuli Mallett 			fprintf(traceout, "%s:\t<%s>\n", p->name, real);
676acc9d408SJuli Mallett 	    	}
677acc9d408SJuli Mallett 	} else
678acc9d408SJuli Mallett 		fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
6799b50d902SRodney W. Grimes }
6809b50d902SRodney W. Grimes 
6819b50d902SRodney W. Grimes /*
6829b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6839b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6849b50d902SRodney W. Grimes  *      hash table is dumped.
6859b50d902SRodney W. Grimes  */
686acc9d408SJuli Mallett static void
6879b50d902SRodney W. Grimes dodump(argv, argc)
688acc9d408SJuli Mallett 	const char *argv[];
689acc9d408SJuli Mallett 	int argc;
6909b50d902SRodney W. Grimes {
691acc9d408SJuli Mallett 	int n;
6929b50d902SRodney W. Grimes 	ndptr p;
6939b50d902SRodney W. Grimes 
6949b50d902SRodney W. Grimes 	if (argc > 2) {
6959b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
6969b50d902SRodney W. Grimes 			if ((p = lookup(argv[n])) != nil)
697acc9d408SJuli Mallett 				dump_one_def(p);
698acc9d408SJuli Mallett 	} else {
6999b50d902SRodney W. Grimes 		for (n = 0; n < HASHSIZE; n++)
7009b50d902SRodney W. Grimes 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
701acc9d408SJuli Mallett 				dump_one_def(p);
7029b50d902SRodney W. Grimes 	}
7039b50d902SRodney W. Grimes }
7049b50d902SRodney W. Grimes 
7059b50d902SRodney W. Grimes /*
706acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
707acc9d408SJuli Mallett  */
708acc9d408SJuli Mallett static void
709acc9d408SJuli Mallett dotrace(argv, argc, on)
710acc9d408SJuli Mallett 	const char *argv[];
711acc9d408SJuli Mallett 	int argc;
712acc9d408SJuli Mallett 	int on;
713acc9d408SJuli Mallett {
714acc9d408SJuli Mallett 	int n;
715acc9d408SJuli Mallett 
716acc9d408SJuli Mallett 	if (argc > 2) {
717acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
718acc9d408SJuli Mallett 			mark_traced(argv[n], on);
719acc9d408SJuli Mallett 	} else
720acc9d408SJuli Mallett 		mark_traced(NULL, on);
721acc9d408SJuli Mallett }
722acc9d408SJuli Mallett 
723acc9d408SJuli Mallett /*
7249b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
7259b50d902SRodney W. Grimes  */
726acc9d408SJuli Mallett static void
7279b50d902SRodney W. Grimes doifelse(argv, argc)
728acc9d408SJuli Mallett 	const char *argv[];
729acc9d408SJuli Mallett 	int argc;
7309b50d902SRodney W. Grimes {
7319b50d902SRodney W. Grimes 	cycle {
7329b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
7339b50d902SRodney W. Grimes 			pbstr(argv[4]);
7349b50d902SRodney W. Grimes 		else if (argc == 6)
7359b50d902SRodney W. Grimes 			pbstr(argv[5]);
7369b50d902SRodney W. Grimes 		else if (argc > 6) {
7379b50d902SRodney W. Grimes 			argv += 3;
7389b50d902SRodney W. Grimes 			argc -= 3;
7399b50d902SRodney W. Grimes 			continue;
7409b50d902SRodney W. Grimes 		}
7419b50d902SRodney W. Grimes 		break;
7429b50d902SRodney W. Grimes 	}
7439b50d902SRodney W. Grimes }
7449b50d902SRodney W. Grimes 
7459b50d902SRodney W. Grimes /*
7469b50d902SRodney W. Grimes  * doinclude - include a given file.
7479b50d902SRodney W. Grimes  */
748acc9d408SJuli Mallett static int
7499b50d902SRodney W. Grimes doincl(ifile)
750acc9d408SJuli Mallett 	const char *ifile;
7519b50d902SRodney W. Grimes {
7529b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
753acc9d408SJuli Mallett 		errx(1, "%s at line %lu: too many include files.",
754acc9d408SJuli Mallett 		    CURRENT_NAME, CURRENT_LINE);
755acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7569b50d902SRodney W. Grimes 		ilevel++;
757b1ea3d46SJuli Mallett 		if ((inname[ilevel] = strdup(ifile)) == NULL)
758b1ea3d46SJuli Mallett 			err(1, NULL);
759b1ea3d46SJuli Mallett 		inlineno[ilevel] = 1;
7609b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
761b1ea3d46SJuli Mallett 		emitline();
7629b50d902SRodney W. Grimes 		return (1);
763acc9d408SJuli Mallett 	} else
7649b50d902SRodney W. Grimes 		return (0);
7659b50d902SRodney W. Grimes }
7669b50d902SRodney W. Grimes 
7679b50d902SRodney W. Grimes #ifdef EXTENDED
7689b50d902SRodney W. Grimes /*
7699b50d902SRodney W. Grimes  * dopaste - include a given file without any
7709b50d902SRodney W. Grimes  *           macro processing.
7719b50d902SRodney W. Grimes  */
772acc9d408SJuli Mallett static int
7739b50d902SRodney W. Grimes dopaste(pfile)
774acc9d408SJuli Mallett 	const char *pfile;
7759b50d902SRodney W. Grimes {
7769b50d902SRodney W. Grimes 	FILE *pf;
777acc9d408SJuli Mallett 	int c;
7789b50d902SRodney W. Grimes 
7799b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
780b1ea3d46SJuli Mallett 		fprintf(active, "#line 1 \"%s\"\n", pfile);
7819b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7829b50d902SRodney W. Grimes 			putc(c, active);
7839b50d902SRodney W. Grimes 		(void) fclose(pf);
784b1ea3d46SJuli Mallett 		emitline();
7859b50d902SRodney W. Grimes 		return (1);
786acc9d408SJuli Mallett 	} else
7879b50d902SRodney W. Grimes 		return (0);
7889b50d902SRodney W. Grimes }
7899b50d902SRodney W. Grimes #endif
7909b50d902SRodney W. Grimes 
791acc9d408SJuli Mallett static void
792acc9d408SJuli Mallett gnu_dochq(argv, ac)
793acc9d408SJuli Mallett 	const char *argv[];
794acc9d408SJuli Mallett 	int ac;
7959b50d902SRodney W. Grimes {
796acc9d408SJuli Mallett 	/* In gnu-m4 mode, the only way to restore quotes is to have no
797acc9d408SJuli Mallett 	 * arguments at all. */
798acc9d408SJuli Mallett 	if (ac == 2) {
799acc9d408SJuli Mallett 		lquote[0] = LQUOTE, lquote[1] = EOS;
800acc9d408SJuli Mallett 		rquote[0] = RQUOTE, rquote[1] = EOS;
801acc9d408SJuli Mallett 	} else {
802acc9d408SJuli Mallett 		strlcpy(lquote, argv[2], sizeof(lquote));
803acc9d408SJuli Mallett 		if(ac > 3)
804acc9d408SJuli Mallett 			strlcpy(rquote, argv[3], sizeof(rquote));
805ef2cea81SJonathan Lemon 		else
806acc9d408SJuli Mallett 			rquote[0] = EOS;
8079b50d902SRodney W. Grimes 	}
8089b50d902SRodney W. Grimes }
8099b50d902SRodney W. Grimes 
8109b50d902SRodney W. Grimes /*
811acc9d408SJuli Mallett  * dochq - change quote characters
8129b50d902SRodney W. Grimes  */
813acc9d408SJuli Mallett static void
814acc9d408SJuli Mallett dochq(argv, argc)
815acc9d408SJuli Mallett 	const char *argv[];
816acc9d408SJuli Mallett 	int argc;
8179b50d902SRodney W. Grimes {
8189b50d902SRodney W. Grimes 	if (argc > 2) {
8199b50d902SRodney W. Grimes 		if (*argv[2])
820acc9d408SJuli Mallett 			strlcpy(lquote, argv[2], sizeof(lquote));
821acc9d408SJuli Mallett 		else {
822acc9d408SJuli Mallett 			lquote[0] = LQUOTE;
823acc9d408SJuli Mallett 			lquote[1] = EOS;
824acc9d408SJuli Mallett 		}
8259b50d902SRodney W. Grimes 		if (argc > 3) {
8269b50d902SRodney W. Grimes 			if (*argv[3])
827acc9d408SJuli Mallett 				strlcpy(rquote, argv[3], sizeof(rquote));
828acc9d408SJuli Mallett 		} else
829acc9d408SJuli Mallett 			strcpy(rquote, lquote);
830acc9d408SJuli Mallett 	} else {
831acc9d408SJuli Mallett 		lquote[0] = LQUOTE, lquote[1] = EOS;
832acc9d408SJuli Mallett 		rquote[0] = RQUOTE, rquote[1] = EOS;
833acc9d408SJuli Mallett 	}
834acc9d408SJuli Mallett }
835acc9d408SJuli Mallett 
836acc9d408SJuli Mallett static void
837acc9d408SJuli Mallett gnu_dochc(argv, ac)
838acc9d408SJuli Mallett 	const char *argv[];
839acc9d408SJuli Mallett 	int ac;
840acc9d408SJuli Mallett {
841acc9d408SJuli Mallett 	/* In gnu-m4 mode, no arguments mean no comment
842acc9d408SJuli Mallett 	 * arguments at all. */
843acc9d408SJuli Mallett 	if (ac == 2) {
844acc9d408SJuli Mallett 		scommt[0] = EOS;
845acc9d408SJuli Mallett 		ecommt[0] = EOS;
846acc9d408SJuli Mallett 	} else {
847acc9d408SJuli Mallett 		if (*argv[2])
848acc9d408SJuli Mallett 			strlcpy(scommt, argv[2], sizeof(scommt));
849acc9d408SJuli Mallett 		else
850acc9d408SJuli Mallett 			scommt[0] = SCOMMT, scommt[1] = EOS;
851acc9d408SJuli Mallett 		if(ac > 3 && *argv[3])
852acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
853acc9d408SJuli Mallett 		else
854acc9d408SJuli Mallett 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
855acc9d408SJuli Mallett 	}
856acc9d408SJuli Mallett }
857acc9d408SJuli Mallett /*
858acc9d408SJuli Mallett  * dochc - change comment characters
859acc9d408SJuli Mallett  */
860acc9d408SJuli Mallett static void
861acc9d408SJuli Mallett dochc(argv, argc)
862acc9d408SJuli Mallett 	const char *argv[];
863acc9d408SJuli Mallett 	int argc;
864acc9d408SJuli Mallett {
865acc9d408SJuli Mallett 	if (argc > 2) {
866acc9d408SJuli Mallett 		if (*argv[2])
867acc9d408SJuli Mallett 			strlcpy(scommt, argv[2], sizeof(scommt));
868acc9d408SJuli Mallett 		if (argc > 3) {
869acc9d408SJuli Mallett 			if (*argv[3])
870acc9d408SJuli Mallett 				strlcpy(ecommt, argv[3], sizeof(ecommt));
8719b50d902SRodney W. Grimes 		}
8729b50d902SRodney W. Grimes 		else
873acc9d408SJuli Mallett 			ecommt[0] = ECOMMT, ecommt[1] = EOS;
8749b50d902SRodney W. Grimes 	}
8759b50d902SRodney W. Grimes 	else {
876acc9d408SJuli Mallett 		scommt[0] = SCOMMT, scommt[1] = EOS;
877acc9d408SJuli Mallett 		ecommt[0] = ECOMMT, ecommt[1] = EOS;
8789b50d902SRodney W. Grimes 	}
8799b50d902SRodney W. Grimes }
8809b50d902SRodney W. Grimes 
8819b50d902SRodney W. Grimes /*
8829b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8839b50d902SRodney W. Grimes  */
884acc9d408SJuli Mallett static void
8859b50d902SRodney W. Grimes dodiv(n)
886acc9d408SJuli Mallett 	int n;
8879b50d902SRodney W. Grimes {
888acc9d408SJuli Mallett 	int fd;
889acc9d408SJuli Mallett 
890ef2cea81SJonathan Lemon 	oindex = n;
891acc9d408SJuli Mallett 	if (n >= maxout) {
892acc9d408SJuli Mallett 		if (mimic_gnu)
893acc9d408SJuli Mallett 			resizedivs(n + 10);
894acc9d408SJuli Mallett 		else
895acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
896acc9d408SJuli Mallett     	}
897acc9d408SJuli Mallett 
898acc9d408SJuli Mallett 	if (n < 0)
8999b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
9009b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
901acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
902acc9d408SJuli Mallett 
903acc9d408SJuli Mallett 		if ((fd = mkstemp(fname)) < 0 ||
904acc9d408SJuli Mallett 			(outfile[n] = fdopen(fd, "w+")) == NULL)
905acc9d408SJuli Mallett 				err(1, "%s: cannot divert", fname);
906acc9d408SJuli Mallett 		if (unlink(fname) == -1)
907acc9d408SJuli Mallett 			err(1, "%s: cannot unlink", fname);
9089b50d902SRodney W. Grimes 	}
9099b50d902SRodney W. Grimes 	active = outfile[n];
9109b50d902SRodney W. Grimes }
9119b50d902SRodney W. Grimes 
9129b50d902SRodney W. Grimes /*
9139b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
9149b50d902SRodney W. Grimes  *              other outputs, in numerical order.
9159b50d902SRodney W. Grimes  */
916acc9d408SJuli Mallett static void
9179b50d902SRodney W. Grimes doundiv(argv, argc)
918acc9d408SJuli Mallett 	const char *argv[];
919acc9d408SJuli Mallett 	int argc;
9209b50d902SRodney W. Grimes {
921acc9d408SJuli Mallett 	int ind;
922acc9d408SJuli Mallett 	int n;
9239b50d902SRodney W. Grimes 
9249b50d902SRodney W. Grimes 	if (argc > 2) {
9259b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
9269b50d902SRodney W. Grimes 			n = atoi(argv[ind]);
927acc9d408SJuli Mallett 			if (n > 0 && n < maxout && outfile[n] != NULL)
9289b50d902SRodney W. Grimes 				getdiv(n);
9299b50d902SRodney W. Grimes 
9309b50d902SRodney W. Grimes 		}
9319b50d902SRodney W. Grimes 	}
9329b50d902SRodney W. Grimes 	else
933acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
9349b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
9359b50d902SRodney W. Grimes 				getdiv(n);
9369b50d902SRodney W. Grimes }
9379b50d902SRodney W. Grimes 
9389b50d902SRodney W. Grimes /*
9399b50d902SRodney W. Grimes  * dosub - select substring
9409b50d902SRodney W. Grimes  */
941acc9d408SJuli Mallett static void
9429b50d902SRodney W. Grimes dosub(argv, argc)
943acc9d408SJuli Mallett 	const char *argv[];
944acc9d408SJuli Mallett 	int argc;
9459b50d902SRodney W. Grimes {
946acc9d408SJuli Mallett 	const char *ap, *fc, *k;
947acc9d408SJuli Mallett 	int nc;
9489b50d902SRodney W. Grimes 
9499b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
9509b50d902SRodney W. Grimes #ifdef EXPR
9519b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
9529b50d902SRodney W. Grimes #else
9539b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
9549b50d902SRodney W. Grimes #endif
9554ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
956acc9d408SJuli Mallett 	if (argc >= 5)
9574ba4d387SGregory Neil Shapiro #ifdef EXPR
958acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
9594ba4d387SGregory Neil Shapiro #else
960acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
9614ba4d387SGregory Neil Shapiro #endif
9629b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
9634ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
9649b50d902SRodney W. Grimes 			putback(*k);
9659b50d902SRodney W. Grimes }
9669b50d902SRodney W. Grimes 
9679b50d902SRodney W. Grimes /*
9689b50d902SRodney W. Grimes  * map:
9699b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
9709b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
9719b50d902SRodney W. Grimes  *
9729b50d902SRodney W. Grimes  * This is a standard implementation of map(s,from,to) function of ICON
9739b50d902SRodney W. Grimes  * language. Within mapvec, we replace every character of "from" with
9749b50d902SRodney W. Grimes  * the corresponding character in "to". If "to" is shorter than "from",
9759b50d902SRodney W. Grimes  * than the corresponding entries are null, which means that those
9769b50d902SRodney W. Grimes  * characters dissapear altogether. Furthermore, imagine
9779b50d902SRodney W. Grimes  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
9789b50d902SRodney W. Grimes  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
9799b50d902SRodney W. Grimes  * ultimately maps to `*'. In order to achieve this effect in an efficient
9809b50d902SRodney W. Grimes  * manner (i.e. without multiple passes over the destination string), we
9819b50d902SRodney W. Grimes  * loop over mapvec, starting with the initial source character. if the
9829b50d902SRodney W. Grimes  * character value (dch) in this location is different than the source
9839b50d902SRodney W. Grimes  * character (sch), sch becomes dch, once again to index into mapvec, until
9849b50d902SRodney W. Grimes  * the character value stabilizes (i.e. sch = dch, in other words
9859b50d902SRodney W. Grimes  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
9869b50d902SRodney W. Grimes  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
9879b50d902SRodney W. Grimes  * end, we restore mapvec* back to normal where mapvec[n] == n for
9889b50d902SRodney W. Grimes  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
9899b50d902SRodney W. Grimes  * about 5 times faster than any algorithm that makes multiple passes over
9909b50d902SRodney W. Grimes  * destination string.
9919b50d902SRodney W. Grimes  */
992acc9d408SJuli Mallett static void
9939b50d902SRodney W. Grimes map(dest, src, from, to)
994acc9d408SJuli Mallett 	char *dest;
995acc9d408SJuli Mallett 	const char *src;
996acc9d408SJuli Mallett 	const char *from;
997acc9d408SJuli Mallett 	const char *to;
9989b50d902SRodney W. Grimes {
999acc9d408SJuli Mallett 	const char *tmp;
1000acc9d408SJuli Mallett 	unsigned char sch, dch;
1001acc9d408SJuli Mallett 	static char frombis[257];
1002acc9d408SJuli Mallett 	static char tobis[257];
1003acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
1004acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
1005acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
1006acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
1007acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
1008acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
1009acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
1010acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
1011acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
1012acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
1013acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
1014acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
1015acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
1016acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
1017acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
1018acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
1019acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
1020acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
1021acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
10229b50d902SRodney W. Grimes 	};
10239b50d902SRodney W. Grimes 
10249b50d902SRodney W. Grimes 	if (*src) {
1025acc9d408SJuli Mallett 		if (mimic_gnu) {
1026acc9d408SJuli Mallett 			/*
1027acc9d408SJuli Mallett 			 * expand character ranges on the fly
1028acc9d408SJuli Mallett 			 */
1029acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
1030acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
1031acc9d408SJuli Mallett 		}
10329b50d902SRodney W. Grimes 		tmp = from;
10339b50d902SRodney W. Grimes 	/*
10349b50d902SRodney W. Grimes 	 * create a mapping between "from" and
10359b50d902SRodney W. Grimes 	 * "to"
10369b50d902SRodney W. Grimes 	 */
10379b50d902SRodney W. Grimes 		while (*from)
1038acc9d408SJuli Mallett 			mapvec[(unsigned char)(*from++)] = (*to) ?
1039acc9d408SJuli Mallett 				(unsigned char)(*to++) : 0;
10409b50d902SRodney W. Grimes 
10419b50d902SRodney W. Grimes 		while (*src) {
1042acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
10439b50d902SRodney W. Grimes 			dch = mapvec[sch];
10449b50d902SRodney W. Grimes 			while (dch != sch) {
10459b50d902SRodney W. Grimes 				sch = dch;
10469b50d902SRodney W. Grimes 				dch = mapvec[sch];
10479b50d902SRodney W. Grimes 			}
1048acc9d408SJuli Mallett 			if ((*dest = (char)dch))
10499b50d902SRodney W. Grimes 				dest++;
10509b50d902SRodney W. Grimes 		}
10519b50d902SRodney W. Grimes 	/*
10529b50d902SRodney W. Grimes 	 * restore all the changed characters
10539b50d902SRodney W. Grimes 	 */
10549b50d902SRodney W. Grimes 		while (*tmp) {
1055acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
10569b50d902SRodney W. Grimes 			tmp++;
10579b50d902SRodney W. Grimes 		}
10589b50d902SRodney W. Grimes 	}
1059acc9d408SJuli Mallett 	*dest = '\0';
10609b50d902SRodney W. Grimes }
1061acc9d408SJuli Mallett 
1062acc9d408SJuli Mallett 
1063acc9d408SJuli Mallett /*
1064acc9d408SJuli Mallett  * handledash:
1065acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
1066acc9d408SJuli Mallett  * on the way.
1067acc9d408SJuli Mallett  */
1068acc9d408SJuli Mallett static const char *
1069acc9d408SJuli Mallett handledash(buffer, end, src)
1070acc9d408SJuli Mallett 	char *buffer;
1071acc9d408SJuli Mallett 	char *end;
1072acc9d408SJuli Mallett 	const char *src;
1073acc9d408SJuli Mallett {
1074acc9d408SJuli Mallett 	char *p;
1075acc9d408SJuli Mallett 
1076acc9d408SJuli Mallett 	p = buffer;
1077acc9d408SJuli Mallett 	while(*src) {
1078acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
1079acc9d408SJuli Mallett 			unsigned char i;
1080acc9d408SJuli Mallett 			for (i = (unsigned char)src[0];
1081acc9d408SJuli Mallett 			    i <= (unsigned char)src[2]; i++) {
1082acc9d408SJuli Mallett 				*p++ = i;
1083acc9d408SJuli Mallett 				if (p == end) {
1084acc9d408SJuli Mallett 					*p = '\0';
1085acc9d408SJuli Mallett 					return buffer;
1086acc9d408SJuli Mallett 				}
1087acc9d408SJuli Mallett 			}
1088acc9d408SJuli Mallett 			src += 3;
1089acc9d408SJuli Mallett 		} else
1090acc9d408SJuli Mallett 			*p++ = *src++;
1091acc9d408SJuli Mallett 		if (p == end)
1092acc9d408SJuli Mallett 			break;
1093acc9d408SJuli Mallett 	}
1094acc9d408SJuli Mallett 	*p = '\0';
1095acc9d408SJuli Mallett 	return buffer;
1096acc9d408SJuli Mallett }
1097acc9d408SJuli Mallett 
1098