xref: /freebsd/usr.bin/m4/eval.c (revision db531a5d1893673c1aa6ca196e184cafddb5c5f7)
1*db531a5dSBaptiste Daroussin /*	$OpenBSD: eval.c,v 1.77 2017/11/11 12:55:59 espie 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;
129*db531a5dSBaptiste Daroussin 	const char *errstr;
130acc9d408SJuli Mallett 	int ac;
1319b50d902SRodney W. Grimes 	static int sysval = 0;
1329b50d902SRodney W. Grimes 
1339b50d902SRodney W. Grimes #ifdef DEBUG
1349b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
1359b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
1369b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
137acc9d408SJuli Mallett 	fflush(stdout);
1389b50d902SRodney W. Grimes #endif
139acc9d408SJuli Mallett 
1409b50d902SRodney W. Grimes  /*
1419b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
1429b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
1439b50d902SRodney W. Grimes   * argc to avoid further checking..
1449b50d902SRodney W. Grimes   */
145a841e1ebSBaptiste Daroussin  /* we keep the initial value for those built-ins that differentiate
146a841e1ebSBaptiste Daroussin   * between builtin() and builtin.
147a841e1ebSBaptiste Daroussin   */
148acc9d408SJuli Mallett 	ac = argc;
149acc9d408SJuli Mallett 
150a841e1ebSBaptiste Daroussin 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
1519b50d902SRodney W. Grimes 		argc--;
1529b50d902SRodney W. Grimes 
153acc9d408SJuli Mallett 	switch (td & TYPEMASK) {
1549b50d902SRodney W. Grimes 
1559b50d902SRodney W. Grimes 	case DEFITYPE:
1569b50d902SRodney W. Grimes 		if (argc > 2)
1579b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1589b50d902SRodney W. Grimes 		break;
1599b50d902SRodney W. Grimes 
1609b50d902SRodney W. Grimes 	case PUSDTYPE:
1619b50d902SRodney W. Grimes 		if (argc > 2)
1629b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1639b50d902SRodney W. Grimes 		break;
1649b50d902SRodney W. Grimes 
1659b50d902SRodney W. Grimes 	case DUMPTYPE:
1669b50d902SRodney W. Grimes 		dodump(argv, argc);
1679b50d902SRodney W. Grimes 		break;
1689b50d902SRodney W. Grimes 
169acc9d408SJuli Mallett 	case TRACEONTYPE:
170acc9d408SJuli Mallett 		dotrace(argv, argc, 1);
171acc9d408SJuli Mallett 		break;
172acc9d408SJuli Mallett 
173acc9d408SJuli Mallett 	case TRACEOFFTYPE:
174acc9d408SJuli Mallett 		dotrace(argv, argc, 0);
175acc9d408SJuli Mallett 		break;
176acc9d408SJuli Mallett 
1779b50d902SRodney W. Grimes 	case EXPRTYPE:
1789b50d902SRodney W. Grimes 	/*
1799b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1809b50d902SRodney W. Grimes 	 * expression
1819b50d902SRodney W. Grimes 	 */
182a841e1ebSBaptiste Daroussin 	{
183a841e1ebSBaptiste Daroussin 		int base = 10;
184a841e1ebSBaptiste Daroussin 		int maxdigits = 0;
185a841e1ebSBaptiste Daroussin 		const char *errstr;
186a841e1ebSBaptiste Daroussin 
187a841e1ebSBaptiste Daroussin 		if (argc > 3) {
188a841e1ebSBaptiste Daroussin 			base = strtonum(argv[3], 2, 36, &errstr);
189a841e1ebSBaptiste Daroussin 			if (errstr) {
190*db531a5dSBaptiste Daroussin 				m4errx(1, "expr: base is %s: %s.",
191*db531a5dSBaptiste Daroussin 				    errstr, argv[3]);
192a841e1ebSBaptiste Daroussin 			}
193a841e1ebSBaptiste Daroussin 		}
194a841e1ebSBaptiste Daroussin 		if (argc > 4) {
195a841e1ebSBaptiste Daroussin 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
196a841e1ebSBaptiste Daroussin 			if (errstr) {
197*db531a5dSBaptiste Daroussin 				m4errx(1, "expr: maxdigits is %s: %s.",
198*db531a5dSBaptiste Daroussin 				    errstr, argv[4]);
199a841e1ebSBaptiste Daroussin 			}
200a841e1ebSBaptiste Daroussin 		}
2019b50d902SRodney W. Grimes 		if (argc > 2)
202a841e1ebSBaptiste Daroussin 			pbnumbase(expr(argv[2]), base, maxdigits);
2039b50d902SRodney W. Grimes 		break;
204a841e1ebSBaptiste Daroussin 	}
2059b50d902SRodney W. Grimes 
2069b50d902SRodney W. Grimes 	case IFELTYPE:
2079b50d902SRodney W. Grimes 		doifelse(argv, argc);
2089b50d902SRodney W. Grimes 		break;
2099b50d902SRodney W. Grimes 
2109b50d902SRodney W. Grimes 	case IFDFTYPE:
2119b50d902SRodney W. Grimes 	/*
2129b50d902SRodney W. Grimes 	 * doifdef - select one of two
2139b50d902SRodney W. Grimes 	 * alternatives based on the existence of
2149b50d902SRodney W. Grimes 	 * another definition
2159b50d902SRodney W. Grimes 	 */
2169b50d902SRodney W. Grimes 		if (argc > 3) {
217a841e1ebSBaptiste Daroussin 			if (lookup_macro_definition(argv[2]) != NULL)
2189b50d902SRodney W. Grimes 				pbstr(argv[3]);
2199b50d902SRodney W. Grimes 			else if (argc > 4)
2209b50d902SRodney W. Grimes 				pbstr(argv[4]);
2219b50d902SRodney W. Grimes 		}
2229b50d902SRodney W. Grimes 		break;
2239b50d902SRodney W. Grimes 
2249b50d902SRodney W. Grimes 	case LENGTYPE:
2259b50d902SRodney W. Grimes 	/*
2269b50d902SRodney W. Grimes 	 * dolen - find the length of the
2279b50d902SRodney W. Grimes 	 * argument
2289b50d902SRodney W. Grimes 	 */
2299b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2309b50d902SRodney W. Grimes 		break;
2319b50d902SRodney W. Grimes 
2329b50d902SRodney W. Grimes 	case INCRTYPE:
2339b50d902SRodney W. Grimes 	/*
2349b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2359b50d902SRodney W. Grimes 	 * argument
2369b50d902SRodney W. Grimes 	 */
237*db531a5dSBaptiste Daroussin 		if (argc > 2) {
238*db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr);
239*db531a5dSBaptiste Daroussin 			if (errstr != NULL)
240*db531a5dSBaptiste Daroussin 				m4errx(1, "incr: argument is %s: %s.",
241*db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
242*db531a5dSBaptiste Daroussin 			pbnum(n + 1);
243*db531a5dSBaptiste Daroussin 		}
2449b50d902SRodney W. Grimes 		break;
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 	case DECRTYPE:
2479b50d902SRodney W. Grimes 	/*
2489b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2499b50d902SRodney W. Grimes 	 * argument
2509b50d902SRodney W. Grimes 	 */
251*db531a5dSBaptiste Daroussin 		if (argc > 2) {
252*db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr);
253*db531a5dSBaptiste Daroussin 			if (errstr)
254*db531a5dSBaptiste Daroussin 				m4errx(1, "decr: argument is %s: %s.",
255*db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
256*db531a5dSBaptiste Daroussin 			pbnum(n - 1);
257*db531a5dSBaptiste Daroussin 		}
2589b50d902SRodney W. Grimes 		break;
2599b50d902SRodney W. Grimes 
2609b50d902SRodney W. Grimes 	case SYSCTYPE:
2619b50d902SRodney W. Grimes 	/*
2629b50d902SRodney W. Grimes 	 * dosys - execute system command
2639b50d902SRodney W. Grimes 	 */
264aef4bb33STim J. Robbins 		if (argc > 2) {
265a841e1ebSBaptiste Daroussin 			fflush(stdout);
2669b50d902SRodney W. Grimes 			sysval = system(argv[2]);
267aef4bb33STim J. Robbins 		}
2689b50d902SRodney W. Grimes 		break;
2699b50d902SRodney W. Grimes 
2709b50d902SRodney W. Grimes 	case SYSVTYPE:
2719b50d902SRodney W. Grimes 	/*
2729b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2739b50d902SRodney W. Grimes 	 * system call.
2749b50d902SRodney W. Grimes 	 *
2759b50d902SRodney W. Grimes 	 */
2769b50d902SRodney W. Grimes 		pbnum(sysval);
2779b50d902SRodney W. Grimes 		break;
2789b50d902SRodney W. Grimes 
279acc9d408SJuli Mallett 	case ESYSCMDTYPE:
280acc9d408SJuli Mallett 		if (argc > 2)
281acc9d408SJuli Mallett 			doesyscmd(argv[2]);
282acc9d408SJuli Mallett 		break;
2839b50d902SRodney W. Grimes 	case INCLTYPE:
28488497f0cSBaptiste Daroussin 		if (argc > 2) {
2852cce1b69SBjoern A. Zeeb 			if (!doincl(argv[2])) {
286fb3f3d7cSBaptiste Daroussin 				if (mimic_gnu) {
2874fff7a14SBaptiste Daroussin 					warn("%s at line %lu: include(%s)",
2884fff7a14SBaptiste Daroussin 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
289fb3f3d7cSBaptiste Daroussin 					exit_code = 1;
290c560b67cSBaptiste Daroussin 					if (fatal_warns) {
291c560b67cSBaptiste Daroussin 						killdiv();
292c560b67cSBaptiste Daroussin 						exit(exit_code);
293c560b67cSBaptiste Daroussin 					}
294fb3f3d7cSBaptiste Daroussin 				} else
295acc9d408SJuli Mallett 					err(1, "%s at line %lu: include(%s)",
296acc9d408SJuli Mallett 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2972cce1b69SBjoern A. Zeeb 			}
29888497f0cSBaptiste Daroussin 		}
2999b50d902SRodney W. Grimes 		break;
3009b50d902SRodney W. Grimes 
3019b50d902SRodney W. Grimes 	case SINCTYPE:
3029b50d902SRodney W. Grimes 		if (argc > 2)
3039b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
3049b50d902SRodney W. Grimes 		break;
3059b50d902SRodney W. Grimes #ifdef EXTENDED
3069b50d902SRodney W. Grimes 	case PASTTYPE:
3079b50d902SRodney W. Grimes 		if (argc > 2)
3089b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
309acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
310acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
3119b50d902SRodney W. Grimes 		break;
3129b50d902SRodney W. Grimes 
3139b50d902SRodney W. Grimes 	case SPASTYPE:
3149b50d902SRodney W. Grimes 		if (argc > 2)
3159b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
3169b50d902SRodney W. Grimes 		break;
317a841e1ebSBaptiste Daroussin 	case FORMATTYPE:
318a841e1ebSBaptiste Daroussin 		doformat(argv, argc);
319a841e1ebSBaptiste Daroussin 		break;
3209b50d902SRodney W. Grimes #endif
3219b50d902SRodney W. Grimes 	case CHNQTYPE:
322a841e1ebSBaptiste Daroussin 		dochq(argv, ac);
3239b50d902SRodney W. Grimes 		break;
3249b50d902SRodney W. Grimes 
3259b50d902SRodney W. Grimes 	case CHNCTYPE:
3269b50d902SRodney W. Grimes 		dochc(argv, argc);
3279b50d902SRodney W. Grimes 		break;
3289b50d902SRodney W. Grimes 
3299b50d902SRodney W. Grimes 	case SUBSTYPE:
3309b50d902SRodney W. Grimes 	/*
3319b50d902SRodney W. Grimes 	 * dosub - select substring
3329b50d902SRodney W. Grimes 	 *
3339b50d902SRodney W. Grimes 	 */
3349b50d902SRodney W. Grimes 		if (argc > 3)
3359b50d902SRodney W. Grimes 			dosub(argv, argc);
3369b50d902SRodney W. Grimes 		break;
3379b50d902SRodney W. Grimes 
3389b50d902SRodney W. Grimes 	case SHIFTYPE:
3399b50d902SRodney W. Grimes 	/*
3409b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3419b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3429b50d902SRodney W. Grimes 	 * argv[2])
3439b50d902SRodney W. Grimes 	 */
3449b50d902SRodney W. Grimes 		if (argc > 3) {
3459b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
346acc9d408SJuli Mallett 				pbstr(rquote);
3479b50d902SRodney W. Grimes 				pbstr(argv[n]);
348acc9d408SJuli Mallett 				pbstr(lquote);
349a841e1ebSBaptiste Daroussin 				pushback(COMMA);
3509b50d902SRodney W. Grimes 			}
351acc9d408SJuli Mallett 			pbstr(rquote);
3529b50d902SRodney W. Grimes 			pbstr(argv[3]);
353acc9d408SJuli Mallett 			pbstr(lquote);
3549b50d902SRodney W. Grimes 		}
3559b50d902SRodney W. Grimes 		break;
3569b50d902SRodney W. Grimes 
3579b50d902SRodney W. Grimes 	case DIVRTYPE:
358*db531a5dSBaptiste Daroussin 		if (argc > 2) {
359*db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr);
360*db531a5dSBaptiste Daroussin 			if (errstr)
361*db531a5dSBaptiste Daroussin 				m4errx(1, "divert: argument is %s: %s.",
362*db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
363*db531a5dSBaptiste Daroussin 			if (n != 0) {
3649b50d902SRodney W. Grimes 				dodiv(n);
365*db531a5dSBaptiste Daroussin 				 break;
366*db531a5dSBaptiste Daroussin 			}
367*db531a5dSBaptiste Daroussin 		}
3689b50d902SRodney W. Grimes 		active = stdout;
3699b50d902SRodney W. Grimes 		oindex = 0;
3709b50d902SRodney W. Grimes 		break;
3719b50d902SRodney W. Grimes 
3729b50d902SRodney W. Grimes 	case UNDVTYPE:
3739b50d902SRodney W. Grimes 		doundiv(argv, argc);
3749b50d902SRodney W. Grimes 		break;
3759b50d902SRodney W. Grimes 
3769b50d902SRodney W. Grimes 	case DIVNTYPE:
3779b50d902SRodney W. Grimes 	/*
3789b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3799b50d902SRodney W. Grimes 	 * current output diversion
3809b50d902SRodney W. Grimes 	 */
3819b50d902SRodney W. Grimes 		pbnum(oindex);
3829b50d902SRodney W. Grimes 		break;
3839b50d902SRodney W. Grimes 
3849b50d902SRodney W. Grimes 	case UNDFTYPE:
3859b50d902SRodney W. Grimes 	/*
3869b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3879b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3889b50d902SRodney W. Grimes 	 */
3899b50d902SRodney W. Grimes 		if (argc > 2)
3909b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
391a841e1ebSBaptiste Daroussin 				macro_undefine(argv[n]);
3929b50d902SRodney W. Grimes 		break;
3939b50d902SRodney W. Grimes 
3949b50d902SRodney W. Grimes 	case POPDTYPE:
3959b50d902SRodney W. Grimes 	/*
3969b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3979b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3989b50d902SRodney W. Grimes 	 * keyword(s).
3999b50d902SRodney W. Grimes 	 */
4009b50d902SRodney W. Grimes 		if (argc > 2)
4019b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
402a841e1ebSBaptiste Daroussin 				macro_popdef(argv[n]);
4039b50d902SRodney W. Grimes 		break;
4049b50d902SRodney W. Grimes 
4059b50d902SRodney W. Grimes 	case MKTMTYPE:
4069b50d902SRodney W. Grimes 	/*
4079b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
4089b50d902SRodney W. Grimes 	 */
409acc9d408SJuli Mallett 		if (argc > 2) {
410acc9d408SJuli Mallett 			int fd;
411acc9d408SJuli Mallett 			char *temp;
412acc9d408SJuli Mallett 
413acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
414acc9d408SJuli Mallett 
415acc9d408SJuli Mallett 			fd = mkstemp(temp);
416acc9d408SJuli Mallett 			if (fd == -1)
417acc9d408SJuli Mallett 				err(1,
418acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
419acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
420acc9d408SJuli Mallett 			close(fd);
421acc9d408SJuli Mallett 			pbstr(temp);
422acc9d408SJuli Mallett 			free(temp);
423acc9d408SJuli Mallett 		}
4249b50d902SRodney W. Grimes 		break;
4259b50d902SRodney W. Grimes 
4269b50d902SRodney W. Grimes 	case TRNLTYPE:
4279b50d902SRodney W. Grimes 	/*
4289b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
4299b50d902SRodney W. Grimes 	 * the source string that appears in the
4309b50d902SRodney W. Grimes 	 * "from" string with the corresponding
4319b50d902SRodney W. Grimes 	 * characters in the "to" string.
4329b50d902SRodney W. Grimes 	 */
4339b50d902SRodney W. Grimes 		if (argc > 3) {
434acc9d408SJuli Mallett 			char *temp;
435acc9d408SJuli Mallett 
436a841e1ebSBaptiste Daroussin 			temp = xalloc(strlen(argv[2])+1, NULL);
4379b50d902SRodney W. Grimes 			if (argc > 4)
4389b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
4399b50d902SRodney W. Grimes 			else
4409b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
4419b50d902SRodney W. Grimes 			pbstr(temp);
442acc9d408SJuli Mallett 			free(temp);
443acc9d408SJuli Mallett 		} else if (argc > 2)
4449b50d902SRodney W. Grimes 			pbstr(argv[2]);
4459b50d902SRodney W. Grimes 		break;
4469b50d902SRodney W. Grimes 
4479b50d902SRodney W. Grimes 	case INDXTYPE:
4489b50d902SRodney W. Grimes 	/*
4499b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4509b50d902SRodney W. Grimes 	 * argument string in the first argument
4519b50d902SRodney W. Grimes 	 * string. -1 if not present.
4529b50d902SRodney W. Grimes 	 */
4539b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4549b50d902SRodney W. Grimes 		break;
4559b50d902SRodney W. Grimes 
4569b50d902SRodney W. Grimes 	case ERRPTYPE:
4579b50d902SRodney W. Grimes 	/*
4589b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4599b50d902SRodney W. Grimes 	 * file
4609b50d902SRodney W. Grimes 	 */
4619b50d902SRodney W. Grimes 		if (argc > 2) {
4629b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4639b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4649b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4659b50d902SRodney W. Grimes 		}
4669b50d902SRodney W. Grimes 		break;
4679b50d902SRodney W. Grimes 
4689b50d902SRodney W. Grimes 	case DNLNTYPE:
4699b50d902SRodney W. Grimes 	/*
4709b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4719b50d902SRodney W. Grimes 	 * newline
4729b50d902SRodney W. Grimes 	 */
4739b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4749b50d902SRodney W. Grimes 			;
4759b50d902SRodney W. Grimes 		break;
4769b50d902SRodney W. Grimes 
4779b50d902SRodney W. Grimes 	case M4WRTYPE:
4789b50d902SRodney W. Grimes 	/*
4799b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4809b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4819b50d902SRodney W. Grimes 	 */
482a841e1ebSBaptiste Daroussin 		if (argc > 2)
483a841e1ebSBaptiste Daroussin 			dom4wrap(argv[2]);
4849b50d902SRodney W. Grimes 		break;
4859b50d902SRodney W. Grimes 
4869b50d902SRodney W. Grimes 	case EXITTYPE:
4879b50d902SRodney W. Grimes 	/*
4889b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4899b50d902SRodney W. Grimes 	 */
490cac6992aSAndrey A. Chernov 		killdiv();
4919b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4929b50d902SRodney W. Grimes 		break;
4939b50d902SRodney W. Grimes 
4949b50d902SRodney W. Grimes 	case DEFNTYPE:
4959b50d902SRodney W. Grimes 		if (argc > 2)
4969b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4979b50d902SRodney W. Grimes 				dodefn(argv[n]);
4989b50d902SRodney W. Grimes 		break;
4999b50d902SRodney W. Grimes 
500acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
501acc9d408SJuli Mallett 		if (argc > 2)
502acc9d408SJuli Mallett 			doindir(argv, argc);
503bbfd1447SSteve Price 		break;
504bbfd1447SSteve Price 
505acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
506acc9d408SJuli Mallett 		if (argc > 2)
507acc9d408SJuli Mallett 			dobuiltin(argv, argc);
508acc9d408SJuli Mallett 		break;
509acc9d408SJuli Mallett 
510acc9d408SJuli Mallett 	case PATSTYPE:
511acc9d408SJuli Mallett 		if (argc > 2)
512acc9d408SJuli Mallett 			dopatsubst(argv, argc);
513acc9d408SJuli Mallett 		break;
514acc9d408SJuli Mallett 	case REGEXPTYPE:
515acc9d408SJuli Mallett 		if (argc > 2)
516acc9d408SJuli Mallett 			doregexp(argv, argc);
517acc9d408SJuli Mallett 		break;
518acc9d408SJuli Mallett 	case LINETYPE:
519acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
520acc9d408SJuli Mallett 		break;
521acc9d408SJuli Mallett 	case FILENAMETYPE:
522acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
523acc9d408SJuli Mallett 		break;
524acc9d408SJuli Mallett 	case SELFTYPE:
525acc9d408SJuli Mallett 		pbstr(rquote);
526acc9d408SJuli Mallett 		pbstr(argv[1]);
527acc9d408SJuli Mallett 		pbstr(lquote);
528acc9d408SJuli Mallett 		break;
5299b50d902SRodney W. Grimes 	default:
530a841e1ebSBaptiste Daroussin 		m4errx(1, "eval: major botch.");
5319b50d902SRodney W. Grimes 		break;
5329b50d902SRodney W. Grimes 	}
5339b50d902SRodney W. Grimes }
5349b50d902SRodney W. Grimes 
5359b50d902SRodney W. Grimes /*
536acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
5379b50d902SRodney W. Grimes  */
5389b50d902SRodney W. Grimes void
539bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc)
5409b50d902SRodney W. Grimes {
541acc9d408SJuli Mallett 	const char *t;
542acc9d408SJuli Mallett 	const char *p;
543acc9d408SJuli Mallett 	int n;
544acc9d408SJuli Mallett 	int argno;
5459b50d902SRodney W. Grimes 
5469b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5479b50d902SRodney W. Grimes 	p = t;
5489b50d902SRodney W. Grimes 	while (*p)
5499b50d902SRodney W. Grimes 		p++;
5509b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5519b50d902SRodney W. Grimes 	while (p > t) {
5529b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
553a841e1ebSBaptiste Daroussin 			PUSHBACK(*p);
5549b50d902SRodney W. Grimes 		else {
5559b50d902SRodney W. Grimes 			switch (*p) {
5569b50d902SRodney W. Grimes 
5579b50d902SRodney W. Grimes 			case '#':
5589b50d902SRodney W. Grimes 				pbnum(argc - 2);
5599b50d902SRodney W. Grimes 				break;
5609b50d902SRodney W. Grimes 			case '0':
5619b50d902SRodney W. Grimes 			case '1':
5629b50d902SRodney W. Grimes 			case '2':
5639b50d902SRodney W. Grimes 			case '3':
5649b50d902SRodney W. Grimes 			case '4':
5659b50d902SRodney W. Grimes 			case '5':
5669b50d902SRodney W. Grimes 			case '6':
5679b50d902SRodney W. Grimes 			case '7':
5689b50d902SRodney W. Grimes 			case '8':
5699b50d902SRodney W. Grimes 			case '9':
5709b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5719b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5729b50d902SRodney W. Grimes 				break;
5739b50d902SRodney W. Grimes 			case '*':
574acc9d408SJuli Mallett 				if (argc > 2) {
5759b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5769b50d902SRodney W. Grimes 						pbstr(argv[n]);
577a841e1ebSBaptiste Daroussin 						pushback(COMMA);
5789b50d902SRodney W. Grimes 					}
5799b50d902SRodney W. Grimes 					pbstr(argv[2]);
580acc9d408SJuli Mallett 				}
5819b50d902SRodney W. Grimes 				break;
582232eaee6SJoerg Wunsch                         case '@':
583acc9d408SJuli Mallett 				if (argc > 2) {
584acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
585acc9d408SJuli Mallett 						pbstr(rquote);
586232eaee6SJoerg Wunsch 						pbstr(argv[n]);
587acc9d408SJuli Mallett 						pbstr(lquote);
588a841e1ebSBaptiste Daroussin 						pushback(COMMA);
589acc9d408SJuli Mallett 					}
590acc9d408SJuli Mallett 					pbstr(rquote);
591acc9d408SJuli Mallett 					pbstr(argv[2]);
592acc9d408SJuli Mallett 					pbstr(lquote);
593232eaee6SJoerg Wunsch 				}
594232eaee6SJoerg Wunsch                                 break;
5959b50d902SRodney W. Grimes 			default:
596a841e1ebSBaptiste Daroussin 				PUSHBACK(*p);
597a841e1ebSBaptiste Daroussin 				PUSHBACK('$');
5989b50d902SRodney W. Grimes 				break;
5999b50d902SRodney W. Grimes 			}
6009b50d902SRodney W. Grimes 			p--;
6019b50d902SRodney W. Grimes 		}
6029b50d902SRodney W. Grimes 		p--;
6039b50d902SRodney W. Grimes 	}
6049b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
605a841e1ebSBaptiste Daroussin 		PUSHBACK(*p);
6069b50d902SRodney W. Grimes }
6079b50d902SRodney W. Grimes 
608a841e1ebSBaptiste Daroussin 
6099b50d902SRodney W. Grimes /*
6109b50d902SRodney W. Grimes  * dodefine - install definition in the table
6119b50d902SRodney W. Grimes  */
6129b50d902SRodney W. Grimes void
613bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn)
6149b50d902SRodney W. Grimes {
615a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
616a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6179b50d902SRodney W. Grimes 	else
618a841e1ebSBaptiste Daroussin 		macro_define(name, defn);
6199b50d902SRodney W. Grimes }
6209b50d902SRodney W. Grimes 
6219b50d902SRodney W. Grimes /*
6229b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
6239b50d902SRodney W. Grimes  *      the given name.
6249b50d902SRodney W. Grimes  */
625acc9d408SJuli Mallett static void
626bd2bfb58SJuli Mallett dodefn(const char *name)
6279b50d902SRodney W. Grimes {
628a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6299b50d902SRodney W. Grimes 
630a841e1ebSBaptiste Daroussin 	if ((p = lookup_macro_definition(name)) != NULL) {
631a841e1ebSBaptiste Daroussin 		if ((p->type & TYPEMASK) == MACRTYPE) {
632acc9d408SJuli Mallett 			pbstr(rquote);
6339b50d902SRodney W. Grimes 			pbstr(p->defn);
634acc9d408SJuli Mallett 			pbstr(lquote);
635a841e1ebSBaptiste Daroussin 		} else {
636a841e1ebSBaptiste Daroussin 			pbstr(p->defn);
637acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
638acc9d408SJuli Mallett 		}
6399b50d902SRodney W. Grimes 	}
6409b50d902SRodney W. Grimes }
6419b50d902SRodney W. Grimes 
6429b50d902SRodney W. Grimes /*
6439b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6449b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6459b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6469b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6479b50d902SRodney W. Grimes  *      lookup.
6489b50d902SRodney W. Grimes  */
649acc9d408SJuli Mallett static void
650bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn)
6519b50d902SRodney W. Grimes {
652a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
653a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6549b50d902SRodney W. Grimes 	else
655a841e1ebSBaptiste Daroussin 		macro_pushdef(name, defn);
656acc9d408SJuli Mallett }
657acc9d408SJuli Mallett 
658acc9d408SJuli Mallett /*
659acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
660acc9d408SJuli Mallett  */
661acc9d408SJuli Mallett static void
662a841e1ebSBaptiste Daroussin dump_one_def(const char *name, struct macro_definition *p)
663acc9d408SJuli Mallett {
664a841e1ebSBaptiste Daroussin 	if (!traceout)
665a841e1ebSBaptiste Daroussin 		traceout = stderr;
666acc9d408SJuli Mallett 	if (mimic_gnu) {
667acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
668a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
669acc9d408SJuli Mallett 		else {
670a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
671acc9d408SJuli Mallett 		}
672acc9d408SJuli Mallett 	} else
673a841e1ebSBaptiste Daroussin 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
6749b50d902SRodney W. Grimes }
6759b50d902SRodney W. Grimes 
6769b50d902SRodney W. Grimes /*
6779b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6789b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6799b50d902SRodney W. Grimes  *      hash table is dumped.
6809b50d902SRodney W. Grimes  */
681acc9d408SJuli Mallett static void
682bd2bfb58SJuli Mallett dodump(const char *argv[], int argc)
6839b50d902SRodney W. Grimes {
684acc9d408SJuli Mallett 	int n;
685a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6869b50d902SRodney W. Grimes 
6879b50d902SRodney W. Grimes 	if (argc > 2) {
6889b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
689a841e1ebSBaptiste Daroussin 			if ((p = lookup_macro_definition(argv[n])) != NULL)
690a841e1ebSBaptiste Daroussin 				dump_one_def(argv[n], p);
691a841e1ebSBaptiste Daroussin 	} else
692a841e1ebSBaptiste Daroussin 		macro_for_all(dump_one_def);
6939b50d902SRodney W. Grimes }
6949b50d902SRodney W. Grimes 
6959b50d902SRodney W. Grimes /*
696acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
697acc9d408SJuli Mallett  */
698acc9d408SJuli Mallett static void
699bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on)
700acc9d408SJuli Mallett {
701acc9d408SJuli Mallett 	int n;
702acc9d408SJuli Mallett 
703acc9d408SJuli Mallett 	if (argc > 2) {
704acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
705acc9d408SJuli Mallett 			mark_traced(argv[n], on);
706acc9d408SJuli Mallett 	} else
707acc9d408SJuli Mallett 		mark_traced(NULL, on);
708acc9d408SJuli Mallett }
709acc9d408SJuli Mallett 
710acc9d408SJuli Mallett /*
7119b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
7129b50d902SRodney W. Grimes  */
713acc9d408SJuli Mallett static void
714bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc)
7159b50d902SRodney W. Grimes {
716e0f4e041SBaptiste Daroussin 	while (argc > 4) {
717e0f4e041SBaptiste Daroussin 		if (STREQ(argv[2], argv[3])) {
7189b50d902SRodney W. Grimes 			pbstr(argv[4]);
719e0f4e041SBaptiste Daroussin 			break;
720e0f4e041SBaptiste Daroussin 		} else if (argc == 6) {
7219b50d902SRodney W. Grimes 			pbstr(argv[5]);
722e0f4e041SBaptiste Daroussin 			break;
723e0f4e041SBaptiste Daroussin 		} else {
7249b50d902SRodney W. Grimes 			argv += 3;
7259b50d902SRodney W. Grimes 			argc -= 3;
7269b50d902SRodney W. Grimes 		}
7279b50d902SRodney W. Grimes 	}
7289b50d902SRodney W. Grimes }
7299b50d902SRodney W. Grimes 
7309b50d902SRodney W. Grimes /*
7319b50d902SRodney W. Grimes  * doinclude - include a given file.
7329b50d902SRodney W. Grimes  */
733acc9d408SJuli Mallett static int
734bd2bfb58SJuli Mallett doincl(const char *ifile)
7359b50d902SRodney W. Grimes {
7369b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
737a841e1ebSBaptiste Daroussin 		m4errx(1, "too many include files.");
738acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7399b50d902SRodney W. Grimes 		ilevel++;
7409b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
7419b50d902SRodney W. Grimes 		return (1);
742acc9d408SJuli Mallett 	} else
7439b50d902SRodney W. Grimes 		return (0);
7449b50d902SRodney W. Grimes }
7459b50d902SRodney W. Grimes 
7469b50d902SRodney W. Grimes #ifdef EXTENDED
7479b50d902SRodney W. Grimes /*
7489b50d902SRodney W. Grimes  * dopaste - include a given file without any
7499b50d902SRodney W. Grimes  *           macro processing.
7509b50d902SRodney W. Grimes  */
751acc9d408SJuli Mallett static int
752bd2bfb58SJuli Mallett dopaste(const char *pfile)
7539b50d902SRodney W. Grimes {
7549b50d902SRodney W. Grimes 	FILE *pf;
755acc9d408SJuli Mallett 	int c;
7569b50d902SRodney W. Grimes 
7579b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
758a841e1ebSBaptiste Daroussin 		if (synch_lines)
759b1ea3d46SJuli Mallett 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
7609b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7619b50d902SRodney W. Grimes 			putc(c, active);
7629b50d902SRodney W. Grimes 		(void) fclose(pf);
763a841e1ebSBaptiste Daroussin 		emit_synchline();
7649b50d902SRodney W. Grimes 		return (1);
765acc9d408SJuli Mallett 	} else
7669b50d902SRodney W. Grimes 		return (0);
7679b50d902SRodney W. Grimes }
7689b50d902SRodney W. Grimes #endif
7699b50d902SRodney W. Grimes 
7709b50d902SRodney W. Grimes /*
771acc9d408SJuli Mallett  * dochq - change quote characters
7729b50d902SRodney W. Grimes  */
773acc9d408SJuli Mallett static void
774a841e1ebSBaptiste Daroussin dochq(const char *argv[], int ac)
7759b50d902SRodney W. Grimes {
776a841e1ebSBaptiste Daroussin 	if (ac == 2) {
777a841e1ebSBaptiste Daroussin 		lquote[0] = LQUOTE; lquote[1] = EOS;
778a841e1ebSBaptiste Daroussin 		rquote[0] = RQUOTE; rquote[1] = EOS;
779acc9d408SJuli Mallett 	} else {
780a841e1ebSBaptiste Daroussin 		strlcpy(lquote, argv[2], sizeof(lquote));
781a841e1ebSBaptiste Daroussin 		if (ac > 3) {
782a841e1ebSBaptiste Daroussin 			strlcpy(rquote, argv[3], sizeof(rquote));
783a841e1ebSBaptiste Daroussin 		} else {
784a841e1ebSBaptiste Daroussin 			rquote[0] = ECOMMT; rquote[1] = EOS;
785a841e1ebSBaptiste Daroussin 		}
786acc9d408SJuli Mallett 	}
787acc9d408SJuli Mallett }
788acc9d408SJuli Mallett 
789acc9d408SJuli Mallett /*
790acc9d408SJuli Mallett  * dochc - change comment characters
791acc9d408SJuli Mallett  */
792acc9d408SJuli Mallett static void
793bd2bfb58SJuli Mallett dochc(const char *argv[], int argc)
794acc9d408SJuli Mallett {
795a841e1ebSBaptiste Daroussin /* XXX Note that there is no difference between no argument and a single
796a841e1ebSBaptiste Daroussin  * empty argument.
797a841e1ebSBaptiste Daroussin  */
798a841e1ebSBaptiste Daroussin 	if (argc == 2) {
799a841e1ebSBaptiste Daroussin 		scommt[0] = EOS;
800a841e1ebSBaptiste Daroussin 		ecommt[0] = EOS;
801a841e1ebSBaptiste Daroussin 	} else {
802acc9d408SJuli Mallett 		strlcpy(scommt, argv[2], sizeof(scommt));
803a841e1ebSBaptiste Daroussin 		if (argc == 3) {
804a841e1ebSBaptiste Daroussin 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
805a841e1ebSBaptiste Daroussin 		} else {
806acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
8079b50d902SRodney W. Grimes 		}
808a841e1ebSBaptiste Daroussin 	}
809a841e1ebSBaptiste Daroussin }
810a841e1ebSBaptiste Daroussin 
811a841e1ebSBaptiste Daroussin /*
812a841e1ebSBaptiste Daroussin  * dom4wrap - expand text at EOF
813a841e1ebSBaptiste Daroussin  */
814a841e1ebSBaptiste Daroussin static void
815a841e1ebSBaptiste Daroussin dom4wrap(const char *text)
816a841e1ebSBaptiste Daroussin {
817a841e1ebSBaptiste Daroussin 	if (wrapindex >= maxwraps) {
818a841e1ebSBaptiste Daroussin 		if (maxwraps == 0)
819a841e1ebSBaptiste Daroussin 			maxwraps = 16;
8209b50d902SRodney W. Grimes 		else
821a841e1ebSBaptiste Daroussin 			maxwraps *= 2;
82288497f0cSBaptiste Daroussin 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
823a841e1ebSBaptiste Daroussin 		   "too many m4wraps");
8249b50d902SRodney W. Grimes 	}
825a841e1ebSBaptiste Daroussin 	m4wraps[wrapindex++] = xstrdup(text);
8269b50d902SRodney W. Grimes }
8279b50d902SRodney W. Grimes 
8289b50d902SRodney W. Grimes /*
8299b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8309b50d902SRodney W. Grimes  */
831acc9d408SJuli Mallett static void
832bd2bfb58SJuli Mallett dodiv(int n)
8339b50d902SRodney W. Grimes {
834acc9d408SJuli Mallett 	int fd;
835acc9d408SJuli Mallett 
836ef2cea81SJonathan Lemon 	oindex = n;
837acc9d408SJuli Mallett 	if (n >= maxout) {
838acc9d408SJuli Mallett 		if (mimic_gnu)
839acc9d408SJuli Mallett 			resizedivs(n + 10);
840acc9d408SJuli Mallett 		else
841acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
842acc9d408SJuli Mallett 	}
843acc9d408SJuli Mallett 
844acc9d408SJuli Mallett 	if (n < 0)
8459b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
8469b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
847acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
848acc9d408SJuli Mallett 
849acc9d408SJuli Mallett 		if ((fd = mkstemp(fname)) < 0 ||
85088497f0cSBaptiste Daroussin 		    unlink(fname) == -1 ||
851acc9d408SJuli Mallett 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
852acc9d408SJuli Mallett 			err(1, "%s: cannot divert", fname);
8539b50d902SRodney W. Grimes 	}
8549b50d902SRodney W. Grimes 	active = outfile[n];
8559b50d902SRodney W. Grimes }
8569b50d902SRodney W. Grimes 
8579b50d902SRodney W. Grimes /*
8589b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
8599b50d902SRodney W. Grimes  *              other outputs, in numerical order.
8609b50d902SRodney W. Grimes  */
861acc9d408SJuli Mallett static void
862bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc)
8639b50d902SRodney W. Grimes {
864acc9d408SJuli Mallett 	int ind;
865acc9d408SJuli Mallett 	int n;
8669b50d902SRodney W. Grimes 
8679b50d902SRodney W. Grimes 	if (argc > 2) {
8689b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
869a841e1ebSBaptiste Daroussin 			const char *errstr;
870a841e1ebSBaptiste Daroussin 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
871a841e1ebSBaptiste Daroussin 			if (errstr) {
872a841e1ebSBaptiste Daroussin 				if (errno == EINVAL && mimic_gnu)
873a841e1ebSBaptiste Daroussin 					getdivfile(argv[ind]);
874a841e1ebSBaptiste Daroussin 			} else {
875a841e1ebSBaptiste Daroussin 				if (n < maxout && outfile[n] != NULL)
8769b50d902SRodney W. Grimes 					getdiv(n);
877a841e1ebSBaptiste Daroussin 			}
8789b50d902SRodney W. Grimes 		}
8799b50d902SRodney W. Grimes 	}
8809b50d902SRodney W. Grimes 	else
881acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
8829b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
8839b50d902SRodney W. Grimes 				getdiv(n);
8849b50d902SRodney W. Grimes }
8859b50d902SRodney W. Grimes 
8869b50d902SRodney W. Grimes /*
8879b50d902SRodney W. Grimes  * dosub - select substring
8889b50d902SRodney W. Grimes  */
889acc9d408SJuli Mallett static void
890bd2bfb58SJuli Mallett dosub(const char *argv[], int argc)
8919b50d902SRodney W. Grimes {
892acc9d408SJuli Mallett 	const char *ap, *fc, *k;
893acc9d408SJuli Mallett 	int nc;
8949b50d902SRodney W. Grimes 
8959b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
8969b50d902SRodney W. Grimes #ifdef EXPR
8979b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
8989b50d902SRodney W. Grimes #else
8999b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
9009b50d902SRodney W. Grimes #endif
9014ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
902acc9d408SJuli Mallett 	if (argc >= 5)
9034ba4d387SGregory Neil Shapiro #ifdef EXPR
904acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
9054ba4d387SGregory Neil Shapiro #else
906acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
9074ba4d387SGregory Neil Shapiro #endif
9089b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
9094ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
910a841e1ebSBaptiste Daroussin 			pushback(*k);
9119b50d902SRodney W. Grimes }
9129b50d902SRodney W. Grimes 
9139b50d902SRodney W. Grimes /*
9149b50d902SRodney W. Grimes  * map:
9159b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
9169b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
9179b50d902SRodney W. Grimes  *
918a841e1ebSBaptiste Daroussin  * This is derived from the a standard implementation of map(s,from,to)
919a841e1ebSBaptiste Daroussin  * function of ICON language. Within mapvec, we replace every character
920a841e1ebSBaptiste Daroussin  * of "from" with the corresponding character in "to".
921a841e1ebSBaptiste Daroussin  * If "to" is shorter than "from", than the corresponding entries are null,
922af7ca7c8SPedro F. Giffuni  * which means that those characters disappear altogether.
9239b50d902SRodney W. Grimes  */
924acc9d408SJuli Mallett static void
925bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to)
9269b50d902SRodney W. Grimes {
927acc9d408SJuli Mallett 	const char *tmp;
928acc9d408SJuli Mallett 	unsigned char sch, dch;
929acc9d408SJuli Mallett 	static char frombis[257];
930acc9d408SJuli Mallett 	static char tobis[257];
931a841e1ebSBaptiste Daroussin 	int i;
932a841e1ebSBaptiste Daroussin 	char seen[256];
933acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
934acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
935acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
936acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
937acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
938acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
939acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
940acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
941acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
942acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
943acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
944acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
945acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
946acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
947acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
948acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
949acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
950acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
951acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9529b50d902SRodney W. Grimes 	};
9539b50d902SRodney W. Grimes 
9549b50d902SRodney W. Grimes 	if (*src) {
955acc9d408SJuli Mallett 		if (mimic_gnu) {
956acc9d408SJuli Mallett 			/*
957acc9d408SJuli Mallett 			 * expand character ranges on the fly
958acc9d408SJuli Mallett 			 */
959acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
960acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
961acc9d408SJuli Mallett 		}
9629b50d902SRodney W. Grimes 		tmp = from;
9639b50d902SRodney W. Grimes 	/*
9649b50d902SRodney W. Grimes 	 * create a mapping between "from" and
9659b50d902SRodney W. Grimes 	 * "to"
9669b50d902SRodney W. Grimes 	 */
967a841e1ebSBaptiste Daroussin 		for (i = 0; i < 256; i++)
968a841e1ebSBaptiste Daroussin 			seen[i] = 0;
969a841e1ebSBaptiste Daroussin 		while (*from) {
970a841e1ebSBaptiste Daroussin 			if (!seen[(unsigned char)(*from)]) {
971a841e1ebSBaptiste Daroussin 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
972a841e1ebSBaptiste Daroussin 				seen[(unsigned char)(*from)] = 1;
973a841e1ebSBaptiste Daroussin 			}
974a841e1ebSBaptiste Daroussin 			from++;
975a841e1ebSBaptiste Daroussin 			if (*to)
976a841e1ebSBaptiste Daroussin 				to++;
977a841e1ebSBaptiste Daroussin 		}
9789b50d902SRodney W. Grimes 
9799b50d902SRodney W. Grimes 		while (*src) {
980acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
9819b50d902SRodney W. Grimes 			dch = mapvec[sch];
982acc9d408SJuli Mallett 			if ((*dest = (char)dch))
9839b50d902SRodney W. Grimes 				dest++;
9849b50d902SRodney W. Grimes 		}
9859b50d902SRodney W. Grimes 	/*
9869b50d902SRodney W. Grimes 	 * restore all the changed characters
9879b50d902SRodney W. Grimes 	 */
9889b50d902SRodney W. Grimes 		while (*tmp) {
989acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9909b50d902SRodney W. Grimes 			tmp++;
9919b50d902SRodney W. Grimes 		}
9929b50d902SRodney W. Grimes 	}
993acc9d408SJuli Mallett 	*dest = '\0';
9949b50d902SRodney W. Grimes }
995acc9d408SJuli Mallett 
996acc9d408SJuli Mallett 
997acc9d408SJuli Mallett /*
998acc9d408SJuli Mallett  * handledash:
999acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
1000acc9d408SJuli Mallett  * on the way.
1001acc9d408SJuli Mallett  */
1002acc9d408SJuli Mallett static const char *
1003bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src)
1004acc9d408SJuli Mallett {
1005acc9d408SJuli Mallett 	char *p;
1006acc9d408SJuli Mallett 
1007acc9d408SJuli Mallett 	p = buffer;
1008acc9d408SJuli Mallett 	while(*src) {
1009acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
1010acc9d408SJuli Mallett 			unsigned char i;
1011a841e1ebSBaptiste Daroussin 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
1012acc9d408SJuli Mallett 				for (i = (unsigned char)src[0];
1013acc9d408SJuli Mallett 				    i <= (unsigned char)src[2]; i++) {
1014acc9d408SJuli Mallett 					*p++ = i;
1015acc9d408SJuli Mallett 					if (p == end) {
1016acc9d408SJuli Mallett 						*p = '\0';
1017acc9d408SJuli Mallett 						return buffer;
1018acc9d408SJuli Mallett 					}
1019acc9d408SJuli Mallett 				}
1020a841e1ebSBaptiste Daroussin 			} else {
1021a841e1ebSBaptiste Daroussin 				for (i = (unsigned char)src[0];
1022a841e1ebSBaptiste Daroussin 				    i >= (unsigned char)src[2]; i--) {
1023a841e1ebSBaptiste Daroussin 					*p++ = i;
1024a841e1ebSBaptiste Daroussin 					if (p == end) {
1025a841e1ebSBaptiste Daroussin 						*p = '\0';
1026a841e1ebSBaptiste Daroussin 						return buffer;
1027a841e1ebSBaptiste Daroussin 					}
1028a841e1ebSBaptiste Daroussin 				}
1029a841e1ebSBaptiste Daroussin 			}
1030acc9d408SJuli Mallett 			src += 3;
1031acc9d408SJuli Mallett 		} else
1032acc9d408SJuli Mallett 			*p++ = *src++;
1033acc9d408SJuli Mallett 		if (p == end)
1034acc9d408SJuli Mallett 			break;
1035acc9d408SJuli Mallett 	}
1036acc9d408SJuli Mallett 	*p = '\0';
1037acc9d408SJuli Mallett 	return buffer;
1038acc9d408SJuli Mallett }
1039