Home | History | Annotate | Line # | Download | only in m4
main.c revision 1.2
      1 /*  File   : main.c
      2     Author : Ozan Yigit
      3     Updated: 4 May 1992
      4     Defines: M4 macro processor.
      5 */
      6 
      7 #include "mdef.h"
      8 #include "extr.h"
      9 #include "ourlims.h"
     10 
     11 char chtype[1 - EOF + UCHAR_MAX];
     12 
     13 #define	is_sym1(c) (chtype[(c)-EOF] > 10)
     14 #define is_sym2(c) (chtype[(c)-EOF] >  0)
     15 #define is_blnk(c) ((unsigned)((c)-1) < ' ')
     16 
     17 /*
     18  * m4 - macro processor
     19  *
     20  * PD m4 is based on the macro tool distributed with the software
     21  * tools (VOS) package, and described in the "SOFTWARE TOOLS" and
     22  * "SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include
     23  * most of the command set of SysV m4, the standard UN*X macro processor.
     24  *
     25  * Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
     26  * there may be certain implementation similarities between
     27  * the two. The PD m4 was produced without ANY references to m4
     28  * sources.
     29  *
     30  * References:
     31  *
     32  *	Software Tools distribution: macro
     33  *
     34  *	Kernighan, Brian W. and P. J. Plauger, SOFTWARE
     35  *	TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
     36  *
     37  *	Kernighan, Brian W. and P. J. Plauger, SOFTWARE
     38  *	TOOLS, Addison-Wesley, Mass. 1976
     39  *
     40  *	Kernighan, Brian W. and Dennis M. Ritchie,
     41  *	THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
     42  *	Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
     43  *
     44  *	System V man page for M4
     45  *
     46  * Modification History:
     47  *
     48  * Mar 26 1992 RAOK	1.  Eliminated magic numbers 8, 255, 256 in favour
     49  *			of the standard limits CHAR_BIT, UCHAR_MAX, which
     50  *			are in the new header ourlims.h.  This is part of
     51  *			the "8-bit-clean M4" project.  To the best of my
     52  *			belief, all of the code should work in EBCDIC,
     53  *			ASCII, DEC MNCS, ISO 8859/n, or the Mac character
     54  *			set, as long as chars are unsigned.  There are
     55  *			still some places where signed bytes can cause
     56  *			trouble.
     57  *
     58  *			2.  Changed expr() to use long int rather than int.
     59  *			This is so that we'd get 32-bit arithmetic on a Sun,
     60  *			Encore, PC, Mac &c.  As part of this, the code for
     61  *			shifts has been elaborated to yield signed shifts
     62  *			on all machines.  The charcon() function didn't work
     63  *			with multi-character literals, although it was meant
     64  *			to.  Now it does.  pbrad() has been changed so that
     65  *			eval('abcd',0) => abcd, not dcba, which was useless.
     66  *
     67  *			3.  I finally got sick of the fact that &&, ||, and
     68  *			?: always evaluate all their arguments.  This is
     69  *			consistent with UNIX System V Release 3, but I for
     70  *			one don't see anything to gain by having eval(0&&1/0)
     71  *			crash when it would simply yield 0 in C.  Now these
     72  *			operators are more consistent with the C preprocessor.
     73  *
     74  * Nov 13 1992 RAOK	Added the quoter facility.  The purpose of this is
     75  *			to make it easier to generate data for a variety of
     76  *			programming languages, including sh, awk, Lisp, C.
     77  *			There are two holes in the implementation:  dumpdef
     78  *			prints junk and undefine doesn't release everything.
     79  *			This was mainly intended as a prototype to show that
     80  *			it could be done.
     81  *
     82  * Jun 16 1992 RAOK	Added vquote and gave changequote a 3rd argument.
     83  *			The idea of this is to make it possible to quote
     84  *			ANY string, including one with unbalanced ` or '.
     85  *			I also made eval(c,0) convert decimal->ASCII, so
     86  *			that eval(39,0) yields ' and eval(96,0) yields `.
     87  *
     88  * Apr 28 1992 RAOK	Used gcc to find and fix ANSI clashes, so that
     89  *			PD M4 could be ported to MS-DOS (Turbo C 3).
     90  *			Main known remaining problem:  use of mktemp().
     91  *			Also, command line handling needs to be worked out.
     92  *
     93  * Mar 26 1992 RAOK	PD M4 now accepts file names on the command line
     94  *			just like UNIX M4.  Warning:  macro calls must NOT
     95  *			cross file boundaries.  UNIX M4 doesn't mind;
     96  *			(m4 a b c) and (cat a b c | m4) are just the same
     97  *			except for error messages.  PD M4 will report an
     98  *			unexpected EOF if a file ends while a macro call or
     99  *			string is still being parsed.  When there is one
    100  *			file name argument, or none, you can't tell the
    101  *			difference, and that's all I need.
    102  *
    103  * May 15 1991 RAOK	DIVNAM was a string constant, but was changed!
    104  *			Fixed that and a couple of other things to make
    105  *			GCC happy.  (Also made "foo$bar" get through.)
    106  *
    107  * Apr 17 1991 RAOK	There was a major mistake.  If you did
    108  *			define(foo, `1 include(bar) 2') where
    109  *			file bar held "-bar-" you would naturally
    110  *			expect "1 -bar- 2" as the output, but you
    111  *			got "1  2-bar-".  That is, include file
    112  *			processing was postponed until all macros
    113  *			had been expanded.  The macro gpbc() was
    114  *			at fault.  I added bb, bbstack[], and the
    115  *			code in main.c and serv.c that maintains
    116  *			them, in order to work around this bug.
    117  *
    118  * Apr 12 1991 RAOK	inspect() didn't handle overflow well.
    119  *			Added the automatically maintained macro
    120  *			__FILE__, just as in C.  To suppress it,
    121  *			define NO__FILE.  At some point, $# had
    122  *			been made to return a value that was off
    123  *			by one; it now agrees with SysV M4.
    124  *
    125  * Aug 13 1990 RAOK	The System V expr() has three arguments:
    126  *			expression [, radix:10 [, mindigits: 1]]
    127  *			Brought in my int2str() and wrote pbrad()
    128  *			to make this work here.  With the wrong #
    129  *			of args, acts like System V.
    130  *
    131  * Aug 11 1990 RAOK	Told expr.c about the Pascal operators
    132  *			not, div, mod, and, or
    133  *			so that Pascal constant expressions could
    134  *			be evaluated.  (It still doesn't handle
    135  *			floats.)  Fixed a mistake in 'character's.
    136  *
    137  * Apr 23 1988 RAOK	Sped it up, mainly by making putback() and
    138  *			chrsave() into macros.
    139  *			Finished the -o option (was half done).
    140  *			Added the System V -e (interactive) option.
    141  *
    142  * Jan 28 1986 Oz	Break the whole thing into little
    143  *			pieces, for easier (?) maintenance.
    144  *
    145  * Dec 12 1985 Oz	Optimize the code, try to squeeze
    146  *			few microseconds out.. [didn't try very hard]
    147  *
    148  * Dec 05 1985 Oz	Add getopt interface, define (-D),
    149  *			undefine (-U) options.
    150  *
    151  * Oct 21 1985 Oz	Clean up various bugs, add comment handling.
    152  *
    153  * June 7 1985 Oz	Add some of SysV m4 stuff (m4wrap, pushdef,
    154  *			popdef, decr, shift etc.).
    155  *
    156  * June 5 1985 Oz	Initial cut.
    157  *
    158  * Implementation Notes:
    159  *
    160  * [1]	PD m4 uses a different (and simpler) stack mechanism than the one
    161  *	described in Software Tools and Software Tools in Pascal books.
    162  *	The triple stack nonsense is replaced with a single stack containing
    163  *	the call frames and the arguments. Each frame is back-linked to a
    164  * 	previous stack frame, which enables us to rewind the stack after
    165  * 	each nested call is completed. Each argument is a character pointer
    166  *	to the beginning of the argument string within the string space.
    167  *	The only exceptions to this are (*) arg 0 and arg 1, which are
    168  * 	the macro definition and macro name strings, stored dynamically
    169  *	for the hash table.
    170  *
    171  *	    .					   .
    172  *	|   .	|  <-- sp			|  .  |
    173  *	+-------+				+-----+
    174  *	| arg 3 ------------------------------->| str |
    175  *	+-------+				|  .  |
    176  *	| arg 2 --------------+ 		   .
    177  *	+-------+	      |
    178  *	    *		      |			|     |
    179  *	+-------+	      | 		+-----+
    180  *	| plev	|  <-- fp     +---------------->| str |
    181  *	+-------+				|  .  |
    182  *	| type	|				   .
    183  *	+-------+
    184  *	| prcf	-----------+		plev: paren level
    185  *	+-------+  	   |		type: call type
    186  *	|   .	| 	   |		prcf: prev. call frame
    187  *	    .	   	   |
    188  *	+-------+	   |
    189  *	|	<----------+
    190  *	+-------+
    191  *
    192  * [2]	We have three types of null values:
    193  *
    194  *		nil  - nodeblock pointer type 0
    195  *		null - null string ("")
    196  *		NULL - Stdio-defined NULL
    197  *
    198  */
    199 
    200 char buf[BUFSIZE];		/* push-back buffer	       */
    201 char *bp = buf; 		/* first available character   */
    202 char *bb = buf;			/* buffer beginning            */
    203 char *endpbb = buf+BUFSIZE;	/* end of push-back buffer     */
    204 stae mstack[STACKMAX+1]; 	/* stack of m4 machine         */
    205 char strspace[STRSPMAX+1];	/* string space for evaluation */
    206 char *ep = strspace;		/* first free char in strspace */
    207 char *endest= strspace+STRSPMAX;/* end of string space	       */
    208 int sp; 			/* current m4  stack pointer   */
    209 int fp; 			/* m4 call frame pointer       */
    210 char *bbstack[MAXINP];		/* stack where bb is saved     */
    211 FILE *infile[MAXINP];		/* input file stack (0=stdin)  */
    212 FILE *outfile[MAXOUT];		/* diversion array(0=bitbucket)*/
    213 FILE *active;			/* active output file pointer  */
    214 int ilevel = 0; 		/* input file stack pointer    */
    215 int oindex = 0; 		/* diversion index..	       */
    216 char *null = "";                /* as it says.. just a null..  */
    217 char *m4wraps = "";             /* m4wrap string default..     */
    218 char lquote = LQUOTE;		/* left quote character  (`)   */
    219 char rquote = RQUOTE;		/* right quote character (')   */
    220 char vquote = VQUOTE;		/* verbatim quote character ^V */
    221 char scommt = SCOMMT;		/* start character for comment */
    222 char ecommt = ECOMMT;		/* end character for comment   */
    223 int strip = 0;			/* throw away comments?        */
    224 
    225 /*  Definitions of diversion files.  The last 6 characters MUST be
    226     "XXXXXX" -- that is a requirement of mktemp().  The character
    227     '0' is to be replaced by the diversion number; we assume here
    228     that it is just before the Xs.  If not, you will have to alter
    229     the definition of UNIQUE.
    230 */
    231 
    232 #if unix
    233 static char DIVNAM[] = "/usr/tmp/m40XXXXXX";
    234 #else
    235 #if vms
    236 static char DIVNAM[] = "sys$login:m40XXXXXX";
    237 #else
    238 static char DIVNAM[] = "M40XXXXXX";	/* was \M4, should it be \\M4? */
    239 #endif
    240 #endif
    241 int UNIQUE = sizeof DIVNAM - 7;	/* where to change m4temp.     */
    242 char *m4temp;			/* filename for diversions     */
    243 extern char *mktemp();
    244 
    245 
    246 void cantread(s)
    247     char *s;
    248     {
    249 	fprintf(stderr, "m4: %s: ", s);
    250 	error("cannot open for input.");
    251     }
    252 
    253 
    254 /*  initkwds()
    255     initialises the hash table to contain all the m4 built-in functions.
    256     The original version breached module boundaries, but there did not
    257     seem to be any benefit in that.
    258 */
    259 static void initkwds()
    260     {
    261 	register int i;
    262 	static struct { char *name; int type; } keyword[] =
    263 	    {
    264 		"include",      INCLTYPE,
    265 		"sinclude",     SINCTYPE,
    266 		"define",       DEFITYPE,
    267 		"defn",         DEFNTYPE,
    268 		"divert",       DIVRTYPE,
    269 		"expr",         EXPRTYPE,
    270 		"eval",         EXPRTYPE,
    271 		"substr",       SUBSTYPE,
    272 		"ifelse",       IFELTYPE,
    273 		"ifdef",        IFDFTYPE,
    274 		"len",          LENGTYPE,
    275 		"incr",         INCRTYPE,
    276 		"decr",         DECRTYPE,
    277 		"dnl",          DNLNTYPE,
    278 		"changequote",  CHNQTYPE,
    279 		"changecom",    CHNCTYPE,
    280 		"index",        INDXTYPE,
    281 #ifdef EXTENDED
    282 		"paste",        PASTTYPE,
    283 		"spaste",       SPASTYPE,
    284 		"m4trim",	TRIMTYPE,
    285 		"defquote",	DEFQTYPE,
    286 #endif
    287 		"popdef",       POPDTYPE,
    288 		"pushdef",      PUSDTYPE,
    289 		"dumpdef",      DUMPTYPE,
    290 		"shift",        SHIFTYPE,
    291 		"translit",     TRNLTYPE,
    292 		"undefine",     UNDFTYPE,
    293 		"undivert",     UNDVTYPE,
    294 		"divnum",       DIVNTYPE,
    295 		"maketemp",     MKTMTYPE,
    296 		"errprint",     ERRPTYPE,
    297 		"m4wrap",       M4WRTYPE,
    298 		"m4exit",       EXITTYPE,
    299 #if unix || vms
    300 		"syscmd",       SYSCTYPE,
    301 		"sysval",       SYSVTYPE,
    302 #endif
    303 #if unix
    304 		"unix",         MACRTYPE,
    305 #else
    306 #if vms
    307 		"vms",          MACRTYPE,
    308 #endif
    309 #endif
    310 		(char*)0,	0
    311 	    };
    312 
    313 	for (i = 0; keyword[i].type != 0; i++)
    314 	    addkywd(keyword[i].name, keyword[i].type);
    315     }
    316 
    317 
    318 /*  inspect(Name)
    319     Build an input token.., considering only those which start with
    320     [A-Za-z_].  This is fused with lookup() to speed things up.
    321     name must point to an array of at least MAXTOK characters.
    322 */
    323 ndptr inspect(name)
    324     char *name;
    325     {
    326 	register char *tp = name;
    327 	register char *etp = name+(MAXTOK-1);
    328 	register int c;
    329 	register unsigned long h = 0;
    330 	register ndptr p;
    331 
    332 	while (is_sym2(c = gpbc())) {
    333 	    if (tp == etp) error("m4: token too long");
    334 	    *tp++ = c, h = (h << 5) + h + c;
    335 	}
    336 	putback(c);
    337 	*tp = EOS;
    338 	for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
    339 	    if (strcmp(name, p->name) == 0)
    340 		return p;
    341 	return nil;
    342     }
    343 
    344 
    345 /*
    346  * macro - the work horse..
    347  *
    348  */
    349 void macro()
    350     {
    351 	char token[MAXTOK];
    352 	register int t;
    353 	register FILE *op = active;
    354 	static char ovmsg[] = "m4: internal stack overflow";
    355 
    356 	for (;;) {
    357 	    t = gpbc();
    358 	    if (is_sym1(t)) {
    359 		register char *s;
    360 		register ndptr p;
    361 
    362 		putback(t);
    363 		if ((p = inspect(s = token)) == nil) {
    364 		    if (sp < 0) {
    365 			while (t = *s++) putc(t, op);
    366 		    } else {
    367 			while (t = *s++) chrsave(t);
    368 		    }
    369 		} else {
    370 		    /* real thing.. First build a call frame */
    371 		    if (sp >= STACKMAX-6) error(ovmsg);
    372 		    mstack[1+sp].sfra = fp;		/* previous call frm */
    373 		    mstack[2+sp].sfra = p->type;	/* type of the call  */
    374 		    mstack[3+sp].sfra = 0;		/* parenthesis level */
    375 		    fp = sp+3;				/* new frame pointer */
    376 		    /* now push the string arguments */
    377 		    mstack[4+sp].sstr = p->defn;	/* defn string */
    378 		    mstack[5+sp].sstr = p->name;	/* macro name  */
    379 		    mstack[6+sp].sstr = ep;		/* start next.. */
    380 		    sp += 6;
    381 
    382 		    t = gpbc();
    383 		    putback(t);
    384 		    if (t != LPAREN) { putback(RPAREN); putback(LPAREN); }
    385 		}
    386 	    } else
    387 	    if (t == EOF) {
    388 		if (sp >= 0) error("m4: unexpected end of input");
    389 		if (--ilevel < 0) break;		/* all done thanks */
    390 #ifndef	NO__FILE
    391 		remhash("__FILE__", TOP);
    392 #endif
    393 		bb = bbstack[ilevel+1];
    394 		(void) fclose(infile[ilevel+1]);
    395 	    } else
    396 	    /* non-alpha single-char token seen..
    397 		[the order of else if .. stmts is important.]
    398 	    */
    399 	    if (t == lquote) {				/* strip quotes */
    400 		register int nlpar;
    401 
    402 		for (nlpar = 1; ; ) {
    403 		    t = gpbc();
    404 		    if (t == rquote) {
    405 			if (--nlpar == 0) break;
    406 		    } else
    407 		    if (t == lquote) {
    408 			nlpar++;
    409 		    } else {
    410 			if (t == vquote) t = gpbc();
    411 			if (t == EOF) {
    412 			    error("m4: missing right quote");
    413 			}
    414 		    }
    415 		    if (sp < 0) {
    416 			putc(t, op);
    417 		    } else {
    418 			chrsave(t);
    419 		    }
    420 		}
    421 	    } else
    422 	    if (sp < 0) {			/* not in a macro at all */
    423 		if (t != scommt) {		/* not a comment, so */
    424 		    putc(t, op);		/* copy it to output */
    425 		} else
    426 		if (strip) {			/* discard a comment */
    427 		    do {
    428 			t = gpbc();
    429 		    } while (t != ecommt && t != EOF);
    430 		} else {			/* copy comment to output */
    431 		    do {
    432 			putc(t, op);
    433 			t = gpbc();
    434 		    } while (t != ecommt && t != EOF);
    435 		    putc(t, op);
    436 		    /*  A note on comment handling:  this is NOT robust.
    437 		    |   We should do something safe with comments that
    438 		    |   are missing their ecommt termination.
    439 		    */
    440 		}
    441 	    } else
    442 	    switch (t) {
    443 		/*  There is a peculiar detail to notice here.
    444 		    Layout is _always_ discarded after left parentheses,
    445 		    but it is only discarded after commas if they separate
    446 		    arguments.  For example,
    447 		    define(foo,`|$1|$2|')
    448 		    foo( a, b)		=> |a|b|
    449 		    foo(( a ), ( b ))	=> |(a )|(b )|
    450 		    foo((a, x), (b, y))	=> |(a, x)|(b, y)|
    451 		    I find this counter-intuitive, and would expect the code
    452 		    for LPAREN to read something like this:
    453 
    454 		    if (PARLEV == 0) {
    455 			(* top level left parenthesis: skip layout *)
    456 			do t = gpbc(); while (is_blnk(t));
    457 			putback(t);
    458 		    } else {
    459 			(* left parenthesis inside an argument *)
    460 			chrsave(t);
    461 		    }
    462 		    PARLEV++;
    463 
    464 		    However, it turned out that Oz wrote the actual code
    465 		    very carefully to mimic the behaviour of "real" m4;
    466 		    UNIX m4 really does skip layout after all left parens
    467 		    but only some commas in just this fashion.  Sigh.
    468 		*/
    469 		case LPAREN:
    470 		    if (PARLEV > 0) chrsave(t);
    471 		    do t = gpbc(); while (is_blnk(t));	/* skip layout */
    472 		    putback(t);
    473 		    PARLEV++;
    474 		    break;
    475 
    476 		case COMMA:
    477 		    if (PARLEV == 1) {
    478 			chrsave(EOS);		/* new argument   */
    479 			if (sp >= STACKMAX) error(ovmsg);
    480 			do t = gpbc(); while (is_blnk(t)); /* skip layout */
    481 			putback(t);
    482 			mstack[++sp].sstr = ep;
    483 		    } else {
    484 			chrsave(t);
    485 		    }
    486 		    break;
    487 
    488 		case RPAREN:
    489 		    if (--PARLEV > 0) {
    490 			chrsave(t);
    491 		    } else {
    492 			char **argv = (char **)(mstack+fp+1);
    493 			int    argc = sp-fp;
    494 #if	unix | vms
    495 			static int sysval;
    496 #endif
    497 
    498 			chrsave(EOS);		/* last argument */
    499 			if (sp >= STACKMAX) error(ovmsg);
    500 #ifdef	DEBUG
    501 			fprintf(stderr, "argc = %d\n", argc);
    502 			for (t = 0; t < argc; t++)
    503 			    fprintf(stderr, "argv[%d] = %s\n", t, argv[t]);
    504 #endif
    505 			/*  If argc == 3 and argv[2] is null, then we
    506 			    have a call like `macro_or_builtin()'.  We
    507 			    adjust argc to avoid further checking..
    508 			*/
    509 			if (argc == 3 && !argv[2][0]) argc--;
    510 
    511 			switch (CALTYP & ~STATIC) {
    512 			    case MACRTYPE:
    513 				expand(argv, argc);
    514 				break;
    515 
    516 			    case DEFITYPE:		/* define(..) */
    517 				for (; argc > 2; argc -= 2, argv += 2)
    518 				    dodefine(argv[2], argc > 3 ? argv[3] : null);
    519 				break;
    520 
    521 			    case PUSDTYPE:		/* pushdef(..) */
    522 				for (; argc > 2; argc -= 2, argv += 2)
    523 				    dopushdef(argv[2], argc > 3 ? argv[3] : null);
    524 				break;
    525 
    526 			    case DUMPTYPE:
    527 				dodump(argv, argc);
    528 				break;
    529 
    530 			    case EXPRTYPE:		/* eval(Expr) */
    531 				{   /* evaluate arithmetic expression */
    532 				    /* eval([val: 0[, radix:10 [,min: 1]]]) */
    533 				    /* excess arguments are ignored */
    534 				    /* eval() with no arguments returns 0 */
    535 				    /* this is based on V.3 behaviour */
    536 				    int min_digits = 1;
    537 				    int radix = 10;
    538 				    long int value = 0;
    539 
    540 				    switch (argc) {
    541 					default:
    542 					    /* ignore excess arguments */
    543 					case 5:
    544 					    min_digits = expr(argv[4]);
    545 					case 4:
    546 					    radix = expr(argv[3]);
    547 					case 3:
    548 					    value = expr(argv[2]);
    549 					case 2:
    550 					    break;
    551 				    }
    552 				    pbrad(value, radix, min_digits);
    553 				}
    554 				break;
    555 
    556 			    case IFELTYPE:		/* ifelse(X,Y,IFX=Y,Else) */
    557 				doifelse(argv, argc);
    558 				break;
    559 
    560 			    case IFDFTYPE:		/* ifdef(Mac,IfDef[,IfNotDef]) */
    561 				/* select one of two alternatives based on the existence */
    562 				/* of another definition */
    563 				if (argc > 3) {
    564 				    if (lookup(argv[2]) != nil) {
    565 					pbstr(argv[3]);
    566 				    } else
    567 				    if (argc > 4) {
    568 					pbstr(argv[4]);
    569 				    }
    570 				}
    571 				break;
    572 
    573 			    case LENGTYPE:		/* len(Arg) */
    574 				/* find the length of the argument */
    575 				pbnum(argc > 2 ? strlen(argv[2]) : 0);
    576 				break;
    577 
    578 			    case INCRTYPE:		/* incr(Expr) */
    579 				/* increment the value of the argument */
    580 				if (argc > 2) pbnum(expr(argv[2]) + 1);
    581 				break;
    582 
    583 			    case DECRTYPE:		/* decr(Expr) */
    584 				/* decrement the value of the argument */
    585 				if (argc > 2) pbnum(expr(argv[2]) - 1);
    586 				break;
    587 
    588 #if unix || vms
    589 			    case SYSCTYPE:		/* syscmd(Command) */
    590 				/* execute system command */
    591 				/* Make sure m4 output is NOT interrupted */
    592 				fflush(stdout);
    593 				fflush(stderr);
    594 
    595 				if (argc > 2) sysval = system(argv[2]);
    596 				break;
    597 
    598 			    case SYSVTYPE:		/* sysval() */
    599 				/* return value of the last system call.  */
    600 				pbnum(sysval);
    601 				break;
    602 #endif
    603 
    604 			    case INCLTYPE:		/* include(File) */
    605 				for (t = 2; t < argc; t++)
    606 				    if (!doincl(argv[t])) cantread(argv[t]);
    607 				break;
    608 
    609 			    case SINCTYPE:		/* sinclude(File) */
    610 				for (t = 2; t < argc; t++)
    611 				    (void) doincl(argv[t]);
    612 				break;
    613 
    614 #ifdef EXTENDED
    615 			    case PASTTYPE:		/* paste(File) */
    616 				for (t = 2; t < argc; t++)
    617 				    if (!dopaste(argv[t])) cantread(argv[t]);
    618 				break;
    619 
    620 			    case SPASTYPE:		/* spaste(File) */
    621 				for (t = 2; t < argc; t++)
    622 				    (void) dopaste(argv[t]);
    623 				break;
    624 
    625 			    case TRIMTYPE:		/* m4trim(Source,..) */
    626 				if (argc > 2) m4trim(argv, argc);
    627 				break;
    628 
    629 			    case DEFQTYPE:		/* defquote(Mac,...) */
    630 				dodefqt(argv, argc);
    631 				break;
    632 
    633 			    case QUTRTYPE:		/* <quote>(text...) */
    634 				doqutr(argv, argc);
    635 				break;
    636 #endif
    637 
    638 			    case CHNQTYPE:		/* changequote([Left[,Right]]) */
    639 				dochq(argv, argc);
    640 				break;
    641 
    642 			    case CHNCTYPE:		/* changecom([Left[,Right]]) */
    643 				dochc(argv, argc);
    644 				break;
    645 
    646 			    case SUBSTYPE:		/* substr(Source[,Offset[,Length]]) */
    647 				/* select substring */
    648 				if (argc > 3) dosub(argv, argc);
    649 				break;
    650 
    651 			    case SHIFTYPE:		/* shift(~args~) */
    652 				/* push back all arguments except the first one */
    653 				/* (i.e.  skip argv[2]) */
    654 				if (argc > 3) {
    655 				    for (t = argc-1; t > 3; t--) {
    656 					pbqtd(argv[t]);
    657 					putback(',');
    658 				    }
    659 				    pbqtd(argv[3]);
    660 				}
    661 				break;
    662 
    663 			    case DIVRTYPE:		/* divert(N) */
    664 				if (argc > 2 && (t = expr(argv[2])) != 0) {
    665 				    dodiv(t);
    666 				} else {
    667 				    active = stdout;
    668 				    oindex = 0;
    669 				}
    670 				op = active;
    671 				break;
    672 
    673 			    case UNDVTYPE:		/* undivert(N...) */
    674 				doundiv(argv, argc);
    675 				op = active;
    676 				break;
    677 
    678 			    case DIVNTYPE:		/* divnum() */
    679 				/* return the number of current output diversion */
    680 				pbnum(oindex);
    681 				break;
    682 
    683 			    case UNDFTYPE:		/* undefine(..) */
    684 				/* undefine a previously defined macro(s) or m4 keyword(s). */
    685 				for (t = 2; t < argc; t++) remhash(argv[t], ALL);
    686 				break;
    687 
    688 			    case POPDTYPE:		/* popdef(Mac...) */
    689 				/* remove the topmost definitions of macro(s) or m4 keyword(s). */
    690 				for (t = 2; t < argc; t++) remhash(argv[t], TOP);
    691 				break;
    692 
    693 			    case MKTMTYPE:		/* maketemp(Pattern) */
    694 				/* create a temporary file */
    695 				if (argc > 2) pbstr(mktemp(argv[2]));
    696 				break;
    697 
    698 			    case TRNLTYPE:		/* translit(Source,Dom,Rng) */
    699 				/* replace all characters in the source string that */
    700 				/* appears in the "from" string with the corresponding */
    701 				/* characters in the "to" string. */
    702 
    703 				if (argc > 3) {
    704 				    char temp[MAXTOK];
    705 
    706 				    if (argc > 4)
    707 					map(temp, argv[2], argv[3], argv[4]);
    708 				    else
    709 					map(temp, argv[2], argv[3], null);
    710 				    pbstr(temp);
    711 				} else if (argc > 2)
    712 				    pbstr(argv[2]);
    713 				break;
    714 
    715 			    case INDXTYPE:		/* index(Source,Target) */
    716 				/* find the index of the second argument string in */
    717 				/* the first argument string. -1 if not present. */
    718 				pbnum(argc > 3 ? indx(argv[2], argv[3]) : -1);
    719 				break;
    720 
    721 			    case ERRPTYPE:		/* errprint(W,...,W) */
    722 				/* print the arguments to stderr file */
    723 				for (t = 2; t < argc; t++) fprintf(stderr, "%s ", argv[t]);
    724 				fprintf(stderr, "\n");
    725 				break;
    726 
    727 			    case DNLNTYPE:		/* dnl() */
    728 				/* eat upto and including newline */
    729 				while ((t = gpbc()) != '\n' && t != EOF) ;
    730 				break;
    731 
    732 			    case M4WRTYPE:		/* m4wrap(AtExit) */
    733 				/* set up for wrap-up/wind-down activity.   */
    734 				/* NB: if there are several calls to m4wrap */
    735 				/* only the last is effective; strange, but */
    736 				/* that's what System V does.               */
    737 				m4wraps = argc > 2 ? strsave(argv[2]) : null;
    738 				break;
    739 
    740 			    case EXITTYPE:		/* m4exit(Expr) */
    741 				/* immediate exit from m4.  */
    742 				killdiv();		/* mustn't forget that one! */
    743 				exit(argc > 2 ? expr(argv[2]) : 0);
    744 				break;
    745 
    746 			    case DEFNTYPE:		/* defn(Mac) */
    747 				for (t = 2; t < argc; t++)
    748 				    dodefn(argv[t]);
    749 				break;
    750 
    751 			    default:
    752 				error("m4: major botch in eval.");
    753 				break;
    754 			}
    755 
    756 			ep = PREVEP;		/* flush strspace */
    757 			sp = PREVSP;		/* previous sp..  */
    758 			fp = PREVFP;		/* rewind stack... */
    759 		    }
    760 		    break;
    761 
    762 		default:
    763 		    chrsave(t);			/* stack the char */
    764 		    break;
    765 	    }
    766 	}
    767     }
    768 
    769 
    770 int main(argc, argv)
    771     int argc;
    772     char **argv;
    773     {
    774 	register int c;
    775 	register int n;
    776 	char *p;
    777 
    778 #ifdef	SIGINT
    779 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    780 		signal(SIGINT, onintr);
    781 #endif
    782 
    783 	/*  Initialise the chtype[] table.
    784 	    '0' .. '9' -> 1..10
    785 	    'A' .. 'Z' -> 11..37
    786 	    'a' .. 'z' -> 11..37
    787 	    '_' -> 38
    788 	    all other characters -> 0
    789 	*/
    790 	for (c = EOF; c <= UCHAR_MAX; c++) chtype[c - EOF] = 0;
    791 	for (c =  1, p = "0123456789"; *p; p++, c++)
    792 	    chtype[*(unsigned char *)p - EOF] = c;
    793 	for (c = 11, p = "abcdefghijklmnopqrstuvwxyz"; *p; p++, c++)
    794 	    chtype[*(unsigned char *)p - EOF] = c;
    795 	for (c = 11, p = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; *p; p++, c++)
    796 	    chtype[*(unsigned char *)p - EOF] = c;
    797 	chtype['_' - EOF] = 38;
    798 
    799 #ifdef NONZEROPAGES
    800 	/*  If your system does not initialise global variables to  */
    801 	/*  0 bits, do it here.					    */
    802 	for (n = 0; n < HASHSIZE; n++) hashtab[n] = nil;
    803 	for (n = 0; n < MAXOUT; n++) outfile[n] = NULL;
    804 #endif
    805 	initkwds();
    806 
    807 	while ((c = getopt(argc, argv, "cetD:U:o:B:H:S:T:")) != EOF) {
    808 	    switch (c) {
    809 #if 0
    810 		case 's':		/* enable #line sync in output */
    811 		    fprintf(stderr, "m4: this version does not support -s\n");
    812 		    exit(2);
    813 #endif
    814 
    815 		case 'c':		/* strip comments */
    816 		    strip ^= 1;
    817 		    break;
    818 
    819 		case 'e':		/* interactive */
    820 		    (void) signal(SIGINT, SIG_IGN);
    821 		    setbuf(stdout, NULL);
    822 		    break;
    823 
    824 		case 'D':               /* define something..*/
    825 		    for (p = optarg; *p && *p != '='; p++) ;
    826 		    if (*p) *p++ = EOS;
    827 		    dodefine(optarg, p);
    828 		    break;
    829 
    830 		case 'U':               /* undefine...       */
    831 		    remhash(optarg, TOP);
    832 		    break;
    833 
    834 		case 'B': case 'H':	/* System V compatibility */
    835 		case 'S': case 'T':	/* ignore them */
    836 		    break;
    837 
    838 		case 'o':		/* specific output   */
    839 		    if (!freopen(optarg, "w", stdout)) {
    840 			perror(optarg);
    841 			exit(1);
    842 		    }
    843 		    break;
    844 
    845 		case '?':
    846 		default:
    847 			usage();
    848 	    }
    849 	}
    850 
    851 	active = stdout;		/* default active output     */
    852 	m4temp = mktemp(DIVNAM);	/* filename for diversions   */
    853 
    854 	sp = -1;			/* stack pointer initialized */
    855 	fp = 0; 			/* frame pointer initialized */
    856 
    857 	if (optind == argc) {		/* no more args; read stdin  */
    858 	    infile[0] = stdin;		/* default input (naturally) */
    859 #ifndef	NO__FILE
    860 	    dodefine("__FILE__", "-");	/* Helas */
    861 #endif
    862 	    macro();			/* process that file         */
    863 	} else				/* file names in commandline */
    864 	for (; optind < argc; optind++) {
    865 	    char *name = argv[optind];	/* next file name            */
    866 	    infile[0] = fopen(name, "r");
    867 	    if (!infile[0]) cantread(name);
    868 #ifndef	NO__FILE
    869 	    dodefine("__FILE__", name);
    870 #endif
    871 	    macro();
    872 	    fclose(infile[0]);
    873 	}
    874 
    875 	if (*m4wraps) { 		/* anything for rundown ??   */
    876 	    ilevel = 0;			/* in case m4wrap includes.. */
    877 	    putback(EOF);		/* eof is a must !!	     */
    878 	    pbstr(m4wraps); 		/* user-defined wrapup act   */
    879 	    macro();			/* last will and testament   */
    880 	} else {			/* default wrap-up: undivert */
    881 	    for (n = 1; n < MAXOUT; n++)
    882 		if (outfile[n] != NULL) getdiv(n);
    883 	}
    884 
    885 	if (outfile[0] != NULL) {	/* remove bitbucket if used  */
    886 	    (void) fclose(outfile[0]);
    887 	    m4temp[UNIQUE] = '0';
    888 #if unix
    889 	    (void) unlink(m4temp);
    890 #else
    891 	    (void) remove(m4temp);
    892 #endif
    893 	}
    894 	exit(0);
    895 	return 0;
    896     }
    897 
    898