Home | History | Annotate | Line # | Download | only in m4
eval.c revision 1.4
      1  1.4      tls /*      $NetBSD: eval.c,v 1.4 1995/09/28 05:37:28 tls Exp $      */
      2  1.4      tls 
      3  1.1      cgd /*
      4  1.2    glass  * Copyright (c) 1989, 1993
      5  1.2    glass  *	The Regents of the University of California.  All rights reserved.
      6  1.1      cgd  *
      7  1.1      cgd  * This code is derived from software contributed to Berkeley by
      8  1.2    glass  * Ozan Yigit at York University.
      9  1.1      cgd  *
     10  1.1      cgd  * Redistribution and use in source and binary forms, with or without
     11  1.1      cgd  * modification, are permitted provided that the following conditions
     12  1.1      cgd  * are met:
     13  1.1      cgd  * 1. Redistributions of source code must retain the above copyright
     14  1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     15  1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     17  1.1      cgd  *    documentation and/or other materials provided with the distribution.
     18  1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     19  1.1      cgd  *    must display the following acknowledgement:
     20  1.1      cgd  *	This product includes software developed by the University of
     21  1.1      cgd  *	California, Berkeley and its contributors.
     22  1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     23  1.1      cgd  *    may be used to endorse or promote products derived from this software
     24  1.1      cgd  *    without specific prior written permission.
     25  1.1      cgd  *
     26  1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  1.1      cgd  * SUCH DAMAGE.
     37  1.1      cgd  */
     38  1.1      cgd 
     39  1.1      cgd #ifndef lint
     40  1.4      tls #if 0
     41  1.4      tls static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
     42  1.4      tls #else
     43  1.4      tls static char rcsid[] = "$NetBSD: eval.c,v 1.4 1995/09/28 05:37:28 tls Exp $";
     44  1.4      tls #endif
     45  1.1      cgd #endif /* not lint */
     46  1.1      cgd 
     47  1.1      cgd /*
     48  1.1      cgd  * eval.c
     49  1.1      cgd  * Facility: m4 macro processor
     50  1.1      cgd  * by: oz
     51  1.1      cgd  */
     52  1.1      cgd 
     53  1.2    glass #include <sys/types.h>
     54  1.2    glass #include <errno.h>
     55  1.1      cgd #include <unistd.h>
     56  1.1      cgd #include <stdio.h>
     57  1.1      cgd #include <stdlib.h>
     58  1.1      cgd #include <string.h>
     59  1.1      cgd #include "mdef.h"
     60  1.2    glass #include "stdd.h"
     61  1.2    glass #include "extern.h"
     62  1.2    glass #include "pathnames.h"
     63  1.1      cgd 
     64  1.1      cgd /*
     65  1.1      cgd  * eval - evaluate built-in macros.
     66  1.1      cgd  *	  argc - number of elements in argv.
     67  1.1      cgd  *	  argv - element vector :
     68  1.1      cgd  *			argv[0] = definition of a user
     69  1.1      cgd  *				  macro or nil if built-in.
     70  1.1      cgd  *			argv[1] = name of the macro or
     71  1.1      cgd  *				  built-in.
     72  1.1      cgd  *			argv[2] = parameters to user-defined
     73  1.1      cgd  *			   .	  macro or built-in.
     74  1.1      cgd  *			   .
     75  1.1      cgd  *
     76  1.1      cgd  * Note that the minimum value for argc is 3. A call in the form
     77  1.1      cgd  * of macro-or-builtin() will result in:
     78  1.1      cgd  *			argv[0] = nullstr
     79  1.1      cgd  *			argv[1] = macro-or-builtin
     80  1.1      cgd  *			argv[2] = nullstr
     81  1.1      cgd  */
     82  1.1      cgd 
     83  1.2    glass void
     84  1.2    glass eval(argv, argc, td)
     85  1.1      cgd register char *argv[];
     86  1.1      cgd register int argc;
     87  1.2    glass register int td;
     88  1.1      cgd {
     89  1.1      cgd 	register int c, n;
     90  1.2    glass 	static int sysval = 0;
     91  1.1      cgd 
     92  1.1      cgd #ifdef DEBUG
     93  1.1      cgd 	printf("argc = %d\n", argc);
     94  1.1      cgd 	for (n = 0; n < argc; n++)
     95  1.1      cgd 		printf("argv[%d] = %s\n", n, argv[n]);
     96  1.1      cgd #endif
     97  1.2    glass  /*
     98  1.2    glass   * if argc == 3 and argv[2] is null, then we
     99  1.2    glass   * have macro-or-builtin() type call. We adjust
    100  1.2    glass   * argc to avoid further checking..
    101  1.2    glass   */
    102  1.1      cgd 	if (argc == 3 && !*(argv[2]))
    103  1.1      cgd 		argc--;
    104  1.1      cgd 
    105  1.1      cgd 	switch (td & ~STATIC) {
    106  1.1      cgd 
    107  1.1      cgd 	case DEFITYPE:
    108  1.1      cgd 		if (argc > 2)
    109  1.1      cgd 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
    110  1.1      cgd 		break;
    111  1.1      cgd 
    112  1.1      cgd 	case PUSDTYPE:
    113  1.1      cgd 		if (argc > 2)
    114  1.1      cgd 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
    115  1.1      cgd 		break;
    116  1.1      cgd 
    117  1.1      cgd 	case DUMPTYPE:
    118  1.1      cgd 		dodump(argv, argc);
    119  1.1      cgd 		break;
    120  1.1      cgd 
    121  1.1      cgd 	case EXPRTYPE:
    122  1.2    glass 	/*
    123  1.2    glass 	 * doexpr - evaluate arithmetic
    124  1.2    glass 	 * expression
    125  1.2    glass 	 */
    126  1.1      cgd 		if (argc > 2)
    127  1.1      cgd 			pbnum(expr(argv[2]));
    128  1.1      cgd 		break;
    129  1.1      cgd 
    130  1.1      cgd 	case IFELTYPE:
    131  1.1      cgd 		if (argc > 4)
    132  1.1      cgd 			doifelse(argv, argc);
    133  1.1      cgd 		break;
    134  1.1      cgd 
    135  1.1      cgd 	case IFDFTYPE:
    136  1.2    glass 	/*
    137  1.2    glass 	 * doifdef - select one of two
    138  1.2    glass 	 * alternatives based on the existence of
    139  1.2    glass 	 * another definition
    140  1.2    glass 	 */
    141  1.1      cgd 		if (argc > 3) {
    142  1.1      cgd 			if (lookup(argv[2]) != nil)
    143  1.1      cgd 				pbstr(argv[3]);
    144  1.1      cgd 			else if (argc > 4)
    145  1.1      cgd 				pbstr(argv[4]);
    146  1.1      cgd 		}
    147  1.1      cgd 		break;
    148  1.1      cgd 
    149  1.1      cgd 	case LENGTYPE:
    150  1.2    glass 	/*
    151  1.2    glass 	 * dolen - find the length of the
    152  1.2    glass 	 * argument
    153  1.2    glass 	 */
    154  1.1      cgd 		if (argc > 2)
    155  1.1      cgd 			pbnum((argc > 2) ? strlen(argv[2]) : 0);
    156  1.1      cgd 		break;
    157  1.1      cgd 
    158  1.1      cgd 	case INCRTYPE:
    159  1.2    glass 	/*
    160  1.2    glass 	 * doincr - increment the value of the
    161  1.2    glass 	 * argument
    162  1.2    glass 	 */
    163  1.1      cgd 		if (argc > 2)
    164  1.1      cgd 			pbnum(atoi(argv[2]) + 1);
    165  1.1      cgd 		break;
    166  1.1      cgd 
    167  1.1      cgd 	case DECRTYPE:
    168  1.2    glass 	/*
    169  1.2    glass 	 * dodecr - decrement the value of the
    170  1.2    glass 	 * argument
    171  1.2    glass 	 */
    172  1.1      cgd 		if (argc > 2)
    173  1.1      cgd 			pbnum(atoi(argv[2]) - 1);
    174  1.1      cgd 		break;
    175  1.1      cgd 
    176  1.1      cgd 	case SYSCTYPE:
    177  1.2    glass 	/*
    178  1.2    glass 	 * dosys - execute system command
    179  1.2    glass 	 */
    180  1.1      cgd 		if (argc > 2)
    181  1.1      cgd 			sysval = system(argv[2]);
    182  1.1      cgd 		break;
    183  1.1      cgd 
    184  1.1      cgd 	case SYSVTYPE:
    185  1.2    glass 	/*
    186  1.2    glass 	 * dosysval - return value of the last
    187  1.2    glass 	 * system call.
    188  1.2    glass 	 *
    189  1.2    glass 	 */
    190  1.1      cgd 		pbnum(sysval);
    191  1.1      cgd 		break;
    192  1.1      cgd 
    193  1.1      cgd 	case INCLTYPE:
    194  1.1      cgd 		if (argc > 2)
    195  1.2    glass 			if (!doincl(argv[2]))
    196  1.2    glass 				oops("%s: %s", argv[2], strerror(errno));
    197  1.1      cgd 		break;
    198  1.1      cgd 
    199  1.1      cgd 	case SINCTYPE:
    200  1.1      cgd 		if (argc > 2)
    201  1.1      cgd 			(void) doincl(argv[2]);
    202  1.1      cgd 		break;
    203  1.1      cgd #ifdef EXTENDED
    204  1.1      cgd 	case PASTTYPE:
    205  1.1      cgd 		if (argc > 2)
    206  1.2    glass 			if (!dopaste(argv[2]))
    207  1.2    glass 				oops("%s: %s", argv[2], strerror(errno));
    208  1.1      cgd 		break;
    209  1.1      cgd 
    210  1.1      cgd 	case SPASTYPE:
    211  1.1      cgd 		if (argc > 2)
    212  1.1      cgd 			(void) dopaste(argv[2]);
    213  1.1      cgd 		break;
    214  1.1      cgd #endif
    215  1.1      cgd 	case CHNQTYPE:
    216  1.1      cgd 		dochq(argv, argc);
    217  1.1      cgd 		break;
    218  1.1      cgd 
    219  1.1      cgd 	case CHNCTYPE:
    220  1.1      cgd 		dochc(argv, argc);
    221  1.1      cgd 		break;
    222  1.1      cgd 
    223  1.1      cgd 	case SUBSTYPE:
    224  1.2    glass 	/*
    225  1.2    glass 	 * dosub - select substring
    226  1.2    glass 	 *
    227  1.2    glass 	 */
    228  1.1      cgd 		if (argc > 3)
    229  1.2    glass 			dosub(argv, argc);
    230  1.1      cgd 		break;
    231  1.1      cgd 
    232  1.1      cgd 	case SHIFTYPE:
    233  1.2    glass 	/*
    234  1.2    glass 	 * doshift - push back all arguments
    235  1.2    glass 	 * except the first one (i.e. skip
    236  1.2    glass 	 * argv[2])
    237  1.2    glass 	 */
    238  1.1      cgd 		if (argc > 3) {
    239  1.2    glass 			for (n = argc - 1; n > 3; n--) {
    240  1.1      cgd 				putback(rquote);
    241  1.1      cgd 				pbstr(argv[n]);
    242  1.1      cgd 				putback(lquote);
    243  1.1      cgd 				putback(',');
    244  1.1      cgd 			}
    245  1.1      cgd 			putback(rquote);
    246  1.1      cgd 			pbstr(argv[3]);
    247  1.1      cgd 			putback(lquote);
    248  1.1      cgd 		}
    249  1.1      cgd 		break;
    250  1.1      cgd 
    251  1.1      cgd 	case DIVRTYPE:
    252  1.1      cgd 		if (argc > 2 && (n = atoi(argv[2])) != 0)
    253  1.1      cgd 			dodiv(n);
    254  1.1      cgd 		else {
    255  1.1      cgd 			active = stdout;
    256  1.1      cgd 			oindex = 0;
    257  1.1      cgd 		}
    258  1.1      cgd 		break;
    259  1.1      cgd 
    260  1.1      cgd 	case UNDVTYPE:
    261  1.1      cgd 		doundiv(argv, argc);
    262  1.1      cgd 		break;
    263  1.1      cgd 
    264  1.1      cgd 	case DIVNTYPE:
    265  1.2    glass 	/*
    266  1.2    glass 	 * dodivnum - return the number of
    267  1.2    glass 	 * current output diversion
    268  1.2    glass 	 */
    269  1.1      cgd 		pbnum(oindex);
    270  1.1      cgd 		break;
    271  1.1      cgd 
    272  1.1      cgd 	case UNDFTYPE:
    273  1.2    glass 	/*
    274  1.2    glass 	 * doundefine - undefine a previously
    275  1.2    glass 	 * defined macro(s) or m4 keyword(s).
    276  1.2    glass 	 */
    277  1.1      cgd 		if (argc > 2)
    278  1.1      cgd 			for (n = 2; n < argc; n++)
    279  1.1      cgd 				remhash(argv[n], ALL);
    280  1.1      cgd 		break;
    281  1.1      cgd 
    282  1.1      cgd 	case POPDTYPE:
    283  1.2    glass 	/*
    284  1.2    glass 	 * dopopdef - remove the topmost
    285  1.2    glass 	 * definitions of macro(s) or m4
    286  1.2    glass 	 * keyword(s).
    287  1.2    glass 	 */
    288  1.1      cgd 		if (argc > 2)
    289  1.1      cgd 			for (n = 2; n < argc; n++)
    290  1.1      cgd 				remhash(argv[n], TOP);
    291  1.1      cgd 		break;
    292  1.1      cgd 
    293  1.1      cgd 	case MKTMTYPE:
    294  1.2    glass 	/*
    295  1.2    glass 	 * dotemp - create a temporary file
    296  1.2    glass 	 */
    297  1.1      cgd 		if (argc > 2)
    298  1.1      cgd 			pbstr(mktemp(argv[2]));
    299  1.1      cgd 		break;
    300  1.1      cgd 
    301  1.1      cgd 	case TRNLTYPE:
    302  1.2    glass 	/*
    303  1.2    glass 	 * dotranslit - replace all characters in
    304  1.2    glass 	 * the source string that appears in the
    305  1.2    glass 	 * "from" string with the corresponding
    306  1.2    glass 	 * characters in the "to" string.
    307  1.2    glass 	 */
    308  1.1      cgd 		if (argc > 3) {
    309  1.1      cgd 			char temp[MAXTOK];
    310  1.1      cgd 			if (argc > 4)
    311  1.1      cgd 				map(temp, argv[2], argv[3], argv[4]);
    312  1.1      cgd 			else
    313  1.1      cgd 				map(temp, argv[2], argv[3], null);
    314  1.1      cgd 			pbstr(temp);
    315  1.1      cgd 		}
    316  1.2    glass 		else if (argc > 2)
    317  1.1      cgd 			pbstr(argv[2]);
    318  1.1      cgd 		break;
    319  1.1      cgd 
    320  1.1      cgd 	case INDXTYPE:
    321  1.2    glass 	/*
    322  1.2    glass 	 * doindex - find the index of the second
    323  1.2    glass 	 * argument string in the first argument
    324  1.2    glass 	 * string. -1 if not present.
    325  1.2    glass 	 */
    326  1.1      cgd 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
    327  1.1      cgd 		break;
    328  1.1      cgd 
    329  1.1      cgd 	case ERRPTYPE:
    330  1.2    glass 	/*
    331  1.2    glass 	 * doerrp - print the arguments to stderr
    332  1.2    glass 	 * file
    333  1.2    glass 	 */
    334  1.1      cgd 		if (argc > 2) {
    335  1.1      cgd 			for (n = 2; n < argc; n++)
    336  1.2    glass 				fprintf(stderr, "%s ", argv[n]);
    337  1.1      cgd 			fprintf(stderr, "\n");
    338  1.1      cgd 		}
    339  1.1      cgd 		break;
    340  1.1      cgd 
    341  1.1      cgd 	case DNLNTYPE:
    342  1.2    glass 	/*
    343  1.2    glass 	 * dodnl - eat-up-to and including
    344  1.2    glass 	 * newline
    345  1.2    glass 	 */
    346  1.1      cgd 		while ((c = gpbc()) != '\n' && c != EOF)
    347  1.1      cgd 			;
    348  1.1      cgd 		break;
    349  1.1      cgd 
    350  1.1      cgd 	case M4WRTYPE:
    351  1.2    glass 	/*
    352  1.2    glass 	 * dom4wrap - set up for
    353  1.2    glass 	 * wrap-up/wind-down activity
    354  1.2    glass 	 */
    355  1.2    glass 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
    356  1.1      cgd 		break;
    357  1.1      cgd 
    358  1.1      cgd 	case EXITTYPE:
    359  1.2    glass 	/*
    360  1.2    glass 	 * doexit - immediate exit from m4.
    361  1.2    glass 	 */
    362  1.3  mycroft 		killdiv();
    363  1.1      cgd 		exit((argc > 2) ? atoi(argv[2]) : 0);
    364  1.1      cgd 		break;
    365  1.1      cgd 
    366  1.1      cgd 	case DEFNTYPE:
    367  1.1      cgd 		if (argc > 2)
    368  1.1      cgd 			for (n = 2; n < argc; n++)
    369  1.1      cgd 				dodefn(argv[n]);
    370  1.1      cgd 		break;
    371  1.1      cgd 
    372  1.1      cgd 	default:
    373  1.2    glass 		oops("%s: major botch.", "eval");
    374  1.1      cgd 		break;
    375  1.1      cgd 	}
    376  1.2    glass }
    377  1.2    glass 
    378  1.2    glass char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
    379  1.2    glass 
    380  1.2    glass /*
    381  1.2    glass  * expand - user-defined macro expansion
    382  1.2    glass  */
    383  1.2    glass void
    384  1.2    glass expand(argv, argc)
    385  1.2    glass register char *argv[];
    386  1.2    glass register int argc;
    387  1.2    glass {
    388  1.2    glass 	register char *t;
    389  1.2    glass 	register char *p;
    390  1.2    glass 	register int n;
    391  1.2    glass 	register int argno;
    392  1.2    glass 
    393  1.2    glass 	t = argv[0];		       /* defn string as a whole */
    394  1.2    glass 	p = t;
    395  1.2    glass 	while (*p)
    396  1.2    glass 		p++;
    397  1.2    glass 	p--;			       /* last character of defn */
    398  1.2    glass 	while (p > t) {
    399  1.2    glass 		if (*(p - 1) != ARGFLAG)
    400  1.2    glass 			putback(*p);
    401  1.2    glass 		else {
    402  1.2    glass 			switch (*p) {
    403  1.2    glass 
    404  1.2    glass 			case '#':
    405  1.2    glass 				pbnum(argc - 2);
    406  1.2    glass 				break;
    407  1.2    glass 			case '0':
    408  1.2    glass 			case '1':
    409  1.2    glass 			case '2':
    410  1.2    glass 			case '3':
    411  1.2    glass 			case '4':
    412  1.2    glass 			case '5':
    413  1.2    glass 			case '6':
    414  1.2    glass 			case '7':
    415  1.2    glass 			case '8':
    416  1.2    glass 			case '9':
    417  1.2    glass 				if ((argno = *p - '0') < argc - 1)
    418  1.2    glass 					pbstr(argv[argno + 1]);
    419  1.2    glass 				break;
    420  1.2    glass 			case '*':
    421  1.2    glass 				for (n = argc - 1; n > 2; n--) {
    422  1.2    glass 					pbstr(argv[n]);
    423  1.2    glass 					putback(',');
    424  1.2    glass 				}
    425  1.2    glass 				pbstr(argv[2]);
    426  1.2    glass 				break;
    427  1.2    glass 			default:
    428  1.2    glass 				putback(*p);
    429  1.2    glass 				putback('$');
    430  1.2    glass 				break;
    431  1.2    glass 			}
    432  1.2    glass 			p--;
    433  1.2    glass 		}
    434  1.2    glass 		p--;
    435  1.2    glass 	}
    436  1.2    glass 	if (p == t)		       /* do last character */
    437  1.2    glass 		putback(*p);
    438  1.2    glass }
    439  1.2    glass 
    440  1.2    glass /*
    441  1.2    glass  * dodefine - install definition in the table
    442  1.2    glass  */
    443  1.2    glass void
    444  1.2    glass dodefine(name, defn)
    445  1.2    glass register char *name;
    446  1.2    glass register char *defn;
    447  1.2    glass {
    448  1.2    glass 	register ndptr p;
    449  1.2    glass 
    450  1.2    glass 	if (!*name)
    451  1.2    glass 		oops("null definition.");
    452  1.2    glass 	if (STREQ(name, defn))
    453  1.2    glass 		oops("%s: recursive definition.", name);
    454  1.2    glass 	if ((p = lookup(name)) == nil)
    455  1.2    glass 		p = addent(name);
    456  1.2    glass 	else if (p->defn != null)
    457  1.2    glass 		free((char *) p->defn);
    458  1.2    glass 	if (!*defn)
    459  1.2    glass 		p->defn = null;
    460  1.2    glass 	else
    461  1.2    glass 		p->defn = xstrdup(defn);
    462  1.2    glass 	p->type = MACRTYPE;
    463  1.2    glass }
    464  1.2    glass 
    465  1.2    glass /*
    466  1.2    glass  * dodefn - push back a quoted definition of
    467  1.2    glass  *      the given name.
    468  1.2    glass  */
    469  1.2    glass void
    470  1.2    glass dodefn(name)
    471  1.2    glass char *name;
    472  1.2    glass {
    473  1.2    glass 	register ndptr p;
    474  1.2    glass 
    475  1.2    glass 	if ((p = lookup(name)) != nil && p->defn != null) {
    476  1.2    glass 		putback(rquote);
    477  1.2    glass 		pbstr(p->defn);
    478  1.2    glass 		putback(lquote);
    479  1.2    glass 	}
    480  1.2    glass }
    481  1.2    glass 
    482  1.2    glass /*
    483  1.2    glass  * dopushdef - install a definition in the hash table
    484  1.2    glass  *      without removing a previous definition. Since
    485  1.2    glass  *      each new entry is entered in *front* of the
    486  1.2    glass  *      hash bucket, it hides a previous definition from
    487  1.2    glass  *      lookup.
    488  1.2    glass  */
    489  1.2    glass void
    490  1.2    glass dopushdef(name, defn)
    491  1.2    glass register char *name;
    492  1.2    glass register char *defn;
    493  1.2    glass {
    494  1.2    glass 	register ndptr p;
    495  1.2    glass 
    496  1.2    glass 	if (!*name)
    497  1.2    glass 		oops("null definition");
    498  1.2    glass 	if (STREQ(name, defn))
    499  1.2    glass 		oops("%s: recursive definition.", name);
    500  1.2    glass 	p = addent(name);
    501  1.2    glass 	if (!*defn)
    502  1.2    glass 		p->defn = null;
    503  1.2    glass 	else
    504  1.2    glass 		p->defn = xstrdup(defn);
    505  1.2    glass 	p->type = MACRTYPE;
    506  1.2    glass }
    507  1.2    glass 
    508  1.2    glass /*
    509  1.2    glass  * dodumpdef - dump the specified definitions in the hash
    510  1.2    glass  *      table to stderr. If nothing is specified, the entire
    511  1.2    glass  *      hash table is dumped.
    512  1.2    glass  */
    513  1.2    glass void
    514  1.2    glass dodump(argv, argc)
    515  1.2    glass register char *argv[];
    516  1.2    glass register int argc;
    517  1.2    glass {
    518  1.2    glass 	register int n;
    519  1.2    glass 	ndptr p;
    520  1.2    glass 
    521  1.2    glass 	if (argc > 2) {
    522  1.2    glass 		for (n = 2; n < argc; n++)
    523  1.2    glass 			if ((p = lookup(argv[n])) != nil)
    524  1.2    glass 				fprintf(stderr, dumpfmt, p->name,
    525  1.2    glass 					p->defn);
    526  1.2    glass 	}
    527  1.2    glass 	else {
    528  1.2    glass 		for (n = 0; n < HASHSIZE; n++)
    529  1.2    glass 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
    530  1.2    glass 				fprintf(stderr, dumpfmt, p->name,
    531  1.2    glass 					p->defn);
    532  1.2    glass 	}
    533  1.2    glass }
    534  1.2    glass 
    535  1.2    glass /*
    536  1.2    glass  * doifelse - select one of two alternatives - loop.
    537  1.2    glass  */
    538  1.2    glass void
    539  1.2    glass doifelse(argv, argc)
    540  1.2    glass register char *argv[];
    541  1.2    glass register int argc;
    542  1.2    glass {
    543  1.2    glass 	cycle {
    544  1.2    glass 		if (STREQ(argv[2], argv[3]))
    545  1.2    glass 			pbstr(argv[4]);
    546  1.2    glass 		else if (argc == 6)
    547  1.2    glass 			pbstr(argv[5]);
    548  1.2    glass 		else if (argc > 6) {
    549  1.2    glass 			argv += 3;
    550  1.2    glass 			argc -= 3;
    551  1.2    glass 			continue;
    552  1.2    glass 		}
    553  1.2    glass 		break;
    554  1.2    glass 	}
    555  1.2    glass }
    556  1.2    glass 
    557  1.2    glass /*
    558  1.2    glass  * doinclude - include a given file.
    559  1.2    glass  */
    560  1.2    glass int
    561  1.2    glass doincl(ifile)
    562  1.2    glass char *ifile;
    563  1.2    glass {
    564  1.2    glass 	if (ilevel + 1 == MAXINP)
    565  1.2    glass 		oops("too many include files.");
    566  1.2    glass 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
    567  1.2    glass 		ilevel++;
    568  1.2    glass 		bbase[ilevel] = bufbase = bp;
    569  1.2    glass 		return (1);
    570  1.2    glass 	}
    571  1.2    glass 	else
    572  1.2    glass 		return (0);
    573  1.2    glass }
    574  1.2    glass 
    575  1.2    glass #ifdef EXTENDED
    576  1.2    glass /*
    577  1.2    glass  * dopaste - include a given file without any
    578  1.2    glass  *           macro processing.
    579  1.2    glass  */
    580  1.2    glass int
    581  1.2    glass dopaste(pfile)
    582  1.2    glass char *pfile;
    583  1.2    glass {
    584  1.2    glass 	FILE *pf;
    585  1.2    glass 	register int c;
    586  1.2    glass 
    587  1.2    glass 	if ((pf = fopen(pfile, "r")) != NULL) {
    588  1.2    glass 		while ((c = getc(pf)) != EOF)
    589  1.2    glass 			putc(c, active);
    590  1.2    glass 		(void) fclose(pf);
    591  1.2    glass 		return (1);
    592  1.2    glass 	}
    593  1.2    glass 	else
    594  1.2    glass 		return (0);
    595  1.2    glass }
    596  1.2    glass #endif
    597  1.2    glass 
    598  1.2    glass /*
    599  1.2    glass  * dochq - change quote characters
    600  1.2    glass  */
    601  1.2    glass void
    602  1.2    glass dochq(argv, argc)
    603  1.2    glass register char *argv[];
    604  1.2    glass register int argc;
    605  1.2    glass {
    606  1.2    glass 	if (argc > 2) {
    607  1.2    glass 		if (*argv[2])
    608  1.2    glass 			lquote = *argv[2];
    609  1.2    glass 		if (argc > 3) {
    610  1.2    glass 			if (*argv[3])
    611  1.2    glass 				rquote = *argv[3];
    612  1.2    glass 		}
    613  1.2    glass 		else
    614  1.2    glass 			rquote = lquote;
    615  1.2    glass 	}
    616  1.2    glass 	else {
    617  1.2    glass 		lquote = LQUOTE;
    618  1.2    glass 		rquote = RQUOTE;
    619  1.2    glass 	}
    620  1.2    glass }
    621  1.2    glass 
    622  1.2    glass /*
    623  1.2    glass  * dochc - change comment characters
    624  1.2    glass  */
    625  1.2    glass void
    626  1.2    glass dochc(argv, argc)
    627  1.2    glass register char *argv[];
    628  1.2    glass register int argc;
    629  1.2    glass {
    630  1.2    glass 	if (argc > 2) {
    631  1.2    glass 		if (*argv[2])
    632  1.2    glass 			scommt = *argv[2];
    633  1.2    glass 		if (argc > 3) {
    634  1.2    glass 			if (*argv[3])
    635  1.2    glass 				ecommt = *argv[3];
    636  1.2    glass 		}
    637  1.2    glass 		else
    638  1.2    glass 			ecommt = ECOMMT;
    639  1.2    glass 	}
    640  1.2    glass 	else {
    641  1.2    glass 		scommt = SCOMMT;
    642  1.2    glass 		ecommt = ECOMMT;
    643  1.2    glass 	}
    644  1.2    glass }
    645  1.2    glass 
    646  1.2    glass /*
    647  1.2    glass  * dodivert - divert the output to a temporary file
    648  1.2    glass  */
    649  1.2    glass void
    650  1.2    glass dodiv(n)
    651  1.2    glass register int n;
    652  1.2    glass {
    653  1.2    glass 	if (n < 0 || n >= MAXOUT)
    654  1.2    glass 		n = 0;		       /* bitbucket */
    655  1.2    glass 	if (outfile[n] == NULL) {
    656  1.2    glass 		m4temp[UNIQUE] = n + '0';
    657  1.2    glass 		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
    658  1.2    glass 			oops("%s: cannot divert.", m4temp);
    659  1.2    glass 	}
    660  1.2    glass 	oindex = n;
    661  1.2    glass 	active = outfile[n];
    662  1.2    glass }
    663  1.2    glass 
    664  1.2    glass /*
    665  1.2    glass  * doundivert - undivert a specified output, or all
    666  1.2    glass  *              other outputs, in numerical order.
    667  1.2    glass  */
    668  1.2    glass void
    669  1.2    glass doundiv(argv, argc)
    670  1.2    glass register char *argv[];
    671  1.2    glass register int argc;
    672  1.2    glass {
    673  1.2    glass 	register int ind;
    674  1.2    glass 	register int n;
    675  1.2    glass 
    676  1.2    glass 	if (argc > 2) {
    677  1.2    glass 		for (ind = 2; ind < argc; ind++) {
    678  1.2    glass 			n = atoi(argv[ind]);
    679  1.2    glass 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
    680  1.2    glass 				getdiv(n);
    681  1.2    glass 
    682  1.2    glass 		}
    683  1.2    glass 	}
    684  1.2    glass 	else
    685  1.2    glass 		for (n = 1; n < MAXOUT; n++)
    686  1.2    glass 			if (outfile[n] != NULL)
    687  1.2    glass 				getdiv(n);
    688  1.2    glass }
    689  1.2    glass 
    690  1.2    glass /*
    691  1.2    glass  * dosub - select substring
    692  1.2    glass  */
    693  1.2    glass void
    694  1.2    glass dosub(argv, argc)
    695  1.2    glass register char *argv[];
    696  1.2    glass register int argc;
    697  1.2    glass {
    698  1.2    glass 	register char *ap, *fc, *k;
    699  1.2    glass 	register int nc;
    700  1.2    glass 
    701  1.2    glass 	if (argc < 5)
    702  1.2    glass 		nc = MAXTOK;
    703  1.2    glass 	else
    704  1.2    glass #ifdef EXPR
    705  1.2    glass 		nc = expr(argv[4]);
    706  1.2    glass #else
    707  1.2    glass 		nc = atoi(argv[4]);
    708  1.2    glass #endif
    709  1.2    glass 	ap = argv[2];		       /* target string */
    710  1.2    glass #ifdef EXPR
    711  1.2    glass 	fc = ap + expr(argv[3]);       /* first char */
    712  1.2    glass #else
    713  1.2    glass 	fc = ap + atoi(argv[3]);       /* first char */
    714  1.2    glass #endif
    715  1.2    glass 	if (fc >= ap && fc < ap + strlen(ap))
    716  1.2    glass 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
    717  1.2    glass 			putback(*k);
    718  1.2    glass }
    719  1.2    glass 
    720  1.2    glass /*
    721  1.2    glass  * map:
    722  1.2    glass  * map every character of s1 that is specified in from
    723  1.2    glass  * into s3 and replace in s. (source s1 remains untouched)
    724  1.2    glass  *
    725  1.2    glass  * This is a standard implementation of map(s,from,to) function of ICON
    726  1.2    glass  * language. Within mapvec, we replace every character of "from" with
    727  1.2    glass  * the corresponding character in "to". If "to" is shorter than "from",
    728  1.2    glass  * than the corresponding entries are null, which means that those
    729  1.2    glass  * characters dissapear altogether. Furthermore, imagine
    730  1.2    glass  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
    731  1.2    glass  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
    732  1.2    glass  * ultimately maps to `*'. In order to achieve this effect in an efficient
    733  1.2    glass  * manner (i.e. without multiple passes over the destination string), we
    734  1.2    glass  * loop over mapvec, starting with the initial source character. if the
    735  1.2    glass  * character value (dch) in this location is different than the source
    736  1.2    glass  * character (sch), sch becomes dch, once again to index into mapvec, until
    737  1.2    glass  * the character value stabilizes (i.e. sch = dch, in other words
    738  1.2    glass  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
    739  1.2    glass  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
    740  1.2    glass  * end, we restore mapvec* back to normal where mapvec[n] == n for
    741  1.2    glass  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
    742  1.2    glass  * about 5 times faster than any algorithm that makes multiple passes over
    743  1.2    glass  * destination string.
    744  1.2    glass  */
    745  1.2    glass void
    746  1.2    glass map(dest, src, from, to)
    747  1.2    glass register char *dest;
    748  1.2    glass register char *src;
    749  1.2    glass register char *from;
    750  1.2    glass register char *to;
    751  1.2    glass {
    752  1.2    glass 	register char *tmp;
    753  1.2    glass 	register char sch, dch;
    754  1.2    glass 	static char mapvec[128] = {
    755  1.2    glass 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
    756  1.2    glass 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
    757  1.2    glass 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
    758  1.2    glass 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
    759  1.2    glass 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
    760  1.2    glass 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
    761  1.2    glass 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
    762  1.2    glass 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
    763  1.2    glass 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
    764  1.2    glass 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
    765  1.2    glass 		120, 121, 122, 123, 124, 125, 126, 127
    766  1.2    glass 	};
    767  1.2    glass 
    768  1.2    glass 	if (*src) {
    769  1.2    glass 		tmp = from;
    770  1.2    glass 	/*
    771  1.2    glass 	 * create a mapping between "from" and
    772  1.2    glass 	 * "to"
    773  1.2    glass 	 */
    774  1.2    glass 		while (*from)
    775  1.2    glass 			mapvec[*from++] = (*to) ? *to++ : (char) 0;
    776  1.2    glass 
    777  1.2    glass 		while (*src) {
    778  1.2    glass 			sch = *src++;
    779  1.2    glass 			dch = mapvec[sch];
    780  1.2    glass 			while (dch != sch) {
    781  1.2    glass 				sch = dch;
    782  1.2    glass 				dch = mapvec[sch];
    783  1.2    glass 			}
    784  1.2    glass 			if (*dest = dch)
    785  1.2    glass 				dest++;
    786  1.2    glass 		}
    787  1.2    glass 	/*
    788  1.2    glass 	 * restore all the changed characters
    789  1.2    glass 	 */
    790  1.2    glass 		while (*tmp) {
    791  1.2    glass 			mapvec[*tmp] = *tmp;
    792  1.2    glass 			tmp++;
    793  1.2    glass 		}
    794  1.2    glass 	}
    795  1.2    glass 	*dest = (char) 0;
    796  1.1      cgd }
    797