xref: /netbsd-src/usr.bin/m4/main.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
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 #include <sys/param.h>
234 #ifdef BSD
235 #include <paths.h>
236 #if __STDC__
237 static char DIVNAM[] = _PATH_VARTMP "m40XXXXXX";
238 #else
239 static char DIVNAM[] = "/usr/tmp/m40XXXXXX";
240 #endif
241 #else
242 static char DIVNAM[] = "/usr/tmp/m40XXXXXX";
243 #endif
244 #else
245 #if vms
246 static char DIVNAM[] = "sys$login:m40XXXXXX";
247 #else
248 static char DIVNAM[] = "M40XXXXXX";	/* was \M4, should it be \\M4? */
249 #endif
250 #endif
251 int UNIQUE = sizeof DIVNAM - 7;	/* where to change m4temp.     */
252 char *m4temp;			/* filename for diversions     */
253 extern char *mktemp();
254 
255 
256 void cantread(s)
257     char *s;
258     {
259 	fprintf(stderr, "m4: %s: ", s);
260 	error("cannot open for input.");
261     }
262 
263 
264 /*  initkwds()
265     initialises the hash table to contain all the m4 built-in functions.
266     The original version breached module boundaries, but there did not
267     seem to be any benefit in that.
268 */
269 static void initkwds()
270     {
271 	register int i;
272 	static struct { char *name; int type; } keyword[] =
273 	    {
274 		"include",      INCLTYPE,
275 		"sinclude",     SINCTYPE,
276 		"define",       DEFITYPE,
277 		"defn",         DEFNTYPE,
278 		"divert",       DIVRTYPE,
279 		"expr",         EXPRTYPE,
280 		"eval",         EXPRTYPE,
281 		"substr",       SUBSTYPE,
282 		"ifelse",       IFELTYPE,
283 		"ifdef",        IFDFTYPE,
284 		"len",          LENGTYPE,
285 		"incr",         INCRTYPE,
286 		"decr",         DECRTYPE,
287 		"dnl",          DNLNTYPE,
288 		"changequote",  CHNQTYPE,
289 		"changecom",    CHNCTYPE,
290 		"index",        INDXTYPE,
291 #ifdef EXTENDED
292 		"paste",        PASTTYPE,
293 		"spaste",       SPASTYPE,
294 		"m4trim",	TRIMTYPE,
295 		"defquote",	DEFQTYPE,
296 #endif
297 		"popdef",       POPDTYPE,
298 		"pushdef",      PUSDTYPE,
299 		"dumpdef",      DUMPTYPE,
300 		"shift",        SHIFTYPE,
301 		"translit",     TRNLTYPE,
302 		"undefine",     UNDFTYPE,
303 		"undivert",     UNDVTYPE,
304 		"divnum",       DIVNTYPE,
305 		"maketemp",     MKTMTYPE,
306 		"errprint",     ERRPTYPE,
307 		"m4wrap",       M4WRTYPE,
308 		"m4exit",       EXITTYPE,
309 #if unix || vms
310 		"syscmd",       SYSCTYPE,
311 		"sysval",       SYSVTYPE,
312 #endif
313 #if unix
314 		"unix",         MACRTYPE,
315 #else
316 #if vms
317 		"vms",          MACRTYPE,
318 #endif
319 #endif
320 		(char*)0,	0
321 	    };
322 
323 	for (i = 0; keyword[i].type != 0; i++)
324 	    addkywd(keyword[i].name, keyword[i].type);
325     }
326 
327 
328 /*  inspect(Name)
329     Build an input token.., considering only those which start with
330     [A-Za-z_].  This is fused with lookup() to speed things up.
331     name must point to an array of at least MAXTOK characters.
332 */
333 ndptr inspect(name)
334     char *name;
335     {
336 	register char *tp = name;
337 	register char *etp = name+(MAXTOK-1);
338 	register int c;
339 	register unsigned long h = 0;
340 	register ndptr p;
341 
342 	while (is_sym2(c = gpbc())) {
343 	    if (tp == etp) error("m4: token too long");
344 	    *tp++ = c, h = (h << 5) + h + c;
345 	}
346 	putback(c);
347 	*tp = EOS;
348 	for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
349 	    if (strcmp(name, p->name) == 0)
350 		return p;
351 	return nil;
352     }
353 
354 
355 /*
356  * macro - the work horse..
357  *
358  */
359 void macro()
360     {
361 	char token[MAXTOK];
362 	register int t;
363 	register FILE *op = active;
364 	static char ovmsg[] = "m4: internal stack overflow";
365 
366 	for (;;) {
367 	    t = gpbc();
368 	    if (is_sym1(t)) {
369 		register char *s;
370 		register ndptr p;
371 
372 		putback(t);
373 		if ((p = inspect(s = token)) == nil) {
374 		    if (sp < 0) {
375 			while (t = *s++) putc(t, op);
376 		    } else {
377 			while (t = *s++) chrsave(t);
378 		    }
379 		} else {
380 		    /* real thing.. First build a call frame */
381 		    if (sp >= STACKMAX-6) error(ovmsg);
382 		    mstack[1+sp].sfra = fp;		/* previous call frm */
383 		    mstack[2+sp].sfra = p->type;	/* type of the call  */
384 		    mstack[3+sp].sfra = 0;		/* parenthesis level */
385 		    fp = sp+3;				/* new frame pointer */
386 		    /* now push the string arguments */
387 		    mstack[4+sp].sstr = p->defn;	/* defn string */
388 		    mstack[5+sp].sstr = p->name;	/* macro name  */
389 		    mstack[6+sp].sstr = ep;		/* start next.. */
390 		    sp += 6;
391 
392 		    t = gpbc();
393 		    putback(t);
394 		    if (t != LPAREN) { putback(RPAREN); putback(LPAREN); }
395 		}
396 	    } else
397 	    if (t == EOF) {
398 		if (sp >= 0) error("m4: unexpected end of input");
399 		if (--ilevel < 0) break;		/* all done thanks */
400 #ifndef	NO__FILE
401 		remhash("__FILE__", TOP);
402 #endif
403 		bb = bbstack[ilevel+1];
404 		(void) fclose(infile[ilevel+1]);
405 	    } else
406 	    /* non-alpha single-char token seen..
407 		[the order of else if .. stmts is important.]
408 	    */
409 	    if (t == lquote) {				/* strip quotes */
410 		register int nlpar;
411 
412 		for (nlpar = 1; ; ) {
413 		    t = gpbc();
414 		    if (t == rquote) {
415 			if (--nlpar == 0) break;
416 		    } else
417 		    if (t == lquote) {
418 			nlpar++;
419 		    } else {
420 			if (t == vquote) t = gpbc();
421 			if (t == EOF) {
422 			    error("m4: missing right quote");
423 			}
424 		    }
425 		    if (sp < 0) {
426 			putc(t, op);
427 		    } else {
428 			chrsave(t);
429 		    }
430 		}
431 	    } else
432 	    if (sp < 0) {			/* not in a macro at all */
433 		if (t != scommt) {		/* not a comment, so */
434 		    putc(t, op);		/* copy it to output */
435 		} else
436 		if (strip) {			/* discard a comment */
437 		    do {
438 			t = gpbc();
439 		    } while (t != ecommt && t != EOF);
440 		} else {			/* copy comment to output */
441 		    do {
442 			putc(t, op);
443 			t = gpbc();
444 		    } while (t != ecommt && t != EOF);
445 		    putc(t, op);
446 		    /*  A note on comment handling:  this is NOT robust.
447 		    |   We should do something safe with comments that
448 		    |   are missing their ecommt termination.
449 		    */
450 		}
451 	    } else
452 	    switch (t) {
453 		/*  There is a peculiar detail to notice here.
454 		    Layout is _always_ discarded after left parentheses,
455 		    but it is only discarded after commas if they separate
456 		    arguments.  For example,
457 		    define(foo,`|$1|$2|')
458 		    foo( a, b)		=> |a|b|
459 		    foo(( a ), ( b ))	=> |(a )|(b )|
460 		    foo((a, x), (b, y))	=> |(a, x)|(b, y)|
461 		    I find this counter-intuitive, and would expect the code
462 		    for LPAREN to read something like this:
463 
464 		    if (PARLEV == 0) {
465 			(* top level left parenthesis: skip layout *)
466 			do t = gpbc(); while (is_blnk(t));
467 			putback(t);
468 		    } else {
469 			(* left parenthesis inside an argument *)
470 			chrsave(t);
471 		    }
472 		    PARLEV++;
473 
474 		    However, it turned out that Oz wrote the actual code
475 		    very carefully to mimic the behaviour of "real" m4;
476 		    UNIX m4 really does skip layout after all left parens
477 		    but only some commas in just this fashion.  Sigh.
478 		*/
479 		case LPAREN:
480 		    if (PARLEV > 0) chrsave(t);
481 		    do t = gpbc(); while (is_blnk(t));	/* skip layout */
482 		    putback(t);
483 		    PARLEV++;
484 		    break;
485 
486 		case COMMA:
487 		    if (PARLEV == 1) {
488 			chrsave(EOS);		/* new argument   */
489 			if (sp >= STACKMAX) error(ovmsg);
490 			do t = gpbc(); while (is_blnk(t)); /* skip layout */
491 			putback(t);
492 			mstack[++sp].sstr = ep;
493 		    } else {
494 			chrsave(t);
495 		    }
496 		    break;
497 
498 		case RPAREN:
499 		    if (--PARLEV > 0) {
500 			chrsave(t);
501 		    } else {
502 			char **argv = (char **)(mstack+fp+1);
503 			int    argc = sp-fp;
504 #if	unix | vms
505 			static int sysval;
506 #endif
507 
508 			chrsave(EOS);		/* last argument */
509 			if (sp >= STACKMAX) error(ovmsg);
510 #ifdef	DEBUG
511 			fprintf(stderr, "argc = %d\n", argc);
512 			for (t = 0; t < argc; t++)
513 			    fprintf(stderr, "argv[%d] = %s\n", t, argv[t]);
514 #endif
515 			/*  If argc == 3 and argv[2] is null, then we
516 			    have a call like `macro_or_builtin()'.  We
517 			    adjust argc to avoid further checking..
518 			*/
519 			if (argc == 3 && !argv[2][0]) argc--;
520 
521 			switch (CALTYP & ~STATIC) {
522 			    case MACRTYPE:
523 				expand(argv, argc);
524 				break;
525 
526 			    case DEFITYPE:		/* define(..) */
527 				for (; argc > 2; argc -= 2, argv += 2)
528 				    dodefine(argv[2], argc > 3 ? argv[3] : null);
529 				break;
530 
531 			    case PUSDTYPE:		/* pushdef(..) */
532 				for (; argc > 2; argc -= 2, argv += 2)
533 				    dopushdef(argv[2], argc > 3 ? argv[3] : null);
534 				break;
535 
536 			    case DUMPTYPE:
537 				dodump(argv, argc);
538 				break;
539 
540 			    case EXPRTYPE:		/* eval(Expr) */
541 				{   /* evaluate arithmetic expression */
542 				    /* eval([val: 0[, radix:10 [,min: 1]]]) */
543 				    /* excess arguments are ignored */
544 				    /* eval() with no arguments returns 0 */
545 				    /* this is based on V.3 behaviour */
546 				    int min_digits = 1;
547 				    int radix = 10;
548 				    long int value = 0;
549 
550 				    switch (argc) {
551 					default:
552 					    /* ignore excess arguments */
553 					case 5:
554 					    min_digits = expr(argv[4]);
555 					case 4:
556 					    radix = expr(argv[3]);
557 					case 3:
558 					    value = expr(argv[2]);
559 					case 2:
560 					    break;
561 				    }
562 				    pbrad(value, radix, min_digits);
563 				}
564 				break;
565 
566 			    case IFELTYPE:		/* ifelse(X,Y,IFX=Y,Else) */
567 				doifelse(argv, argc);
568 				break;
569 
570 			    case IFDFTYPE:		/* ifdef(Mac,IfDef[,IfNotDef]) */
571 				/* select one of two alternatives based on the existence */
572 				/* of another definition */
573 				if (argc > 3) {
574 				    if (lookup(argv[2]) != nil) {
575 					pbstr(argv[3]);
576 				    } else
577 				    if (argc > 4) {
578 					pbstr(argv[4]);
579 				    }
580 				}
581 				break;
582 
583 			    case LENGTYPE:		/* len(Arg) */
584 				/* find the length of the argument */
585 				pbnum(argc > 2 ? strlen(argv[2]) : 0);
586 				break;
587 
588 			    case INCRTYPE:		/* incr(Expr) */
589 				/* increment the value of the argument */
590 				if (argc > 2) pbnum(expr(argv[2]) + 1);
591 				break;
592 
593 			    case DECRTYPE:		/* decr(Expr) */
594 				/* decrement the value of the argument */
595 				if (argc > 2) pbnum(expr(argv[2]) - 1);
596 				break;
597 
598 #if unix || vms
599 			    case SYSCTYPE:		/* syscmd(Command) */
600 				/* execute system command */
601 				/* Make sure m4 output is NOT interrupted */
602 				fflush(stdout);
603 				fflush(stderr);
604 
605 				if (argc > 2) sysval = system(argv[2]);
606 				break;
607 
608 			    case SYSVTYPE:		/* sysval() */
609 				/* return value of the last system call.  */
610 				pbnum(sysval);
611 				break;
612 #endif
613 
614 			    case INCLTYPE:		/* include(File) */
615 				for (t = 2; t < argc; t++)
616 				    if (!doincl(argv[t])) cantread(argv[t]);
617 				break;
618 
619 			    case SINCTYPE:		/* sinclude(File) */
620 				for (t = 2; t < argc; t++)
621 				    (void) doincl(argv[t]);
622 				break;
623 
624 #ifdef EXTENDED
625 			    case PASTTYPE:		/* paste(File) */
626 				for (t = 2; t < argc; t++)
627 				    if (!dopaste(argv[t])) cantread(argv[t]);
628 				break;
629 
630 			    case SPASTYPE:		/* spaste(File) */
631 				for (t = 2; t < argc; t++)
632 				    (void) dopaste(argv[t]);
633 				break;
634 
635 			    case TRIMTYPE:		/* m4trim(Source,..) */
636 				if (argc > 2) m4trim(argv, argc);
637 				break;
638 
639 			    case DEFQTYPE:		/* defquote(Mac,...) */
640 				dodefqt(argv, argc);
641 				break;
642 
643 			    case QUTRTYPE:		/* <quote>(text...) */
644 				doqutr(argv, argc);
645 				break;
646 #endif
647 
648 			    case CHNQTYPE:		/* changequote([Left[,Right]]) */
649 				dochq(argv, argc);
650 				break;
651 
652 			    case CHNCTYPE:		/* changecom([Left[,Right]]) */
653 				dochc(argv, argc);
654 				break;
655 
656 			    case SUBSTYPE:		/* substr(Source[,Offset[,Length]]) */
657 				/* select substring */
658 				if (argc > 3) dosub(argv, argc);
659 				break;
660 
661 			    case SHIFTYPE:		/* shift(~args~) */
662 				/* push back all arguments except the first one */
663 				/* (i.e.  skip argv[2]) */
664 				if (argc > 3) {
665 				    for (t = argc-1; t > 3; t--) {
666 					pbqtd(argv[t]);
667 					putback(',');
668 				    }
669 				    pbqtd(argv[3]);
670 				}
671 				break;
672 
673 			    case DIVRTYPE:		/* divert(N) */
674 				if (argc > 2 && (t = expr(argv[2])) != 0) {
675 				    dodiv(t);
676 				} else {
677 				    active = stdout;
678 				    oindex = 0;
679 				}
680 				op = active;
681 				break;
682 
683 			    case UNDVTYPE:		/* undivert(N...) */
684 				doundiv(argv, argc);
685 				op = active;
686 				break;
687 
688 			    case DIVNTYPE:		/* divnum() */
689 				/* return the number of current output diversion */
690 				pbnum(oindex);
691 				break;
692 
693 			    case UNDFTYPE:		/* undefine(..) */
694 				/* undefine a previously defined macro(s) or m4 keyword(s). */
695 				for (t = 2; t < argc; t++) remhash(argv[t], ALL);
696 				break;
697 
698 			    case POPDTYPE:		/* popdef(Mac...) */
699 				/* remove the topmost definitions of macro(s) or m4 keyword(s). */
700 				for (t = 2; t < argc; t++) remhash(argv[t], TOP);
701 				break;
702 
703 			    case MKTMTYPE:		/* maketemp(Pattern) */
704 				/* create a temporary file */
705 				if (argc > 2) pbstr(mktemp(argv[2]));
706 				break;
707 
708 			    case TRNLTYPE:		/* translit(Source,Dom,Rng) */
709 				/* replace all characters in the source string that */
710 				/* appears in the "from" string with the corresponding */
711 				/* characters in the "to" string. */
712 
713 				if (argc > 3) {
714 				    char temp[MAXTOK];
715 
716 				    if (argc > 4)
717 					map(temp, argv[2], argv[3], argv[4]);
718 				    else
719 					map(temp, argv[2], argv[3], null);
720 				    pbstr(temp);
721 				} else if (argc > 2)
722 				    pbstr(argv[2]);
723 				break;
724 
725 			    case INDXTYPE:		/* index(Source,Target) */
726 				/* find the index of the second argument string in */
727 				/* the first argument string. -1 if not present. */
728 				pbnum(argc > 3 ? indx(argv[2], argv[3]) : -1);
729 				break;
730 
731 			    case ERRPTYPE:		/* errprint(W,...,W) */
732 				/* print the arguments to stderr file */
733 				for (t = 2; t < argc; t++) fprintf(stderr, "%s ", argv[t]);
734 				fprintf(stderr, "\n");
735 				break;
736 
737 			    case DNLNTYPE:		/* dnl() */
738 				/* eat upto and including newline */
739 				while ((t = gpbc()) != '\n' && t != EOF) ;
740 				break;
741 
742 			    case M4WRTYPE:		/* m4wrap(AtExit) */
743 				/* set up for wrap-up/wind-down activity.   */
744 				/* NB: if there are several calls to m4wrap */
745 				/* only the last is effective; strange, but */
746 				/* that's what System V does.               */
747 				m4wraps = argc > 2 ? strsave(argv[2]) : null;
748 				break;
749 
750 			    case EXITTYPE:		/* m4exit(Expr) */
751 				/* immediate exit from m4.  */
752 				killdiv();		/* mustn't forget that one! */
753 				exit(argc > 2 ? expr(argv[2]) : 0);
754 				break;
755 
756 			    case DEFNTYPE:		/* defn(Mac) */
757 				for (t = 2; t < argc; t++)
758 				    dodefn(argv[t]);
759 				break;
760 
761 			    default:
762 				error("m4: major botch in eval.");
763 				break;
764 			}
765 
766 			ep = PREVEP;		/* flush strspace */
767 			sp = PREVSP;		/* previous sp..  */
768 			fp = PREVFP;		/* rewind stack... */
769 		    }
770 		    break;
771 
772 		default:
773 		    chrsave(t);			/* stack the char */
774 		    break;
775 	    }
776 	}
777     }
778 
779 
780 int main(argc, argv)
781     int argc;
782     char **argv;
783     {
784 	register int c;
785 	register int n;
786 	char *p;
787 
788 #ifdef	SIGINT
789 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
790 		signal(SIGINT, onintr);
791 #endif
792 
793 	/*  Initialise the chtype[] table.
794 	    '0' .. '9' -> 1..10
795 	    'A' .. 'Z' -> 11..37
796 	    'a' .. 'z' -> 11..37
797 	    '_' -> 38
798 	    all other characters -> 0
799 	*/
800 	for (c = EOF; c <= UCHAR_MAX; c++) chtype[c - EOF] = 0;
801 	for (c =  1, p = "0123456789"; *p; p++, c++)
802 	    chtype[*(unsigned char *)p - EOF] = c;
803 	for (c = 11, p = "abcdefghijklmnopqrstuvwxyz"; *p; p++, c++)
804 	    chtype[*(unsigned char *)p - EOF] = c;
805 	for (c = 11, p = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; *p; p++, c++)
806 	    chtype[*(unsigned char *)p - EOF] = c;
807 	chtype['_' - EOF] = 38;
808 
809 #ifdef NONZEROPAGES
810 	/*  If your system does not initialise global variables to  */
811 	/*  0 bits, do it here.					    */
812 	for (n = 0; n < HASHSIZE; n++) hashtab[n] = nil;
813 	for (n = 0; n < MAXOUT; n++) outfile[n] = NULL;
814 #endif
815 	initkwds();
816 
817 	while ((c = getopt(argc, argv, "cetD:U:o:B:H:S:T:")) != EOF) {
818 	    switch (c) {
819 #if 0
820 		case 's':		/* enable #line sync in output */
821 		    fprintf(stderr, "m4: this version does not support -s\n");
822 		    exit(2);
823 #endif
824 
825 		case 'c':		/* strip comments */
826 		    strip ^= 1;
827 		    break;
828 
829 		case 'e':		/* interactive */
830 		    (void) signal(SIGINT, SIG_IGN);
831 		    setbuf(stdout, NULL);
832 		    break;
833 
834 		case 'D':               /* define something..*/
835 		    for (p = optarg; *p && *p != '='; p++) ;
836 		    if (*p) *p++ = EOS;
837 		    dodefine(optarg, p);
838 		    break;
839 
840 		case 'U':               /* undefine...       */
841 		    remhash(optarg, TOP);
842 		    break;
843 
844 		case 'B': case 'H':	/* System V compatibility */
845 		case 'S': case 'T':	/* ignore them */
846 		    break;
847 
848 		case 'o':		/* specific output   */
849 		    if (!freopen(optarg, "w", stdout)) {
850 			perror(optarg);
851 			exit(1);
852 		    }
853 		    break;
854 
855 		case '?':
856 		default:
857 			usage();
858 	    }
859 	}
860 
861 	active = stdout;		/* default active output     */
862 	m4temp = mktemp(DIVNAM);	/* filename for diversions   */
863 
864 	sp = -1;			/* stack pointer initialized */
865 	fp = 0; 			/* frame pointer initialized */
866 
867 	if (optind == argc) {		/* no more args; read stdin  */
868 	    infile[0] = stdin;		/* default input (naturally) */
869 #ifndef	NO__FILE
870 	    dodefine("__FILE__", "-");	/* Helas */
871 #endif
872 	    macro();			/* process that file         */
873 	} else				/* file names in commandline */
874 	for (; optind < argc; optind++) {
875 	    char *name = argv[optind];	/* next file name            */
876 	    infile[0] = fopen(name, "r");
877 	    if (!infile[0]) cantread(name);
878 #ifndef	NO__FILE
879 	    dodefine("__FILE__", name);
880 #endif
881 	    macro();
882 	    fclose(infile[0]);
883 	}
884 
885 	if (*m4wraps) { 		/* anything for rundown ??   */
886 	    ilevel = 0;			/* in case m4wrap includes.. */
887 	    putback(EOF);		/* eof is a must !!	     */
888 	    pbstr(m4wraps); 		/* user-defined wrapup act   */
889 	    macro();			/* last will and testament   */
890 	} else {			/* default wrap-up: undivert */
891 	    for (n = 1; n < MAXOUT; n++)
892 		if (outfile[n] != NULL) getdiv(n);
893 	}
894 
895 	if (outfile[0] != NULL) {	/* remove bitbucket if used  */
896 	    (void) fclose(outfile[0]);
897 	    m4temp[UNIQUE] = '0';
898 #if unix
899 	    (void) unlink(m4temp);
900 #else
901 	    (void) remove(m4temp);
902 #endif
903 	}
904 	exit(0);
905 	return 0;
906     }
907 
908