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