Home | History | Annotate | Line # | Download | only in m4
      1 /*	$OpenBSD: eval.c,v 1.81 2026/02/25 05:37:25 op Exp $	*/
      2 /*	$NetBSD: eval.c,v 1.31 2026/06/10 22:25:02 christos Exp $ */
      3 
      4 /*
      5  * Copyright (c) 1989, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * Ozan Yigit at York University.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 /*
     37  * eval.c
     38  * Facility: m4 macro processor
     39  * by: oz
     40  */
     41 #if HAVE_NBTOOL_CONFIG_H
     42 #include "nbtool_config.h"
     43 #endif
     44 #include <sys/cdefs.h>
     45 __RCSID("$NetBSD: eval.c,v 1.31 2026/06/10 22:25:02 christos Exp $");
     46 
     47 #include <sys/types.h>
     48 #include <ctype.h>
     49 #include <err.h>
     50 #include <errno.h>
     51 #include <limits.h>
     52 #include <unistd.h>
     53 #include <stdio.h>
     54 #include <stdint.h>
     55 #include <stdlib.h>
     56 #include <stddef.h>
     57 #include <string.h>
     58 #include <inttypes.h>
     59 #include <fcntl.h>
     60 #include "mdef.h"
     61 #include "stdd.h"
     62 #include "extern.h"
     63 #include "pathnames.h"
     64 
     65 static void	dodefn(const char *);
     66 static void	dopushdef(const char *, const char *);
     67 static void	dodumpdef(const char *[], int);
     68 static void	dotrace(const char *[], int, int);
     69 static void	doifelse(const char *[], int);
     70 static int	doinclude(const char *);
     71 static int	dopaste(const char *);
     72 static void	dochangequote(const char *[], int);
     73 static void	dochangecom(const char *[], int);
     74 static void	dom4wrap(const char *);
     75 static void	dodivert(int);
     76 static void	doundivert(const char *[], int);
     77 static void	dosubstr(const char *[], int);
     78 static void	map(char *, const char *, const char *, const char *);
     79 static const char *handledash(char *, char *, const char *);
     80 static void	expand_builtin(const char *[], int, int);
     81 static void	expand_macro(const char *[], int);
     82 static void	dump_one_def(const char *, struct macro_definition *);
     83 
     84 unsigned long	expansion_id;
     85 
     86 /*
     87  * eval - eval all macros and builtins calls
     88  *	  argc - number of elements in argv.
     89  *	  argv - element vector :
     90  *			argv[0] = definition of a user
     91  *				  macro or NULL if built-in.
     92  *			argv[1] = name of the macro or
     93  *				  built-in.
     94  *			argv[2] = parameters to user-defined
     95  *			   .	  macro or built-in.
     96  *			   .
     97  *
     98  * A call in the form of macro-or-builtin() will result in:
     99  *			argv[0] = nullstr
    100  *			argv[1] = macro-or-builtin
    101  *			argv[2] = nullstr
    102  *
    103  * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
    104  */
    105 void
    106 eval(const char *argv[], int argc, int td, int is_traced)
    107 {
    108 	size_t mark = SIZE_MAX;
    109 
    110 	expansion_id++;
    111 	if (td & RECDEF)
    112 		m4errx(1, "expanding recursive definition for %s.", argv[1]);
    113 	if (is_traced)
    114 		mark = trace(argv, argc, infile+ilevel);
    115 	if (td == MACROTYPE)
    116 		expand_macro(argv, argc);
    117 	else
    118 		expand_builtin(argv, argc, td);
    119 	if (mark != SIZE_MAX)
    120 		finish_trace(mark);
    121 }
    122 
    123 /*
    124  * expand_builtin - evaluate built-in macros.
    125  */
    126 void
    127 expand_builtin(const char *argv[], int argc, int td)
    128 {
    129 	int c, n, e;
    130 	int ac;
    131 	static int sysval = 0;
    132 
    133 #ifdef DEBUG
    134 	printf("argc = %d\n", argc);
    135 	for (n = 0; n < argc; n++)
    136 		printf("argv[%d] = %s\n", n, argv[n]);
    137 	fflush(stdout);
    138 #endif
    139 
    140  /*
    141   * if argc == 3 and argv[2] is null, then we
    142   * have macro-or-builtin() type call. We adjust
    143   * argc to avoid further checking..
    144   */
    145  /* we keep the initial value for those built-ins that differentiate
    146   * between builtin() and builtin.
    147   */
    148 	ac = argc;
    149 
    150 	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
    151 		argc--;
    152 
    153 	switch (td & TYPEMASK) {
    154 
    155 	case DEFINETYPE:
    156 		if (argc > 2)
    157 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
    158 		break;
    159 
    160 	case PUSHDEFTYPE:
    161 		if (argc > 2)
    162 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
    163 		break;
    164 
    165 	case DUMPDEFTYPE:
    166 		dodumpdef(argv, argc);
    167 		break;
    168 
    169 	case TRACEONTYPE:
    170 		dotrace(argv, argc, 1);
    171 		break;
    172 
    173 	case TRACEOFFTYPE:
    174 		dotrace(argv, argc, 0);
    175 		break;
    176 
    177 	case EVALTYPE:
    178 	/*
    179 	 * doeval - evaluate arithmetic expression
    180 	 */
    181 	{
    182 		int base = 10;
    183 		int maxdigits = 0;
    184 
    185 		if (argc > 3 && *argv[3] != '\0') {
    186 			base = (int)strtoi(argv[3], NULL, 0, 2, 36, &e);
    187 			if (e) {
    188 				m4errx(1, "expr: base %s invalid.", argv[3]);
    189 			}
    190 		}
    191 		if (argc > 4) {
    192 			maxdigits = (int)strtoi(argv[4], NULL, 0, 0, INT_MAX, &e);
    193 			if (e) {
    194 				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
    195 			}
    196 		}
    197 		if (argc > 2)
    198 			pbnumbase(expr(argv[2]), base, maxdigits);
    199 		break;
    200 	}
    201 
    202 	case IFELSETYPE:
    203 		if (argc > 4)
    204 			doifelse(argv, argc);
    205 		break;
    206 
    207 	case IFDEFTYPE:
    208 	/*
    209 	 * doifdef - select one of two alternatives based
    210 	 * on the existence of another definition
    211 	 */
    212 		if (argc > 3) {
    213 			if (lookup_macro_definition(argv[2]) != NULL)
    214 				pbstr(argv[3]);
    215 			else if (argc > 4)
    216 				pbstr(argv[4]);
    217 		}
    218 		break;
    219 
    220 	case LENTYPE:
    221 	/*
    222 	 * dolen - find the length of the argument
    223 	 */
    224 		pbnum((argc > 2) ? strlen(argv[2]) : 0);
    225 		break;
    226 
    227 	case INCRTYPE:
    228 	/*
    229 	 * doincr - increment the value of the argument
    230 	 */
    231 		if (argc > 2) {
    232 			n = (int)strtoi(argv[2], NULL, 0, INT_MIN, INT_MAX-1, &e);
    233 			if (e) {
    234 				m4errx(1, "incr: argument %s: %s,", argv[2],
    235 				    strerror(e));
    236 			}
    237 			pbnum(n + 1);
    238 		}
    239 		break;
    240 
    241 	case DECRTYPE:
    242 	/*
    243 	 * dodecr - decrement the value of the argument
    244 	 */
    245 		if (argc > 2) {
    246 			n = (int)strtoi(argv[2], NULL, 0, INT_MIN, INT_MAX-1, &e);
    247 			if (e) {
    248 				m4errx(1, "decr: argument %s: %s,", argv[2],
    249 				    strerror(e));
    250 			}
    251 			pbnum(n - 1);
    252 		}
    253 		break;
    254 
    255 	case SYSCMDTYPE:
    256 	/*
    257 	 * dosyscmd - execute system command
    258 	 */
    259 		if (argc > 2) {
    260 			fflush(stdout);
    261 			sysval = system(argv[2]);
    262 		}
    263 		break;
    264 
    265 	case SYSVALTYPE:
    266 	/*
    267 	 * dosysval - return value of the last system call.
    268 	 *
    269 	 */
    270 		pbnum(sysval);
    271 		break;
    272 
    273 	case ESYSCMDTYPE:
    274 		if (argc > 2)
    275 			doesyscmd(argv[2]);
    276 		break;
    277 	case INCLUDETYPE:
    278 		if (argc > 2) {
    279 			if (!doinclude(argv[2])) {
    280 				if (mimic_gnu) {
    281 					warn("%s at line %lu: include(%s)",
    282 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
    283 					exit_code = 1;
    284 					if (fatal_warns) {
    285 						killdiv();
    286 						exit(exit_code);
    287 					}
    288 				} else
    289 					err(1, "%s at line %lu: include(%s)",
    290 					    CURRENT_NAME, CURRENT_LINE, argv[2]);
    291 			}
    292 		}
    293 		break;
    294 
    295 	case SINCLUDETYPE:
    296 	/* like include, but don't error out if file not found */
    297 		if (argc > 2)
    298 			(void) doinclude(argv[2]);
    299 		break;
    300 #ifdef EXTENDED
    301 	case PASTETYPE:
    302 		if (argc > 2)
    303 			if (!dopaste(argv[2]))
    304 				err(1, "%s at line %lu: paste(%s)",
    305 				    CURRENT_NAME, CURRENT_LINE, argv[2]);
    306 		break;
    307 
    308 	case SPASTETYPE:
    309 		if (argc > 2)
    310 			(void) dopaste(argv[2]);
    311 		break;
    312 	case FORMATTYPE:
    313 		doformat(argv, argc);
    314 		break;
    315 #endif
    316 	case CHANGEQUOTETYPE:
    317 		dochangequote(argv, ac);
    318 		break;
    319 
    320 	case CHANGECOMTYPE:
    321 		dochangecom(argv, argc);
    322 		break;
    323 
    324 	case SUBSTRTYPE:
    325 	/*
    326 	 * dosubstr - select substring
    327 	 *
    328 	 */
    329 		if (argc > 3)
    330 			dosubstr(argv, argc);
    331 		break;
    332 
    333 	case SHIFTTYPE:
    334 	/*
    335 	 * doshift - push back all arguments except the first one
    336 	 * (i.e. skip argv[2])
    337 	 */
    338 		if (argc > 3) {
    339 			for (n = argc - 1; n > 3; n--) {
    340 				pbstr(rquote);
    341 				pbstr(argv[n]);
    342 				pbstr(lquote);
    343 				pushback(COMMA);
    344 			}
    345 			pbstr(rquote);
    346 			pbstr(argv[3]);
    347 			pbstr(lquote);
    348 		}
    349 		break;
    350 
    351 	case DIVERTTYPE:
    352 		if (argc > 2) {
    353 			n = (int)strtoi(argv[2], NULL, 0, INT_MIN, INT_MAX, &e);
    354 			if (e) {
    355 				m4errx(1, "divert: argument %s: %s,", argv[2],
    356 				    strerror(e));
    357 			}
    358 			if (n != 0) {
    359 				dodivert(n);
    360 				break;
    361 			}
    362 		}
    363 		active = stdout;
    364 		oindex = 0;
    365 		break;
    366 
    367 	case UNDIVERTTYPE:
    368 		doundivert(argv, argc);
    369 		break;
    370 
    371 	case DIVNUMTYPE:
    372 	/*
    373 	 * dodivnum - return the number of current output diversion
    374 	 */
    375 		pbnum(oindex);
    376 		break;
    377 
    378 	case UNDEFINETYPE:
    379 	/*
    380 	 * doundefine - undefine a previously defined macro(s) or m4 keyword(s).
    381 	 */
    382 		if (argc > 2)
    383 			for (n = 2; n < argc; n++)
    384 				macro_undefine(argv[n]);
    385 		break;
    386 
    387 	case POPDEFTYPE:
    388 	/*
    389 	 * dopopdef - remove the topmost definitions of macro(s)
    390 	 * or m4 keyword(s).
    391 	 */
    392 		if (argc > 2)
    393 			for (n = 2; n < argc; n++)
    394 				macro_popdef(argv[n]);
    395 		break;
    396 
    397 	case MKSTEMPTYPE:
    398 	/*
    399 	 * domkstemp - create a temporary file
    400 	 */
    401 		if (argc > 2) {
    402 			int fd;
    403 			char *temp;
    404 
    405 			temp = xstrdup(argv[2]);
    406 
    407 			fd = mkstemp(temp);
    408 			if (fd == -1)
    409 				err(1,
    410 	    "%s at line %lu: couldn't make temp file %s",
    411 	    CURRENT_NAME, CURRENT_LINE, argv[2]);
    412 			close(fd);
    413 			pbstr(temp);
    414 			free(temp);
    415 		}
    416 		break;
    417 
    418 	case TRANSLITTYPE:
    419 	/*
    420 	 * dotranslit - replace all characters in the source string
    421 	 * that appears in the "from" string with the corresponding
    422 	 * characters in the "to" string.
    423 	 */
    424 		if (argc > 3) {
    425 			char *temp;
    426 
    427 			temp = xalloc(strlen(argv[2])+1, NULL);
    428 			if (argc > 4)
    429 				map(temp, argv[2], argv[3], argv[4]);
    430 			else
    431 				map(temp, argv[2], argv[3], null);
    432 			pbstr(temp);
    433 			free(temp);
    434 		} else if (argc > 2)
    435 			pbstr(argv[2]);
    436 		break;
    437 
    438 	case INDEXTYPE:
    439 	/*
    440 	 * doindex - find the index of the second argument string
    441 	 * in the first argument string. -1 if not present.
    442 	 */
    443 		pbnum((int)((argc > 3) ? doindex(argv[2], argv[3]) : -1));
    444 		break;
    445 
    446 	case ERRPRINTTYPE:
    447 	/*
    448 	 * doerrprint - print the arguments to stderr
    449 	 */
    450 		if (argc > 2) {
    451 			for (n = 2; n < argc; n++)
    452 				fprintf(stderr, "%s%s",
    453 				    mimic_gnu && n == 2 ? "" : " ",
    454 				    argv[n]);
    455 			if (!mimic_gnu)
    456 				fprintf(stderr, "\n");
    457 		}
    458 		break;
    459 
    460 	case DNLTYPE:
    461 	/*
    462 	 * dodnl - eat-up-to and including newline
    463 	 */
    464 		while ((c = gpbc()) != '\n' && c != EOF)
    465 			;
    466 		break;
    467 
    468 	case M4WRAPTYPE:
    469 	/*
    470 	 * dom4wrap - set up for wrap-up/wind-down activity
    471 	 */
    472 		if (argc > 2)
    473 			dom4wrap(argv[2]);
    474 		break;
    475 
    476 	case M4EXITTYPE:
    477 	/*
    478 	 * dom4exit - immediate exit from m4.
    479 	 */
    480 		killdiv();
    481 		exit((argc > 2) ? atoi(argv[2]) : 0);
    482 
    483 	case DEFNTYPE:
    484 		if (argc > 2)
    485 			for (n = 2; n < argc; n++)
    486 				dodefn(argv[n]);
    487 		break;
    488 
    489 	case INDIRTYPE:	/* Indirect call */
    490 		if (argc > 2)
    491 			doindir(argv, argc);
    492 		break;
    493 
    494 	case BUILTINTYPE: /* Builtins only */
    495 		if (argc > 2)
    496 			dobuiltin(argv, argc);
    497 		break;
    498 
    499 	case PATSUBSTTYPE:
    500 		if (argc > 2)
    501 			dopatsubst(argv, argc);
    502 		break;
    503 	case REGEXPTYPE:
    504 		if (argc > 2)
    505 			doregexp(argv, argc);
    506 		break;
    507 	case LINETYPE:
    508 		doprintlineno(infile+ilevel);
    509 		break;
    510 	case FILENAMETYPE:
    511 		doprintfilename(infile+ilevel);
    512 		break;
    513 	case SELFTYPE:
    514 		pbstr(rquote);
    515 		pbstr(argv[1]);
    516 		pbstr(lquote);
    517 		break;
    518 	default:
    519 		m4errx(1, "eval: major botch.");
    520 	}
    521 }
    522 
    523 /*
    524  * expand_macro - user-defined macro expansion
    525  */
    526 void
    527 expand_macro(const char *argv[], int argc)
    528 {
    529 	const char *t;
    530 	const char *p;
    531 	int n;
    532 	int argno;
    533 
    534 	t = argv[0];		       /* defn string as a whole */
    535 	p = t;
    536 	while (*p)
    537 		p++;
    538 	p--;			       /* last character of defn */
    539 	while (p > t) {
    540 		if (*(p - 1) != ARGFLAG)
    541 			PUSHBACK(*p);
    542 		else {
    543 			switch (*p) {
    544 
    545 			case '#':
    546 				pbnum(argc - 2);
    547 				break;
    548 			case '0':
    549 			case '1':
    550 			case '2':
    551 			case '3':
    552 			case '4':
    553 			case '5':
    554 			case '6':
    555 			case '7':
    556 			case '8':
    557 			case '9':
    558 				argno = *p - '0';
    559 				if (mimic_gnu) {
    560 					const unsigned char *q =
    561 					    (const unsigned char *)p;
    562 					while (isdigit(*++q)) {
    563 						bp--;
    564 						argno = argno * 10 + *q - '0';
    565 					}
    566 				}
    567 				if (argno < argc - 1)
    568 					pbstr(argv[argno + 1]);
    569 				break;
    570 			case '*':
    571 				if (argc > 2) {
    572 					for (n = argc - 1; n > 2; n--) {
    573 						pbstr(argv[n]);
    574 						pushback(COMMA);
    575 					}
    576 					pbstr(argv[2]);
    577 				}
    578 				break;
    579 			case '@':
    580 				if (argc > 2) {
    581 					for (n = argc - 1; n > 2; n--) {
    582 						pbstr(rquote);
    583 						pbstr(argv[n]);
    584 						pbstr(lquote);
    585 						pushback(COMMA);
    586 					}
    587 					pbstr(rquote);
    588 					pbstr(argv[2]);
    589 					pbstr(lquote);
    590 				}
    591 				break;
    592 			default:
    593 				PUSHBACK(*p);
    594 				PUSHBACK('$');
    595 				break;
    596 			}
    597 			p--;
    598 		}
    599 		p--;
    600 	}
    601 	if (p == t)		       /* do last character */
    602 		PUSHBACK(*p);
    603 }
    604 
    605 
    606 /*
    607  * dodefine - install definition in the table
    608  */
    609 void
    610 dodefine(const char *name, const char *defn)
    611 {
    612 	if (!*name && !mimic_gnu)
    613 		m4errx(1, "define macro with empty name.");
    614 	else
    615 		macro_define(name, defn);
    616 }
    617 
    618 /*
    619  * dodefn - push back a quoted definition of
    620  *	the given name.
    621  */
    622 static void
    623 dodefn(const char *name)
    624 {
    625 	struct macro_definition *p;
    626 
    627 	if ((p = lookup_macro_definition(name)) != NULL) {
    628 		if ((p->type & TYPEMASK) == MACROTYPE) {
    629 			pbstr(rquote);
    630 			pbstr(p->defn);
    631 			pbstr(lquote);
    632 		} else {
    633 			pbstr(p->defn);
    634 			pbstr(BUILTIN_MARKER);
    635 		}
    636 	}
    637 }
    638 
    639 /*
    640  * dopushdef - install a definition in the hash table
    641  *	without removing a previous definition. Since
    642  *	each new entry is entered in *front* of the
    643  *	hash bucket, it hides a previous definition from
    644  *	lookup.
    645  */
    646 static void
    647 dopushdef(const char *name, const char *defn)
    648 {
    649 	if (!*name && !mimic_gnu)
    650 		m4errx(1, "pushdef macro with empty name.");
    651 	else
    652 		macro_pushdef(name, defn);
    653 }
    654 
    655 /*
    656  * dump_one_def - dump the specified definition.
    657  */
    658 static void
    659 dump_one_def(const char *name, struct macro_definition *p)
    660 {
    661 	if (!traceout)
    662 		traceout = stderr;
    663 	if (mimic_gnu) {
    664 		if ((p->type & TYPEMASK) == MACROTYPE)
    665 			fprintf(traceout, "%s:\t%s\n", name, p->defn);
    666 		else {
    667 			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
    668 		}
    669 	} else
    670 		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
    671 }
    672 
    673 /*
    674  * dodumpdef - dump the specified definitions in the hash
    675  *	table to stderr. If nothing is specified, the entire
    676  *	hash table is dumped.
    677  */
    678 static void
    679 dodumpdef(const char *argv[], int argc)
    680 {
    681 	int n;
    682 	struct macro_definition *p;
    683 
    684 	if (argc > 2) {
    685 		for (n = 2; n < argc; n++)
    686 			if ((p = lookup_macro_definition(argv[n])) != NULL)
    687 				dump_one_def(argv[n], p);
    688 	} else
    689 		macro_for_all(dump_one_def);
    690 }
    691 
    692 /*
    693  * dotrace - mark some macros as traced/untraced depending upon on.
    694  */
    695 static void
    696 dotrace(const char *argv[], int argc, int on)
    697 {
    698 	int n;
    699 
    700 	if (argc > 2) {
    701 		for (n = 2; n < argc; n++)
    702 			mark_traced(argv[n], on);
    703 	} else
    704 		mark_traced(NULL, on);
    705 }
    706 
    707 /*
    708  * doifelse - select one of two alternatives - loop.
    709  */
    710 static void
    711 doifelse(const char *argv[], int argc)
    712 {
    713 	while (argc > 4) {
    714 		if (argc < 5)
    715 			m4errx(1, "wrong number of args for ifelse");
    716 		if (STREQ(argv[2], argv[3])) {
    717 			pbstr(argv[4]);
    718 			break;
    719 		} else if (argc == 6) {
    720 			pbstr(argv[5]);
    721 			break;
    722 		} else {
    723 			argv += 3;
    724 			argc -= 3;
    725 		}
    726 	}
    727 }
    728 
    729 /*
    730  * doinclude - include a given file.
    731  */
    732 static int
    733 doinclude(const char *ifile)
    734 {
    735 #ifndef REAL_FREEZE
    736 	if (thawing)
    737 		return 1;
    738 #endif
    739 	if (ilevel + 1 == MAXINP)
    740 		m4errx(1, "too many include files.");
    741 	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
    742 		ilevel++;
    743 		bbase[ilevel] = bufbase = bp;
    744 		return (1);
    745 	} else
    746 		return (0);
    747 }
    748 
    749 #ifdef EXTENDED
    750 /*
    751  * dopaste - include a given file without any
    752  *	     macro processing.
    753  */
    754 static int
    755 dopaste(const char *pfile)
    756 {
    757 	FILE *pf;
    758 	int c;
    759 
    760 	if ((pf = fopen(pfile, "r")) != NULL) {
    761 		if (synch_lines)
    762 		    fprintf(active, "#line 1 \"%s\"\n", pfile);
    763 		while ((c = getc(pf)) != EOF)
    764 			putc(c, active);
    765 		(void) fclose(pf);
    766 		emit_synchline();
    767 		return (1);
    768 	} else
    769 		return (0);
    770 }
    771 #endif
    772 
    773 /*
    774  * dochangequote - change quote characters
    775  */
    776 static void
    777 dochangequote(const char *argv[], int ac)
    778 {
    779 	if (ac == 2) {
    780 		lquote[0] = LQUOTE; lquote[1] = EOS;
    781 		rquote[0] = RQUOTE; rquote[1] = EOS;
    782 	} else {
    783 		strlcpy(lquote, argv[2], sizeof(lquote));
    784 		if (ac > 3) {
    785 			strlcpy(rquote, argv[3], sizeof(rquote));
    786 		} else {
    787 			rquote[0] = ECOMMT; rquote[1] = EOS;
    788 		}
    789 	}
    790 }
    791 
    792 /*
    793  * dochangecom - change comment characters
    794  */
    795 static void
    796 dochangecom(const char *argv[], int argc)
    797 {
    798 /* XXX Note that there is no difference between no argument and a single
    799  * empty argument.
    800  */
    801 	if (argc == 2) {
    802 		scommt[0] = EOS;
    803 		ecommt[0] = EOS;
    804 	} else {
    805 		strlcpy(scommt, argv[2], sizeof(scommt));
    806 		if (argc == 3) {
    807 			ecommt[0] = ECOMMT; ecommt[1] = EOS;
    808 		} else {
    809 			strlcpy(ecommt, argv[3], sizeof(ecommt));
    810 		}
    811 	}
    812 }
    813 
    814 /*
    815  * dom4wrap - expand text at EOF
    816  */
    817 static void
    818 dom4wrap(const char *text)
    819 {
    820 	if (wrapindex >= maxwraps) {
    821 		if (maxwraps == 0)
    822 			maxwraps = 16;
    823 		else
    824 			maxwraps *= 2;
    825 		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
    826 		   "too many m4wraps");
    827 	}
    828 	m4wraps[wrapindex++] = xstrdup(text);
    829 }
    830 
    831 /*
    832  * dodivert - divert the output to a temporary file
    833  */
    834 static void
    835 dodivert(int n)
    836 {
    837 	int fd;
    838 
    839 	oindex = n;
    840 	if (n >= maxout) {
    841 		if (mimic_gnu)
    842 			resizedivs(n + 10);
    843 		else
    844 			n = 0;		/* bitbucket */
    845 	}
    846 
    847 	if (n < 0)
    848 		n = 0;		       /* bitbucket */
    849 	if (outfile[n] == NULL) {
    850 		char fname[] = _PATH_DIVNAME;
    851 
    852 		if ((fd = mkstemp(fname)) == -1 ||
    853 		    unlink(fname) == -1 ||
    854 		    (outfile[n] = fdopen(fd, "w+")) == NULL)
    855 			err(1, "%s: cannot divert", fname);
    856 	}
    857 	active = outfile[n];
    858 }
    859 
    860 /*
    861  * doundivert - undivert a specified output, or all
    862  *		other outputs, in numerical order.
    863  */
    864 static void
    865 doundivert(const char *argv[], int argc)
    866 {
    867 	int ind;
    868 	int n;
    869 
    870 	if (argc > 2) {
    871 		for (ind = 2; ind < argc; ind++) {
    872 			int e;
    873 			n = (int)strtoi(argv[ind], NULL, 0, 1, INT_MAX, &e);
    874 			if (e) {
    875 				if (errno == EINVAL && mimic_gnu)
    876 					getdivfile(argv[ind]);
    877 			} else {
    878 				if (n < maxout && outfile[n] != NULL)
    879 					getdiv(n);
    880 			}
    881 		}
    882 	}
    883 	else
    884 		for (n = 1; n < maxout; n++)
    885 			if (outfile[n] != NULL)
    886 				getdiv(n);
    887 }
    888 
    889 /*
    890  * dosubstr - select substring
    891  */
    892 static void
    893 dosubstr(const char *argv[], int argc)
    894 {
    895 	const char *ap, *fc, *k;
    896 	int nc;
    897 
    898 	ap = argv[2];		       /* target string */
    899 #ifdef EXPR
    900 	fc = ap + expr(argv[3]);       /* first char */
    901 #else
    902 	fc = ap + atoi(argv[3]);       /* first char */
    903 #endif
    904 	nc = strlen(fc);
    905 	if (argc >= 5)
    906 #ifdef EXPR
    907 		nc = min(nc, expr(argv[4]));
    908 #else
    909 		nc = min(nc, atoi(argv[4]));
    910 #endif
    911 	if (fc >= ap && fc < ap + strlen(ap))
    912 		for (k = fc + nc - 1; k >= fc; k--)
    913 			pushback(*k);
    914 }
    915 
    916 /*
    917  * map:
    918  * map every character of s1 that is specified in from
    919  * into s3 and replace in s. (source s1 remains untouched)
    920  *
    921  * This is a standard implementation of map(s,from,to) function of ICON
    922  * language. Within mapvec, we replace every character of "from" with
    923  * the corresponding character in "to". If "to" is shorter than "from",
    924  * than the corresponding entries are null, which means that those
    925  * characters disappear altogether. Furthermore, imagine
    926  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
    927  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
    928  * ultimately maps to `*'. In order to achieve this effect in an efficient
    929  * manner (i.e. without multiple passes over the destination string), we
    930  * loop over mapvec, starting with the initial source character. if the
    931  * character value (dch) in this location is different than the source
    932  * character (sch), sch becomes dch, once again to index into mapvec, until
    933  * the character value stabilizes (i.e. sch = dch, in other words
    934  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
    935  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
    936  * end, we restore mapvec* back to normal where mapvec[n] == n for
    937  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
    938  * about 5 times faster than any algorithm that makes multiple passes over
    939  * destination string.
    940  */
    941 static void
    942 map(char *dest, const char *src, const char *from, const char *to)
    943 {
    944 	const char *tmp;
    945 	unsigned char sch, dch;
    946 	unsigned char found[256];
    947 	static char frombis[257];
    948 	static char tobis[257];
    949 	static unsigned char mapvec[256] = {
    950 	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
    951 	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
    952 	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
    953 	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
    954 	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
    955 	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
    956 	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
    957 	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
    958 	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
    959 	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
    960 	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
    961 	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
    962 	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
    963 	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
    964 	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
    965 	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
    966 	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
    967 	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
    968 	};
    969 
    970 	if (*src) {
    971 		if (mimic_gnu) {
    972 			/*
    973 			 * expand character ranges on the fly
    974 			 */
    975 			from = handledash(frombis, frombis + 256, from);
    976 			to = handledash(tobis, tobis + 256, to);
    977 		}
    978 		tmp = from;
    979 	/*
    980 	 * create a mapping between "from" and
    981 	 * "to"
    982 	 */
    983 		memset(found, 0, sizeof(found));
    984 		for (; (sch = (unsigned char)*from) != '\0'; from++) {
    985 			if (!mimic_gnu || !found[sch]) {
    986 				found[sch] = 1;
    987 				mapvec[sch] = *to;
    988 			}
    989 			if (*to)
    990 				to++;
    991 		}
    992 
    993 		if (mimic_gnu) {
    994 			for (; (sch = (unsigned char)*src) != '\0'; src++) {
    995 				if (!found[sch])
    996 					*dest++ = sch;
    997 				else if ((dch = mapvec[sch]) != '\0')
    998 					*dest++ = dch;
    999 			}
   1000 		} else {
   1001 			while (*src) {
   1002 				sch = (unsigned char)(*src++);
   1003 				dch = mapvec[sch];
   1004 				while (dch != sch) {
   1005 					sch = dch;
   1006 					dch = mapvec[sch];
   1007 				}
   1008 				if ((*dest = (char)dch))
   1009 					dest++;
   1010 			}
   1011 		}
   1012 	/*
   1013 	 * restore all the changed characters
   1014 	 */
   1015 		while (*tmp) {
   1016 			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
   1017 			tmp++;
   1018 		}
   1019 	}
   1020 	*dest = '\0';
   1021 }
   1022 
   1023 
   1024 /*
   1025  * handledash:
   1026  *  use buffer to copy the src string, expanding character ranges
   1027  * on the way.
   1028  */
   1029 static const char *
   1030 handledash(char *buffer, char *end, const char *src)
   1031 {
   1032 	char *p;
   1033 
   1034 	p = buffer;
   1035 	while(*src) {
   1036 		if (src[1] == '-' && src[2]) {
   1037 			unsigned char i;
   1038 			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
   1039 				for (i = (unsigned char)src[0];
   1040 				    i <= (unsigned char)src[2]; i++) {
   1041 					*p++ = i;
   1042 					if (p == end) {
   1043 						*p = '\0';
   1044 						return buffer;
   1045 					}
   1046 				}
   1047 			} else {
   1048 				for (i = (unsigned char)src[0];
   1049 				    i >= (unsigned char)src[2]; i--) {
   1050 					*p++ = i;
   1051 					if (p == end) {
   1052 						*p = '\0';
   1053 						return buffer;
   1054 					}
   1055 				}
   1056 			}
   1057 			src += 3;
   1058 		} else
   1059 			*p++ = *src++;
   1060 		if (p == end)
   1061 			break;
   1062 	}
   1063 	*p = '\0';
   1064 	return buffer;
   1065 }
   1066