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