This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.bin / m4 / main.c
CommitLineData
78ed81a3 1/* File : main.c
2 Author : Ozan Yigit
3 Updated: 4 May 1992
4 Defines: M4 macro processor.
5*/
15637ed4 6
78ed81a3 7#include "mdef.h"
8#include "extr.h"
9#include "ourlims.h"
15637ed4 10
78ed81a3 11char chtype[1 - EOF + UCHAR_MAX];
15637ed4 12
78ed81a3 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) < ' ')
15637ed4
RG
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 *
78ed81a3 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 *
15637ed4
RG
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
78ed81a3 146 * few microseconds out.. [didn't try very hard]
15637ed4
RG
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
15637ed4
RG
200char buf[BUFSIZE]; /* push-back buffer */
201char *bp = buf; /* first available character */
78ed81a3 202char *bb = buf; /* buffer beginning */
15637ed4
RG
203char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
204stae mstack[STACKMAX+1]; /* stack of m4 machine */
205char strspace[STRSPMAX+1]; /* string space for evaluation */
206char *ep = strspace; /* first free char in strspace */
207char *endest= strspace+STRSPMAX;/* end of string space */
208int sp; /* current m4 stack pointer */
209int fp; /* m4 call frame pointer */
78ed81a3 210char *bbstack[MAXINP]; /* stack where bb is saved */
15637ed4
RG
211FILE *infile[MAXINP]; /* input file stack (0=stdin) */
212FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
213FILE *active; /* active output file pointer */
15637ed4
RG
214int ilevel = 0; /* input file stack pointer */
215int oindex = 0; /* diversion index.. */
216char *null = ""; /* as it says.. just a null.. */
217char *m4wraps = ""; /* m4wrap string default.. */
218char lquote = LQUOTE; /* left quote character (`) */
219char rquote = RQUOTE; /* right quote character (') */
78ed81a3 220char vquote = VQUOTE; /* verbatim quote character ^V */
15637ed4
RG
221char scommt = SCOMMT; /* start character for comment */
222char ecommt = ECOMMT; /* end character for comment */
78ed81a3 223int 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__
237static char DIVNAM[] = _PATH_VARTMP "m40XXXXXX";
238#else
239static char DIVNAM[] = "/usr/tmp/m40XXXXXX";
15637ed4 240#endif
78ed81a3 241#else
242static char DIVNAM[] = "/usr/tmp/m40XXXXXX";
15637ed4 243#endif
78ed81a3 244#else
245#if vms
246static char DIVNAM[] = "sys$login:m40XXXXXX";
247#else
248static char DIVNAM[] = "M40XXXXXX"; /* was \M4, should it be \\M4? */
249#endif
250#endif
251int UNIQUE = sizeof DIVNAM - 7; /* where to change m4temp. */
252char *m4temp; /* filename for diversions */
253extern char *mktemp();
15637ed4 254
15637ed4 255
78ed81a3 256void cantread(s)
257 char *s;
258 {
259 fprintf(stderr, "m4: %s: ", s);
260 error("cannot open for input.");
261 }
15637ed4 262
15637ed4 263
78ed81a3 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*/
269static 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*/
333ndptr 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;
15637ed4 341
78ed81a3 342 while (is_sym2(c = gpbc())) {
343 if (tp == etp) error("m4: token too long");
344 *tp++ = c, h = (h << 5) + h + c;
15637ed4 345 }
78ed81a3 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 }
15637ed4 353
15637ed4
RG
354
355/*
356 * macro - the work horse..
357 *
358 */
78ed81a3 359void macro()
360 {
15637ed4 361 char token[MAXTOK];
78ed81a3 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");
15637ed4 423 }
78ed81a3 424 }
425 if (sp < 0) {
426 putc(t, op);
427 } else {
428 chrsave(t);
429 }
15637ed4 430 }
78ed81a3 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 */
15637ed4 450 }
78ed81a3 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);
15637ed4 563 }
78ed81a3 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
15637ed4 613
78ed81a3 614 case INCLTYPE: /* include(File) */
615 for (t = 2; t < argc; t++)
616 if (!doincl(argv[t])) cantread(argv[t]);
617 break;
15637ed4 618
78ed81a3 619 case SINCTYPE: /* sinclude(File) */
620 for (t = 2; t < argc; t++)
621 (void) doincl(argv[t]);
622 break;
15637ed4 623
78ed81a3 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
15637ed4 647
78ed81a3 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;
15637ed4 764 }
15637ed4 765
78ed81a3 766 ep = PREVEP; /* flush strspace */
767 sp = PREVSP; /* previous sp.. */
768 fp = PREVFP; /* rewind stack... */
769 }
770 break;
771
15637ed4 772 default:
78ed81a3 773 chrsave(t); /* stack the char */
774 break;
775 }
15637ed4 776 }
78ed81a3 777 }
15637ed4
RG
778
779
78ed81a3 780int main(argc, argv)
781 int argc;
782 char **argv;
783 {
784 register int c;
785 register int n;
786 char *p;
15637ed4 787
78ed81a3 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;
15637ed4
RG
808
809#ifdef NONZEROPAGES
78ed81a3 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();
15637ed4 816
78ed81a3 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);
15637ed4
RG
823#endif
824
78ed81a3 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;
15637ed4 843
78ed81a3 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 }
15637ed4 859 }
78ed81a3 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