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