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