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