1352281Sbapt/*	$OpenBSD: eval.c,v 1.78 2019/06/28 05:35:34 deraadt Exp $	*/
295060Sjmallett/*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
395060Sjmallett
4331722Seadler/*
51590Srgrimes * Copyright (c) 1989, 1993
61590Srgrimes *	The Regents of the University of California.  All rights reserved.
71590Srgrimes *
81590Srgrimes * This code is derived from software contributed to Berkeley by
91590Srgrimes * Ozan Yigit at York University.
101590Srgrimes *
111590Srgrimes * Redistribution and use in source and binary forms, with or without
121590Srgrimes * modification, are permitted provided that the following conditions
131590Srgrimes * are met:
141590Srgrimes * 1. Redistributions of source code must retain the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer.
161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171590Srgrimes *    notice, this list of conditions and the following disclaimer in the
181590Srgrimes *    documentation and/or other materials provided with the distribution.
19228063Sbapt * 3. Neither the name of the University nor the names of its contributors
201590Srgrimes *    may be used to endorse or promote products derived from this software
211590Srgrimes *    without specific prior written permission.
221590Srgrimes *
231590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
241590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
261590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
271590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331590Srgrimes * SUCH DAMAGE.
341590Srgrimes */
351590Srgrimes
3695060Sjmallett#include <sys/cdefs.h>
3795060Sjmallett__FBSDID("$FreeBSD: stable/11/usr.bin/m4/eval.c 352281 2019-09-13 07:22:09Z bapt $");
381590Srgrimes
39228063Sbapt
401590Srgrimes/*
411590Srgrimes * eval.c
421590Srgrimes * Facility: m4 macro processor
431590Srgrimes * by: oz
441590Srgrimes */
451590Srgrimes
461590Srgrimes#include <sys/types.h>
47228063Sbapt#include <err.h>
4895060Sjmallett#include <errno.h>
49228063Sbapt#include <limits.h>
5095060Sjmallett#include <unistd.h>
51291128Sbapt#include <stdio.h>
52228063Sbapt#include <stdint.h>
531590Srgrimes#include <stdlib.h>
5495060Sjmallett#include <stddef.h>
551590Srgrimes#include <string.h>
5695060Sjmallett#include <fcntl.h>
571590Srgrimes#include "mdef.h"
581590Srgrimes#include "stdd.h"
591590Srgrimes#include "extern.h"
601590Srgrimes#include "pathnames.h"
611590Srgrimes
6295060Sjmallettstatic void	dodefn(const char *);
6395060Sjmallettstatic void	dopushdef(const char *, const char *);
6495060Sjmallettstatic void	dodump(const char *[], int);
6595060Sjmallettstatic void	dotrace(const char *[], int, int);
6695060Sjmallettstatic void	doifelse(const char *[], int);
6795060Sjmallettstatic int	doincl(const char *);
6895060Sjmallettstatic int	dopaste(const char *);
6995060Sjmallettstatic void	dochq(const char *[], int);
7095060Sjmallettstatic void	dochc(const char *[], int);
71228063Sbaptstatic void	dom4wrap(const char *);
7295060Sjmallettstatic void	dodiv(int);
7395060Sjmallettstatic void	doundiv(const char *[], int);
7495060Sjmallettstatic void	dosub(const char *[], int);
7595060Sjmallettstatic void	map(char *, const char *, const char *, const char *);
7695060Sjmallettstatic const char *handledash(char *, char *, const char *);
7795060Sjmallettstatic void	expand_builtin(const char *[], int, int);
7895060Sjmallettstatic void	expand_macro(const char *[], int);
79228063Sbaptstatic void	dump_one_def(const char *, struct macro_definition *);
8095060Sjmallett
8195060Sjmallettunsigned long	expansion_id;
8295060Sjmallett
831590Srgrimes/*
8495060Sjmallett * eval - eval all macros and builtins calls
851590Srgrimes *	  argc - number of elements in argv.
861590Srgrimes *	  argv - element vector :
871590Srgrimes *			argv[0] = definition of a user
88228063Sbapt *				  macro or NULL if built-in.
891590Srgrimes *			argv[1] = name of the macro or
901590Srgrimes *				  built-in.
911590Srgrimes *			argv[2] = parameters to user-defined
921590Srgrimes *			   .	  macro or built-in.
931590Srgrimes *			   .
941590Srgrimes *
9595060Sjmallett * A call in the form of macro-or-builtin() will result in:
961590Srgrimes *			argv[0] = nullstr
971590Srgrimes *			argv[1] = macro-or-builtin
981590Srgrimes *			argv[2] = nullstr
9995060Sjmallett *
10095060Sjmallett * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
1011590Srgrimes */
1021590Srgrimesvoid
103228063Sbapteval(const char *argv[], int argc, int td, int is_traced)
1041590Srgrimes{
105228063Sbapt	size_t mark = SIZE_MAX;
10695060Sjmallett
10795060Sjmallett	expansion_id++;
108100014Sjmallett	if (td & RECDEF)
109228063Sbapt		m4errx(1, "expanding recursive definition for %s.", argv[1]);
110228063Sbapt	if (is_traced)
11195060Sjmallett		mark = trace(argv, argc, infile+ilevel);
11295060Sjmallett	if (td == MACRTYPE)
11395060Sjmallett		expand_macro(argv, argc);
11495060Sjmallett	else
11595060Sjmallett		expand_builtin(argv, argc, td);
116228063Sbapt	if (mark != SIZE_MAX)
11795060Sjmallett		finish_trace(mark);
11895060Sjmallett}
11995060Sjmallett
12095060Sjmallett/*
12195060Sjmallett * expand_builtin - evaluate built-in macros.
12295060Sjmallett */
12395060Sjmallettvoid
12495887Sjmallettexpand_builtin(const char *argv[], int argc, int td)
12595060Sjmallett{
12695060Sjmallett	int c, n;
127352281Sbapt	const char *errstr;
12895060Sjmallett	int ac;
1291590Srgrimes	static int sysval = 0;
1301590Srgrimes
1311590Srgrimes#ifdef DEBUG
1321590Srgrimes	printf("argc = %d\n", argc);
1331590Srgrimes	for (n = 0; n < argc; n++)
1341590Srgrimes		printf("argv[%d] = %s\n", n, argv[n]);
13595060Sjmallett	fflush(stdout);
1361590Srgrimes#endif
13795060Sjmallett
1381590Srgrimes /*
1391590Srgrimes  * if argc == 3 and argv[2] is null, then we
1401590Srgrimes  * have macro-or-builtin() type call. We adjust
1411590Srgrimes  * argc to avoid further checking..
1421590Srgrimes  */
143228063Sbapt /* we keep the initial value for those built-ins that differentiate
144228063Sbapt  * between builtin() and builtin.
145228063Sbapt  */
146228063Sbapt	ac = argc;
14795060Sjmallett
148228063Sbapt	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
1491590Srgrimes		argc--;
1501590Srgrimes
15195060Sjmallett	switch (td & TYPEMASK) {
1521590Srgrimes
1531590Srgrimes	case DEFITYPE:
1541590Srgrimes		if (argc > 2)
1551590Srgrimes			dodefine(argv[2], (argc > 3) ? argv[3] : null);
1561590Srgrimes		break;
1571590Srgrimes
1581590Srgrimes	case PUSDTYPE:
1591590Srgrimes		if (argc > 2)
1601590Srgrimes			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
1611590Srgrimes		break;
1621590Srgrimes
1631590Srgrimes	case DUMPTYPE:
1641590Srgrimes		dodump(argv, argc);
1651590Srgrimes		break;
1661590Srgrimes
16795060Sjmallett	case TRACEONTYPE:
16895060Sjmallett		dotrace(argv, argc, 1);
16995060Sjmallett		break;
17095060Sjmallett
17195060Sjmallett	case TRACEOFFTYPE:
17295060Sjmallett		dotrace(argv, argc, 0);
17395060Sjmallett		break;
17495060Sjmallett
1751590Srgrimes	case EXPRTYPE:
1761590Srgrimes	/*
1771590Srgrimes	 * doexpr - evaluate arithmetic
1781590Srgrimes	 * expression
1791590Srgrimes	 */
180228063Sbapt	{
181228063Sbapt		int base = 10;
182228063Sbapt		int maxdigits = 0;
183228063Sbapt		const char *errstr;
184228063Sbapt
185228063Sbapt		if (argc > 3) {
186228063Sbapt			base = strtonum(argv[3], 2, 36, &errstr);
187228063Sbapt			if (errstr) {
188352281Sbapt				m4errx(1, "expr: base is %s: %s.",
189352281Sbapt				    errstr, argv[3]);
190228063Sbapt			}
191228063Sbapt		}
192228063Sbapt		if (argc > 4) {
193228063Sbapt			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
194228063Sbapt			if (errstr) {
195352281Sbapt				m4errx(1, "expr: maxdigits is %s: %s.",
196352281Sbapt				    errstr, argv[4]);
197228063Sbapt			}
198228063Sbapt		}
1991590Srgrimes		if (argc > 2)
200228063Sbapt			pbnumbase(expr(argv[2]), base, maxdigits);
2011590Srgrimes		break;
202228063Sbapt	}
2031590Srgrimes
2041590Srgrimes	case IFELTYPE:
205352281Sbapt		doifelse(argv, argc);
2061590Srgrimes		break;
2071590Srgrimes
2081590Srgrimes	case IFDFTYPE:
2091590Srgrimes	/*
2101590Srgrimes	 * doifdef - select one of two
2111590Srgrimes	 * alternatives based on the existence of
2121590Srgrimes	 * another definition
2131590Srgrimes	 */
2141590Srgrimes		if (argc > 3) {
215228063Sbapt			if (lookup_macro_definition(argv[2]) != NULL)
2161590Srgrimes				pbstr(argv[3]);
2171590Srgrimes			else if (argc > 4)
2181590Srgrimes				pbstr(argv[4]);
2191590Srgrimes		}
2201590Srgrimes		break;
2211590Srgrimes
2221590Srgrimes	case LENGTYPE:
2231590Srgrimes	/*
2241590Srgrimes	 * dolen - find the length of the
2251590Srgrimes	 * argument
2261590Srgrimes	 */
22777378Sgshapiro		pbnum((argc > 2) ? strlen(argv[2]) : 0);
2281590Srgrimes		break;
2291590Srgrimes
2301590Srgrimes	case INCRTYPE:
2311590Srgrimes	/*
2321590Srgrimes	 * doincr - increment the value of the
2331590Srgrimes	 * argument
2341590Srgrimes	 */
235352281Sbapt		if (argc > 2) {
236352281Sbapt			n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr);
237352281Sbapt			if (errstr != NULL)
238352281Sbapt				m4errx(1, "incr: argument is %s: %s.",
239352281Sbapt				    errstr, argv[2]);
240352281Sbapt			pbnum(n + 1);
241352281Sbapt		}
2421590Srgrimes		break;
2431590Srgrimes
2441590Srgrimes	case DECRTYPE:
2451590Srgrimes	/*
2461590Srgrimes	 * dodecr - decrement the value of the
2471590Srgrimes	 * argument
2481590Srgrimes	 */
249352281Sbapt		if (argc > 2) {
250352281Sbapt			n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr);
251352281Sbapt			if (errstr)
252352281Sbapt				m4errx(1, "decr: argument is %s: %s.",
253352281Sbapt				    errstr, argv[2]);
254352281Sbapt			pbnum(n - 1);
255352281Sbapt		}
2561590Srgrimes		break;
2571590Srgrimes
2581590Srgrimes	case SYSCTYPE:
2591590Srgrimes	/*
2601590Srgrimes	 * dosys - execute system command
2618874Srgrimes	 */
262114368Stjr		if (argc > 2) {
263228063Sbapt			fflush(stdout);
2641590Srgrimes			sysval = system(argv[2]);
265114368Stjr		}
2661590Srgrimes		break;
2671590Srgrimes
2681590Srgrimes	case SYSVTYPE:
2691590Srgrimes	/*
2701590Srgrimes	 * dosysval - return value of the last
2711590Srgrimes	 * system call.
272100014Sjmallett	 *
2731590Srgrimes	 */
2741590Srgrimes		pbnum(sysval);
2751590Srgrimes		break;
2761590Srgrimes
27795060Sjmallett	case ESYSCMDTYPE:
27895060Sjmallett		if (argc > 2)
27995060Sjmallett			doesyscmd(argv[2]);
280228063Sbapt		break;
2811590Srgrimes	case INCLTYPE:
282269162Sbapt		if (argc > 2) {
283228701Sbz			if (!doincl(argv[2])) {
284234310Sbapt				if (mimic_gnu) {
285228697Sbapt					warn("%s at line %lu: include(%s)",
286228697Sbapt					    CURRENT_NAME, CURRENT_LINE, argv[2]);
287234310Sbapt					exit_code = 1;
288352281Sbapt					if (fatal_warns) {
289352281Sbapt						killdiv();
290352281Sbapt						exit(exit_code);
291352281Sbapt					}
292234310Sbapt				} else
293228697Sbapt					err(1, "%s at line %lu: include(%s)",
294228697Sbapt					    CURRENT_NAME, CURRENT_LINE, argv[2]);
295228701Sbz			}
296269162Sbapt		}
2971590Srgrimes		break;
2981590Srgrimes
2991590Srgrimes	case SINCTYPE:
3001590Srgrimes		if (argc > 2)
3011590Srgrimes			(void) doincl(argv[2]);
3021590Srgrimes		break;
3031590Srgrimes#ifdef EXTENDED
3041590Srgrimes	case PASTTYPE:
3051590Srgrimes		if (argc > 2)
3061590Srgrimes			if (!dopaste(argv[2]))
307228063Sbapt				err(1, "%s at line %lu: paste(%s)",
30895060Sjmallett				    CURRENT_NAME, CURRENT_LINE, argv[2]);
3091590Srgrimes		break;
3101590Srgrimes
3111590Srgrimes	case SPASTYPE:
3121590Srgrimes		if (argc > 2)
3131590Srgrimes			(void) dopaste(argv[2]);
3141590Srgrimes		break;
315228063Sbapt	case FORMATTYPE:
316228063Sbapt		doformat(argv, argc);
317228063Sbapt		break;
3181590Srgrimes#endif
3191590Srgrimes	case CHNQTYPE:
320228063Sbapt		dochq(argv, ac);
3211590Srgrimes		break;
3221590Srgrimes
3231590Srgrimes	case CHNCTYPE:
324228063Sbapt		dochc(argv, argc);
3251590Srgrimes		break;
3261590Srgrimes
3271590Srgrimes	case SUBSTYPE:
3281590Srgrimes	/*
3291590Srgrimes	 * dosub - select substring
330100014Sjmallett	 *
3311590Srgrimes	 */
3321590Srgrimes		if (argc > 3)
3331590Srgrimes			dosub(argv, argc);
3341590Srgrimes		break;
3351590Srgrimes
3361590Srgrimes	case SHIFTYPE:
3371590Srgrimes	/*
3381590Srgrimes	 * doshift - push back all arguments
3391590Srgrimes	 * except the first one (i.e. skip
3401590Srgrimes	 * argv[2])
3411590Srgrimes	 */
3421590Srgrimes		if (argc > 3) {
3431590Srgrimes			for (n = argc - 1; n > 3; n--) {
34495060Sjmallett				pbstr(rquote);
3451590Srgrimes				pbstr(argv[n]);
34695060Sjmallett				pbstr(lquote);
347228063Sbapt				pushback(COMMA);
3481590Srgrimes			}
34995060Sjmallett			pbstr(rquote);
3501590Srgrimes			pbstr(argv[3]);
35195060Sjmallett			pbstr(lquote);
3521590Srgrimes		}
3531590Srgrimes		break;
3541590Srgrimes
3551590Srgrimes	case DIVRTYPE:
356352281Sbapt		if (argc > 2) {
357352281Sbapt			n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr);
358352281Sbapt			if (errstr)
359352281Sbapt				m4errx(1, "divert: argument is %s: %s.",
360352281Sbapt				    errstr, argv[2]);
361352281Sbapt			if (n != 0) {
362352281Sbapt				dodiv(n);
363352281Sbapt				 break;
364352281Sbapt			}
3651590Srgrimes		}
366352281Sbapt		active = stdout;
367352281Sbapt		oindex = 0;
3681590Srgrimes		break;
3691590Srgrimes
3701590Srgrimes	case UNDVTYPE:
3711590Srgrimes		doundiv(argv, argc);
3721590Srgrimes		break;
3731590Srgrimes
3741590Srgrimes	case DIVNTYPE:
3751590Srgrimes	/*
3761590Srgrimes	 * dodivnum - return the number of
3771590Srgrimes	 * current output diversion
3781590Srgrimes	 */
3791590Srgrimes		pbnum(oindex);
3801590Srgrimes		break;
3811590Srgrimes
3821590Srgrimes	case UNDFTYPE:
3831590Srgrimes	/*
3841590Srgrimes	 * doundefine - undefine a previously
3851590Srgrimes	 * defined macro(s) or m4 keyword(s).
3861590Srgrimes	 */
3871590Srgrimes		if (argc > 2)
3881590Srgrimes			for (n = 2; n < argc; n++)
389228063Sbapt				macro_undefine(argv[n]);
3901590Srgrimes		break;
3911590Srgrimes
3921590Srgrimes	case POPDTYPE:
3931590Srgrimes	/*
3941590Srgrimes	 * dopopdef - remove the topmost
3951590Srgrimes	 * definitions of macro(s) or m4
3961590Srgrimes	 * keyword(s).
3971590Srgrimes	 */
3981590Srgrimes		if (argc > 2)
3991590Srgrimes			for (n = 2; n < argc; n++)
400228063Sbapt				macro_popdef(argv[n]);
4011590Srgrimes		break;
4021590Srgrimes
4031590Srgrimes	case MKTMTYPE:
4041590Srgrimes	/*
4051590Srgrimes	 * dotemp - create a temporary file
4061590Srgrimes	 */
40795060Sjmallett		if (argc > 2) {
40895060Sjmallett			int fd;
40995060Sjmallett			char *temp;
41095060Sjmallett
41195060Sjmallett			temp = xstrdup(argv[2]);
412100014Sjmallett
41395060Sjmallett			fd = mkstemp(temp);
41495060Sjmallett			if (fd == -1)
415100014Sjmallett				err(1,
416100014Sjmallett	    "%s at line %lu: couldn't make temp file %s",
41795060Sjmallett	    CURRENT_NAME, CURRENT_LINE, argv[2]);
41895060Sjmallett			close(fd);
41995060Sjmallett			pbstr(temp);
42095060Sjmallett			free(temp);
42195060Sjmallett		}
4221590Srgrimes		break;
4231590Srgrimes
4241590Srgrimes	case TRNLTYPE:
4251590Srgrimes	/*
4261590Srgrimes	 * dotranslit - replace all characters in
4271590Srgrimes	 * the source string that appears in the
4281590Srgrimes	 * "from" string with the corresponding
4291590Srgrimes	 * characters in the "to" string.
4301590Srgrimes	 */
4311590Srgrimes		if (argc > 3) {
43295060Sjmallett			char *temp;
43395060Sjmallett
434228063Sbapt			temp = xalloc(strlen(argv[2])+1, NULL);
4351590Srgrimes			if (argc > 4)
4361590Srgrimes				map(temp, argv[2], argv[3], argv[4]);
4371590Srgrimes			else
4381590Srgrimes				map(temp, argv[2], argv[3], null);
4391590Srgrimes			pbstr(temp);
44095060Sjmallett			free(temp);
44195060Sjmallett		} else if (argc > 2)
4421590Srgrimes			pbstr(argv[2]);
4431590Srgrimes		break;
4441590Srgrimes
4451590Srgrimes	case INDXTYPE:
4461590Srgrimes	/*
4471590Srgrimes	 * doindex - find the index of the second
4481590Srgrimes	 * argument string in the first argument
4491590Srgrimes	 * string. -1 if not present.
4501590Srgrimes	 */
4511590Srgrimes		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
4521590Srgrimes		break;
4531590Srgrimes
4541590Srgrimes	case ERRPTYPE:
4551590Srgrimes	/*
4561590Srgrimes	 * doerrp - print the arguments to stderr
4571590Srgrimes	 * file
4581590Srgrimes	 */
4591590Srgrimes		if (argc > 2) {
4601590Srgrimes			for (n = 2; n < argc; n++)
4611590Srgrimes				fprintf(stderr, "%s ", argv[n]);
4621590Srgrimes			fprintf(stderr, "\n");
4631590Srgrimes		}
4641590Srgrimes		break;
4651590Srgrimes
4661590Srgrimes	case DNLNTYPE:
4671590Srgrimes	/*
4681590Srgrimes	 * dodnl - eat-up-to and including
4691590Srgrimes	 * newline
4701590Srgrimes	 */
4711590Srgrimes		while ((c = gpbc()) != '\n' && c != EOF)
4721590Srgrimes			;
4731590Srgrimes		break;
4741590Srgrimes
4751590Srgrimes	case M4WRTYPE:
4761590Srgrimes	/*
4771590Srgrimes	 * dom4wrap - set up for
4781590Srgrimes	 * wrap-up/wind-down activity
4791590Srgrimes	 */
480228063Sbapt		if (argc > 2)
481228063Sbapt			dom4wrap(argv[2]);
4821590Srgrimes		break;
4831590Srgrimes
4841590Srgrimes	case EXITTYPE:
4851590Srgrimes	/*
4861590Srgrimes	 * doexit - immediate exit from m4.
4871590Srgrimes	 */
4887896Sache		killdiv();
4891590Srgrimes		exit((argc > 2) ? atoi(argv[2]) : 0);
4901590Srgrimes		break;
4911590Srgrimes
4921590Srgrimes	case DEFNTYPE:
4931590Srgrimes		if (argc > 2)
4941590Srgrimes			for (n = 2; n < argc; n++)
4951590Srgrimes				dodefn(argv[n]);
4961590Srgrimes		break;
4971590Srgrimes
49895060Sjmallett	case INDIRTYPE:	/* Indirect call */
49995060Sjmallett		if (argc > 2)
50095060Sjmallett			doindir(argv, argc);
50138926Ssteve		break;
502100014Sjmallett
50395060Sjmallett	case BUILTINTYPE: /* Builtins only */
50495060Sjmallett		if (argc > 2)
50595060Sjmallett			dobuiltin(argv, argc);
50695060Sjmallett		break;
50738926Ssteve
50895060Sjmallett	case PATSTYPE:
50995060Sjmallett		if (argc > 2)
51095060Sjmallett			dopatsubst(argv, argc);
51195060Sjmallett		break;
51295060Sjmallett	case REGEXPTYPE:
51395060Sjmallett		if (argc > 2)
51495060Sjmallett			doregexp(argv, argc);
51595060Sjmallett		break;
51695060Sjmallett	case LINETYPE:
51795060Sjmallett		doprintlineno(infile+ilevel);
51895060Sjmallett		break;
51995060Sjmallett	case FILENAMETYPE:
52095060Sjmallett		doprintfilename(infile+ilevel);
52195060Sjmallett		break;
52295060Sjmallett	case SELFTYPE:
52395060Sjmallett		pbstr(rquote);
52495060Sjmallett		pbstr(argv[1]);
52595060Sjmallett		pbstr(lquote);
52695060Sjmallett		break;
5271590Srgrimes	default:
528228063Sbapt		m4errx(1, "eval: major botch.");
5291590Srgrimes		break;
5301590Srgrimes	}
5311590Srgrimes}
5321590Srgrimes
5331590Srgrimes/*
53495060Sjmallett * expand_macro - user-defined macro expansion
5351590Srgrimes */
5361590Srgrimesvoid
53795887Sjmallettexpand_macro(const char *argv[], int argc)
5381590Srgrimes{
53995060Sjmallett	const char *t;
54095060Sjmallett	const char *p;
54195060Sjmallett	int n;
54295060Sjmallett	int argno;
5431590Srgrimes
5441590Srgrimes	t = argv[0];		       /* defn string as a whole */
5451590Srgrimes	p = t;
5461590Srgrimes	while (*p)
5471590Srgrimes		p++;
5481590Srgrimes	p--;			       /* last character of defn */
5491590Srgrimes	while (p > t) {
5501590Srgrimes		if (*(p - 1) != ARGFLAG)
551228063Sbapt			PUSHBACK(*p);
5521590Srgrimes		else {
5531590Srgrimes			switch (*p) {
5541590Srgrimes
5551590Srgrimes			case '#':
5561590Srgrimes				pbnum(argc - 2);
5571590Srgrimes				break;
5581590Srgrimes			case '0':
5591590Srgrimes			case '1':
5601590Srgrimes			case '2':
5611590Srgrimes			case '3':
5621590Srgrimes			case '4':
5631590Srgrimes			case '5':
5641590Srgrimes			case '6':
5651590Srgrimes			case '7':
5661590Srgrimes			case '8':
5671590Srgrimes			case '9':
5681590Srgrimes				if ((argno = *p - '0') < argc - 1)
5691590Srgrimes					pbstr(argv[argno + 1]);
5701590Srgrimes				break;
5711590Srgrimes			case '*':
57295060Sjmallett				if (argc > 2) {
57395060Sjmallett					for (n = argc - 1; n > 2; n--) {
57495060Sjmallett						pbstr(argv[n]);
575228063Sbapt						pushback(COMMA);
57695060Sjmallett					}
57795060Sjmallett					pbstr(argv[2]);
578228063Sbapt				}
5791590Srgrimes				break;
58095060Sjmallett                        case '@':
58195060Sjmallett				if (argc > 2) {
58295060Sjmallett					for (n = argc - 1; n > 2; n--) {
58395060Sjmallett						pbstr(rquote);
58495060Sjmallett						pbstr(argv[n]);
58595060Sjmallett						pbstr(lquote);
586228063Sbapt						pushback(COMMA);
58795060Sjmallett					}
58895060Sjmallett					pbstr(rquote);
58995060Sjmallett					pbstr(argv[2]);
59095060Sjmallett					pbstr(lquote);
59124901Sjoerg				}
59295060Sjmallett                                break;
5931590Srgrimes			default:
594228063Sbapt				PUSHBACK(*p);
595228063Sbapt				PUSHBACK('$');
5961590Srgrimes				break;
5971590Srgrimes			}
5981590Srgrimes			p--;
5991590Srgrimes		}
6001590Srgrimes		p--;
6011590Srgrimes	}
6021590Srgrimes	if (p == t)		       /* do last character */
603228063Sbapt		PUSHBACK(*p);
6041590Srgrimes}
6051590Srgrimes
606228063Sbapt
6071590Srgrimes/*
6081590Srgrimes * dodefine - install definition in the table
6091590Srgrimes */
6101590Srgrimesvoid
61195887Sjmallettdodefine(const char *name, const char *defn)
6121590Srgrimes{
613228063Sbapt	if (!*name && !mimic_gnu)
614228063Sbapt		m4errx(1, "null definition.");
6151590Srgrimes	else
616228063Sbapt		macro_define(name, defn);
6171590Srgrimes}
6181590Srgrimes
6191590Srgrimes/*
6201590Srgrimes * dodefn - push back a quoted definition of
6211590Srgrimes *      the given name.
6221590Srgrimes */
62395060Sjmallettstatic void
62495887Sjmallettdodefn(const char *name)
6251590Srgrimes{
626228063Sbapt	struct macro_definition *p;
6271590Srgrimes
628228063Sbapt	if ((p = lookup_macro_definition(name)) != NULL) {
629228063Sbapt		if ((p->type & TYPEMASK) == MACRTYPE) {
63095060Sjmallett			pbstr(rquote);
63195060Sjmallett			pbstr(p->defn);
63295060Sjmallett			pbstr(lquote);
633228063Sbapt		} else {
634228063Sbapt			pbstr(p->defn);
63595060Sjmallett			pbstr(BUILTIN_MARKER);
63695060Sjmallett		}
6371590Srgrimes	}
6381590Srgrimes}
6391590Srgrimes
6401590Srgrimes/*
6411590Srgrimes * dopushdef - install a definition in the hash table
6421590Srgrimes *      without removing a previous definition. Since
6431590Srgrimes *      each new entry is entered in *front* of the
6441590Srgrimes *      hash bucket, it hides a previous definition from
6451590Srgrimes *      lookup.
6461590Srgrimes */
64795060Sjmallettstatic void
64895887Sjmallettdopushdef(const char *name, const char *defn)
6491590Srgrimes{
650228063Sbapt	if (!*name && !mimic_gnu)
651228063Sbapt		m4errx(1, "null definition.");
6521590Srgrimes	else
653228063Sbapt		macro_pushdef(name, defn);
6541590Srgrimes}
6551590Srgrimes
6561590Srgrimes/*
65795060Sjmallett * dump_one_def - dump the specified definition.
65895060Sjmallett */
65995060Sjmallettstatic void
660228063Sbaptdump_one_def(const char *name, struct macro_definition *p)
66195060Sjmallett{
662228063Sbapt	if (!traceout)
663228063Sbapt		traceout = stderr;
66495060Sjmallett	if (mimic_gnu) {
66595060Sjmallett		if ((p->type & TYPEMASK) == MACRTYPE)
666228063Sbapt			fprintf(traceout, "%s:\t%s\n", name, p->defn);
66795060Sjmallett		else {
668228063Sbapt			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
669228063Sbapt		}
67095060Sjmallett	} else
671228063Sbapt		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
67295060Sjmallett}
67395060Sjmallett
67495060Sjmallett/*
6751590Srgrimes * dodumpdef - dump the specified definitions in the hash
6761590Srgrimes *      table to stderr. If nothing is specified, the entire
6771590Srgrimes *      hash table is dumped.
6781590Srgrimes */
67995060Sjmallettstatic void
68095887Sjmallettdodump(const char *argv[], int argc)
6811590Srgrimes{
68295060Sjmallett	int n;
683228063Sbapt	struct macro_definition *p;
6841590Srgrimes
6851590Srgrimes	if (argc > 2) {
6861590Srgrimes		for (n = 2; n < argc; n++)
687228063Sbapt			if ((p = lookup_macro_definition(argv[n])) != NULL)
688228063Sbapt				dump_one_def(argv[n], p);
689228063Sbapt	} else
690228063Sbapt		macro_for_all(dump_one_def);
6911590Srgrimes}
6921590Srgrimes
6931590Srgrimes/*
69495060Sjmallett * dotrace - mark some macros as traced/untraced depending upon on.
69595060Sjmallett */
69695060Sjmallettstatic void
69795887Sjmallettdotrace(const char *argv[], int argc, int on)
69895060Sjmallett{
69995060Sjmallett	int n;
70095060Sjmallett
70195060Sjmallett	if (argc > 2) {
70295060Sjmallett		for (n = 2; n < argc; n++)
70395060Sjmallett			mark_traced(argv[n], on);
70495060Sjmallett	} else
70595060Sjmallett		mark_traced(NULL, on);
70695060Sjmallett}
70795060Sjmallett
70895060Sjmallett/*
7091590Srgrimes * doifelse - select one of two alternatives - loop.
7101590Srgrimes */
71195060Sjmallettstatic void
71295887Sjmallettdoifelse(const char *argv[], int argc)
7131590Srgrimes{
714352281Sbapt	while (argc > 4) {
715352281Sbapt		if (STREQ(argv[2], argv[3])) {
7161590Srgrimes			pbstr(argv[4]);
717352281Sbapt			break;
718352281Sbapt		} else if (argc == 6) {
7191590Srgrimes			pbstr(argv[5]);
720352281Sbapt			break;
721352281Sbapt		} else {
7221590Srgrimes			argv += 3;
7231590Srgrimes			argc -= 3;
7241590Srgrimes		}
7251590Srgrimes	}
7261590Srgrimes}
7271590Srgrimes
7281590Srgrimes/*
7291590Srgrimes * doinclude - include a given file.
7301590Srgrimes */
73195060Sjmallettstatic int
73295887Sjmallettdoincl(const char *ifile)
7331590Srgrimes{
7341590Srgrimes	if (ilevel + 1 == MAXINP)
735228063Sbapt		m4errx(1, "too many include files.");
73695060Sjmallett	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
7371590Srgrimes		ilevel++;
7381590Srgrimes		bbase[ilevel] = bufbase = bp;
7391590Srgrimes		return (1);
74095060Sjmallett	} else
7411590Srgrimes		return (0);
7421590Srgrimes}
7431590Srgrimes
7441590Srgrimes#ifdef EXTENDED
7451590Srgrimes/*
7461590Srgrimes * dopaste - include a given file without any
7471590Srgrimes *           macro processing.
7481590Srgrimes */
74995060Sjmallettstatic int
75095887Sjmallettdopaste(const char *pfile)
7511590Srgrimes{
7521590Srgrimes	FILE *pf;
75395060Sjmallett	int c;
7541590Srgrimes
7551590Srgrimes	if ((pf = fopen(pfile, "r")) != NULL) {
756228063Sbapt		if (synch_lines)
757228063Sbapt		    fprintf(active, "#line 1 \"%s\"\n", pfile);
7581590Srgrimes		while ((c = getc(pf)) != EOF)
7591590Srgrimes			putc(c, active);
7601590Srgrimes		(void) fclose(pf);
761228063Sbapt		emit_synchline();
7621590Srgrimes		return (1);
76395060Sjmallett	} else
7641590Srgrimes		return (0);
7651590Srgrimes}
7661590Srgrimes#endif
7671590Srgrimes
768228063Sbapt/*
769228063Sbapt * dochq - change quote characters
770228063Sbapt */
77195060Sjmallettstatic void
772228063Sbaptdochq(const char *argv[], int ac)
77395060Sjmallett{
77495060Sjmallett	if (ac == 2) {
775228063Sbapt		lquote[0] = LQUOTE; lquote[1] = EOS;
776228063Sbapt		rquote[0] = RQUOTE; rquote[1] = EOS;
77795060Sjmallett	} else {
77895060Sjmallett		strlcpy(lquote, argv[2], sizeof(lquote));
779228063Sbapt		if (ac > 3) {
78095060Sjmallett			strlcpy(rquote, argv[3], sizeof(rquote));
781228063Sbapt		} else {
782228063Sbapt			rquote[0] = ECOMMT; rquote[1] = EOS;
783228063Sbapt		}
78495060Sjmallett	}
78595060Sjmallett}
78695060Sjmallett
7871590Srgrimes/*
788228063Sbapt * dochc - change comment characters
7891590Srgrimes */
79095060Sjmallettstatic void
791228063Sbaptdochc(const char *argv[], int argc)
7921590Srgrimes{
793228063Sbapt/* XXX Note that there is no difference between no argument and a single
794228063Sbapt * empty argument.
795228063Sbapt */
796228063Sbapt	if (argc == 2) {
79795060Sjmallett		scommt[0] = EOS;
79895060Sjmallett		ecommt[0] = EOS;
79995060Sjmallett	} else {
800228063Sbapt		strlcpy(scommt, argv[2], sizeof(scommt));
801228063Sbapt		if (argc == 3) {
802228063Sbapt			ecommt[0] = ECOMMT; ecommt[1] = EOS;
803228063Sbapt		} else {
80495060Sjmallett			strlcpy(ecommt, argv[3], sizeof(ecommt));
805228063Sbapt		}
8061590Srgrimes	}
8071590Srgrimes}
808228063Sbapt
8091590Srgrimes/*
810228063Sbapt * dom4wrap - expand text at EOF
8111590Srgrimes */
81295060Sjmallettstatic void
813228063Sbaptdom4wrap(const char *text)
8141590Srgrimes{
815228063Sbapt	if (wrapindex >= maxwraps) {
816228063Sbapt		if (maxwraps == 0)
817228063Sbapt			maxwraps = 16;
8181590Srgrimes		else
819228063Sbapt			maxwraps *= 2;
820269162Sbapt		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
821228063Sbapt		   "too many m4wraps");
8221590Srgrimes	}
823228063Sbapt	m4wraps[wrapindex++] = xstrdup(text);
8241590Srgrimes}
8251590Srgrimes
8261590Srgrimes/*
8271590Srgrimes * dodivert - divert the output to a temporary file
8281590Srgrimes */
82995060Sjmallettstatic void
83095887Sjmallettdodiv(int n)
8311590Srgrimes{
83295060Sjmallett	int fd;
83395060Sjmallett
83428386Sjlemon	oindex = n;
83595060Sjmallett	if (n >= maxout) {
83695060Sjmallett		if (mimic_gnu)
83795060Sjmallett			resizedivs(n + 10);
83895060Sjmallett		else
83995060Sjmallett			n = 0;		/* bitbucket */
840228063Sbapt	}
84195060Sjmallett
84295060Sjmallett	if (n < 0)
8431590Srgrimes		n = 0;		       /* bitbucket */
8441590Srgrimes	if (outfile[n] == NULL) {
84595060Sjmallett		char fname[] = _PATH_DIVNAME;
84695060Sjmallett
847352281Sbapt		if ((fd = mkstemp(fname)) == -1 ||
848269162Sbapt		    unlink(fname) == -1 ||
849269162Sbapt		    (outfile[n] = fdopen(fd, "w+")) == NULL)
850269162Sbapt			err(1, "%s: cannot divert", fname);
8511590Srgrimes	}
8521590Srgrimes	active = outfile[n];
8531590Srgrimes}
8541590Srgrimes
8551590Srgrimes/*
8561590Srgrimes * doundivert - undivert a specified output, or all
8571590Srgrimes *              other outputs, in numerical order.
8581590Srgrimes */
85995060Sjmallettstatic void
86095887Sjmallettdoundiv(const char *argv[], int argc)
8611590Srgrimes{
86295060Sjmallett	int ind;
86395060Sjmallett	int n;
8641590Srgrimes
8651590Srgrimes	if (argc > 2) {
8661590Srgrimes		for (ind = 2; ind < argc; ind++) {
867228063Sbapt			const char *errstr;
868228063Sbapt			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
869228063Sbapt			if (errstr) {
870228063Sbapt				if (errno == EINVAL && mimic_gnu)
871228063Sbapt					getdivfile(argv[ind]);
872228063Sbapt			} else {
873228063Sbapt				if (n < maxout && outfile[n] != NULL)
874228063Sbapt					getdiv(n);
875228063Sbapt			}
8761590Srgrimes		}
8771590Srgrimes	}
8781590Srgrimes	else
87995060Sjmallett		for (n = 1; n < maxout; n++)
8801590Srgrimes			if (outfile[n] != NULL)
8811590Srgrimes				getdiv(n);
8821590Srgrimes}
8831590Srgrimes
8841590Srgrimes/*
8851590Srgrimes * dosub - select substring
8861590Srgrimes */
88795060Sjmallettstatic void
88895887Sjmallettdosub(const char *argv[], int argc)
8891590Srgrimes{
89095060Sjmallett	const char *ap, *fc, *k;
89195060Sjmallett	int nc;
8921590Srgrimes
89376822Sgshapiro	ap = argv[2];		       /* target string */
89476822Sgshapiro#ifdef EXPR
89576822Sgshapiro	fc = ap + expr(argv[3]);       /* first char */
89676822Sgshapiro#else
89776822Sgshapiro	fc = ap + atoi(argv[3]);       /* first char */
89876822Sgshapiro#endif
89995060Sjmallett	nc = strlen(fc);
90095060Sjmallett	if (argc >= 5)
9011590Srgrimes#ifdef EXPR
90295060Sjmallett		nc = min(nc, expr(argv[4]));
9031590Srgrimes#else
90495060Sjmallett		nc = min(nc, atoi(argv[4]));
9051590Srgrimes#endif
9061590Srgrimes	if (fc >= ap && fc < ap + strlen(ap))
90776822Sgshapiro		for (k = fc + nc - 1; k >= fc; k--)
908228063Sbapt			pushback(*k);
9091590Srgrimes}
9101590Srgrimes
9111590Srgrimes/*
9121590Srgrimes * map:
9131590Srgrimes * map every character of s1 that is specified in from
9141590Srgrimes * into s3 and replace in s. (source s1 remains untouched)
9151590Srgrimes *
916228063Sbapt * This is derived from the a standard implementation of map(s,from,to)
917228063Sbapt * function of ICON language. Within mapvec, we replace every character
918228063Sbapt * of "from" with the corresponding character in "to".
919228063Sbapt * If "to" is shorter than "from", than the corresponding entries are null,
920298879Spfg * which means that those characters disappear altogether.
9211590Srgrimes */
92295060Sjmallettstatic void
92395887Sjmallettmap(char *dest, const char *src, const char *from, const char *to)
9241590Srgrimes{
92595060Sjmallett	const char *tmp;
92695060Sjmallett	unsigned char sch, dch;
92795060Sjmallett	static char frombis[257];
92895060Sjmallett	static char tobis[257];
929228063Sbapt	int i;
930228063Sbapt	char seen[256];
93195060Sjmallett	static unsigned char mapvec[256] = {
93295060Sjmallett	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
93395060Sjmallett	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
93495060Sjmallett	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
93595060Sjmallett	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
93695060Sjmallett	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
93795060Sjmallett	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
93895060Sjmallett	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
93995060Sjmallett	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
94095060Sjmallett	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
94195060Sjmallett	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
94295060Sjmallett	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
94395060Sjmallett	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
94495060Sjmallett	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
94595060Sjmallett	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
94695060Sjmallett	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
94795060Sjmallett	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
94895060Sjmallett	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
94995060Sjmallett	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
9501590Srgrimes	};
9511590Srgrimes
9521590Srgrimes	if (*src) {
95395060Sjmallett		if (mimic_gnu) {
95495060Sjmallett			/*
95595060Sjmallett			 * expand character ranges on the fly
95695060Sjmallett			 */
95795060Sjmallett			from = handledash(frombis, frombis + 256, from);
95895060Sjmallett			to = handledash(tobis, tobis + 256, to);
95995060Sjmallett		}
9601590Srgrimes		tmp = from;
9611590Srgrimes	/*
9621590Srgrimes	 * create a mapping between "from" and
9631590Srgrimes	 * "to"
9641590Srgrimes	 */
965228063Sbapt		for (i = 0; i < 256; i++)
966228063Sbapt			seen[i] = 0;
967228063Sbapt		while (*from) {
968228063Sbapt			if (!seen[(unsigned char)(*from)]) {
969228063Sbapt				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
970228063Sbapt				seen[(unsigned char)(*from)] = 1;
971228063Sbapt			}
972228063Sbapt			from++;
973228063Sbapt			if (*to)
974228063Sbapt				to++;
975228063Sbapt		}
9761590Srgrimes
9771590Srgrimes		while (*src) {
97895060Sjmallett			sch = (unsigned char)(*src++);
9791590Srgrimes			dch = mapvec[sch];
98095060Sjmallett			if ((*dest = (char)dch))
9811590Srgrimes				dest++;
9821590Srgrimes		}
9831590Srgrimes	/*
9841590Srgrimes	 * restore all the changed characters
9851590Srgrimes	 */
9861590Srgrimes		while (*tmp) {
98795060Sjmallett			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
9881590Srgrimes			tmp++;
9891590Srgrimes		}
9901590Srgrimes	}
99195060Sjmallett	*dest = '\0';
9921590Srgrimes}
99395060Sjmallett
99495060Sjmallett
99595060Sjmallett/*
99695060Sjmallett * handledash:
99795060Sjmallett *  use buffer to copy the src string, expanding character ranges
99895060Sjmallett * on the way.
99995060Sjmallett */
100095060Sjmallettstatic const char *
100195887Sjmalletthandledash(char *buffer, char *end, const char *src)
100295060Sjmallett{
100395060Sjmallett	char *p;
1004100014Sjmallett
100595060Sjmallett	p = buffer;
100695060Sjmallett	while(*src) {
100795060Sjmallett		if (src[1] == '-' && src[2]) {
100895060Sjmallett			unsigned char i;
1009228063Sbapt			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
1010228063Sbapt				for (i = (unsigned char)src[0];
1011228063Sbapt				    i <= (unsigned char)src[2]; i++) {
1012228063Sbapt					*p++ = i;
1013228063Sbapt					if (p == end) {
1014228063Sbapt						*p = '\0';
1015228063Sbapt						return buffer;
1016228063Sbapt					}
101795060Sjmallett				}
1018228063Sbapt			} else {
1019228063Sbapt				for (i = (unsigned char)src[0];
1020228063Sbapt				    i >= (unsigned char)src[2]; i--) {
1021228063Sbapt					*p++ = i;
1022228063Sbapt					if (p == end) {
1023228063Sbapt						*p = '\0';
1024228063Sbapt						return buffer;
1025228063Sbapt					}
1026228063Sbapt				}
102795060Sjmallett			}
102895060Sjmallett			src += 3;
102995060Sjmallett		} else
103095060Sjmallett			*p++ = *src++;
103195060Sjmallett		if (p == end)
103295060Sjmallett			break;
103395060Sjmallett	}
103495060Sjmallett	*p = '\0';
103595060Sjmallett	return buffer;
103695060Sjmallett}
1037