xref: /freebsd/usr.bin/m4/eval.c (revision fb3f3d7caf95b5a4ed1708ebaf7291330a6e249d)
1a841e1ebSBaptiste Daroussin /*	$OpenBSD: eval.c,v 1.69 2011/03/24 11:23:08 espie Exp $	*/
2acc9d408SJuli Mallett /*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
3acc9d408SJuli Mallett 
49b50d902SRodney W. Grimes /*
59b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
69b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
99b50d902SRodney W. Grimes  * Ozan Yigit at York University.
109b50d902SRodney W. Grimes  *
119b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
129b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
139b50d902SRodney W. Grimes  * are met:
149b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
159b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
169b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
179b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
189b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19a841e1ebSBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
209b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
219b50d902SRodney W. Grimes  *    without specific prior written permission.
229b50d902SRodney W. Grimes  *
239b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
249b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
259b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
269b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
279b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
289b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
299b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
309b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
319b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
329b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
339b50d902SRodney W. Grimes  * SUCH DAMAGE.
349b50d902SRodney W. Grimes  */
359b50d902SRodney W. Grimes 
36acc9d408SJuli Mallett #include <sys/cdefs.h>
37acc9d408SJuli Mallett __FBSDID("$FreeBSD$");
389b50d902SRodney W. Grimes 
39a841e1ebSBaptiste Daroussin 
409b50d902SRodney W. Grimes /*
419b50d902SRodney W. Grimes  * eval.c
429b50d902SRodney W. Grimes  * Facility: m4 macro processor
439b50d902SRodney W. Grimes  * by: oz
449b50d902SRodney W. Grimes  */
459b50d902SRodney W. Grimes 
469b50d902SRodney W. Grimes #include <sys/types.h>
47a841e1ebSBaptiste Daroussin #include <err.h>
48acc9d408SJuli Mallett #include <errno.h>
49a841e1ebSBaptiste Daroussin #include <limits.h>
50acc9d408SJuli Mallett #include <unistd.h>
51a841e1ebSBaptiste Daroussin #include <stdint.h>
529b50d902SRodney W. Grimes #include <stdio.h>
539b50d902SRodney W. Grimes #include <stdlib.h>
54acc9d408SJuli Mallett #include <stddef.h>
559b50d902SRodney W. Grimes #include <string.h>
56acc9d408SJuli Mallett #include <fcntl.h>
579b50d902SRodney W. Grimes #include "mdef.h"
589b50d902SRodney W. Grimes #include "stdd.h"
599b50d902SRodney W. Grimes #include "extern.h"
609b50d902SRodney W. Grimes #include "pathnames.h"
619b50d902SRodney W. Grimes 
62acc9d408SJuli Mallett static void	dodefn(const char *);
63acc9d408SJuli Mallett static void	dopushdef(const char *, const char *);
64acc9d408SJuli Mallett static void	dodump(const char *[], int);
65acc9d408SJuli Mallett static void	dotrace(const char *[], int, int);
66acc9d408SJuli Mallett static void	doifelse(const char *[], int);
67acc9d408SJuli Mallett static int	doincl(const char *);
68acc9d408SJuli Mallett static int	dopaste(const char *);
69acc9d408SJuli Mallett static void	dochq(const char *[], int);
70acc9d408SJuli Mallett static void	dochc(const char *[], int);
71a841e1ebSBaptiste Daroussin static void	dom4wrap(const char *);
72acc9d408SJuli Mallett static void	dodiv(int);
73acc9d408SJuli Mallett static void	doundiv(const char *[], int);
74acc9d408SJuli Mallett static void	dosub(const char *[], int);
75acc9d408SJuli Mallett static void	map(char *, const char *, const char *, const char *);
76acc9d408SJuli Mallett static const char *handledash(char *, char *, const char *);
77acc9d408SJuli Mallett static void	expand_builtin(const char *[], int, int);
78acc9d408SJuli Mallett static void	expand_macro(const char *[], int);
79a841e1ebSBaptiste Daroussin static void	dump_one_def(const char *, struct macro_definition *);
80acc9d408SJuli Mallett 
81acc9d408SJuli Mallett unsigned long	expansion_id;
82acc9d408SJuli Mallett 
839b50d902SRodney W. Grimes /*
84acc9d408SJuli Mallett  * eval - eval all macros and builtins calls
859b50d902SRodney W. Grimes  *	  argc - number of elements in argv.
869b50d902SRodney W. Grimes  *	  argv - element vector :
879b50d902SRodney W. Grimes  *			argv[0] = definition of a user
88a841e1ebSBaptiste Daroussin  *				  macro or NULL if built-in.
899b50d902SRodney W. Grimes  *			argv[1] = name of the macro or
909b50d902SRodney W. Grimes  *				  built-in.
919b50d902SRodney W. Grimes  *			argv[2] = parameters to user-defined
929b50d902SRodney W. Grimes  *			   .	  macro or built-in.
939b50d902SRodney W. Grimes  *			   .
949b50d902SRodney W. Grimes  *
95acc9d408SJuli Mallett  * A call in the form of macro-or-builtin() will result in:
969b50d902SRodney W. Grimes  *			argv[0] = nullstr
979b50d902SRodney W. Grimes  *			argv[1] = macro-or-builtin
989b50d902SRodney W. Grimes  *			argv[2] = nullstr
99acc9d408SJuli Mallett  *
100acc9d408SJuli Mallett  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1019b50d902SRodney W. Grimes  */
1029b50d902SRodney W. Grimes void
103a841e1ebSBaptiste Daroussin eval(const char *argv[], int argc, int td, int is_traced)
1049b50d902SRodney W. Grimes {
105a841e1ebSBaptiste Daroussin 	size_t mark = SIZE_MAX;
106acc9d408SJuli Mallett 
107acc9d408SJuli Mallett 	expansion_id++;
108acc9d408SJuli Mallett 	if (td & RECDEF)
109a841e1ebSBaptiste Daroussin 		m4errx(1, "expanding recursive definition for %s.", argv[1]);
110a841e1ebSBaptiste Daroussin 	if (is_traced)
111acc9d408SJuli Mallett 		mark = trace(argv, argc, infile+ilevel);
112acc9d408SJuli Mallett 	if (td == MACRTYPE)
113acc9d408SJuli Mallett 		expand_macro(argv, argc);
114acc9d408SJuli Mallett 	else
115acc9d408SJuli Mallett 		expand_builtin(argv, argc, td);
116a841e1ebSBaptiste Daroussin 	if (mark != SIZE_MAX)
117acc9d408SJuli Mallett 		finish_trace(mark);
118acc9d408SJuli Mallett }
119acc9d408SJuli Mallett 
120acc9d408SJuli Mallett /*
121acc9d408SJuli Mallett  * expand_builtin - evaluate built-in macros.
122acc9d408SJuli Mallett  */
123acc9d408SJuli Mallett void
124bd2bfb58SJuli Mallett expand_builtin(const char *argv[], int argc, int td)
125acc9d408SJuli Mallett {
126acc9d408SJuli Mallett 	int c, n;
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) {
187a841e1ebSBaptiste Daroussin 				m4errx(1, "expr: base %s invalid.", argv[3]);
188a841e1ebSBaptiste Daroussin 			}
189a841e1ebSBaptiste Daroussin 		}
190a841e1ebSBaptiste Daroussin 		if (argc > 4) {
191a841e1ebSBaptiste Daroussin 			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
192a841e1ebSBaptiste Daroussin 			if (errstr) {
193a841e1ebSBaptiste Daroussin 				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
194a841e1ebSBaptiste Daroussin 			}
195a841e1ebSBaptiste Daroussin 		}
1969b50d902SRodney W. Grimes 		if (argc > 2)
197a841e1ebSBaptiste Daroussin 			pbnumbase(expr(argv[2]), base, maxdigits);
1989b50d902SRodney W. Grimes 		break;
199a841e1ebSBaptiste Daroussin 	}
2009b50d902SRodney W. Grimes 
2019b50d902SRodney W. Grimes 	case IFELTYPE:
2029b50d902SRodney W. Grimes 		if (argc > 4)
2039b50d902SRodney W. Grimes 			doifelse(argv, argc);
2049b50d902SRodney W. Grimes 		break;
2059b50d902SRodney W. Grimes 
2069b50d902SRodney W. Grimes 	case IFDFTYPE:
2079b50d902SRodney W. Grimes 	/*
2089b50d902SRodney W. Grimes 	 * doifdef - select one of two
2099b50d902SRodney W. Grimes 	 * alternatives based on the existence of
2109b50d902SRodney W. Grimes 	 * another definition
2119b50d902SRodney W. Grimes 	 */
2129b50d902SRodney W. Grimes 		if (argc > 3) {
213a841e1ebSBaptiste Daroussin 			if (lookup_macro_definition(argv[2]) != NULL)
2149b50d902SRodney W. Grimes 				pbstr(argv[3]);
2159b50d902SRodney W. Grimes 			else if (argc > 4)
2169b50d902SRodney W. Grimes 				pbstr(argv[4]);
2179b50d902SRodney W. Grimes 		}
2189b50d902SRodney W. Grimes 		break;
2199b50d902SRodney W. Grimes 
2209b50d902SRodney W. Grimes 	case LENGTYPE:
2219b50d902SRodney W. Grimes 	/*
2229b50d902SRodney W. Grimes 	 * dolen - find the length of the
2239b50d902SRodney W. Grimes 	 * argument
2249b50d902SRodney W. Grimes 	 */
2259b50d902SRodney W. Grimes 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2269b50d902SRodney W. Grimes 		break;
2279b50d902SRodney W. Grimes 
2289b50d902SRodney W. Grimes 	case INCRTYPE:
2299b50d902SRodney W. Grimes 	/*
2309b50d902SRodney W. Grimes 	 * doincr - increment the value of the
2319b50d902SRodney W. Grimes 	 * argument
2329b50d902SRodney W. Grimes 	 */
2339b50d902SRodney W. Grimes 		if (argc > 2)
2349b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) + 1);
2359b50d902SRodney W. Grimes 		break;
2369b50d902SRodney W. Grimes 
2379b50d902SRodney W. Grimes 	case DECRTYPE:
2389b50d902SRodney W. Grimes 	/*
2399b50d902SRodney W. Grimes 	 * dodecr - decrement the value of the
2409b50d902SRodney W. Grimes 	 * argument
2419b50d902SRodney W. Grimes 	 */
2429b50d902SRodney W. Grimes 		if (argc > 2)
2439b50d902SRodney W. Grimes 			pbnum(atoi(argv[2]) - 1);
2449b50d902SRodney W. Grimes 		break;
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 	case SYSCTYPE:
2479b50d902SRodney W. Grimes 	/*
2489b50d902SRodney W. Grimes 	 * dosys - execute system command
2499b50d902SRodney W. Grimes 	 */
250aef4bb33STim J. Robbins 		if (argc > 2) {
251a841e1ebSBaptiste Daroussin 			fflush(stdout);
2529b50d902SRodney W. Grimes 			sysval = system(argv[2]);
253aef4bb33STim J. Robbins 		}
2549b50d902SRodney W. Grimes 		break;
2559b50d902SRodney W. Grimes 
2569b50d902SRodney W. Grimes 	case SYSVTYPE:
2579b50d902SRodney W. Grimes 	/*
2589b50d902SRodney W. Grimes 	 * dosysval - return value of the last
2599b50d902SRodney W. Grimes 	 * system call.
2609b50d902SRodney W. Grimes 	 *
2619b50d902SRodney W. Grimes 	 */
2629b50d902SRodney W. Grimes 		pbnum(sysval);
2639b50d902SRodney W. Grimes 		break;
2649b50d902SRodney W. Grimes 
265acc9d408SJuli Mallett 	case ESYSCMDTYPE:
266acc9d408SJuli Mallett 		if (argc > 2)
267acc9d408SJuli Mallett 			doesyscmd(argv[2]);
268acc9d408SJuli Mallett 		break;
2699b50d902SRodney W. Grimes 	case INCLTYPE:
2709b50d902SRodney W. Grimes 		if (argc > 2)
2712cce1b69SBjoern A. Zeeb 			if (!doincl(argv[2])) {
272*fb3f3d7cSBaptiste Daroussin 				if (mimic_gnu) {
2734fff7a14SBaptiste Daroussin 					warn("%s at line %lu: include(%s)",
2744fff7a14SBaptiste Daroussin 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
275*fb3f3d7cSBaptiste Daroussin 					exit_code = 1;
276*fb3f3d7cSBaptiste Daroussin 				} else
277acc9d408SJuli Mallett 					err(1, "%s at line %lu: include(%s)",
278acc9d408SJuli Mallett 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
2792cce1b69SBjoern A. Zeeb 			}
2809b50d902SRodney W. Grimes 		break;
2819b50d902SRodney W. Grimes 
2829b50d902SRodney W. Grimes 	case SINCTYPE:
2839b50d902SRodney W. Grimes 		if (argc > 2)
2849b50d902SRodney W. Grimes 			(void) doincl(argv[2]);
2859b50d902SRodney W. Grimes 		break;
2869b50d902SRodney W. Grimes #ifdef EXTENDED
2879b50d902SRodney W. Grimes 	case PASTTYPE:
2889b50d902SRodney W. Grimes 		if (argc > 2)
2899b50d902SRodney W. Grimes 			if (!dopaste(argv[2]))
290acc9d408SJuli Mallett 				err(1, "%s at line %lu: paste(%s)",
291acc9d408SJuli Mallett 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
2929b50d902SRodney W. Grimes 		break;
2939b50d902SRodney W. Grimes 
2949b50d902SRodney W. Grimes 	case SPASTYPE:
2959b50d902SRodney W. Grimes 		if (argc > 2)
2969b50d902SRodney W. Grimes 			(void) dopaste(argv[2]);
2979b50d902SRodney W. Grimes 		break;
298a841e1ebSBaptiste Daroussin 	case FORMATTYPE:
299a841e1ebSBaptiste Daroussin 		doformat(argv, argc);
300a841e1ebSBaptiste Daroussin 		break;
3019b50d902SRodney W. Grimes #endif
3029b50d902SRodney W. Grimes 	case CHNQTYPE:
303a841e1ebSBaptiste Daroussin 		dochq(argv, ac);
3049b50d902SRodney W. Grimes 		break;
3059b50d902SRodney W. Grimes 
3069b50d902SRodney W. Grimes 	case CHNCTYPE:
3079b50d902SRodney W. Grimes 		dochc(argv, argc);
3089b50d902SRodney W. Grimes 		break;
3099b50d902SRodney W. Grimes 
3109b50d902SRodney W. Grimes 	case SUBSTYPE:
3119b50d902SRodney W. Grimes 	/*
3129b50d902SRodney W. Grimes 	 * dosub - select substring
3139b50d902SRodney W. Grimes 	 *
3149b50d902SRodney W. Grimes 	 */
3159b50d902SRodney W. Grimes 		if (argc > 3)
3169b50d902SRodney W. Grimes 			dosub(argv, argc);
3179b50d902SRodney W. Grimes 		break;
3189b50d902SRodney W. Grimes 
3199b50d902SRodney W. Grimes 	case SHIFTYPE:
3209b50d902SRodney W. Grimes 	/*
3219b50d902SRodney W. Grimes 	 * doshift - push back all arguments
3229b50d902SRodney W. Grimes 	 * except the first one (i.e. skip
3239b50d902SRodney W. Grimes 	 * argv[2])
3249b50d902SRodney W. Grimes 	 */
3259b50d902SRodney W. Grimes 		if (argc > 3) {
3269b50d902SRodney W. Grimes 			for (n = argc - 1; n > 3; n--) {
327acc9d408SJuli Mallett 				pbstr(rquote);
3289b50d902SRodney W. Grimes 				pbstr(argv[n]);
329acc9d408SJuli Mallett 				pbstr(lquote);
330a841e1ebSBaptiste Daroussin 				pushback(COMMA);
3319b50d902SRodney W. Grimes 			}
332acc9d408SJuli Mallett 			pbstr(rquote);
3339b50d902SRodney W. Grimes 			pbstr(argv[3]);
334acc9d408SJuli Mallett 			pbstr(lquote);
3359b50d902SRodney W. Grimes 		}
3369b50d902SRodney W. Grimes 		break;
3379b50d902SRodney W. Grimes 
3389b50d902SRodney W. Grimes 	case DIVRTYPE:
3399b50d902SRodney W. Grimes 		if (argc > 2 && (n = atoi(argv[2])) != 0)
3409b50d902SRodney W. Grimes 			dodiv(n);
3419b50d902SRodney W. Grimes 		else {
3429b50d902SRodney W. Grimes 			active = stdout;
3439b50d902SRodney W. Grimes 			oindex = 0;
3449b50d902SRodney W. Grimes 		}
3459b50d902SRodney W. Grimes 		break;
3469b50d902SRodney W. Grimes 
3479b50d902SRodney W. Grimes 	case UNDVTYPE:
3489b50d902SRodney W. Grimes 		doundiv(argv, argc);
3499b50d902SRodney W. Grimes 		break;
3509b50d902SRodney W. Grimes 
3519b50d902SRodney W. Grimes 	case DIVNTYPE:
3529b50d902SRodney W. Grimes 	/*
3539b50d902SRodney W. Grimes 	 * dodivnum - return the number of
3549b50d902SRodney W. Grimes 	 * current output diversion
3559b50d902SRodney W. Grimes 	 */
3569b50d902SRodney W. Grimes 		pbnum(oindex);
3579b50d902SRodney W. Grimes 		break;
3589b50d902SRodney W. Grimes 
3599b50d902SRodney W. Grimes 	case UNDFTYPE:
3609b50d902SRodney W. Grimes 	/*
3619b50d902SRodney W. Grimes 	 * doundefine - undefine a previously
3629b50d902SRodney W. Grimes 	 * defined macro(s) or m4 keyword(s).
3639b50d902SRodney W. Grimes 	 */
3649b50d902SRodney W. Grimes 		if (argc > 2)
3659b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
366a841e1ebSBaptiste Daroussin 				macro_undefine(argv[n]);
3679b50d902SRodney W. Grimes 		break;
3689b50d902SRodney W. Grimes 
3699b50d902SRodney W. Grimes 	case POPDTYPE:
3709b50d902SRodney W. Grimes 	/*
3719b50d902SRodney W. Grimes 	 * dopopdef - remove the topmost
3729b50d902SRodney W. Grimes 	 * definitions of macro(s) or m4
3739b50d902SRodney W. Grimes 	 * keyword(s).
3749b50d902SRodney W. Grimes 	 */
3759b50d902SRodney W. Grimes 		if (argc > 2)
3769b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
377a841e1ebSBaptiste Daroussin 				macro_popdef(argv[n]);
3789b50d902SRodney W. Grimes 		break;
3799b50d902SRodney W. Grimes 
3809b50d902SRodney W. Grimes 	case MKTMTYPE:
3819b50d902SRodney W. Grimes 	/*
3829b50d902SRodney W. Grimes 	 * dotemp - create a temporary file
3839b50d902SRodney W. Grimes 	 */
384acc9d408SJuli Mallett 		if (argc > 2) {
385acc9d408SJuli Mallett 			int fd;
386acc9d408SJuli Mallett 			char *temp;
387acc9d408SJuli Mallett 
388acc9d408SJuli Mallett 			temp = xstrdup(argv[2]);
389acc9d408SJuli Mallett 
390acc9d408SJuli Mallett 			fd = mkstemp(temp);
391acc9d408SJuli Mallett 			if (fd == -1)
392acc9d408SJuli Mallett 				err(1,
393acc9d408SJuli Mallett 	    "%s at line %lu: couldn't make temp file %s",
394acc9d408SJuli Mallett 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
395acc9d408SJuli Mallett 			close(fd);
396acc9d408SJuli Mallett 			pbstr(temp);
397acc9d408SJuli Mallett 			free(temp);
398acc9d408SJuli Mallett 		}
3999b50d902SRodney W. Grimes 		break;
4009b50d902SRodney W. Grimes 
4019b50d902SRodney W. Grimes 	case TRNLTYPE:
4029b50d902SRodney W. Grimes 	/*
4039b50d902SRodney W. Grimes 	 * dotranslit - replace all characters in
4049b50d902SRodney W. Grimes 	 * the source string that appears in the
4059b50d902SRodney W. Grimes 	 * "from" string with the corresponding
4069b50d902SRodney W. Grimes 	 * characters in the "to" string.
4079b50d902SRodney W. Grimes 	 */
4089b50d902SRodney W. Grimes 		if (argc > 3) {
409acc9d408SJuli Mallett 			char *temp;
410acc9d408SJuli Mallett 
411a841e1ebSBaptiste Daroussin 			temp = xalloc(strlen(argv[2])+1, NULL);
4129b50d902SRodney W. Grimes 			if (argc > 4)
4139b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], argv[4]);
4149b50d902SRodney W. Grimes 			else
4159b50d902SRodney W. Grimes 				map(temp, argv[2], argv[3], null);
4169b50d902SRodney W. Grimes 			pbstr(temp);
417acc9d408SJuli Mallett 			free(temp);
418acc9d408SJuli Mallett 		} else if (argc > 2)
4199b50d902SRodney W. Grimes 			pbstr(argv[2]);
4209b50d902SRodney W. Grimes 		break;
4219b50d902SRodney W. Grimes 
4229b50d902SRodney W. Grimes 	case INDXTYPE:
4239b50d902SRodney W. Grimes 	/*
4249b50d902SRodney W. Grimes 	 * doindex - find the index of the second
4259b50d902SRodney W. Grimes 	 * argument string in the first argument
4269b50d902SRodney W. Grimes 	 * string. -1 if not present.
4279b50d902SRodney W. Grimes 	 */
4289b50d902SRodney W. Grimes 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4299b50d902SRodney W. Grimes 		break;
4309b50d902SRodney W. Grimes 
4319b50d902SRodney W. Grimes 	case ERRPTYPE:
4329b50d902SRodney W. Grimes 	/*
4339b50d902SRodney W. Grimes 	 * doerrp - print the arguments to stderr
4349b50d902SRodney W. Grimes 	 * file
4359b50d902SRodney W. Grimes 	 */
4369b50d902SRodney W. Grimes 		if (argc > 2) {
4379b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4389b50d902SRodney W. Grimes 				fprintf(stderr, "%s ", argv[n]);
4399b50d902SRodney W. Grimes 			fprintf(stderr, "\n");
4409b50d902SRodney W. Grimes 		}
4419b50d902SRodney W. Grimes 		break;
4429b50d902SRodney W. Grimes 
4439b50d902SRodney W. Grimes 	case DNLNTYPE:
4449b50d902SRodney W. Grimes 	/*
4459b50d902SRodney W. Grimes 	 * dodnl - eat-up-to and including
4469b50d902SRodney W. Grimes 	 * newline
4479b50d902SRodney W. Grimes 	 */
4489b50d902SRodney W. Grimes 		while ((c = gpbc()) != '\n' && c != EOF)
4499b50d902SRodney W. Grimes 			;
4509b50d902SRodney W. Grimes 		break;
4519b50d902SRodney W. Grimes 
4529b50d902SRodney W. Grimes 	case M4WRTYPE:
4539b50d902SRodney W. Grimes 	/*
4549b50d902SRodney W. Grimes 	 * dom4wrap - set up for
4559b50d902SRodney W. Grimes 	 * wrap-up/wind-down activity
4569b50d902SRodney W. Grimes 	 */
457a841e1ebSBaptiste Daroussin 		if (argc > 2)
458a841e1ebSBaptiste Daroussin 			dom4wrap(argv[2]);
4599b50d902SRodney W. Grimes 		break;
4609b50d902SRodney W. Grimes 
4619b50d902SRodney W. Grimes 	case EXITTYPE:
4629b50d902SRodney W. Grimes 	/*
4639b50d902SRodney W. Grimes 	 * doexit - immediate exit from m4.
4649b50d902SRodney W. Grimes 	 */
465cac6992aSAndrey A. Chernov 		killdiv();
4669b50d902SRodney W. Grimes 		exit((argc > 2) ? atoi(argv[2]) : 0);
4679b50d902SRodney W. Grimes 		break;
4689b50d902SRodney W. Grimes 
4699b50d902SRodney W. Grimes 	case DEFNTYPE:
4709b50d902SRodney W. Grimes 		if (argc > 2)
4719b50d902SRodney W. Grimes 			for (n = 2; n < argc; n++)
4729b50d902SRodney W. Grimes 				dodefn(argv[n]);
4739b50d902SRodney W. Grimes 		break;
4749b50d902SRodney W. Grimes 
475acc9d408SJuli Mallett 	case INDIRTYPE:	/* Indirect call */
476acc9d408SJuli Mallett 		if (argc > 2)
477acc9d408SJuli Mallett 			doindir(argv, argc);
478bbfd1447SSteve Price 		break;
479bbfd1447SSteve Price 
480acc9d408SJuli Mallett 	case BUILTINTYPE: /* Builtins only */
481acc9d408SJuli Mallett 		if (argc > 2)
482acc9d408SJuli Mallett 			dobuiltin(argv, argc);
483acc9d408SJuli Mallett 		break;
484acc9d408SJuli Mallett 
485acc9d408SJuli Mallett 	case PATSTYPE:
486acc9d408SJuli Mallett 		if (argc > 2)
487acc9d408SJuli Mallett 			dopatsubst(argv, argc);
488acc9d408SJuli Mallett 		break;
489acc9d408SJuli Mallett 	case REGEXPTYPE:
490acc9d408SJuli Mallett 		if (argc > 2)
491acc9d408SJuli Mallett 			doregexp(argv, argc);
492acc9d408SJuli Mallett 		break;
493acc9d408SJuli Mallett 	case LINETYPE:
494acc9d408SJuli Mallett 		doprintlineno(infile+ilevel);
495acc9d408SJuli Mallett 		break;
496acc9d408SJuli Mallett 	case FILENAMETYPE:
497acc9d408SJuli Mallett 		doprintfilename(infile+ilevel);
498acc9d408SJuli Mallett 		break;
499acc9d408SJuli Mallett 	case SELFTYPE:
500acc9d408SJuli Mallett 		pbstr(rquote);
501acc9d408SJuli Mallett 		pbstr(argv[1]);
502acc9d408SJuli Mallett 		pbstr(lquote);
503acc9d408SJuli Mallett 		break;
5049b50d902SRodney W. Grimes 	default:
505a841e1ebSBaptiste Daroussin 		m4errx(1, "eval: major botch.");
5069b50d902SRodney W. Grimes 		break;
5079b50d902SRodney W. Grimes 	}
5089b50d902SRodney W. Grimes }
5099b50d902SRodney W. Grimes 
5109b50d902SRodney W. Grimes /*
511acc9d408SJuli Mallett  * expand_macro - user-defined macro expansion
5129b50d902SRodney W. Grimes  */
5139b50d902SRodney W. Grimes void
514bd2bfb58SJuli Mallett expand_macro(const char *argv[], int argc)
5159b50d902SRodney W. Grimes {
516acc9d408SJuli Mallett 	const char *t;
517acc9d408SJuli Mallett 	const char *p;
518acc9d408SJuli Mallett 	int n;
519acc9d408SJuli Mallett 	int argno;
5209b50d902SRodney W. Grimes 
5219b50d902SRodney W. Grimes 	t = argv[0];		       /* defn string as a whole */
5229b50d902SRodney W. Grimes 	p = t;
5239b50d902SRodney W. Grimes 	while (*p)
5249b50d902SRodney W. Grimes 		p++;
5259b50d902SRodney W. Grimes 	p--;			       /* last character of defn */
5269b50d902SRodney W. Grimes 	while (p > t) {
5279b50d902SRodney W. Grimes 		if (*(p - 1) != ARGFLAG)
528a841e1ebSBaptiste Daroussin 			PUSHBACK(*p);
5299b50d902SRodney W. Grimes 		else {
5309b50d902SRodney W. Grimes 			switch (*p) {
5319b50d902SRodney W. Grimes 
5329b50d902SRodney W. Grimes 			case '#':
5339b50d902SRodney W. Grimes 				pbnum(argc - 2);
5349b50d902SRodney W. Grimes 				break;
5359b50d902SRodney W. Grimes 			case '0':
5369b50d902SRodney W. Grimes 			case '1':
5379b50d902SRodney W. Grimes 			case '2':
5389b50d902SRodney W. Grimes 			case '3':
5399b50d902SRodney W. Grimes 			case '4':
5409b50d902SRodney W. Grimes 			case '5':
5419b50d902SRodney W. Grimes 			case '6':
5429b50d902SRodney W. Grimes 			case '7':
5439b50d902SRodney W. Grimes 			case '8':
5449b50d902SRodney W. Grimes 			case '9':
5459b50d902SRodney W. Grimes 				if ((argno = *p - '0') < argc - 1)
5469b50d902SRodney W. Grimes 					pbstr(argv[argno + 1]);
5479b50d902SRodney W. Grimes 				break;
5489b50d902SRodney W. Grimes 			case '*':
549acc9d408SJuli Mallett 				if (argc > 2) {
5509b50d902SRodney W. Grimes 					for (n = argc - 1; n > 2; n--) {
5519b50d902SRodney W. Grimes 						pbstr(argv[n]);
552a841e1ebSBaptiste Daroussin 						pushback(COMMA);
5539b50d902SRodney W. Grimes 					}
5549b50d902SRodney W. Grimes 					pbstr(argv[2]);
555acc9d408SJuli Mallett 				}
5569b50d902SRodney W. Grimes 				break;
557232eaee6SJoerg Wunsch                         case '@':
558acc9d408SJuli Mallett 				if (argc > 2) {
559acc9d408SJuli Mallett 					for (n = argc - 1; n > 2; n--) {
560acc9d408SJuli Mallett 						pbstr(rquote);
561232eaee6SJoerg Wunsch 						pbstr(argv[n]);
562acc9d408SJuli Mallett 						pbstr(lquote);
563a841e1ebSBaptiste Daroussin 						pushback(COMMA);
564acc9d408SJuli Mallett 					}
565acc9d408SJuli Mallett 					pbstr(rquote);
566acc9d408SJuli Mallett 					pbstr(argv[2]);
567acc9d408SJuli Mallett 					pbstr(lquote);
568232eaee6SJoerg Wunsch 				}
569232eaee6SJoerg Wunsch                                 break;
5709b50d902SRodney W. Grimes 			default:
571a841e1ebSBaptiste Daroussin 				PUSHBACK(*p);
572a841e1ebSBaptiste Daroussin 				PUSHBACK('$');
5739b50d902SRodney W. Grimes 				break;
5749b50d902SRodney W. Grimes 			}
5759b50d902SRodney W. Grimes 			p--;
5769b50d902SRodney W. Grimes 		}
5779b50d902SRodney W. Grimes 		p--;
5789b50d902SRodney W. Grimes 	}
5799b50d902SRodney W. Grimes 	if (p == t)		       /* do last character */
580a841e1ebSBaptiste Daroussin 		PUSHBACK(*p);
5819b50d902SRodney W. Grimes }
5829b50d902SRodney W. Grimes 
583a841e1ebSBaptiste Daroussin 
5849b50d902SRodney W. Grimes /*
5859b50d902SRodney W. Grimes  * dodefine - install definition in the table
5869b50d902SRodney W. Grimes  */
5879b50d902SRodney W. Grimes void
588bd2bfb58SJuli Mallett dodefine(const char *name, const char *defn)
5899b50d902SRodney W. Grimes {
590a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
591a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
5929b50d902SRodney W. Grimes 	else
593a841e1ebSBaptiste Daroussin 		macro_define(name, defn);
5949b50d902SRodney W. Grimes }
5959b50d902SRodney W. Grimes 
5969b50d902SRodney W. Grimes /*
5979b50d902SRodney W. Grimes  * dodefn - push back a quoted definition of
5989b50d902SRodney W. Grimes  *      the given name.
5999b50d902SRodney W. Grimes  */
600acc9d408SJuli Mallett static void
601bd2bfb58SJuli Mallett dodefn(const char *name)
6029b50d902SRodney W. Grimes {
603a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6049b50d902SRodney W. Grimes 
605a841e1ebSBaptiste Daroussin 	if ((p = lookup_macro_definition(name)) != NULL) {
606a841e1ebSBaptiste Daroussin 		if ((p->type & TYPEMASK) == MACRTYPE) {
607acc9d408SJuli Mallett 			pbstr(rquote);
6089b50d902SRodney W. Grimes 			pbstr(p->defn);
609acc9d408SJuli Mallett 			pbstr(lquote);
610a841e1ebSBaptiste Daroussin 		} else {
611a841e1ebSBaptiste Daroussin 			pbstr(p->defn);
612acc9d408SJuli Mallett 			pbstr(BUILTIN_MARKER);
613acc9d408SJuli Mallett 		}
6149b50d902SRodney W. Grimes 	}
6159b50d902SRodney W. Grimes }
6169b50d902SRodney W. Grimes 
6179b50d902SRodney W. Grimes /*
6189b50d902SRodney W. Grimes  * dopushdef - install a definition in the hash table
6199b50d902SRodney W. Grimes  *      without removing a previous definition. Since
6209b50d902SRodney W. Grimes  *      each new entry is entered in *front* of the
6219b50d902SRodney W. Grimes  *      hash bucket, it hides a previous definition from
6229b50d902SRodney W. Grimes  *      lookup.
6239b50d902SRodney W. Grimes  */
624acc9d408SJuli Mallett static void
625bd2bfb58SJuli Mallett dopushdef(const char *name, const char *defn)
6269b50d902SRodney W. Grimes {
627a841e1ebSBaptiste Daroussin 	if (!*name && !mimic_gnu)
628a841e1ebSBaptiste Daroussin 		m4errx(1, "null definition.");
6299b50d902SRodney W. Grimes 	else
630a841e1ebSBaptiste Daroussin 		macro_pushdef(name, defn);
631acc9d408SJuli Mallett }
632acc9d408SJuli Mallett 
633acc9d408SJuli Mallett /*
634acc9d408SJuli Mallett  * dump_one_def - dump the specified definition.
635acc9d408SJuli Mallett  */
636acc9d408SJuli Mallett static void
637a841e1ebSBaptiste Daroussin dump_one_def(const char *name, struct macro_definition *p)
638acc9d408SJuli Mallett {
639a841e1ebSBaptiste Daroussin 	if (!traceout)
640a841e1ebSBaptiste Daroussin 		traceout = stderr;
641acc9d408SJuli Mallett 	if (mimic_gnu) {
642acc9d408SJuli Mallett 		if ((p->type & TYPEMASK) == MACRTYPE)
643a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
644acc9d408SJuli Mallett 		else {
645a841e1ebSBaptiste Daroussin 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
646acc9d408SJuli Mallett 		}
647acc9d408SJuli Mallett 	} else
648a841e1ebSBaptiste Daroussin 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
6499b50d902SRodney W. Grimes }
6509b50d902SRodney W. Grimes 
6519b50d902SRodney W. Grimes /*
6529b50d902SRodney W. Grimes  * dodumpdef - dump the specified definitions in the hash
6539b50d902SRodney W. Grimes  *      table to stderr. If nothing is specified, the entire
6549b50d902SRodney W. Grimes  *      hash table is dumped.
6559b50d902SRodney W. Grimes  */
656acc9d408SJuli Mallett static void
657bd2bfb58SJuli Mallett dodump(const char *argv[], int argc)
6589b50d902SRodney W. Grimes {
659acc9d408SJuli Mallett 	int n;
660a841e1ebSBaptiste Daroussin 	struct macro_definition *p;
6619b50d902SRodney W. Grimes 
6629b50d902SRodney W. Grimes 	if (argc > 2) {
6639b50d902SRodney W. Grimes 		for (n = 2; n < argc; n++)
664a841e1ebSBaptiste Daroussin 			if ((p = lookup_macro_definition(argv[n])) != NULL)
665a841e1ebSBaptiste Daroussin 				dump_one_def(argv[n], p);
666a841e1ebSBaptiste Daroussin 	} else
667a841e1ebSBaptiste Daroussin 		macro_for_all(dump_one_def);
6689b50d902SRodney W. Grimes }
6699b50d902SRodney W. Grimes 
6709b50d902SRodney W. Grimes /*
671acc9d408SJuli Mallett  * dotrace - mark some macros as traced/untraced depending upon on.
672acc9d408SJuli Mallett  */
673acc9d408SJuli Mallett static void
674bd2bfb58SJuli Mallett dotrace(const char *argv[], int argc, int on)
675acc9d408SJuli Mallett {
676acc9d408SJuli Mallett 	int n;
677acc9d408SJuli Mallett 
678acc9d408SJuli Mallett 	if (argc > 2) {
679acc9d408SJuli Mallett 		for (n = 2; n < argc; n++)
680acc9d408SJuli Mallett 			mark_traced(argv[n], on);
681acc9d408SJuli Mallett 	} else
682acc9d408SJuli Mallett 		mark_traced(NULL, on);
683acc9d408SJuli Mallett }
684acc9d408SJuli Mallett 
685acc9d408SJuli Mallett /*
6869b50d902SRodney W. Grimes  * doifelse - select one of two alternatives - loop.
6879b50d902SRodney W. Grimes  */
688acc9d408SJuli Mallett static void
689bd2bfb58SJuli Mallett doifelse(const char *argv[], int argc)
6909b50d902SRodney W. Grimes {
6919b50d902SRodney W. Grimes 	cycle {
6929b50d902SRodney W. Grimes 		if (STREQ(argv[2], argv[3]))
6939b50d902SRodney W. Grimes 			pbstr(argv[4]);
6949b50d902SRodney W. Grimes 		else if (argc == 6)
6959b50d902SRodney W. Grimes 			pbstr(argv[5]);
6969b50d902SRodney W. Grimes 		else if (argc > 6) {
6979b50d902SRodney W. Grimes 			argv += 3;
6989b50d902SRodney W. Grimes 			argc -= 3;
6999b50d902SRodney W. Grimes 			continue;
7009b50d902SRodney W. Grimes 		}
7019b50d902SRodney W. Grimes 		break;
7029b50d902SRodney W. Grimes 	}
7039b50d902SRodney W. Grimes }
7049b50d902SRodney W. Grimes 
7059b50d902SRodney W. Grimes /*
7069b50d902SRodney W. Grimes  * doinclude - include a given file.
7079b50d902SRodney W. Grimes  */
708acc9d408SJuli Mallett static int
709bd2bfb58SJuli Mallett doincl(const char *ifile)
7109b50d902SRodney W. Grimes {
7119b50d902SRodney W. Grimes 	if (ilevel + 1 == MAXINP)
712a841e1ebSBaptiste Daroussin 		m4errx(1, "too many include files.");
713acc9d408SJuli Mallett 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7149b50d902SRodney W. Grimes 		ilevel++;
7159b50d902SRodney W. Grimes 		bbase[ilevel] = bufbase = bp;
7169b50d902SRodney W. Grimes 		return (1);
717acc9d408SJuli Mallett 	} else
7189b50d902SRodney W. Grimes 		return (0);
7199b50d902SRodney W. Grimes }
7209b50d902SRodney W. Grimes 
7219b50d902SRodney W. Grimes #ifdef EXTENDED
7229b50d902SRodney W. Grimes /*
7239b50d902SRodney W. Grimes  * dopaste - include a given file without any
7249b50d902SRodney W. Grimes  *           macro processing.
7259b50d902SRodney W. Grimes  */
726acc9d408SJuli Mallett static int
727bd2bfb58SJuli Mallett dopaste(const char *pfile)
7289b50d902SRodney W. Grimes {
7299b50d902SRodney W. Grimes 	FILE *pf;
730acc9d408SJuli Mallett 	int c;
7319b50d902SRodney W. Grimes 
7329b50d902SRodney W. Grimes 	if ((pf = fopen(pfile, "r")) != NULL) {
733a841e1ebSBaptiste Daroussin 		if (synch_lines)
734b1ea3d46SJuli Mallett 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
7359b50d902SRodney W. Grimes 		while ((c = getc(pf)) != EOF)
7369b50d902SRodney W. Grimes 			putc(c, active);
7379b50d902SRodney W. Grimes 		(void) fclose(pf);
738a841e1ebSBaptiste Daroussin 		emit_synchline();
7399b50d902SRodney W. Grimes 		return (1);
740acc9d408SJuli Mallett 	} else
7419b50d902SRodney W. Grimes 		return (0);
7429b50d902SRodney W. Grimes }
7439b50d902SRodney W. Grimes #endif
7449b50d902SRodney W. Grimes 
7459b50d902SRodney W. Grimes /*
746acc9d408SJuli Mallett  * dochq - change quote characters
7479b50d902SRodney W. Grimes  */
748acc9d408SJuli Mallett static void
749a841e1ebSBaptiste Daroussin dochq(const char *argv[], int ac)
7509b50d902SRodney W. Grimes {
751a841e1ebSBaptiste Daroussin 	if (ac == 2) {
752a841e1ebSBaptiste Daroussin 		lquote[0] = LQUOTE; lquote[1] = EOS;
753a841e1ebSBaptiste Daroussin 		rquote[0] = RQUOTE; rquote[1] = EOS;
754acc9d408SJuli Mallett 	} else {
755a841e1ebSBaptiste Daroussin 		strlcpy(lquote, argv[2], sizeof(lquote));
756a841e1ebSBaptiste Daroussin 		if (ac > 3) {
757a841e1ebSBaptiste Daroussin 			strlcpy(rquote, argv[3], sizeof(rquote));
758a841e1ebSBaptiste Daroussin 		} else {
759a841e1ebSBaptiste Daroussin 			rquote[0] = ECOMMT; rquote[1] = EOS;
760a841e1ebSBaptiste Daroussin 		}
761acc9d408SJuli Mallett 	}
762acc9d408SJuli Mallett }
763acc9d408SJuli Mallett 
764acc9d408SJuli Mallett /*
765acc9d408SJuli Mallett  * dochc - change comment characters
766acc9d408SJuli Mallett  */
767acc9d408SJuli Mallett static void
768bd2bfb58SJuli Mallett dochc(const char *argv[], int argc)
769acc9d408SJuli Mallett {
770a841e1ebSBaptiste Daroussin /* XXX Note that there is no difference between no argument and a single
771a841e1ebSBaptiste Daroussin  * empty argument.
772a841e1ebSBaptiste Daroussin  */
773a841e1ebSBaptiste Daroussin 	if (argc == 2) {
774a841e1ebSBaptiste Daroussin 		scommt[0] = EOS;
775a841e1ebSBaptiste Daroussin 		ecommt[0] = EOS;
776a841e1ebSBaptiste Daroussin 	} else {
777acc9d408SJuli Mallett 		strlcpy(scommt, argv[2], sizeof(scommt));
778a841e1ebSBaptiste Daroussin 		if (argc == 3) {
779a841e1ebSBaptiste Daroussin 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
780a841e1ebSBaptiste Daroussin 		} else {
781acc9d408SJuli Mallett 			strlcpy(ecommt, argv[3], sizeof(ecommt));
7829b50d902SRodney W. Grimes 		}
783a841e1ebSBaptiste Daroussin 	}
784a841e1ebSBaptiste Daroussin }
785a841e1ebSBaptiste Daroussin 
786a841e1ebSBaptiste Daroussin /*
787a841e1ebSBaptiste Daroussin  * dom4wrap - expand text at EOF
788a841e1ebSBaptiste Daroussin  */
789a841e1ebSBaptiste Daroussin static void
790a841e1ebSBaptiste Daroussin dom4wrap(const char *text)
791a841e1ebSBaptiste Daroussin {
792a841e1ebSBaptiste Daroussin 	if (wrapindex >= maxwraps) {
793a841e1ebSBaptiste Daroussin 		if (maxwraps == 0)
794a841e1ebSBaptiste Daroussin 			maxwraps = 16;
7959b50d902SRodney W. Grimes 		else
796a841e1ebSBaptiste Daroussin 			maxwraps *= 2;
797a841e1ebSBaptiste Daroussin 		m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
798a841e1ebSBaptiste Daroussin 		   "too many m4wraps");
7999b50d902SRodney W. Grimes 	}
800a841e1ebSBaptiste Daroussin 	m4wraps[wrapindex++] = xstrdup(text);
8019b50d902SRodney W. Grimes }
8029b50d902SRodney W. Grimes 
8039b50d902SRodney W. Grimes /*
8049b50d902SRodney W. Grimes  * dodivert - divert the output to a temporary file
8059b50d902SRodney W. Grimes  */
806acc9d408SJuli Mallett static void
807bd2bfb58SJuli Mallett dodiv(int n)
8089b50d902SRodney W. Grimes {
809acc9d408SJuli Mallett 	int fd;
810acc9d408SJuli Mallett 
811ef2cea81SJonathan Lemon 	oindex = n;
812acc9d408SJuli Mallett 	if (n >= maxout) {
813acc9d408SJuli Mallett 		if (mimic_gnu)
814acc9d408SJuli Mallett 			resizedivs(n + 10);
815acc9d408SJuli Mallett 		else
816acc9d408SJuli Mallett 			n = 0;		/* bitbucket */
817acc9d408SJuli Mallett 	}
818acc9d408SJuli Mallett 
819acc9d408SJuli Mallett 	if (n < 0)
8209b50d902SRodney W. Grimes 		n = 0;		       /* bitbucket */
8219b50d902SRodney W. Grimes 	if (outfile[n] == NULL) {
822acc9d408SJuli Mallett 		char fname[] = _PATH_DIVNAME;
823acc9d408SJuli Mallett 
824acc9d408SJuli Mallett 		if ((fd = mkstemp(fname)) < 0 ||
825acc9d408SJuli Mallett 			(outfile[n] = fdopen(fd, "w+")) == NULL)
826acc9d408SJuli Mallett 				err(1, "%s: cannot divert", fname);
827acc9d408SJuli Mallett 		if (unlink(fname) == -1)
828acc9d408SJuli Mallett 			err(1, "%s: cannot unlink", fname);
8299b50d902SRodney W. Grimes 	}
8309b50d902SRodney W. Grimes 	active = outfile[n];
8319b50d902SRodney W. Grimes }
8329b50d902SRodney W. Grimes 
8339b50d902SRodney W. Grimes /*
8349b50d902SRodney W. Grimes  * doundivert - undivert a specified output, or all
8359b50d902SRodney W. Grimes  *              other outputs, in numerical order.
8369b50d902SRodney W. Grimes  */
837acc9d408SJuli Mallett static void
838bd2bfb58SJuli Mallett doundiv(const char *argv[], int argc)
8399b50d902SRodney W. Grimes {
840acc9d408SJuli Mallett 	int ind;
841acc9d408SJuli Mallett 	int n;
8429b50d902SRodney W. Grimes 
8439b50d902SRodney W. Grimes 	if (argc > 2) {
8449b50d902SRodney W. Grimes 		for (ind = 2; ind < argc; ind++) {
845a841e1ebSBaptiste Daroussin 			const char *errstr;
846a841e1ebSBaptiste Daroussin 			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
847a841e1ebSBaptiste Daroussin 			if (errstr) {
848a841e1ebSBaptiste Daroussin 				if (errno == EINVAL && mimic_gnu)
849a841e1ebSBaptiste Daroussin 					getdivfile(argv[ind]);
850a841e1ebSBaptiste Daroussin 			} else {
851a841e1ebSBaptiste Daroussin 				if (n < maxout && outfile[n] != NULL)
8529b50d902SRodney W. Grimes 					getdiv(n);
853a841e1ebSBaptiste Daroussin 			}
8549b50d902SRodney W. Grimes 		}
8559b50d902SRodney W. Grimes 	}
8569b50d902SRodney W. Grimes 	else
857acc9d408SJuli Mallett 		for (n = 1; n < maxout; n++)
8589b50d902SRodney W. Grimes 			if (outfile[n] != NULL)
8599b50d902SRodney W. Grimes 				getdiv(n);
8609b50d902SRodney W. Grimes }
8619b50d902SRodney W. Grimes 
8629b50d902SRodney W. Grimes /*
8639b50d902SRodney W. Grimes  * dosub - select substring
8649b50d902SRodney W. Grimes  */
865acc9d408SJuli Mallett static void
866bd2bfb58SJuli Mallett dosub(const char *argv[], int argc)
8679b50d902SRodney W. Grimes {
868acc9d408SJuli Mallett 	const char *ap, *fc, *k;
869acc9d408SJuli Mallett 	int nc;
8709b50d902SRodney W. Grimes 
8719b50d902SRodney W. Grimes 	ap = argv[2];		       /* target string */
8729b50d902SRodney W. Grimes #ifdef EXPR
8739b50d902SRodney W. Grimes 	fc = ap + expr(argv[3]);       /* first char */
8749b50d902SRodney W. Grimes #else
8759b50d902SRodney W. Grimes 	fc = ap + atoi(argv[3]);       /* first char */
8769b50d902SRodney W. Grimes #endif
8774ba4d387SGregory Neil Shapiro 	nc = strlen(fc);
878acc9d408SJuli Mallett 	if (argc >= 5)
8794ba4d387SGregory Neil Shapiro #ifdef EXPR
880acc9d408SJuli Mallett 		nc = min(nc, expr(argv[4]));
8814ba4d387SGregory Neil Shapiro #else
882acc9d408SJuli Mallett 		nc = min(nc, atoi(argv[4]));
8834ba4d387SGregory Neil Shapiro #endif
8849b50d902SRodney W. Grimes 	if (fc >= ap && fc < ap + strlen(ap))
8854ba4d387SGregory Neil Shapiro 		for (k = fc + nc - 1; k >= fc; k--)
886a841e1ebSBaptiste Daroussin 			pushback(*k);
8879b50d902SRodney W. Grimes }
8889b50d902SRodney W. Grimes 
8899b50d902SRodney W. Grimes /*
8909b50d902SRodney W. Grimes  * map:
8919b50d902SRodney W. Grimes  * map every character of s1 that is specified in from
8929b50d902SRodney W. Grimes  * into s3 and replace in s. (source s1 remains untouched)
8939b50d902SRodney W. Grimes  *
894a841e1ebSBaptiste Daroussin  * This is derived from the a standard implementation of map(s,from,to)
895a841e1ebSBaptiste Daroussin  * function of ICON language. Within mapvec, we replace every character
896a841e1ebSBaptiste Daroussin  * of "from" with the corresponding character in "to".
897a841e1ebSBaptiste Daroussin  * If "to" is shorter than "from", than the corresponding entries are null,
898a841e1ebSBaptiste Daroussin  * which means that those characters dissapear altogether.
8999b50d902SRodney W. Grimes  */
900acc9d408SJuli Mallett static void
901bd2bfb58SJuli Mallett map(char *dest, const char *src, const char *from, const char *to)
9029b50d902SRodney W. Grimes {
903acc9d408SJuli Mallett 	const char *tmp;
904acc9d408SJuli Mallett 	unsigned char sch, dch;
905acc9d408SJuli Mallett 	static char frombis[257];
906acc9d408SJuli Mallett 	static char tobis[257];
907a841e1ebSBaptiste Daroussin 	int i;
908a841e1ebSBaptiste Daroussin 	char seen[256];
909acc9d408SJuli Mallett 	static unsigned char mapvec[256] = {
910acc9d408SJuli Mallett 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
911acc9d408SJuli Mallett 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
912acc9d408SJuli Mallett 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
913acc9d408SJuli Mallett 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
914acc9d408SJuli Mallett 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
915acc9d408SJuli Mallett 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
916acc9d408SJuli Mallett 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
917acc9d408SJuli Mallett 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
918acc9d408SJuli Mallett 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
919acc9d408SJuli Mallett 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
920acc9d408SJuli Mallett 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
921acc9d408SJuli Mallett 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
922acc9d408SJuli Mallett 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
923acc9d408SJuli Mallett 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
924acc9d408SJuli Mallett 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
925acc9d408SJuli Mallett 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
926acc9d408SJuli Mallett 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
927acc9d408SJuli Mallett 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9289b50d902SRodney W. Grimes 	};
9299b50d902SRodney W. Grimes 
9309b50d902SRodney W. Grimes 	if (*src) {
931acc9d408SJuli Mallett 		if (mimic_gnu) {
932acc9d408SJuli Mallett 			/*
933acc9d408SJuli Mallett 			 * expand character ranges on the fly
934acc9d408SJuli Mallett 			 */
935acc9d408SJuli Mallett 			from = handledash(frombis, frombis + 256, from);
936acc9d408SJuli Mallett 			to = handledash(tobis, tobis + 256, to);
937acc9d408SJuli Mallett 		}
9389b50d902SRodney W. Grimes 		tmp = from;
9399b50d902SRodney W. Grimes 	/*
9409b50d902SRodney W. Grimes 	 * create a mapping between "from" and
9419b50d902SRodney W. Grimes 	 * "to"
9429b50d902SRodney W. Grimes 	 */
943a841e1ebSBaptiste Daroussin 		for (i = 0; i < 256; i++)
944a841e1ebSBaptiste Daroussin 			seen[i] = 0;
945a841e1ebSBaptiste Daroussin 		while (*from) {
946a841e1ebSBaptiste Daroussin 			if (!seen[(unsigned char)(*from)]) {
947a841e1ebSBaptiste Daroussin 				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
948a841e1ebSBaptiste Daroussin 				seen[(unsigned char)(*from)] = 1;
949a841e1ebSBaptiste Daroussin 			}
950a841e1ebSBaptiste Daroussin 			from++;
951a841e1ebSBaptiste Daroussin 			if (*to)
952a841e1ebSBaptiste Daroussin 				to++;
953a841e1ebSBaptiste Daroussin 		}
9549b50d902SRodney W. Grimes 
9559b50d902SRodney W. Grimes 		while (*src) {
956acc9d408SJuli Mallett 			sch = (unsigned char)(*src++);
9579b50d902SRodney W. Grimes 			dch = mapvec[sch];
958acc9d408SJuli Mallett 			if ((*dest = (char)dch))
9599b50d902SRodney W. Grimes 				dest++;
9609b50d902SRodney W. Grimes 		}
9619b50d902SRodney W. Grimes 	/*
9629b50d902SRodney W. Grimes 	 * restore all the changed characters
9639b50d902SRodney W. Grimes 	 */
9649b50d902SRodney W. Grimes 		while (*tmp) {
965acc9d408SJuli Mallett 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9669b50d902SRodney W. Grimes 			tmp++;
9679b50d902SRodney W. Grimes 		}
9689b50d902SRodney W. Grimes 	}
969acc9d408SJuli Mallett 	*dest = '\0';
9709b50d902SRodney W. Grimes }
971acc9d408SJuli Mallett 
972acc9d408SJuli Mallett 
973acc9d408SJuli Mallett /*
974acc9d408SJuli Mallett  * handledash:
975acc9d408SJuli Mallett  *  use buffer to copy the src string, expanding character ranges
976acc9d408SJuli Mallett  * on the way.
977acc9d408SJuli Mallett  */
978acc9d408SJuli Mallett static const char *
979bd2bfb58SJuli Mallett handledash(char *buffer, char *end, const char *src)
980acc9d408SJuli Mallett {
981acc9d408SJuli Mallett 	char *p;
982acc9d408SJuli Mallett 
983acc9d408SJuli Mallett 	p = buffer;
984acc9d408SJuli Mallett 	while(*src) {
985acc9d408SJuli Mallett 		if (src[1] == '-' && src[2]) {
986acc9d408SJuli Mallett 			unsigned char i;
987a841e1ebSBaptiste Daroussin 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
988acc9d408SJuli Mallett 				for (i = (unsigned char)src[0];
989acc9d408SJuli Mallett 				    i <= (unsigned char)src[2]; i++) {
990acc9d408SJuli Mallett 					*p++ = i;
991acc9d408SJuli Mallett 					if (p == end) {
992acc9d408SJuli Mallett 						*p = '\0';
993acc9d408SJuli Mallett 						return buffer;
994acc9d408SJuli Mallett 					}
995acc9d408SJuli Mallett 				}
996a841e1ebSBaptiste Daroussin 			} else {
997a841e1ebSBaptiste Daroussin 				for (i = (unsigned char)src[0];
998a841e1ebSBaptiste Daroussin 				    i >= (unsigned char)src[2]; i--) {
999a841e1ebSBaptiste Daroussin 					*p++ = i;
1000a841e1ebSBaptiste Daroussin 					if (p == end) {
1001a841e1ebSBaptiste Daroussin 						*p = '\0';
1002a841e1ebSBaptiste Daroussin 						return buffer;
1003a841e1ebSBaptiste Daroussin 					}
1004a841e1ebSBaptiste Daroussin 				}
1005a841e1ebSBaptiste Daroussin 			}
1006acc9d408SJuli Mallett 			src += 3;
1007acc9d408SJuli Mallett 		} else
1008acc9d408SJuli Mallett 			*p++ = *src++;
1009acc9d408SJuli Mallett 		if (p == end)
1010acc9d408SJuli Mallett 			break;
1011acc9d408SJuli Mallett 	}
1012acc9d408SJuli Mallett 	*p = '\0';
1013acc9d408SJuli Mallett 	return buffer;
1014acc9d408SJuli Mallett }
1015