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