xref: /freebsd/usr.bin/m4/eval.c (revision c560b67c5cc5edda2df3f2d887e67fd8275d2f05)
1*c560b67cSBaptiste Daroussin /*	$OpenBSD: eval.c,v 1.75 2017/06/15 13:48:42 bcallah Exp $	*/
2acc9d408SJuli Mallett /*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3acc9d408SJuli Mallett 
48a16b7a1SPedro F. Giffuni /*-
58a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
68a16b7a1SPedro F. Giffuni  *
79b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
89b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
99b50d902SRodney W. Grimes  *
109b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
119b50d902SRodney W. Grimes  * Ozan Yigit at York University.
129b50d902SRodney W. Grimes  *
139b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
149b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
159b50d902SRodney W. Grimes  * are met:
169b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
179b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
189b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
199b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
209b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
21a841e1ebSBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
229b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
239b50d902SRodney W. Grimes  *    without specific prior written permission.
249b50d902SRodney W. Grimes  *
259b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
269b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
279b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
289b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
299b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
309b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
319b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
329b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
339b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
349b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
359b50d902SRodney W. Grimes  * SUCH DAMAGE.
369b50d902SRodney W. Grimes  */
379b50d902SRodney W. Grimes 
38acc9d408SJuli Mallett #include <sys/cdefs.h>
39acc9d408SJuli Mallett __FBSDID("$FreeBSD$");
409b50d902SRodney W. Grimes 
41a841e1ebSBaptiste Daroussin 
429b50d902SRodney W. Grimes /*
439b50d902SRodney W. Grimes  * eval.c
449b50d902SRodney W. Grimes  * Facility: m4 macro processor
459b50d902SRodney W. Grimes  * by: oz
469b50d902SRodney W. Grimes  */
479b50d902SRodney W. Grimes 
489b50d902SRodney W. Grimes #include <sys/types.h>
49a841e1ebSBaptiste Daroussin #include <err.h>
50acc9d408SJuli Mallett #include <errno.h>
51a841e1ebSBaptiste Daroussin #include <limits.h>
52acc9d408SJuli Mallett #include <unistd.h>
539b50d902SRodney W. Grimes #include <stdio.h>
5446ef9581SBaptiste Daroussin #include <stdint.h>
559b50d902SRodney W. Grimes #include <stdlib.h>
56acc9d408SJuli Mallett #include <stddef.h>
579b50d902SRodney W. Grimes #include <string.h>
58acc9d408SJuli Mallett #include <fcntl.h>
599b50d902SRodney W. Grimes #include "mdef.h"
609b50d902SRodney W. Grimes #include "stdd.h"
619b50d902SRodney W. Grimes #include "extern.h"
629b50d902SRodney W. Grimes #include "pathnames.h"
639b50d902SRodney W. Grimes 
64acc9d408SJuli Mallett static void	dodefn(const char *);
65acc9d408SJuli Mallett static void	dopushdef(const char *, const char *);
66acc9d408SJuli Mallett static void	dodump(const char *[], int);
67acc9d408SJuli Mallett static void	dotrace(const char *[], int, int);
68acc9d408SJuli Mallett static void	doifelse(const char *[], int);
69acc9d408SJuli Mallett static int	doincl(const char *);
70acc9d408SJuli Mallett static int	dopaste(const char *);
71acc9d408SJuli Mallett static void	dochq(const char *[], int);
72acc9d408SJuli Mallett static void	dochc(const char *[], int);
73a841e1ebSBaptiste Daroussin static void	dom4wrap(const char *);
74acc9d408SJuli Mallett static void	dodiv(int);
75acc9d408SJuli Mallett static void	doundiv(const char *[], int);
76acc9d408SJuli Mallett static void	dosub(const char *[], int);
77acc9d408SJuli Mallett static void	map(char *, const char *, const char *, const char *);
78acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *);
79acc9d408SJuli Mallett static void	expand_builtin(const char *[], int, int);
80acc9d408SJuli Mallett static void	expand_macro(const char *[], int);
81a841e1ebSBaptiste Daroussin static void	dump_one_def(const char *, struct macro_definition *);
82acc9d408SJuli Mallett 
83acc9d408SJuli Mallett unsigned long	expansion_id;
84acc9d408SJuli Mallett 
859b50d902SRodney W. Grimes /*
86acc9d408SJuli Mallett  * eval - eval all macros and builtins calls
879b50d902SRodney W. Grimes  *	  argc - number of elements in argv.
889b50d902SRodney W. Grimes  *	  argv - element vector :
899b50d902SRodney W. Grimes  *			argv[0] = definition of a user
90a841e1ebSBaptiste Daroussin  *				  macro or NULL if built-in.
919b50d902SRodney W. Grimes  *			argv[1] = name of the macro or
929b50d902SRodney W. Grimes  *				  built-in.
939b50d902SRodney W. Grimes  *			argv[2] = parameters to user-defined
949b50d902SRodney W. Grimes  *			   .	  macro or built-in.
959b50d902SRodney W. Grimes  *			   .
969b50d902SRodney W. Grimes  *
97acc9d408SJuli Mallett  * A call in the form of macro-or-builtin() will result in:
989b50d902SRodney W. Grimes  *			argv[0] = nullstr
999b50d902SRodney W. Grimes  *			argv[1] = macro-or-builtin
1009b50d902SRodney W. Grimes  *			argv[2] = nullstr
101acc9d408SJuli Mallett  *
102acc9d408SJuli Mallett  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1039b50d902SRodney W. Grimes  */
1049b50d902SRodney W. Grimes void
105a841e1ebSBaptiste Daroussin eval(const char *argv[], int argc, int td, int is_traced)
1069b50d902SRodney W. Grimes {
107a841e1ebSBaptiste Daroussin 	size_t mark = SIZE_MAX;
108acc9d408SJuli Mallett 
109acc9d408SJuli Mallett 	expansion_id++;
110acc9d408SJuli Mallett 	if (td & RECDEF)
111a841e1ebSBaptiste Daroussin 		m4errx(1, "expanding recursive definition for %s.", argv[1]);
112a841e1ebSBaptiste Daroussin 	if (is_traced)
113acc9d408SJuli Mallett 		mark = trace(argv, argc, infile+ilevel);
114acc9d408SJuli Mallett 	if (td == MACRTYPE)
115acc9d408SJuli Mallett 		expand_macro(argv, argc);
116acc9d408SJuli Mallett 	else
117acc9d408SJuli Mallett 		expand_builtin(argv, argc, td);
118a841e1ebSBaptiste Daroussin 	if (mark != SIZE_MAX)
119acc9d408SJuli Mallett 		finish_trace(mark);
120acc9d408SJuli Mallett }
121acc9d408SJuli Mallett 
122acc9d408SJuli Mallett /*
123acc9d408SJuli Mallett  * expand_builtin - evaluate built-in macros.
124acc9d408SJuli Mallett  */
125acc9d408SJuli Mallett void
126bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td)
127acc9d408SJuli Mallett {
128acc9d408SJuli Mallett 	int c, n;
129acc9d408SJuli Mallett 	int ac;
1309b50d902SRodney W. Grimes 	static int sysval = 0;
1319b50d902SRodney W. Grimes 
1329b50d902SRodney W. Grimes #ifdef DEBUG
1339b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
1349b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
1359b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
136acc9d408SJuli Mallett 	fflush(stdout);
1379b50d902SRodney W. Grimes #endif
138acc9d408SJuli Mallett 
1399b50d902SRodney W. Grimes  /*
1409b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
1419b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
1429b50d902SRodney W. Grimes   * argc to avoid further checking..
1439b50d902SRodney W. Grimes   */
144a841e1ebSBaptiste Daroussin  /* we keep the initial value for those built-ins that differentiate
145a841e1ebSBaptiste Daroussin   * between builtin() and builtin.
146a841e1ebSBaptiste Daroussin   */
147acc9d408SJuli Mallett 	ac = argc;
148acc9d408SJuli Mallett 
149a841e1ebSBaptiste Daroussin 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
1509b50d902SRodney W. Grimes 		argc--;
1519b50d902SRodney W. Grimes 
152acc9d408SJuli Mallett 	switch (td & TYPEMASK) {
1539b50d902SRodney W. Grimes 
1549b50d902SRodney W. Grimes 	case DEFITYPE:
1559b50d902SRodney W. Grimes 		if (argc > 2)
1569b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1579b50d902SRodney W. Grimes 		break;
1589b50d902SRodney W. Grimes 
1599b50d902SRodney W. Grimes 	case PUSDTYPE:
1609b50d902SRodney W. Grimes 		if (argc > 2)
1619b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1629b50d902SRodney W. Grimes 		break;
1639b50d902SRodney W. Grimes 
1649b50d902SRodney W. Grimes 	case DUMPTYPE:
1659b50d902SRodney W. Grimes 		dodump(argv, argc);
1669b50d902SRodney W. Grimes 		break;
1679b50d902SRodney W. Grimes 
168acc9d408SJuli Mallett 	case TRACEONTYPE:
169acc9d408SJuli Mallett 		dotrace(argv, argc, 1);
170acc9d408SJuli Mallett 		break;
171acc9d408SJuli Mallett 
172acc9d408SJuli Mallett 	case TRACEOFFTYPE:
173acc9d408SJuli Mallett 		dotrace(argv, argc, 0);
174acc9d408SJuli Mallett 		break;
175acc9d408SJuli Mallett 
1769b50d902SRodney W. Grimes 	case EXPRTYPE:
1779b50d902SRodney W. Grimes 	/*
1789b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1799b50d902SRodney W. Grimes 	 * expression
1809b50d902SRodney W. Grimes 	 */
181a841e1ebSBaptiste Daroussin 	{
182a841e1ebSBaptiste Daroussin 		int base = 10;
183a841e1ebSBaptiste Daroussin 		int maxdigits = 0;
184a841e1ebSBaptiste Daroussin 		const char *errstr;
185a841e1ebSBaptiste Daroussin 
186a841e1ebSBaptiste Daroussin 		if (argc > 3) {
187a841e1ebSBaptiste Daroussin 			base = strtonum(argv[3], 2, 36, &errstr);
188a841e1ebSBaptiste Daroussin 			if (errstr) {
189a841e1ebSBaptiste Daroussin 				m4errx(1, "expr: base %s invalid.", argv[3]);
190a841e1ebSBaptiste Daroussin 			}
191a841e1ebSBaptiste Daroussin 		}
192a841e1ebSBaptiste Daroussin 		if (argc > 4) {
193a841e1ebSBaptiste Daroussin 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
194a841e1ebSBaptiste Daroussin 			if (errstr) {
195a841e1ebSBaptiste Daroussin 				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
196a841e1ebSBaptiste Daroussin 			}
197a841e1ebSBaptiste Daroussin 		}
1989b50d902SRodney W. Grimes 		if (argc > 2)
199a841e1ebSBaptiste Daroussin 			pbnumbase(expr(argv[2]), base, maxdigits);
2009b50d902SRodney W. Grimes 		break;
201a841e1ebSBaptiste Daroussin 	}
2029b50d902SRodney W. Grimes 
2039b50d902SRodney W. Grimes 	case IFELTYPE:
2049b50d902SRodney W. Grimes 		if (argc > 4)
2059b50d902SRodney W. Grimes 			doifelse(argv, argc);
2069b50d902SRodney W. Grimes 		break;
2079b50d902SRodney W. Grimes 
2089b50d902SRodney W. Grimes 	case IFDFTYPE:
2099b50d902SRodney W. Grimes 	/*
2109b50d902SRodney W. Grimes 	 * doifdef - select one of two
2119b50d902SRodney W. Grimes 	 * alternatives based on the existence of
2129b50d902SRodney W. Grimes 	 * another definition
2139b50d902SRodney W. Grimes 	 */
2149b50d902SRodney W. Grimes 		if (argc > 3) {
215a841e1ebSBaptiste Daroussin 			if (lookup_macro_definition(argv[2]) != NULL)
2169b50d902SRodney W. Grimes 				pbstr(argv[3]);
2179b50d902SRodney W. Grimes 			else if (argc > 4)
2189b50d902SRodney W. Grimes 				pbstr(argv[4]);
2199b50d902SRodney W. Grimes 		}
2209b50d902SRodney W. Grimes 		break;
2219b50d902SRodney W. Grimes 
2229b50d902SRodney W. Grimes 	case LENGTYPE:
2239b50d902SRodney W. Grimes 	/*
2249b50d902SRodney W. Grimes 	 * dolen - find the length of the
2259b50d902SRodney W. Grimes 	 * argument
2269b50d902SRodney W. Grimes 	 */
2279b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2289b50d902SRodney W. Grimes 		break;
2299b50d902SRodney W. Grimes 
2309b50d902SRodney W. Grimes 	case INCRTYPE:
2319b50d902SRodney W. Grimes 	/*
2329b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2339b50d902SRodney W. Grimes 	 * argument
2349b50d902SRodney W. Grimes 	 */
2359b50d902SRodney W. Grimes 		if (argc > 2)
2369b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) + 1);
2379b50d902SRodney W. Grimes 		break;
2389b50d902SRodney W. Grimes 
2399b50d902SRodney W. Grimes 	case DECRTYPE:
2409b50d902SRodney W. Grimes 	/*
2419b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2429b50d902SRodney W. Grimes 	 * argument
2439b50d902SRodney W. Grimes 	 */
2449b50d902SRodney W. Grimes 		if (argc > 2)
2459b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) - 1);
2469b50d902SRodney W. Grimes 		break;
2479b50d902SRodney W. Grimes 
2489b50d902SRodney W. Grimes 	case SYSCTYPE:
2499b50d902SRodney W. Grimes 	/*
2509b50d902SRodney W. Grimes 	 * dosys - execute system command
2519b50d902SRodney W. Grimes 	 */
252aef4bb33STim J. Robbins 		if (argc > 2) {
253a841e1ebSBaptiste Daroussin 			fflush(stdout);
2549b50d902SRodney W. Grimes 			sysval = system(argv[2]);
255aef4bb33STim J. Robbins 		}
2569b50d902SRodney W. Grimes 		break;
2579b50d902SRodney W. Grimes 
2589b50d902SRodney W. Grimes 	case SYSVTYPE:
2599b50d902SRodney W. Grimes 	/*
2609b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2619b50d902SRodney W. Grimes 	 * system call.
2629b50d902SRodney W. Grimes 	 *
2639b50d902SRodney W. Grimes 	 */
2649b50d902SRodney W. Grimes 		pbnum(sysval);
2659b50d902SRodney W. Grimes 		break;
2669b50d902SRodney W. Grimes 
267acc9d408SJuli Mallett 	case ESYSCMDTYPE:
268acc9d408SJuli Mallett 		if (argc > 2)
269acc9d408SJuli Mallett 			doesyscmd(argv[2]);
270acc9d408SJuli Mallett 		break;
2719b50d902SRodney W. Grimes 	case INCLTYPE:
27288497f0cSBaptiste Daroussin 		if (argc > 2) {
2732cce1b69SBjoern A. Zeeb 			if (!doincl(argv[2])) {
274fb3f3d7cSBaptiste Daroussin 				if (mimic_gnu) {
2754fff7a14SBaptiste Daroussin 					warn("%s at line %lu: include(%s)",
2764fff7a14SBaptiste Daroussin 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
277fb3f3d7cSBaptiste Daroussin 					exit_code = 1;
278*c560b67cSBaptiste Daroussin 					if (fatal_warns) {
279*c560b67cSBaptiste Daroussin 						killdiv();
280*c560b67cSBaptiste Daroussin 						exit(exit_code);
281*c560b67cSBaptiste Daroussin 					}
282fb3f3d7cSBaptiste Daroussin 				} else
283acc9d408SJuli Mallett 					err(1, "%s at line %lu: include(%s)",
284acc9d408SJuli Mallett 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2852cce1b69SBjoern A. Zeeb 			}
28688497f0cSBaptiste Daroussin 		}
2879b50d902SRodney W. Grimes 		break;
2889b50d902SRodney W. Grimes 
2899b50d902SRodney W. Grimes 	case SINCTYPE:
2909b50d902SRodney W. Grimes 		if (argc > 2)
2919b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
2929b50d902SRodney W. Grimes 		break;
2939b50d902SRodney W. Grimes #ifdef EXTENDED
2949b50d902SRodney W. Grimes 	case PASTTYPE:
2959b50d902SRodney W. Grimes 		if (argc > 2)
2969b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
297acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
298acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2999b50d902SRodney W. Grimes 		break;
3009b50d902SRodney W. Grimes 
3019b50d902SRodney W. Grimes 	case SPASTYPE:
3029b50d902SRodney W. Grimes 		if (argc > 2)
3039b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
3049b50d902SRodney W. Grimes 		break;
305a841e1ebSBaptiste Daroussin 	case FORMATTYPE:
306a841e1ebSBaptiste Daroussin 		doformat(argv, argc);
307a841e1ebSBaptiste Daroussin 		break;
3089b50d902SRodney W. Grimes #endif
3099b50d902SRodney W. Grimes 	case CHNQTYPE:
310a841e1ebSBaptiste Daroussin 		dochq(argv, ac);
3119b50d902SRodney W. Grimes 		break;
3129b50d902SRodney W. Grimes 
3139b50d902SRodney W. Grimes 	case CHNCTYPE:
3149b50d902SRodney W. Grimes 		dochc(argv, argc);
3159b50d902SRodney W. Grimes 		break;
3169b50d902SRodney W. Grimes 
3179b50d902SRodney W. Grimes 	case SUBSTYPE:
3189b50d902SRodney W. Grimes 	/*
3199b50d902SRodney W. Grimes 	 * dosub - select substring
3209b50d902SRodney W. Grimes 	 *
3219b50d902SRodney W. Grimes 	 */
3229b50d902SRodney W. Grimes 		if (argc > 3)
3239b50d902SRodney W. Grimes 			dosub(argv, argc);
3249b50d902SRodney W. Grimes 		break;
3259b50d902SRodney W. Grimes 
3269b50d902SRodney W. Grimes 	case SHIFTYPE:
3279b50d902SRodney W. Grimes 	/*
3289b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3299b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3309b50d902SRodney W. Grimes 	 * argv[2])
3319b50d902SRodney W. Grimes 	 */
3329b50d902SRodney W. Grimes 		if (argc > 3) {
3339b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
334acc9d408SJuli Mallett 				pbstr(rquote);
3359b50d902SRodney W. Grimes 				pbstr(argv[n]);
336acc9d408SJuli Mallett 				pbstr(lquote);
337a841e1ebSBaptiste Daroussin 				pushback(COMMA);
3389b50d902SRodney W. Grimes 			}
339acc9d408SJuli Mallett 			pbstr(rquote);
3409b50d902SRodney W. Grimes 			pbstr(argv[3]);
341acc9d408SJuli Mallett 			pbstr(lquote);
3429b50d902SRodney W. Grimes 		}
3439b50d902SRodney W. Grimes 		break;
3449b50d902SRodney W. Grimes 
3459b50d902SRodney W. Grimes 	case DIVRTYPE:
3469b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
3479b50d902SRodney W. Grimes 			dodiv(n);
3489b50d902SRodney W. Grimes 		else {
3499b50d902SRodney W. Grimes 			active = stdout;
3509b50d902SRodney W. Grimes 			oindex = 0;
3519b50d902SRodney W. Grimes 		}
3529b50d902SRodney W. Grimes 		break;
3539b50d902SRodney W. Grimes 
3549b50d902SRodney W. Grimes 	case UNDVTYPE:
3559b50d902SRodney W. Grimes 		doundiv(argv, argc);
3569b50d902SRodney W. Grimes 		break;
3579b50d902SRodney W. Grimes 
3589b50d902SRodney W. Grimes 	case DIVNTYPE:
3599b50d902SRodney W. Grimes 	/*
3609b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3619b50d902SRodney W. Grimes 	 * current output diversion
3629b50d902SRodney W. Grimes 	 */
3639b50d902SRodney W. Grimes 		pbnum(oindex);
3649b50d902SRodney W. Grimes 		break;
3659b50d902SRodney W. Grimes 
3669b50d902SRodney W. Grimes 	case UNDFTYPE:
3679b50d902SRodney W. Grimes 	/*
3689b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3699b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3709b50d902SRodney W. Grimes 	 */
3719b50d902SRodney W. Grimes 		if (argc > 2)
3729b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
373a841e1ebSBaptiste Daroussin 				macro_undefine(argv[n]);
3749b50d902SRodney W. Grimes 		break;
3759b50d902SRodney W. Grimes 
3769b50d902SRodney W. Grimes 	case POPDTYPE:
3779b50d902SRodney W. Grimes 	/*
3789b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3799b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3809b50d902SRodney W. Grimes 	 * keyword(s).
3819b50d902SRodney W. Grimes 	 */
3829b50d902SRodney W. Grimes 		if (argc > 2)
3839b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
384a841e1ebSBaptiste Daroussin 				macro_popdef(argv[n]);
3859b50d902SRodney W. Grimes 		break;
3869b50d902SRodney W. Grimes 
3879b50d902SRodney W. Grimes 	case MKTMTYPE:
3889b50d902SRodney W. Grimes 	/*
3899b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
3909b50d902SRodney W. Grimes 	 */
391acc9d408SJuli Mallett 		if (argc > 2) {
392acc9d408SJuli Mallett 			int fd;
393acc9d408SJuli Mallett 			char *temp;
394acc9d408SJuli Mallett 
395acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
396acc9d408SJuli Mallett 
397acc9d408SJuli Mallett 			fd = mkstemp(temp);
398acc9d408SJuli Mallett 			if (fd == -1)
399acc9d408SJuli Mallett 				err(1,
400acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
401acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
402acc9d408SJuli Mallett 			close(fd);
403acc9d408SJuli Mallett 			pbstr(temp);
404acc9d408SJuli Mallett 			free(temp);
405acc9d408SJuli Mallett 		}
4069b50d902SRodney W. Grimes 		break;
4079b50d902SRodney W. Grimes 
4089b50d902SRodney W. Grimes 	case TRNLTYPE:
4099b50d902SRodney W. Grimes 	/*
4109b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
4119b50d902SRodney W. Grimes 	 * the source string that appears in the
4129b50d902SRodney W. Grimes 	 * "from" string with the corresponding
4139b50d902SRodney W. Grimes 	 * characters in the "to" string.
4149b50d902SRodney W. Grimes 	 */
4159b50d902SRodney W. Grimes 		if (argc > 3) {
416acc9d408SJuli Mallett 			char *temp;
417acc9d408SJuli Mallett 
418a841e1ebSBaptiste Daroussin 			temp = xalloc(strlen(argv[2])+1, NULL);
4199b50d902SRodney W. Grimes 			if (argc > 4)
4209b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
4219b50d902SRodney W. Grimes 			else
4229b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
4239b50d902SRodney W. Grimes 			pbstr(temp);
424acc9d408SJuli Mallett 			free(temp);
425acc9d408SJuli Mallett 		} else if (argc > 2)
4269b50d902SRodney W. Grimes 			pbstr(argv[2]);
4279b50d902SRodney W. Grimes 		break;
4289b50d902SRodney W. Grimes 
4299b50d902SRodney W. Grimes 	case INDXTYPE:
4309b50d902SRodney W. Grimes 	/*
4319b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4329b50d902SRodney W. Grimes 	 * argument string in the first argument
4339b50d902SRodney W. Grimes 	 * string. -1 if not present.
4349b50d902SRodney W. Grimes 	 */
4359b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4369b50d902SRodney W. Grimes 		break;
4379b50d902SRodney W. Grimes 
4389b50d902SRodney W. Grimes 	case ERRPTYPE:
4399b50d902SRodney W. Grimes 	/*
4409b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4419b50d902SRodney W. Grimes 	 * file
4429b50d902SRodney W. Grimes 	 */
4439b50d902SRodney W. Grimes 		if (argc > 2) {
4449b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4459b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4469b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4479b50d902SRodney W. Grimes 		}
4489b50d902SRodney W. Grimes 		break;
4499b50d902SRodney W. Grimes 
4509b50d902SRodney W. Grimes 	case DNLNTYPE:
4519b50d902SRodney W. Grimes 	/*
4529b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4539b50d902SRodney W. Grimes 	 * newline
4549b50d902SRodney W. Grimes 	 */
4559b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4569b50d902SRodney W. Grimes 			;
4579b50d902SRodney W. Grimes 		break;
4589b50d902SRodney W. Grimes 
4599b50d902SRodney W. Grimes 	case M4WRTYPE:
4609b50d902SRodney W. Grimes 	/*
4619b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4629b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4639b50d902SRodney W. Grimes 	 */
464a841e1ebSBaptiste Daroussin 		if (argc > 2)
465a841e1ebSBaptiste Daroussin 			dom4wrap(argv[2]);
4669b50d902SRodney W. Grimes 		break;
4679b50d902SRodney W. Grimes 
4689b50d902SRodney W. Grimes 	case EXITTYPE:
4699b50d902SRodney W. Grimes 	/*
4709b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4719b50d902SRodney W. Grimes 	 */
472cac6992aSAndrey A. Chernov 		killdiv();
4739b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4749b50d902SRodney W. Grimes 		break;
4759b50d902SRodney W. Grimes 
4769b50d902SRodney W. Grimes 	case DEFNTYPE:
4779b50d902SRodney W. Grimes 		if (argc > 2)
4789b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4799b50d902SRodney W. Grimes 				dodefn(argv[n]);
4809b50d902SRodney W. Grimes 		break;
4819b50d902SRodney W. Grimes 
482acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
483acc9d408SJuli Mallett 		if (argc > 2)
484acc9d408SJuli Mallett 			doindir(argv, argc);
485bbfd1447SSteve Price 		break;
486bbfd1447SSteve Price 
487acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
488acc9d408SJuli Mallett 		if (argc > 2)
489acc9d408SJuli Mallett 			dobuiltin(argv, argc);
490acc9d408SJuli Mallett 		break;
491acc9d408SJuli Mallett 
492acc9d408SJuli Mallett 	case PATSTYPE:
493acc9d408SJuli Mallett 		if (argc > 2)
494acc9d408SJuli Mallett 			dopatsubst(argv, argc);
495acc9d408SJuli Mallett 		break;
496acc9d408SJuli Mallett 	case REGEXPTYPE:
497acc9d408SJuli Mallett 		if (argc > 2)
498acc9d408SJuli Mallett 			doregexp(argv, argc);
499acc9d408SJuli Mallett 		break;
500acc9d408SJuli Mallett 	case LINETYPE:
501acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
502acc9d408SJuli Mallett 		break;
503acc9d408SJuli Mallett 	case FILENAMETYPE:
504acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
505acc9d408SJuli Mallett 		break;
506acc9d408SJuli Mallett 	case SELFTYPE:
507acc9d408SJuli Mallett 		pbstr(rquote);
508acc9d408SJuli Mallett 		pbstr(argv[1]);
509acc9d408SJuli Mallett 		pbstr(lquote);
510acc9d408SJuli Mallett 		break;
5119b50d902SRodney W. Grimes 	default:
512a841e1ebSBaptiste Daroussin 		m4errx(1, "eval: major botch.");
5139b50d902SRodney W. Grimes 		break;
5149b50d902SRodney W. Grimes 	}
5159b50d902SRodney W. Grimes }
5169b50d902SRodney W. Grimes 
5179b50d902SRodney W. Grimes /*
518acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
5199b50d902SRodney W. Grimes  */
5209b50d902SRodney W. Grimes void
521bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc)
5229b50d902SRodney W. Grimes {
523acc9d408SJuli Mallett 	const char *t;
524acc9d408SJuli Mallett 	const char *p;
525acc9d408SJuli Mallett 	int n;
526acc9d408SJuli Mallett 	int argno;
5279b50d902SRodney W. Grimes 
5289b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5299b50d902SRodney W. Grimes 	p = t;
5309b50d902SRodney W. Grimes 	while (*p)
5319b50d902SRodney W. Grimes 		p++;
5329b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5339b50d902SRodney W. Grimes 	while (p > t) {
5349b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
535a841e1ebSBaptiste Daroussin 			PUSHBACK(*p);
5369b50d902SRodney W. Grimes 		else {
5379b50d902SRodney W. Grimes 			switch (*p) {
5389b50d902SRodney W. Grimes 
5399b50d902SRodney W. Grimes 			case '#':
5409b50d902SRodney W. Grimes 				pbnum(argc - 2);
5419b50d902SRodney W. Grimes 				break;
5429b50d902SRodney W. Grimes 			case '0':
5439b50d902SRodney W. Grimes 			case '1':
5449b50d902SRodney W. Grimes 			case '2':
5459b50d902SRodney W. Grimes 			case '3':
5469b50d902SRodney W. Grimes 			case '4':
5479b50d902SRodney W. Grimes 			case '5':
5489b50d902SRodney W. Grimes 			case '6':
5499b50d902SRodney W. Grimes 			case '7':
5509b50d902SRodney W. Grimes 			case '8':
5519b50d902SRodney W. Grimes 			case '9':
5529b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5539b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5549b50d902SRodney W. Grimes 				break;
5559b50d902SRodney W. Grimes 			case '*':
556acc9d408SJuli Mallett 				if (argc > 2) {
5579b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5589b50d902SRodney W. Grimes 						pbstr(argv[n]);
559a841e1ebSBaptiste Daroussin 						pushback(COMMA);
5609b50d902SRodney W. Grimes 					}
5619b50d902SRodney W. Grimes 					pbstr(argv[2]);
562acc9d408SJuli Mallett 				}
5639b50d902SRodney W. Grimes 				break;
564232eaee6SJoerg Wunsch                         case '@':
565acc9d408SJuli Mallett 				if (argc > 2) {
566acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
567acc9d408SJuli Mallett 						pbstr(rquote);
568232eaee6SJoerg Wunsch 						pbstr(argv[n]);
569acc9d408SJuli Mallett 						pbstr(lquote);
570a841e1ebSBaptiste Daroussin 						pushback(COMMA);
571acc9d408SJuli Mallett 					}
572acc9d408SJuli Mallett 					pbstr(rquote);
573acc9d408SJuli Mallett 					pbstr(argv[2]);
574acc9d408SJuli Mallett 					pbstr(lquote);
575232eaee6SJoerg Wunsch 				}
576232eaee6SJoerg Wunsch                                 break;
5779b50d902SRodney W. Grimes 			default:
578a841e1ebSBaptiste Daroussin 				PUSHBACK(*p);
579a841e1ebSBaptiste Daroussin 				PUSHBACK('$');
5809b50d902SRodney W. Grimes 				break;
5819b50d902SRodney W. Grimes 			}
5829b50d902SRodney W. Grimes 			p--;
5839b50d902SRodney W. Grimes 		}
5849b50d902SRodney W. Grimes 		p--;
5859b50d902SRodney W. Grimes 	}
5869b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
587a841e1ebSBaptiste Daroussin 		PUSHBACK(*p);
5889b50d902SRodney W. Grimes }
5899b50d902SRodney W. Grimes 
590a841e1ebSBaptiste Daroussin 
5919b50d902SRodney W. Grimes /*
5929b50d902SRodney W. Grimes  * dodefine - install definition in the table
5939b50d902SRodney W. Grimes  */
5949b50d902SRodney W. Grimes void
595bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn)
5969b50d902SRodney W. Grimes {
597a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
598a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
5999b50d902SRodney W. Grimes 	else
600a841e1ebSBaptiste Daroussin 		macro_define(name, defn);
6019b50d902SRodney W. Grimes }
6029b50d902SRodney W. Grimes 
6039b50d902SRodney W. Grimes /*
6049b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
6059b50d902SRodney W. Grimes  *      the given name.
6069b50d902SRodney W. Grimes  */
607acc9d408SJuli Mallett static void
608bd2bfb58SJuli Mallett dodefn(const char *name)
6099b50d902SRodney W. Grimes {
610a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6119b50d902SRodney W. Grimes 
612a841e1ebSBaptiste Daroussin 	if ((p = lookup_macro_definition(name)) != NULL) {
613a841e1ebSBaptiste Daroussin 		if ((p->type & TYPEMASK) == MACRTYPE) {
614acc9d408SJuli Mallett 			pbstr(rquote);
6159b50d902SRodney W. Grimes 			pbstr(p->defn);
616acc9d408SJuli Mallett 			pbstr(lquote);
617a841e1ebSBaptiste Daroussin 		} else {
618a841e1ebSBaptiste Daroussin 			pbstr(p->defn);
619acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
620acc9d408SJuli Mallett 		}
6219b50d902SRodney W. Grimes 	}
6229b50d902SRodney W. Grimes }
6239b50d902SRodney W. Grimes 
6249b50d902SRodney W. Grimes /*
6259b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6269b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6279b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6289b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6299b50d902SRodney W. Grimes  *      lookup.
6309b50d902SRodney W. Grimes  */
631acc9d408SJuli Mallett static void
632bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn)
6339b50d902SRodney W. Grimes {
634a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
635a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6369b50d902SRodney W. Grimes 	else
637a841e1ebSBaptiste Daroussin 		macro_pushdef(name, defn);
638acc9d408SJuli Mallett }
639acc9d408SJuli Mallett 
640acc9d408SJuli Mallett /*
641acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
642acc9d408SJuli Mallett  */
643acc9d408SJuli Mallett static void
644a841e1ebSBaptiste Daroussin dump_one_def(const char *name, struct macro_definition *p)
645acc9d408SJuli Mallett {
646a841e1ebSBaptiste Daroussin 	if (!traceout)
647a841e1ebSBaptiste Daroussin 		traceout = stderr;
648acc9d408SJuli Mallett 	if (mimic_gnu) {
649acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
650a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
651acc9d408SJuli Mallett 		else {
652a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
653acc9d408SJuli Mallett 		}
654acc9d408SJuli Mallett 	} else
655a841e1ebSBaptiste Daroussin 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
6569b50d902SRodney W. Grimes }
6579b50d902SRodney W. Grimes 
6589b50d902SRodney W. Grimes /*
6599b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6609b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6619b50d902SRodney W. Grimes  *      hash table is dumped.
6629b50d902SRodney W. Grimes  */
663acc9d408SJuli Mallett static void
664bd2bfb58SJuli Mallett dodump(const char *argv[], int argc)
6659b50d902SRodney W. Grimes {
666acc9d408SJuli Mallett 	int n;
667a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6689b50d902SRodney W. Grimes 
6699b50d902SRodney W. Grimes 	if (argc > 2) {
6709b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
671a841e1ebSBaptiste Daroussin 			if ((p = lookup_macro_definition(argv[n])) != NULL)
672a841e1ebSBaptiste Daroussin 				dump_one_def(argv[n], p);
673a841e1ebSBaptiste Daroussin 	} else
674a841e1ebSBaptiste Daroussin 		macro_for_all(dump_one_def);
6759b50d902SRodney W. Grimes }
6769b50d902SRodney W. Grimes 
6779b50d902SRodney W. Grimes /*
678acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
679acc9d408SJuli Mallett  */
680acc9d408SJuli Mallett static void
681bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on)
682acc9d408SJuli Mallett {
683acc9d408SJuli Mallett 	int n;
684acc9d408SJuli Mallett 
685acc9d408SJuli Mallett 	if (argc > 2) {
686acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
687acc9d408SJuli Mallett 			mark_traced(argv[n], on);
688acc9d408SJuli Mallett 	} else
689acc9d408SJuli Mallett 		mark_traced(NULL, on);
690acc9d408SJuli Mallett }
691acc9d408SJuli Mallett 
692acc9d408SJuli Mallett /*
6939b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
6949b50d902SRodney W. Grimes  */
695acc9d408SJuli Mallett static void
696bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc)
6979b50d902SRodney W. Grimes {
6989b50d902SRodney W. Grimes 	cycle {
6999b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
7009b50d902SRodney W. Grimes 			pbstr(argv[4]);
7019b50d902SRodney W. Grimes 		else if (argc == 6)
7029b50d902SRodney W. Grimes 			pbstr(argv[5]);
7039b50d902SRodney W. Grimes 		else if (argc > 6) {
7049b50d902SRodney W. Grimes 			argv += 3;
7059b50d902SRodney W. Grimes 			argc -= 3;
7069b50d902SRodney W. Grimes 			continue;
7079b50d902SRodney W. Grimes 		}
7089b50d902SRodney W. Grimes 		break;
7099b50d902SRodney W. Grimes 	}
7109b50d902SRodney W. Grimes }
7119b50d902SRodney W. Grimes 
7129b50d902SRodney W. Grimes /*
7139b50d902SRodney W. Grimes  * doinclude - include a given file.
7149b50d902SRodney W. Grimes  */
715acc9d408SJuli Mallett static int
716bd2bfb58SJuli Mallett doincl(const char *ifile)
7179b50d902SRodney W. Grimes {
7189b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
719a841e1ebSBaptiste Daroussin 		m4errx(1, "too many include files.");
720acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7219b50d902SRodney W. Grimes 		ilevel++;
7229b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
7239b50d902SRodney W. Grimes 		return (1);
724acc9d408SJuli Mallett 	} else
7259b50d902SRodney W. Grimes 		return (0);
7269b50d902SRodney W. Grimes }
7279b50d902SRodney W. Grimes 
7289b50d902SRodney W. Grimes #ifdef EXTENDED
7299b50d902SRodney W. Grimes /*
7309b50d902SRodney W. Grimes  * dopaste - include a given file without any
7319b50d902SRodney W. Grimes  *           macro processing.
7329b50d902SRodney W. Grimes  */
733acc9d408SJuli Mallett static int
734bd2bfb58SJuli Mallett dopaste(const char *pfile)
7359b50d902SRodney W. Grimes {
7369b50d902SRodney W. Grimes 	FILE *pf;
737acc9d408SJuli Mallett 	int c;
7389b50d902SRodney W. Grimes 
7399b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
740a841e1ebSBaptiste Daroussin 		if (synch_lines)
741b1ea3d46SJuli Mallett 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
7429b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7439b50d902SRodney W. Grimes 			putc(c, active);
7449b50d902SRodney W. Grimes 		(void) fclose(pf);
745a841e1ebSBaptiste Daroussin 		emit_synchline();
7469b50d902SRodney W. Grimes 		return (1);
747acc9d408SJuli Mallett 	} else
7489b50d902SRodney W. Grimes 		return (0);
7499b50d902SRodney W. Grimes }
7509b50d902SRodney W. Grimes #endif
7519b50d902SRodney W. Grimes 
7529b50d902SRodney W. Grimes /*
753acc9d408SJuli Mallett  * dochq - change quote characters
7549b50d902SRodney W. Grimes  */
755acc9d408SJuli Mallett static void
756a841e1ebSBaptiste Daroussin dochq(const char *argv[], int ac)
7579b50d902SRodney W. Grimes {
758a841e1ebSBaptiste Daroussin 	if (ac == 2) {
759a841e1ebSBaptiste Daroussin 		lquote[0] = LQUOTE; lquote[1] = EOS;
760a841e1ebSBaptiste Daroussin 		rquote[0] = RQUOTE; rquote[1] = EOS;
761acc9d408SJuli Mallett 	} else {
762a841e1ebSBaptiste Daroussin 		strlcpy(lquote, argv[2], sizeof(lquote));
763a841e1ebSBaptiste Daroussin 		if (ac > 3) {
764a841e1ebSBaptiste Daroussin 			strlcpy(rquote, argv[3], sizeof(rquote));
765a841e1ebSBaptiste Daroussin 		} else {
766a841e1ebSBaptiste Daroussin 			rquote[0] = ECOMMT; rquote[1] = EOS;
767a841e1ebSBaptiste Daroussin 		}
768acc9d408SJuli Mallett 	}
769acc9d408SJuli Mallett }
770acc9d408SJuli Mallett 
771acc9d408SJuli Mallett /*
772acc9d408SJuli Mallett  * dochc - change comment characters
773acc9d408SJuli Mallett  */
774acc9d408SJuli Mallett static void
775bd2bfb58SJuli Mallett dochc(const char *argv[], int argc)
776acc9d408SJuli Mallett {
777a841e1ebSBaptiste Daroussin /* XXX Note that there is no difference between no argument and a single
778a841e1ebSBaptiste Daroussin  * empty argument.
779a841e1ebSBaptiste Daroussin  */
780a841e1ebSBaptiste Daroussin 	if (argc == 2) {
781a841e1ebSBaptiste Daroussin 		scommt[0] = EOS;
782a841e1ebSBaptiste Daroussin 		ecommt[0] = EOS;
783a841e1ebSBaptiste Daroussin 	} else {
784acc9d408SJuli Mallett 		strlcpy(scommt, argv[2], sizeof(scommt));
785a841e1ebSBaptiste Daroussin 		if (argc == 3) {
786a841e1ebSBaptiste Daroussin 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
787a841e1ebSBaptiste Daroussin 		} else {
788acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
7899b50d902SRodney W. Grimes 		}
790a841e1ebSBaptiste Daroussin 	}
791a841e1ebSBaptiste Daroussin }
792a841e1ebSBaptiste Daroussin 
793a841e1ebSBaptiste Daroussin /*
794a841e1ebSBaptiste Daroussin  * dom4wrap - expand text at EOF
795a841e1ebSBaptiste Daroussin  */
796a841e1ebSBaptiste Daroussin static void
797a841e1ebSBaptiste Daroussin dom4wrap(const char *text)
798a841e1ebSBaptiste Daroussin {
799a841e1ebSBaptiste Daroussin 	if (wrapindex >= maxwraps) {
800a841e1ebSBaptiste Daroussin 		if (maxwraps == 0)
801a841e1ebSBaptiste Daroussin 			maxwraps = 16;
8029b50d902SRodney W. Grimes 		else
803a841e1ebSBaptiste Daroussin 			maxwraps *= 2;
80488497f0cSBaptiste Daroussin 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
805a841e1ebSBaptiste Daroussin 		   "too many m4wraps");
8069b50d902SRodney W. Grimes 	}
807a841e1ebSBaptiste Daroussin 	m4wraps[wrapindex++] = xstrdup(text);
8089b50d902SRodney W. Grimes }
8099b50d902SRodney W. Grimes 
8109b50d902SRodney W. Grimes /*
8119b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8129b50d902SRodney W. Grimes  */
813acc9d408SJuli Mallett static void
814bd2bfb58SJuli Mallett dodiv(int n)
8159b50d902SRodney W. Grimes {
816acc9d408SJuli Mallett 	int fd;
817acc9d408SJuli Mallett 
818ef2cea81SJonathan Lemon 	oindex = n;
819acc9d408SJuli Mallett 	if (n >= maxout) {
820acc9d408SJuli Mallett 		if (mimic_gnu)
821acc9d408SJuli Mallett 			resizedivs(n + 10);
822acc9d408SJuli Mallett 		else
823acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
824acc9d408SJuli Mallett 	}
825acc9d408SJuli Mallett 
826acc9d408SJuli Mallett 	if (n < 0)
8279b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
8289b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
829acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
830acc9d408SJuli Mallett 
831acc9d408SJuli Mallett 		if ((fd = mkstemp(fname)) < 0 ||
83288497f0cSBaptiste Daroussin 		    unlink(fname) == -1 ||
833acc9d408SJuli Mallett 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
834acc9d408SJuli Mallett 			err(1, "%s: cannot divert", fname);
8359b50d902SRodney W. Grimes 	}
8369b50d902SRodney W. Grimes 	active = outfile[n];
8379b50d902SRodney W. Grimes }
8389b50d902SRodney W. Grimes 
8399b50d902SRodney W. Grimes /*
8409b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
8419b50d902SRodney W. Grimes  *              other outputs, in numerical order.
8429b50d902SRodney W. Grimes  */
843acc9d408SJuli Mallett static void
844bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc)
8459b50d902SRodney W. Grimes {
846acc9d408SJuli Mallett 	int ind;
847acc9d408SJuli Mallett 	int n;
8489b50d902SRodney W. Grimes 
8499b50d902SRodney W. Grimes 	if (argc > 2) {
8509b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
851a841e1ebSBaptiste Daroussin 			const char *errstr;
852a841e1ebSBaptiste Daroussin 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
853a841e1ebSBaptiste Daroussin 			if (errstr) {
854a841e1ebSBaptiste Daroussin 				if (errno == EINVAL && mimic_gnu)
855a841e1ebSBaptiste Daroussin 					getdivfile(argv[ind]);
856a841e1ebSBaptiste Daroussin 			} else {
857a841e1ebSBaptiste Daroussin 				if (n < maxout && outfile[n] != NULL)
8589b50d902SRodney W. Grimes 					getdiv(n);
859a841e1ebSBaptiste Daroussin 			}
8609b50d902SRodney W. Grimes 		}
8619b50d902SRodney W. Grimes 	}
8629b50d902SRodney W. Grimes 	else
863acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
8649b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
8659b50d902SRodney W. Grimes 				getdiv(n);
8669b50d902SRodney W. Grimes }
8679b50d902SRodney W. Grimes 
8689b50d902SRodney W. Grimes /*
8699b50d902SRodney W. Grimes  * dosub - select substring
8709b50d902SRodney W. Grimes  */
871acc9d408SJuli Mallett static void
872bd2bfb58SJuli Mallett dosub(const char *argv[], int argc)
8739b50d902SRodney W. Grimes {
874acc9d408SJuli Mallett 	const char *ap, *fc, *k;
875acc9d408SJuli Mallett 	int nc;
8769b50d902SRodney W. Grimes 
8779b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
8789b50d902SRodney W. Grimes #ifdef EXPR
8799b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
8809b50d902SRodney W. Grimes #else
8819b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
8829b50d902SRodney W. Grimes #endif
8834ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
884acc9d408SJuli Mallett 	if (argc >= 5)
8854ba4d387SGregory Neil Shapiro #ifdef EXPR
886acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
8874ba4d387SGregory Neil Shapiro #else
888acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
8894ba4d387SGregory Neil Shapiro #endif
8909b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
8914ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
892a841e1ebSBaptiste Daroussin 			pushback(*k);
8939b50d902SRodney W. Grimes }
8949b50d902SRodney W. Grimes 
8959b50d902SRodney W. Grimes /*
8969b50d902SRodney W. Grimes  * map:
8979b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
8989b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
8999b50d902SRodney W. Grimes  *
900a841e1ebSBaptiste Daroussin  * This is derived from the a standard implementation of map(s,from,to)
901a841e1ebSBaptiste Daroussin  * function of ICON language. Within mapvec, we replace every character
902a841e1ebSBaptiste Daroussin  * of "from" with the corresponding character in "to".
903a841e1ebSBaptiste Daroussin  * If "to" is shorter than "from", than the corresponding entries are null,
904af7ca7c8SPedro F. Giffuni  * which means that those characters disappear altogether.
9059b50d902SRodney W. Grimes  */
906acc9d408SJuli Mallett static void
907bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to)
9089b50d902SRodney W. Grimes {
909acc9d408SJuli Mallett 	const char *tmp;
910acc9d408SJuli Mallett 	unsigned char sch, dch;
911acc9d408SJuli Mallett 	static char frombis[257];
912acc9d408SJuli Mallett 	static char tobis[257];
913a841e1ebSBaptiste Daroussin 	int i;
914a841e1ebSBaptiste Daroussin 	char seen[256];
915acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
916acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
917acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
918acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
919acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
920acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
921acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
922acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
923acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
924acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
925acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
926acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
927acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
928acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
929acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
930acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
931acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
932acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
933acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9349b50d902SRodney W. Grimes 	};
9359b50d902SRodney W. Grimes 
9369b50d902SRodney W. Grimes 	if (*src) {
937acc9d408SJuli Mallett 		if (mimic_gnu) {
938acc9d408SJuli Mallett 			/*
939acc9d408SJuli Mallett 			 * expand character ranges on the fly
940acc9d408SJuli Mallett 			 */
941acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
942acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
943acc9d408SJuli Mallett 		}
9449b50d902SRodney W. Grimes 		tmp = from;
9459b50d902SRodney W. Grimes 	/*
9469b50d902SRodney W. Grimes 	 * create a mapping between "from" and
9479b50d902SRodney W. Grimes 	 * "to"
9489b50d902SRodney W. Grimes 	 */
949a841e1ebSBaptiste Daroussin 		for (i = 0; i < 256; i++)
950a841e1ebSBaptiste Daroussin 			seen[i] = 0;
951a841e1ebSBaptiste Daroussin 		while (*from) {
952a841e1ebSBaptiste Daroussin 			if (!seen[(unsigned char)(*from)]) {
953a841e1ebSBaptiste Daroussin 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
954a841e1ebSBaptiste Daroussin 				seen[(unsigned char)(*from)] = 1;
955a841e1ebSBaptiste Daroussin 			}
956a841e1ebSBaptiste Daroussin 			from++;
957a841e1ebSBaptiste Daroussin 			if (*to)
958a841e1ebSBaptiste Daroussin 				to++;
959a841e1ebSBaptiste Daroussin 		}
9609b50d902SRodney W. Grimes 
9619b50d902SRodney W. Grimes 		while (*src) {
962acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
9639b50d902SRodney W. Grimes 			dch = mapvec[sch];
964acc9d408SJuli Mallett 			if ((*dest = (char)dch))
9659b50d902SRodney W. Grimes 				dest++;
9669b50d902SRodney W. Grimes 		}
9679b50d902SRodney W. Grimes 	/*
9689b50d902SRodney W. Grimes 	 * restore all the changed characters
9699b50d902SRodney W. Grimes 	 */
9709b50d902SRodney W. Grimes 		while (*tmp) {
971acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9729b50d902SRodney W. Grimes 			tmp++;
9739b50d902SRodney W. Grimes 		}
9749b50d902SRodney W. Grimes 	}
975acc9d408SJuli Mallett 	*dest = '\0';
9769b50d902SRodney W. Grimes }
977acc9d408SJuli Mallett 
978acc9d408SJuli Mallett 
979acc9d408SJuli Mallett /*
980acc9d408SJuli Mallett  * handledash:
981acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
982acc9d408SJuli Mallett  * on the way.
983acc9d408SJuli Mallett  */
984acc9d408SJuli Mallett static const char *
985bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src)
986acc9d408SJuli Mallett {
987acc9d408SJuli Mallett 	char *p;
988acc9d408SJuli Mallett 
989acc9d408SJuli Mallett 	p = buffer;
990acc9d408SJuli Mallett 	while(*src) {
991acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
992acc9d408SJuli Mallett 			unsigned char i;
993a841e1ebSBaptiste Daroussin 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
994acc9d408SJuli Mallett 				for (i = (unsigned char)src[0];
995acc9d408SJuli Mallett 				    i <= (unsigned char)src[2]; i++) {
996acc9d408SJuli Mallett 					*p++ = i;
997acc9d408SJuli Mallett 					if (p == end) {
998acc9d408SJuli Mallett 						*p = '\0';
999acc9d408SJuli Mallett 						return buffer;
1000acc9d408SJuli Mallett 					}
1001acc9d408SJuli Mallett 				}
1002a841e1ebSBaptiste Daroussin 			} else {
1003a841e1ebSBaptiste Daroussin 				for (i = (unsigned char)src[0];
1004a841e1ebSBaptiste Daroussin 				    i >= (unsigned char)src[2]; i--) {
1005a841e1ebSBaptiste Daroussin 					*p++ = i;
1006a841e1ebSBaptiste Daroussin 					if (p == end) {
1007a841e1ebSBaptiste Daroussin 						*p = '\0';
1008a841e1ebSBaptiste Daroussin 						return buffer;
1009a841e1ebSBaptiste Daroussin 					}
1010a841e1ebSBaptiste Daroussin 				}
1011a841e1ebSBaptiste Daroussin 			}
1012acc9d408SJuli Mallett 			src += 3;
1013acc9d408SJuli Mallett 		} else
1014acc9d408SJuli Mallett 			*p++ = *src++;
1015acc9d408SJuli Mallett 		if (p == end)
1016acc9d408SJuli Mallett 			break;
1017acc9d408SJuli Mallett 	}
1018acc9d408SJuli Mallett 	*p = '\0';
1019acc9d408SJuli Mallett 	return buffer;
1020acc9d408SJuli Mallett }
1021