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