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