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