xref: /freebsd/usr.bin/m4/eval.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1*c57596e1SBaptiste Daroussin /*	$OpenBSD: eval.c,v 1.78 2019/06/28 05:35:34 deraadt 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>
399b50d902SRodney W. Grimes /*
409b50d902SRodney W. Grimes  * eval.c
419b50d902SRodney W. Grimes  * Facility: m4 macro processor
429b50d902SRodney W. Grimes  * by: oz
439b50d902SRodney W. Grimes  */
449b50d902SRodney W. Grimes 
459b50d902SRodney W. Grimes #include <sys/types.h>
46a841e1ebSBaptiste Daroussin #include <err.h>
47acc9d408SJuli Mallett #include <errno.h>
48a841e1ebSBaptiste Daroussin #include <limits.h>
49acc9d408SJuli Mallett #include <unistd.h>
509b50d902SRodney W. Grimes #include <stdio.h>
5146ef9581SBaptiste Daroussin #include <stdint.h>
529b50d902SRodney W. Grimes #include <stdlib.h>
53acc9d408SJuli Mallett #include <stddef.h>
549b50d902SRodney W. Grimes #include <string.h>
55acc9d408SJuli Mallett #include <fcntl.h>
569b50d902SRodney W. Grimes #include "mdef.h"
579b50d902SRodney W. Grimes #include "stdd.h"
589b50d902SRodney W. Grimes #include "extern.h"
599b50d902SRodney W. Grimes #include "pathnames.h"
609b50d902SRodney W. Grimes 
61acc9d408SJuli Mallett static void	dodefn(const char *);
62acc9d408SJuli Mallett static void	dopushdef(const char *, const char *);
63acc9d408SJuli Mallett static void	dodump(const char *[], int);
64acc9d408SJuli Mallett static void	dotrace(const char *[], int, int);
65acc9d408SJuli Mallett static void	doifelse(const char *[], int);
66acc9d408SJuli Mallett static int	doincl(const char *);
67acc9d408SJuli Mallett static int	dopaste(const char *);
68acc9d408SJuli Mallett static void	dochq(const char *[], int);
69acc9d408SJuli Mallett static void	dochc(const char *[], int);
70a841e1ebSBaptiste Daroussin static void	dom4wrap(const char *);
71acc9d408SJuli Mallett static void	dodiv(int);
72acc9d408SJuli Mallett static void	doundiv(const char *[], int);
73acc9d408SJuli Mallett static void	dosub(const char *[], int);
74acc9d408SJuli Mallett static void	map(char *, const char *, const char *, const char *);
75acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *);
76acc9d408SJuli Mallett static void	expand_builtin(const char *[], int, int);
77acc9d408SJuli Mallett static void	expand_macro(const char *[], int);
78a841e1ebSBaptiste Daroussin static void	dump_one_def(const char *, struct macro_definition *);
79acc9d408SJuli Mallett 
80acc9d408SJuli Mallett unsigned long	expansion_id;
81acc9d408SJuli Mallett 
829b50d902SRodney W. Grimes /*
83acc9d408SJuli Mallett  * eval - eval all macros and builtins calls
849b50d902SRodney W. Grimes  *	  argc - number of elements in argv.
859b50d902SRodney W. Grimes  *	  argv - element vector :
869b50d902SRodney W. Grimes  *			argv[0] = definition of a user
87a841e1ebSBaptiste Daroussin  *				  macro or NULL if built-in.
889b50d902SRodney W. Grimes  *			argv[1] = name of the macro or
899b50d902SRodney W. Grimes  *				  built-in.
909b50d902SRodney W. Grimes  *			argv[2] = parameters to user-defined
919b50d902SRodney W. Grimes  *			   .	  macro or built-in.
929b50d902SRodney W. Grimes  *			   .
939b50d902SRodney W. Grimes  *
94acc9d408SJuli Mallett  * A call in the form of macro-or-builtin() will result in:
959b50d902SRodney W. Grimes  *			argv[0] = nullstr
969b50d902SRodney W. Grimes  *			argv[1] = macro-or-builtin
979b50d902SRodney W. Grimes  *			argv[2] = nullstr
98acc9d408SJuli Mallett  *
99acc9d408SJuli Mallett  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1009b50d902SRodney W. Grimes  */
1019b50d902SRodney W. Grimes void
eval(const char * argv[],int argc,int td,int is_traced)102a841e1ebSBaptiste Daroussin eval(const char *argv[], int argc, int td, int is_traced)
1039b50d902SRodney W. Grimes {
104a841e1ebSBaptiste Daroussin 	size_t mark = SIZE_MAX;
105acc9d408SJuli Mallett 
106acc9d408SJuli Mallett 	expansion_id++;
107acc9d408SJuli Mallett 	if (td & RECDEF)
108a841e1ebSBaptiste Daroussin 		m4errx(1, "expanding recursive definition for %s.", argv[1]);
109a841e1ebSBaptiste Daroussin 	if (is_traced)
110acc9d408SJuli Mallett 		mark = trace(argv, argc, infile+ilevel);
111acc9d408SJuli Mallett 	if (td == MACRTYPE)
112acc9d408SJuli Mallett 		expand_macro(argv, argc);
113acc9d408SJuli Mallett 	else
114acc9d408SJuli Mallett 		expand_builtin(argv, argc, td);
115a841e1ebSBaptiste Daroussin 	if (mark != SIZE_MAX)
116acc9d408SJuli Mallett 		finish_trace(mark);
117acc9d408SJuli Mallett }
118acc9d408SJuli Mallett 
119acc9d408SJuli Mallett /*
120acc9d408SJuli Mallett  * expand_builtin - evaluate built-in macros.
121acc9d408SJuli Mallett  */
122acc9d408SJuli Mallett void
expand_builtin(const char * argv[],int argc,int td)123bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td)
124acc9d408SJuli Mallett {
125acc9d408SJuli Mallett 	int c, n;
126db531a5dSBaptiste Daroussin 	const char *errstr;
127acc9d408SJuli Mallett 	int ac;
1289b50d902SRodney W. Grimes 	static int sysval = 0;
1299b50d902SRodney W. Grimes 
1309b50d902SRodney W. Grimes #ifdef DEBUG
1319b50d902SRodney W. Grimes 	printf("argc = %d\n", argc);
1329b50d902SRodney W. Grimes 	for (n = 0; n < argc; n++)
1339b50d902SRodney W. Grimes 		printf("argv[%d] = %s\n", n, argv[n]);
134acc9d408SJuli Mallett 	fflush(stdout);
1359b50d902SRodney W. Grimes #endif
136acc9d408SJuli Mallett 
1379b50d902SRodney W. Grimes  /*
1389b50d902SRodney W. Grimes   * if argc == 3 and argv[2] is null, then we
1399b50d902SRodney W. Grimes   * have macro-or-builtin() type call. We adjust
1409b50d902SRodney W. Grimes   * argc to avoid further checking..
1419b50d902SRodney W. Grimes   */
142a841e1ebSBaptiste Daroussin  /* we keep the initial value for those built-ins that differentiate
143a841e1ebSBaptiste Daroussin   * between builtin() and builtin.
144a841e1ebSBaptiste Daroussin   */
145acc9d408SJuli Mallett 	ac = argc;
146acc9d408SJuli Mallett 
147a841e1ebSBaptiste Daroussin 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
1489b50d902SRodney W. Grimes 		argc--;
1499b50d902SRodney W. Grimes 
150acc9d408SJuli Mallett 	switch (td & TYPEMASK) {
1519b50d902SRodney W. Grimes 
1529b50d902SRodney W. Grimes 	case DEFITYPE:
1539b50d902SRodney W. Grimes 		if (argc > 2)
1549b50d902SRodney W. Grimes 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1559b50d902SRodney W. Grimes 		break;
1569b50d902SRodney W. Grimes 
1579b50d902SRodney W. Grimes 	case PUSDTYPE:
1589b50d902SRodney W. Grimes 		if (argc > 2)
1599b50d902SRodney W. Grimes 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1609b50d902SRodney W. Grimes 		break;
1619b50d902SRodney W. Grimes 
1629b50d902SRodney W. Grimes 	case DUMPTYPE:
1639b50d902SRodney W. Grimes 		dodump(argv, argc);
1649b50d902SRodney W. Grimes 		break;
1659b50d902SRodney W. Grimes 
166acc9d408SJuli Mallett 	case TRACEONTYPE:
167acc9d408SJuli Mallett 		dotrace(argv, argc, 1);
168acc9d408SJuli Mallett 		break;
169acc9d408SJuli Mallett 
170acc9d408SJuli Mallett 	case TRACEOFFTYPE:
171acc9d408SJuli Mallett 		dotrace(argv, argc, 0);
172acc9d408SJuli Mallett 		break;
173acc9d408SJuli Mallett 
1749b50d902SRodney W. Grimes 	case EXPRTYPE:
1759b50d902SRodney W. Grimes 	/*
1769b50d902SRodney W. Grimes 	 * doexpr - evaluate arithmetic
1779b50d902SRodney W. Grimes 	 * expression
1789b50d902SRodney W. Grimes 	 */
179a841e1ebSBaptiste Daroussin 	{
180a841e1ebSBaptiste Daroussin 		int base = 10;
181a841e1ebSBaptiste Daroussin 		int maxdigits = 0;
182a841e1ebSBaptiste Daroussin 		const char *errstr;
183a841e1ebSBaptiste Daroussin 
184a841e1ebSBaptiste Daroussin 		if (argc > 3) {
185a841e1ebSBaptiste Daroussin 			base = strtonum(argv[3], 2, 36, &errstr);
186a841e1ebSBaptiste Daroussin 			if (errstr) {
187db531a5dSBaptiste Daroussin 				m4errx(1, "expr: base is %s: %s.",
188db531a5dSBaptiste Daroussin 				    errstr, argv[3]);
189a841e1ebSBaptiste Daroussin 			}
190a841e1ebSBaptiste Daroussin 		}
191a841e1ebSBaptiste Daroussin 		if (argc > 4) {
192a841e1ebSBaptiste Daroussin 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
193a841e1ebSBaptiste Daroussin 			if (errstr) {
194db531a5dSBaptiste Daroussin 				m4errx(1, "expr: maxdigits is %s: %s.",
195db531a5dSBaptiste Daroussin 				    errstr, 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 		doifelse(argv, argc);
2059b50d902SRodney W. Grimes 		break;
2069b50d902SRodney W. Grimes 
2079b50d902SRodney W. Grimes 	case IFDFTYPE:
2089b50d902SRodney W. Grimes 	/*
2099b50d902SRodney W. Grimes 	 * doifdef - select one of two
2109b50d902SRodney W. Grimes 	 * alternatives based on the existence of
2119b50d902SRodney W. Grimes 	 * another definition
2129b50d902SRodney W. Grimes 	 */
2139b50d902SRodney W. Grimes 		if (argc > 3) {
214a841e1ebSBaptiste Daroussin 			if (lookup_macro_definition(argv[2]) != NULL)
2159b50d902SRodney W. Grimes 				pbstr(argv[3]);
2169b50d902SRodney W. Grimes 			else if (argc > 4)
2179b50d902SRodney W. Grimes 				pbstr(argv[4]);
2189b50d902SRodney W. Grimes 		}
2199b50d902SRodney W. Grimes 		break;
2209b50d902SRodney W. Grimes 
2219b50d902SRodney W. Grimes 	case LENGTYPE:
2229b50d902SRodney W. Grimes 	/*
2239b50d902SRodney W. Grimes 	 * dolen - find the length of the
2249b50d902SRodney W. Grimes 	 * argument
2259b50d902SRodney W. Grimes 	 */
2269b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2279b50d902SRodney W. Grimes 		break;
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes 	case INCRTYPE:
2309b50d902SRodney W. Grimes 	/*
2319b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2329b50d902SRodney W. Grimes 	 * argument
2339b50d902SRodney W. Grimes 	 */
234db531a5dSBaptiste Daroussin 		if (argc > 2) {
235db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr);
236db531a5dSBaptiste Daroussin 			if (errstr != NULL)
237db531a5dSBaptiste Daroussin 				m4errx(1, "incr: argument is %s: %s.",
238db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
239db531a5dSBaptiste Daroussin 			pbnum(n + 1);
240db531a5dSBaptiste Daroussin 		}
2419b50d902SRodney W. Grimes 		break;
2429b50d902SRodney W. Grimes 
2439b50d902SRodney W. Grimes 	case DECRTYPE:
2449b50d902SRodney W. Grimes 	/*
2459b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2469b50d902SRodney W. Grimes 	 * argument
2479b50d902SRodney W. Grimes 	 */
248db531a5dSBaptiste Daroussin 		if (argc > 2) {
249db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr);
250db531a5dSBaptiste Daroussin 			if (errstr)
251db531a5dSBaptiste Daroussin 				m4errx(1, "decr: argument is %s: %s.",
252db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
253db531a5dSBaptiste Daroussin 			pbnum(n - 1);
254db531a5dSBaptiste Daroussin 		}
2559b50d902SRodney W. Grimes 		break;
2569b50d902SRodney W. Grimes 
2579b50d902SRodney W. Grimes 	case SYSCTYPE:
2589b50d902SRodney W. Grimes 	/*
2599b50d902SRodney W. Grimes 	 * dosys - execute system command
2609b50d902SRodney W. Grimes 	 */
261aef4bb33STim J. Robbins 		if (argc > 2) {
262a841e1ebSBaptiste Daroussin 			fflush(stdout);
2639b50d902SRodney W. Grimes 			sysval = system(argv[2]);
264aef4bb33STim J. Robbins 		}
2659b50d902SRodney W. Grimes 		break;
2669b50d902SRodney W. Grimes 
2679b50d902SRodney W. Grimes 	case SYSVTYPE:
2689b50d902SRodney W. Grimes 	/*
2699b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2709b50d902SRodney W. Grimes 	 * system call.
2719b50d902SRodney W. Grimes 	 *
2729b50d902SRodney W. Grimes 	 */
2739b50d902SRodney W. Grimes 		pbnum(sysval);
2749b50d902SRodney W. Grimes 		break;
2759b50d902SRodney W. Grimes 
276acc9d408SJuli Mallett 	case ESYSCMDTYPE:
277acc9d408SJuli Mallett 		if (argc > 2)
278acc9d408SJuli Mallett 			doesyscmd(argv[2]);
279acc9d408SJuli Mallett 		break;
2809b50d902SRodney W. Grimes 	case INCLTYPE:
28188497f0cSBaptiste Daroussin 		if (argc > 2) {
2822cce1b69SBjoern A. Zeeb 			if (!doincl(argv[2])) {
283fb3f3d7cSBaptiste Daroussin 				if (mimic_gnu) {
2844fff7a14SBaptiste Daroussin 					warn("%s at line %lu: include(%s)",
2854fff7a14SBaptiste Daroussin 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
286fb3f3d7cSBaptiste Daroussin 					exit_code = 1;
287c560b67cSBaptiste Daroussin 					if (fatal_warns) {
288c560b67cSBaptiste Daroussin 						killdiv();
289c560b67cSBaptiste Daroussin 						exit(exit_code);
290c560b67cSBaptiste Daroussin 					}
291fb3f3d7cSBaptiste Daroussin 				} else
292acc9d408SJuli Mallett 					err(1, "%s at line %lu: include(%s)",
293acc9d408SJuli Mallett 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2942cce1b69SBjoern A. Zeeb 			}
29588497f0cSBaptiste Daroussin 		}
2969b50d902SRodney W. Grimes 		break;
2979b50d902SRodney W. Grimes 
2989b50d902SRodney W. Grimes 	case SINCTYPE:
2999b50d902SRodney W. Grimes 		if (argc > 2)
3009b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
3019b50d902SRodney W. Grimes 		break;
3029b50d902SRodney W. Grimes #ifdef EXTENDED
3039b50d902SRodney W. Grimes 	case PASTTYPE:
3049b50d902SRodney W. Grimes 		if (argc > 2)
3059b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
306acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
307acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
3089b50d902SRodney W. Grimes 		break;
3099b50d902SRodney W. Grimes 
3109b50d902SRodney W. Grimes 	case SPASTYPE:
3119b50d902SRodney W. Grimes 		if (argc > 2)
3129b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
3139b50d902SRodney W. Grimes 		break;
314a841e1ebSBaptiste Daroussin 	case FORMATTYPE:
315a841e1ebSBaptiste Daroussin 		doformat(argv, argc);
316a841e1ebSBaptiste Daroussin 		break;
3179b50d902SRodney W. Grimes #endif
3189b50d902SRodney W. Grimes 	case CHNQTYPE:
319a841e1ebSBaptiste Daroussin 		dochq(argv, ac);
3209b50d902SRodney W. Grimes 		break;
3219b50d902SRodney W. Grimes 
3229b50d902SRodney W. Grimes 	case CHNCTYPE:
3239b50d902SRodney W. Grimes 		dochc(argv, argc);
3249b50d902SRodney W. Grimes 		break;
3259b50d902SRodney W. Grimes 
3269b50d902SRodney W. Grimes 	case SUBSTYPE:
3279b50d902SRodney W. Grimes 	/*
3289b50d902SRodney W. Grimes 	 * dosub - select substring
3299b50d902SRodney W. Grimes 	 *
3309b50d902SRodney W. Grimes 	 */
3319b50d902SRodney W. Grimes 		if (argc > 3)
3329b50d902SRodney W. Grimes 			dosub(argv, argc);
3339b50d902SRodney W. Grimes 		break;
3349b50d902SRodney W. Grimes 
3359b50d902SRodney W. Grimes 	case SHIFTYPE:
3369b50d902SRodney W. Grimes 	/*
3379b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3389b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3399b50d902SRodney W. Grimes 	 * argv[2])
3409b50d902SRodney W. Grimes 	 */
3419b50d902SRodney W. Grimes 		if (argc > 3) {
3429b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
343acc9d408SJuli Mallett 				pbstr(rquote);
3449b50d902SRodney W. Grimes 				pbstr(argv[n]);
345acc9d408SJuli Mallett 				pbstr(lquote);
346a841e1ebSBaptiste Daroussin 				pushback(COMMA);
3479b50d902SRodney W. Grimes 			}
348acc9d408SJuli Mallett 			pbstr(rquote);
3499b50d902SRodney W. Grimes 			pbstr(argv[3]);
350acc9d408SJuli Mallett 			pbstr(lquote);
3519b50d902SRodney W. Grimes 		}
3529b50d902SRodney W. Grimes 		break;
3539b50d902SRodney W. Grimes 
3549b50d902SRodney W. Grimes 	case DIVRTYPE:
355db531a5dSBaptiste Daroussin 		if (argc > 2) {
356db531a5dSBaptiste Daroussin 			n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr);
357db531a5dSBaptiste Daroussin 			if (errstr)
358db531a5dSBaptiste Daroussin 				m4errx(1, "divert: argument is %s: %s.",
359db531a5dSBaptiste Daroussin 				    errstr, argv[2]);
360db531a5dSBaptiste Daroussin 			if (n != 0) {
3619b50d902SRodney W. Grimes 				dodiv(n);
362db531a5dSBaptiste Daroussin 				 break;
363db531a5dSBaptiste Daroussin 			}
364db531a5dSBaptiste Daroussin 		}
3659b50d902SRodney W. Grimes 		active = stdout;
3669b50d902SRodney W. Grimes 		oindex = 0;
3679b50d902SRodney W. Grimes 		break;
3689b50d902SRodney W. Grimes 
3699b50d902SRodney W. Grimes 	case UNDVTYPE:
3709b50d902SRodney W. Grimes 		doundiv(argv, argc);
3719b50d902SRodney W. Grimes 		break;
3729b50d902SRodney W. Grimes 
3739b50d902SRodney W. Grimes 	case DIVNTYPE:
3749b50d902SRodney W. Grimes 	/*
3759b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3769b50d902SRodney W. Grimes 	 * current output diversion
3779b50d902SRodney W. Grimes 	 */
3789b50d902SRodney W. Grimes 		pbnum(oindex);
3799b50d902SRodney W. Grimes 		break;
3809b50d902SRodney W. Grimes 
3819b50d902SRodney W. Grimes 	case UNDFTYPE:
3829b50d902SRodney W. Grimes 	/*
3839b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3849b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3859b50d902SRodney W. Grimes 	 */
3869b50d902SRodney W. Grimes 		if (argc > 2)
3879b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
388a841e1ebSBaptiste Daroussin 				macro_undefine(argv[n]);
3899b50d902SRodney W. Grimes 		break;
3909b50d902SRodney W. Grimes 
3919b50d902SRodney W. Grimes 	case POPDTYPE:
3929b50d902SRodney W. Grimes 	/*
3939b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3949b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3959b50d902SRodney W. Grimes 	 * keyword(s).
3969b50d902SRodney W. Grimes 	 */
3979b50d902SRodney W. Grimes 		if (argc > 2)
3989b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
399a841e1ebSBaptiste Daroussin 				macro_popdef(argv[n]);
4009b50d902SRodney W. Grimes 		break;
4019b50d902SRodney W. Grimes 
4029b50d902SRodney W. Grimes 	case MKTMTYPE:
4039b50d902SRodney W. Grimes 	/*
4049b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
4059b50d902SRodney W. Grimes 	 */
406acc9d408SJuli Mallett 		if (argc > 2) {
407acc9d408SJuli Mallett 			int fd;
408acc9d408SJuli Mallett 			char *temp;
409acc9d408SJuli Mallett 
410acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
411acc9d408SJuli Mallett 
412acc9d408SJuli Mallett 			fd = mkstemp(temp);
413acc9d408SJuli Mallett 			if (fd == -1)
414acc9d408SJuli Mallett 				err(1,
415acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
416acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
417acc9d408SJuli Mallett 			close(fd);
418acc9d408SJuli Mallett 			pbstr(temp);
419acc9d408SJuli Mallett 			free(temp);
420acc9d408SJuli Mallett 		}
4219b50d902SRodney W. Grimes 		break;
4229b50d902SRodney W. Grimes 
4239b50d902SRodney W. Grimes 	case TRNLTYPE:
4249b50d902SRodney W. Grimes 	/*
4259b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
4269b50d902SRodney W. Grimes 	 * the source string that appears in the
4279b50d902SRodney W. Grimes 	 * "from" string with the corresponding
4289b50d902SRodney W. Grimes 	 * characters in the "to" string.
4299b50d902SRodney W. Grimes 	 */
4309b50d902SRodney W. Grimes 		if (argc > 3) {
431acc9d408SJuli Mallett 			char *temp;
432acc9d408SJuli Mallett 
433a841e1ebSBaptiste Daroussin 			temp = xalloc(strlen(argv[2])+1, NULL);
4349b50d902SRodney W. Grimes 			if (argc > 4)
4359b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
4369b50d902SRodney W. Grimes 			else
4379b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
4389b50d902SRodney W. Grimes 			pbstr(temp);
439acc9d408SJuli Mallett 			free(temp);
440acc9d408SJuli Mallett 		} else if (argc > 2)
4419b50d902SRodney W. Grimes 			pbstr(argv[2]);
4429b50d902SRodney W. Grimes 		break;
4439b50d902SRodney W. Grimes 
4449b50d902SRodney W. Grimes 	case INDXTYPE:
4459b50d902SRodney W. Grimes 	/*
4469b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4479b50d902SRodney W. Grimes 	 * argument string in the first argument
4489b50d902SRodney W. Grimes 	 * string. -1 if not present.
4499b50d902SRodney W. Grimes 	 */
4509b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4519b50d902SRodney W. Grimes 		break;
4529b50d902SRodney W. Grimes 
4539b50d902SRodney W. Grimes 	case ERRPTYPE:
4549b50d902SRodney W. Grimes 	/*
4559b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4569b50d902SRodney W. Grimes 	 * file
4579b50d902SRodney W. Grimes 	 */
4589b50d902SRodney W. Grimes 		if (argc > 2) {
4599b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4609b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4619b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4629b50d902SRodney W. Grimes 		}
4639b50d902SRodney W. Grimes 		break;
4649b50d902SRodney W. Grimes 
4659b50d902SRodney W. Grimes 	case DNLNTYPE:
4669b50d902SRodney W. Grimes 	/*
4679b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4689b50d902SRodney W. Grimes 	 * newline
4699b50d902SRodney W. Grimes 	 */
4709b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4719b50d902SRodney W. Grimes 			;
4729b50d902SRodney W. Grimes 		break;
4739b50d902SRodney W. Grimes 
4749b50d902SRodney W. Grimes 	case M4WRTYPE:
4759b50d902SRodney W. Grimes 	/*
4769b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4779b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4789b50d902SRodney W. Grimes 	 */
479a841e1ebSBaptiste Daroussin 		if (argc > 2)
480a841e1ebSBaptiste Daroussin 			dom4wrap(argv[2]);
4819b50d902SRodney W. Grimes 		break;
4829b50d902SRodney W. Grimes 
4839b50d902SRodney W. Grimes 	case EXITTYPE:
4849b50d902SRodney W. Grimes 	/*
4859b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4869b50d902SRodney W. Grimes 	 */
487cac6992aSAndrey A. Chernov 		killdiv();
4889b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4899b50d902SRodney W. Grimes 		break;
4909b50d902SRodney W. Grimes 
4919b50d902SRodney W. Grimes 	case DEFNTYPE:
4929b50d902SRodney W. Grimes 		if (argc > 2)
4939b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4949b50d902SRodney W. Grimes 				dodefn(argv[n]);
4959b50d902SRodney W. Grimes 		break;
4969b50d902SRodney W. Grimes 
497acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
498acc9d408SJuli Mallett 		if (argc > 2)
499acc9d408SJuli Mallett 			doindir(argv, argc);
500bbfd1447SSteve Price 		break;
501bbfd1447SSteve Price 
502acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
503acc9d408SJuli Mallett 		if (argc > 2)
504acc9d408SJuli Mallett 			dobuiltin(argv, argc);
505acc9d408SJuli Mallett 		break;
506acc9d408SJuli Mallett 
507acc9d408SJuli Mallett 	case PATSTYPE:
508acc9d408SJuli Mallett 		if (argc > 2)
509acc9d408SJuli Mallett 			dopatsubst(argv, argc);
510acc9d408SJuli Mallett 		break;
511acc9d408SJuli Mallett 	case REGEXPTYPE:
512acc9d408SJuli Mallett 		if (argc > 2)
513acc9d408SJuli Mallett 			doregexp(argv, argc);
514acc9d408SJuli Mallett 		break;
515acc9d408SJuli Mallett 	case LINETYPE:
516acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
517acc9d408SJuli Mallett 		break;
518acc9d408SJuli Mallett 	case FILENAMETYPE:
519acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
520acc9d408SJuli Mallett 		break;
521acc9d408SJuli Mallett 	case SELFTYPE:
522acc9d408SJuli Mallett 		pbstr(rquote);
523acc9d408SJuli Mallett 		pbstr(argv[1]);
524acc9d408SJuli Mallett 		pbstr(lquote);
525acc9d408SJuli Mallett 		break;
5269b50d902SRodney W. Grimes 	default:
527a841e1ebSBaptiste Daroussin 		m4errx(1, "eval: major botch.");
5289b50d902SRodney W. Grimes 		break;
5299b50d902SRodney W. Grimes 	}
5309b50d902SRodney W. Grimes }
5319b50d902SRodney W. Grimes 
5329b50d902SRodney W. Grimes /*
533acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
5349b50d902SRodney W. Grimes  */
5359b50d902SRodney W. Grimes void
expand_macro(const char * argv[],int argc)536bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc)
5379b50d902SRodney W. Grimes {
538acc9d408SJuli Mallett 	const char *t;
539acc9d408SJuli Mallett 	const char *p;
540acc9d408SJuli Mallett 	int n;
541acc9d408SJuli Mallett 	int argno;
5429b50d902SRodney W. Grimes 
5439b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5449b50d902SRodney W. Grimes 	p = t;
5459b50d902SRodney W. Grimes 	while (*p)
5469b50d902SRodney W. Grimes 		p++;
5479b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5489b50d902SRodney W. Grimes 	while (p > t) {
5499b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
550a841e1ebSBaptiste Daroussin 			PUSHBACK(*p);
5519b50d902SRodney W. Grimes 		else {
5529b50d902SRodney W. Grimes 			switch (*p) {
5539b50d902SRodney W. Grimes 
5549b50d902SRodney W. Grimes 			case '#':
5559b50d902SRodney W. Grimes 				pbnum(argc - 2);
5569b50d902SRodney W. Grimes 				break;
5579b50d902SRodney W. Grimes 			case '0':
5589b50d902SRodney W. Grimes 			case '1':
5599b50d902SRodney W. Grimes 			case '2':
5609b50d902SRodney W. Grimes 			case '3':
5619b50d902SRodney W. Grimes 			case '4':
5629b50d902SRodney W. Grimes 			case '5':
5639b50d902SRodney W. Grimes 			case '6':
5649b50d902SRodney W. Grimes 			case '7':
5659b50d902SRodney W. Grimes 			case '8':
5669b50d902SRodney W. Grimes 			case '9':
5679b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5689b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5699b50d902SRodney W. Grimes 				break;
5709b50d902SRodney W. Grimes 			case '*':
571acc9d408SJuli Mallett 				if (argc > 2) {
5729b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5739b50d902SRodney W. Grimes 						pbstr(argv[n]);
574a841e1ebSBaptiste Daroussin 						pushback(COMMA);
5759b50d902SRodney W. Grimes 					}
5769b50d902SRodney W. Grimes 					pbstr(argv[2]);
577acc9d408SJuli Mallett 				}
5789b50d902SRodney W. Grimes 				break;
579232eaee6SJoerg Wunsch                         case '@':
580acc9d408SJuli Mallett 				if (argc > 2) {
581acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
582acc9d408SJuli Mallett 						pbstr(rquote);
583232eaee6SJoerg Wunsch 						pbstr(argv[n]);
584acc9d408SJuli Mallett 						pbstr(lquote);
585a841e1ebSBaptiste Daroussin 						pushback(COMMA);
586acc9d408SJuli Mallett 					}
587acc9d408SJuli Mallett 					pbstr(rquote);
588acc9d408SJuli Mallett 					pbstr(argv[2]);
589acc9d408SJuli Mallett 					pbstr(lquote);
590232eaee6SJoerg Wunsch 				}
591232eaee6SJoerg Wunsch                                 break;
5929b50d902SRodney W. Grimes 			default:
593a841e1ebSBaptiste Daroussin 				PUSHBACK(*p);
594a841e1ebSBaptiste Daroussin 				PUSHBACK('$');
5959b50d902SRodney W. Grimes 				break;
5969b50d902SRodney W. Grimes 			}
5979b50d902SRodney W. Grimes 			p--;
5989b50d902SRodney W. Grimes 		}
5999b50d902SRodney W. Grimes 		p--;
6009b50d902SRodney W. Grimes 	}
6019b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
602a841e1ebSBaptiste Daroussin 		PUSHBACK(*p);
6039b50d902SRodney W. Grimes }
6049b50d902SRodney W. Grimes 
605a841e1ebSBaptiste Daroussin 
6069b50d902SRodney W. Grimes /*
6079b50d902SRodney W. Grimes  * dodefine - install definition in the table
6089b50d902SRodney W. Grimes  */
6099b50d902SRodney W. Grimes void
dodefine(const char * name,const char * defn)610bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn)
6119b50d902SRodney W. Grimes {
612a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
613a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6149b50d902SRodney W. Grimes 	else
615a841e1ebSBaptiste Daroussin 		macro_define(name, defn);
6169b50d902SRodney W. Grimes }
6179b50d902SRodney W. Grimes 
6189b50d902SRodney W. Grimes /*
6199b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
6209b50d902SRodney W. Grimes  *      the given name.
6219b50d902SRodney W. Grimes  */
622acc9d408SJuli Mallett static void
dodefn(const char * name)623bd2bfb58SJuli Mallett dodefn(const char *name)
6249b50d902SRodney W. Grimes {
625a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6269b50d902SRodney W. Grimes 
627a841e1ebSBaptiste Daroussin 	if ((p = lookup_macro_definition(name)) != NULL) {
628a841e1ebSBaptiste Daroussin 		if ((p->type & TYPEMASK) == MACRTYPE) {
629acc9d408SJuli Mallett 			pbstr(rquote);
6309b50d902SRodney W. Grimes 			pbstr(p->defn);
631acc9d408SJuli Mallett 			pbstr(lquote);
632a841e1ebSBaptiste Daroussin 		} else {
633a841e1ebSBaptiste Daroussin 			pbstr(p->defn);
634acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
635acc9d408SJuli Mallett 		}
6369b50d902SRodney W. Grimes 	}
6379b50d902SRodney W. Grimes }
6389b50d902SRodney W. Grimes 
6399b50d902SRodney W. Grimes /*
6409b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6419b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6429b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6439b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6449b50d902SRodney W. Grimes  *      lookup.
6459b50d902SRodney W. Grimes  */
646acc9d408SJuli Mallett static void
dopushdef(const char * name,const char * defn)647bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn)
6489b50d902SRodney W. Grimes {
649a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
650a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6519b50d902SRodney W. Grimes 	else
652a841e1ebSBaptiste Daroussin 		macro_pushdef(name, defn);
653acc9d408SJuli Mallett }
654acc9d408SJuli Mallett 
655acc9d408SJuli Mallett /*
656acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
657acc9d408SJuli Mallett  */
658acc9d408SJuli Mallett static void
dump_one_def(const char * name,struct macro_definition * p)659a841e1ebSBaptiste Daroussin dump_one_def(const char *name, struct macro_definition *p)
660acc9d408SJuli Mallett {
661a841e1ebSBaptiste Daroussin 	if (!traceout)
662a841e1ebSBaptiste Daroussin 		traceout = stderr;
663acc9d408SJuli Mallett 	if (mimic_gnu) {
664acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
665a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
666acc9d408SJuli Mallett 		else {
667a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
668acc9d408SJuli Mallett 		}
669acc9d408SJuli Mallett 	} else
670a841e1ebSBaptiste Daroussin 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
6719b50d902SRodney W. Grimes }
6729b50d902SRodney W. Grimes 
6739b50d902SRodney W. Grimes /*
6749b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6759b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6769b50d902SRodney W. Grimes  *      hash table is dumped.
6779b50d902SRodney W. Grimes  */
678acc9d408SJuli Mallett static void
dodump(const char * argv[],int argc)679bd2bfb58SJuli Mallett dodump(const char *argv[], int argc)
6809b50d902SRodney W. Grimes {
681acc9d408SJuli Mallett 	int n;
682a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6839b50d902SRodney W. Grimes 
6849b50d902SRodney W. Grimes 	if (argc > 2) {
6859b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
686a841e1ebSBaptiste Daroussin 			if ((p = lookup_macro_definition(argv[n])) != NULL)
687a841e1ebSBaptiste Daroussin 				dump_one_def(argv[n], p);
688a841e1ebSBaptiste Daroussin 	} else
689a841e1ebSBaptiste Daroussin 		macro_for_all(dump_one_def);
6909b50d902SRodney W. Grimes }
6919b50d902SRodney W. Grimes 
6929b50d902SRodney W. Grimes /*
693acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
694acc9d408SJuli Mallett  */
695acc9d408SJuli Mallett static void
dotrace(const char * argv[],int argc,int on)696bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on)
697acc9d408SJuli Mallett {
698acc9d408SJuli Mallett 	int n;
699acc9d408SJuli Mallett 
700acc9d408SJuli Mallett 	if (argc > 2) {
701acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
702acc9d408SJuli Mallett 			mark_traced(argv[n], on);
703acc9d408SJuli Mallett 	} else
704acc9d408SJuli Mallett 		mark_traced(NULL, on);
705acc9d408SJuli Mallett }
706acc9d408SJuli Mallett 
707acc9d408SJuli Mallett /*
7089b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
7099b50d902SRodney W. Grimes  */
710acc9d408SJuli Mallett static void
doifelse(const char * argv[],int argc)711bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc)
7129b50d902SRodney W. Grimes {
713e0f4e041SBaptiste Daroussin 	while (argc > 4) {
714e0f4e041SBaptiste Daroussin 		if (STREQ(argv[2], argv[3])) {
7159b50d902SRodney W. Grimes 			pbstr(argv[4]);
716e0f4e041SBaptiste Daroussin 			break;
717e0f4e041SBaptiste Daroussin 		} else if (argc == 6) {
7189b50d902SRodney W. Grimes 			pbstr(argv[5]);
719e0f4e041SBaptiste Daroussin 			break;
720e0f4e041SBaptiste Daroussin 		} else {
7219b50d902SRodney W. Grimes 			argv += 3;
7229b50d902SRodney W. Grimes 			argc -= 3;
7239b50d902SRodney W. Grimes 		}
7249b50d902SRodney W. Grimes 	}
7259b50d902SRodney W. Grimes }
7269b50d902SRodney W. Grimes 
7279b50d902SRodney W. Grimes /*
7289b50d902SRodney W. Grimes  * doinclude - include a given file.
7299b50d902SRodney W. Grimes  */
730acc9d408SJuli Mallett static int
doincl(const char * ifile)731bd2bfb58SJuli Mallett doincl(const char *ifile)
7329b50d902SRodney W. Grimes {
7339b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
734a841e1ebSBaptiste Daroussin 		m4errx(1, "too many include files.");
735acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7369b50d902SRodney W. Grimes 		ilevel++;
7379b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
7389b50d902SRodney W. Grimes 		return (1);
739acc9d408SJuli Mallett 	} else
7409b50d902SRodney W. Grimes 		return (0);
7419b50d902SRodney W. Grimes }
7429b50d902SRodney W. Grimes 
7439b50d902SRodney W. Grimes #ifdef EXTENDED
7449b50d902SRodney W. Grimes /*
7459b50d902SRodney W. Grimes  * dopaste - include a given file without any
7469b50d902SRodney W. Grimes  *           macro processing.
7479b50d902SRodney W. Grimes  */
748acc9d408SJuli Mallett static int
dopaste(const char * pfile)749bd2bfb58SJuli Mallett dopaste(const char *pfile)
7509b50d902SRodney W. Grimes {
7519b50d902SRodney W. Grimes 	FILE *pf;
752acc9d408SJuli Mallett 	int c;
7539b50d902SRodney W. Grimes 
7549b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
755a841e1ebSBaptiste Daroussin 		if (synch_lines)
756b1ea3d46SJuli Mallett 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
7579b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7589b50d902SRodney W. Grimes 			putc(c, active);
7599b50d902SRodney W. Grimes 		(void) fclose(pf);
760a841e1ebSBaptiste Daroussin 		emit_synchline();
7619b50d902SRodney W. Grimes 		return (1);
762acc9d408SJuli Mallett 	} else
7639b50d902SRodney W. Grimes 		return (0);
7649b50d902SRodney W. Grimes }
7659b50d902SRodney W. Grimes #endif
7669b50d902SRodney W. Grimes 
7679b50d902SRodney W. Grimes /*
768acc9d408SJuli Mallett  * dochq - change quote characters
7699b50d902SRodney W. Grimes  */
770acc9d408SJuli Mallett static void
dochq(const char * argv[],int ac)771a841e1ebSBaptiste Daroussin dochq(const char *argv[], int ac)
7729b50d902SRodney W. Grimes {
773a841e1ebSBaptiste Daroussin 	if (ac == 2) {
774a841e1ebSBaptiste Daroussin 		lquote[0] = LQUOTE; lquote[1] = EOS;
775a841e1ebSBaptiste Daroussin 		rquote[0] = RQUOTE; rquote[1] = EOS;
776acc9d408SJuli Mallett 	} else {
777a841e1ebSBaptiste Daroussin 		strlcpy(lquote, argv[2], sizeof(lquote));
778a841e1ebSBaptiste Daroussin 		if (ac > 3) {
779a841e1ebSBaptiste Daroussin 			strlcpy(rquote, argv[3], sizeof(rquote));
780a841e1ebSBaptiste Daroussin 		} else {
781a841e1ebSBaptiste Daroussin 			rquote[0] = ECOMMT; rquote[1] = EOS;
782a841e1ebSBaptiste Daroussin 		}
783acc9d408SJuli Mallett 	}
784acc9d408SJuli Mallett }
785acc9d408SJuli Mallett 
786acc9d408SJuli Mallett /*
787acc9d408SJuli Mallett  * dochc - change comment characters
788acc9d408SJuli Mallett  */
789acc9d408SJuli Mallett static void
dochc(const char * argv[],int argc)790bd2bfb58SJuli Mallett dochc(const char *argv[], int argc)
791acc9d408SJuli Mallett {
792a841e1ebSBaptiste Daroussin /* XXX Note that there is no difference between no argument and a single
793a841e1ebSBaptiste Daroussin  * empty argument.
794a841e1ebSBaptiste Daroussin  */
795a841e1ebSBaptiste Daroussin 	if (argc == 2) {
796a841e1ebSBaptiste Daroussin 		scommt[0] = EOS;
797a841e1ebSBaptiste Daroussin 		ecommt[0] = EOS;
798a841e1ebSBaptiste Daroussin 	} else {
799acc9d408SJuli Mallett 		strlcpy(scommt, argv[2], sizeof(scommt));
800a841e1ebSBaptiste Daroussin 		if (argc == 3) {
801a841e1ebSBaptiste Daroussin 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
802a841e1ebSBaptiste Daroussin 		} else {
803acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
8049b50d902SRodney W. Grimes 		}
805a841e1ebSBaptiste Daroussin 	}
806a841e1ebSBaptiste Daroussin }
807a841e1ebSBaptiste Daroussin 
808a841e1ebSBaptiste Daroussin /*
809a841e1ebSBaptiste Daroussin  * dom4wrap - expand text at EOF
810a841e1ebSBaptiste Daroussin  */
811a841e1ebSBaptiste Daroussin static void
dom4wrap(const char * text)812a841e1ebSBaptiste Daroussin dom4wrap(const char *text)
813a841e1ebSBaptiste Daroussin {
814a841e1ebSBaptiste Daroussin 	if (wrapindex >= maxwraps) {
815a841e1ebSBaptiste Daroussin 		if (maxwraps == 0)
816a841e1ebSBaptiste Daroussin 			maxwraps = 16;
8179b50d902SRodney W. Grimes 		else
818a841e1ebSBaptiste Daroussin 			maxwraps *= 2;
81988497f0cSBaptiste Daroussin 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
820a841e1ebSBaptiste Daroussin 		   "too many m4wraps");
8219b50d902SRodney W. Grimes 	}
822a841e1ebSBaptiste Daroussin 	m4wraps[wrapindex++] = xstrdup(text);
8239b50d902SRodney W. Grimes }
8249b50d902SRodney W. Grimes 
8259b50d902SRodney W. Grimes /*
8269b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8279b50d902SRodney W. Grimes  */
828acc9d408SJuli Mallett static void
dodiv(int n)829bd2bfb58SJuli Mallett dodiv(int n)
8309b50d902SRodney W. Grimes {
831acc9d408SJuli Mallett 	int fd;
832acc9d408SJuli Mallett 
833ef2cea81SJonathan Lemon 	oindex = n;
834acc9d408SJuli Mallett 	if (n >= maxout) {
835acc9d408SJuli Mallett 		if (mimic_gnu)
836acc9d408SJuli Mallett 			resizedivs(n + 10);
837acc9d408SJuli Mallett 		else
838acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
839acc9d408SJuli Mallett 	}
840acc9d408SJuli Mallett 
841acc9d408SJuli Mallett 	if (n < 0)
8429b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
8439b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
844acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
845acc9d408SJuli Mallett 
846*c57596e1SBaptiste Daroussin 		if ((fd = mkstemp(fname)) == -1 ||
84788497f0cSBaptiste Daroussin 		    unlink(fname) == -1 ||
848acc9d408SJuli Mallett 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
849acc9d408SJuli Mallett 			err(1, "%s: cannot divert", fname);
8509b50d902SRodney W. Grimes 	}
8519b50d902SRodney W. Grimes 	active = outfile[n];
8529b50d902SRodney W. Grimes }
8539b50d902SRodney W. Grimes 
8549b50d902SRodney W. Grimes /*
8559b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
8569b50d902SRodney W. Grimes  *              other outputs, in numerical order.
8579b50d902SRodney W. Grimes  */
858acc9d408SJuli Mallett static void
doundiv(const char * argv[],int argc)859bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc)
8609b50d902SRodney W. Grimes {
861acc9d408SJuli Mallett 	int ind;
862acc9d408SJuli Mallett 	int n;
8639b50d902SRodney W. Grimes 
8649b50d902SRodney W. Grimes 	if (argc > 2) {
8659b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
866a841e1ebSBaptiste Daroussin 			const char *errstr;
867a841e1ebSBaptiste Daroussin 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
868a841e1ebSBaptiste Daroussin 			if (errstr) {
869a841e1ebSBaptiste Daroussin 				if (errno == EINVAL && mimic_gnu)
870a841e1ebSBaptiste Daroussin 					getdivfile(argv[ind]);
871a841e1ebSBaptiste Daroussin 			} else {
872a841e1ebSBaptiste Daroussin 				if (n < maxout && outfile[n] != NULL)
8739b50d902SRodney W. Grimes 					getdiv(n);
874a841e1ebSBaptiste Daroussin 			}
8759b50d902SRodney W. Grimes 		}
8769b50d902SRodney W. Grimes 	}
8779b50d902SRodney W. Grimes 	else
878acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
8799b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
8809b50d902SRodney W. Grimes 				getdiv(n);
8819b50d902SRodney W. Grimes }
8829b50d902SRodney W. Grimes 
8839b50d902SRodney W. Grimes /*
8849b50d902SRodney W. Grimes  * dosub - select substring
8859b50d902SRodney W. Grimes  */
886acc9d408SJuli Mallett static void
dosub(const char * argv[],int argc)887bd2bfb58SJuli Mallett dosub(const char *argv[], int argc)
8889b50d902SRodney W. Grimes {
889acc9d408SJuli Mallett 	const char *ap, *fc, *k;
890acc9d408SJuli Mallett 	int nc;
8919b50d902SRodney W. Grimes 
8929b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
8939b50d902SRodney W. Grimes #ifdef EXPR
8949b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
8959b50d902SRodney W. Grimes #else
8969b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
8979b50d902SRodney W. Grimes #endif
8984ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
899acc9d408SJuli Mallett 	if (argc >= 5)
9004ba4d387SGregory Neil Shapiro #ifdef EXPR
901acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
9024ba4d387SGregory Neil Shapiro #else
903acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
9044ba4d387SGregory Neil Shapiro #endif
9059b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
9064ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
907a841e1ebSBaptiste Daroussin 			pushback(*k);
9089b50d902SRodney W. Grimes }
9099b50d902SRodney W. Grimes 
9109b50d902SRodney W. Grimes /*
9119b50d902SRodney W. Grimes  * map:
9129b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
9139b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
9149b50d902SRodney W. Grimes  *
915a841e1ebSBaptiste Daroussin  * This is derived from the a standard implementation of map(s,from,to)
916a841e1ebSBaptiste Daroussin  * function of ICON language. Within mapvec, we replace every character
917a841e1ebSBaptiste Daroussin  * of "from" with the corresponding character in "to".
918a841e1ebSBaptiste Daroussin  * If "to" is shorter than "from", than the corresponding entries are null,
919af7ca7c8SPedro F. Giffuni  * which means that those characters disappear altogether.
9209b50d902SRodney W. Grimes  */
921acc9d408SJuli Mallett static void
map(char * dest,const char * src,const char * from,const char * to)922bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to)
9239b50d902SRodney W. Grimes {
924acc9d408SJuli Mallett 	const char *tmp;
925acc9d408SJuli Mallett 	unsigned char sch, dch;
926acc9d408SJuli Mallett 	static char frombis[257];
927acc9d408SJuli Mallett 	static char tobis[257];
928a841e1ebSBaptiste Daroussin 	int i;
929a841e1ebSBaptiste Daroussin 	char seen[256];
930acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
931acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
932acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
933acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
934acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
935acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
936acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
937acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
938acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
939acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
940acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
941acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
942acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
943acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
944acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
945acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
946acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
947acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
948acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9499b50d902SRodney W. Grimes 	};
9509b50d902SRodney W. Grimes 
9519b50d902SRodney W. Grimes 	if (*src) {
952acc9d408SJuli Mallett 		if (mimic_gnu) {
953acc9d408SJuli Mallett 			/*
954acc9d408SJuli Mallett 			 * expand character ranges on the fly
955acc9d408SJuli Mallett 			 */
956acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
957acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
958acc9d408SJuli Mallett 		}
9599b50d902SRodney W. Grimes 		tmp = from;
9609b50d902SRodney W. Grimes 	/*
9619b50d902SRodney W. Grimes 	 * create a mapping between "from" and
9629b50d902SRodney W. Grimes 	 * "to"
9639b50d902SRodney W. Grimes 	 */
964a841e1ebSBaptiste Daroussin 		for (i = 0; i < 256; i++)
965a841e1ebSBaptiste Daroussin 			seen[i] = 0;
966a841e1ebSBaptiste Daroussin 		while (*from) {
967a841e1ebSBaptiste Daroussin 			if (!seen[(unsigned char)(*from)]) {
968a841e1ebSBaptiste Daroussin 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
969a841e1ebSBaptiste Daroussin 				seen[(unsigned char)(*from)] = 1;
970a841e1ebSBaptiste Daroussin 			}
971a841e1ebSBaptiste Daroussin 			from++;
972a841e1ebSBaptiste Daroussin 			if (*to)
973a841e1ebSBaptiste Daroussin 				to++;
974a841e1ebSBaptiste Daroussin 		}
9759b50d902SRodney W. Grimes 
9769b50d902SRodney W. Grimes 		while (*src) {
977acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
9789b50d902SRodney W. Grimes 			dch = mapvec[sch];
979acc9d408SJuli Mallett 			if ((*dest = (char)dch))
9809b50d902SRodney W. Grimes 				dest++;
9819b50d902SRodney W. Grimes 		}
9829b50d902SRodney W. Grimes 	/*
9839b50d902SRodney W. Grimes 	 * restore all the changed characters
9849b50d902SRodney W. Grimes 	 */
9859b50d902SRodney W. Grimes 		while (*tmp) {
986acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9879b50d902SRodney W. Grimes 			tmp++;
9889b50d902SRodney W. Grimes 		}
9899b50d902SRodney W. Grimes 	}
990acc9d408SJuli Mallett 	*dest = '\0';
9919b50d902SRodney W. Grimes }
992acc9d408SJuli Mallett 
993acc9d408SJuli Mallett 
994acc9d408SJuli Mallett /*
995acc9d408SJuli Mallett  * handledash:
996acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
997acc9d408SJuli Mallett  * on the way.
998acc9d408SJuli Mallett  */
999acc9d408SJuli Mallett static const char *
handledash(char * buffer,char * end,const char * src)1000bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src)
1001acc9d408SJuli Mallett {
1002acc9d408SJuli Mallett 	char *p;
1003acc9d408SJuli Mallett 
1004acc9d408SJuli Mallett 	p = buffer;
1005acc9d408SJuli Mallett 	while(*src) {
1006acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
1007acc9d408SJuli Mallett 			unsigned char i;
1008a841e1ebSBaptiste Daroussin 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
1009acc9d408SJuli Mallett 				for (i = (unsigned char)src[0];
1010acc9d408SJuli Mallett 				    i <= (unsigned char)src[2]; i++) {
1011acc9d408SJuli Mallett 					*p++ = i;
1012acc9d408SJuli Mallett 					if (p == end) {
1013acc9d408SJuli Mallett 						*p = '\0';
1014acc9d408SJuli Mallett 						return buffer;
1015acc9d408SJuli Mallett 					}
1016acc9d408SJuli Mallett 				}
1017a841e1ebSBaptiste Daroussin 			} else {
1018a841e1ebSBaptiste Daroussin 				for (i = (unsigned char)src[0];
1019a841e1ebSBaptiste Daroussin 				    i >= (unsigned char)src[2]; i--) {
1020a841e1ebSBaptiste Daroussin 					*p++ = i;
1021a841e1ebSBaptiste Daroussin 					if (p == end) {
1022a841e1ebSBaptiste Daroussin 						*p = '\0';
1023a841e1ebSBaptiste Daroussin 						return buffer;
1024a841e1ebSBaptiste Daroussin 					}
1025a841e1ebSBaptiste Daroussin 				}
1026a841e1ebSBaptiste Daroussin 			}
1027acc9d408SJuli Mallett 			src += 3;
1028acc9d408SJuli Mallett 		} else
1029acc9d408SJuli Mallett 			*p++ = *src++;
1030acc9d408SJuli Mallett 		if (p == end)
1031acc9d408SJuli Mallett 			break;
1032acc9d408SJuli Mallett 	}
1033acc9d408SJuli Mallett 	*p = '\0';
1034acc9d408SJuli Mallett 	return buffer;
1035acc9d408SJuli Mallett }
1036