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