xref: /netbsd-src/usr.bin/m4/main.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
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[] = "/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 	    sp = -1;			/* stack pointer initialized */
869 	    fp = 0; 			/* frame pointer initialized */
870 	    ilevel = 0;			/* reset input file stack ptr*/
871 #ifndef	NO__FILE
872 	    dodefine("__FILE__", name);
873 #endif
874 	    macro();
875 	    fclose(infile[0]);
876 	}
877 
878 	if (*m4wraps) { 		/* anything for rundown ??   */
879 	    ilevel = 0;			/* in case m4wrap includes.. */
880 	    putback(EOF);		/* eof is a must !!	     */
881 	    pbstr(m4wraps); 		/* user-defined wrapup act   */
882 	    macro();			/* last will and testament   */
883 	}
884 
885 	if (active != stdout)
886 	    active = stdout;		/* reset output just in case */
887 
888 	for (n = 1; n < MAXOUT; n++)	/* default wrap-up: undivert */
889 	    if (outfile[n] != NULL) getdiv(n);
890 
891 	if (outfile[0] != NULL) {	/* remove bitbucket if used  */
892 	    (void) fclose(outfile[0]);
893 	    m4temp[UNIQUE] = '0';
894 #if unix
895 	    (void) unlink(m4temp);
896 #else
897 	    (void) remove(m4temp);
898 #endif
899 	}
900 	exit(0);
901 	return 0;
902     }
903 
904