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