1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ozan Yigit at York University. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; 40 #endif 41 static const char rcsid[] = 42 "$FreeBSD$"; 43 #endif /* not lint */ 44 45 /* 46 * eval.c 47 * Facility: m4 macro processor 48 * by: oz 49 */ 50 51 #include <sys/types.h> 52 #include <err.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include "mdef.h" 58 #include "stdd.h" 59 #include "extern.h" 60 #include "pathnames.h" 61 62 /* 63 * eval - evaluate built-in macros. 64 * argc - number of elements in argv. 65 * argv - element vector : 66 * argv[0] = definition of a user 67 * macro or nil if built-in. 68 * argv[1] = name of the macro or 69 * built-in. 70 * argv[2] = parameters to user-defined 71 * . macro or built-in. 72 * . 73 * 74 * Note that the minimum value for argc is 3. A call in the form 75 * of macro-or-builtin() will result in: 76 * argv[0] = nullstr 77 * argv[1] = macro-or-builtin 78 * argv[2] = nullstr 79 */ 80 81 void 82 eval(argv, argc, td) 83 register char *argv[]; 84 register int argc; 85 register int td; 86 { 87 register int c, n; 88 static int sysval = 0; 89 90 #ifdef DEBUG 91 printf("argc = %d\n", argc); 92 for (n = 0; n < argc; n++) 93 printf("argv[%d] = %s\n", n, argv[n]); 94 #endif 95 /* 96 * if argc == 3 and argv[2] is null, then we 97 * have macro-or-builtin() type call. We adjust 98 * argc to avoid further checking.. 99 */ 100 if (argc == 3 && !*(argv[2])) 101 argc--; 102 103 switch (td & ~STATIC) { 104 105 case DEFITYPE: 106 if (argc > 2) 107 dodefine(argv[2], (argc > 3) ? argv[3] : null); 108 break; 109 110 case PUSDTYPE: 111 if (argc > 2) 112 dopushdef(argv[2], (argc > 3) ? argv[3] : null); 113 break; 114 115 case DUMPTYPE: 116 dodump(argv, argc); 117 break; 118 119 case EXPRTYPE: 120 /* 121 * doexpr - evaluate arithmetic 122 * expression 123 */ 124 if (argc > 2) 125 pbnum(expr(argv[2])); 126 break; 127 128 case IFELTYPE: 129 if (argc > 4) 130 doifelse(argv, argc); 131 break; 132 133 case IFDFTYPE: 134 /* 135 * doifdef - select one of two 136 * alternatives based on the existence of 137 * another definition 138 */ 139 if (argc > 3) { 140 if (lookup(argv[2]) != nil) 141 pbstr(argv[3]); 142 else if (argc > 4) 143 pbstr(argv[4]); 144 } 145 break; 146 147 case LENGTYPE: 148 /* 149 * dolen - find the length of the 150 * argument 151 */ 152 if (argc > 2) 153 pbnum((argc > 2) ? strlen(argv[2]) : 0); 154 break; 155 156 case INCRTYPE: 157 /* 158 * doincr - increment the value of the 159 * argument 160 */ 161 if (argc > 2) 162 pbnum(atoi(argv[2]) + 1); 163 break; 164 165 case DECRTYPE: 166 /* 167 * dodecr - decrement the value of the 168 * argument 169 */ 170 if (argc > 2) 171 pbnum(atoi(argv[2]) - 1); 172 break; 173 174 case SYSCTYPE: 175 /* 176 * dosys - execute system command 177 */ 178 /* Make sure m4 output is NOT interrupted */ 179 fflush(stdout); 180 fflush(stderr); 181 if (argc > 2) 182 sysval = system(argv[2]); 183 break; 184 185 case SYSVTYPE: 186 /* 187 * dosysval - return value of the last 188 * system call. 189 * 190 */ 191 pbnum(sysval); 192 break; 193 194 case INCLTYPE: 195 if (argc > 2) 196 if (!doincl(argv[2])) 197 err(1, "%s", argv[2]); 198 break; 199 200 case SINCTYPE: 201 if (argc > 2) 202 (void) doincl(argv[2]); 203 break; 204 #ifdef EXTENDED 205 case PASTTYPE: 206 if (argc > 2) 207 if (!dopaste(argv[2])) 208 err(1, "%s", argv[2]); 209 break; 210 211 case SPASTYPE: 212 if (argc > 2) 213 (void) dopaste(argv[2]); 214 break; 215 #endif 216 case CHNQTYPE: 217 dochq(argv, argc); 218 break; 219 220 case CHNCTYPE: 221 dochc(argv, argc); 222 break; 223 224 case SUBSTYPE: 225 /* 226 * dosub - select substring 227 * 228 */ 229 if (argc > 3) 230 dosub(argv, argc); 231 break; 232 233 case SHIFTYPE: 234 /* 235 * doshift - push back all arguments 236 * except the first one (i.e. skip 237 * argv[2]) 238 */ 239 if (argc > 3) { 240 for (n = argc - 1; n > 3; n--) { 241 putback(rquote); 242 pbstr(argv[n]); 243 putback(lquote); 244 putback(','); 245 } 246 putback(rquote); 247 pbstr(argv[3]); 248 putback(lquote); 249 } 250 break; 251 252 case DIVRTYPE: 253 if (argc > 2 && (n = atoi(argv[2])) != 0) 254 dodiv(n); 255 else { 256 active = stdout; 257 oindex = 0; 258 } 259 break; 260 261 case UNDVTYPE: 262 doundiv(argv, argc); 263 break; 264 265 case DIVNTYPE: 266 /* 267 * dodivnum - return the number of 268 * current output diversion 269 */ 270 pbnum(oindex); 271 break; 272 273 case UNDFTYPE: 274 /* 275 * doundefine - undefine a previously 276 * defined macro(s) or m4 keyword(s). 277 */ 278 if (argc > 2) 279 for (n = 2; n < argc; n++) 280 remhash(argv[n], ALL); 281 break; 282 283 case POPDTYPE: 284 /* 285 * dopopdef - remove the topmost 286 * definitions of macro(s) or m4 287 * keyword(s). 288 */ 289 if (argc > 2) 290 for (n = 2; n < argc; n++) 291 remhash(argv[n], TOP); 292 break; 293 294 case MKTMTYPE: 295 /* 296 * dotemp - create a temporary file 297 */ 298 if (argc > 2) 299 pbstr(mktemp(argv[2])); 300 break; 301 302 case TRNLTYPE: 303 /* 304 * dotranslit - replace all characters in 305 * the source string that appears in the 306 * "from" string with the corresponding 307 * characters in the "to" string. 308 */ 309 if (argc > 3) { 310 char temp[STRSPMAX+1]; 311 if (argc > 4) 312 map(temp, argv[2], argv[3], argv[4]); 313 else 314 map(temp, argv[2], argv[3], null); 315 pbstr(temp); 316 } 317 else if (argc > 2) 318 pbstr(argv[2]); 319 break; 320 321 case INDXTYPE: 322 /* 323 * doindex - find the index of the second 324 * argument string in the first argument 325 * string. -1 if not present. 326 */ 327 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 328 break; 329 330 case ERRPTYPE: 331 /* 332 * doerrp - print the arguments to stderr 333 * file 334 */ 335 if (argc > 2) { 336 for (n = 2; n < argc; n++) 337 fprintf(stderr, "%s ", argv[n]); 338 fprintf(stderr, "\n"); 339 } 340 break; 341 342 case DNLNTYPE: 343 /* 344 * dodnl - eat-up-to and including 345 * newline 346 */ 347 while ((c = gpbc()) != '\n' && c != EOF) 348 ; 349 break; 350 351 case M4WRTYPE: 352 /* 353 * dom4wrap - set up for 354 * wrap-up/wind-down activity 355 */ 356 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 357 break; 358 359 case EXITTYPE: 360 /* 361 * doexit - immediate exit from m4. 362 */ 363 killdiv(); 364 exit((argc > 2) ? atoi(argv[2]) : 0); 365 break; 366 367 case DEFNTYPE: 368 if (argc > 2) 369 for (n = 2; n < argc; n++) 370 dodefn(argv[n]); 371 break; 372 373 case MACRTYPE: 374 pbstr(""); 375 break; 376 377 default: 378 errx(1, "eval: major botch"); 379 break; 380 } 381 } 382 383 const char dumpfmt[] = "`%s'\t`%s'\n"; /* format string for dumpdef */ 384 385 /* 386 * expand - user-defined macro expansion 387 */ 388 void 389 expand(argv, argc) 390 register char *argv[]; 391 register int argc; 392 { 393 register unsigned char *t; 394 register unsigned char *p; 395 register int n; 396 register int argno; 397 398 t = argv[0]; /* defn string as a whole */ 399 p = t; 400 while (*p) 401 p++; 402 p--; /* last character of defn */ 403 while (p > t) { 404 if (*(p - 1) != ARGFLAG) 405 putback(*p); 406 else { 407 switch (*p) { 408 409 case '#': 410 pbnum(argc - 2); 411 break; 412 case '0': 413 case '1': 414 case '2': 415 case '3': 416 case '4': 417 case '5': 418 case '6': 419 case '7': 420 case '8': 421 case '9': 422 if ((argno = *p - '0') < argc - 1) 423 pbstr(argv[argno + 1]); 424 break; 425 case '*': 426 for (n = argc - 1; n > 2; n--) { 427 pbstr(argv[n]); 428 putback(','); 429 } 430 pbstr(argv[2]); 431 break; 432 case '@': 433 for( n = argc - 1; n >= 2; n-- ) 434 { 435 putback(rquote); 436 pbstr(argv[n]); 437 putback(lquote); 438 if( n > 2 ) 439 putback(','); 440 } 441 break; 442 default: 443 putback(*p); 444 putback('$'); 445 break; 446 } 447 p--; 448 } 449 p--; 450 } 451 if (p == t) /* do last character */ 452 putback(*p); 453 } 454 455 /* 456 * dodefine - install definition in the table 457 */ 458 void 459 dodefine(name, defn) 460 register char *name; 461 register char *defn; 462 { 463 register ndptr p; 464 465 if (!*name) 466 errx(1, "null definition"); 467 if (STREQ(name, defn)) 468 errx(1, "%s: recursive definition", name); 469 if ((p = lookup(name)) == nil) 470 p = addent(name); 471 else if (p->defn != null) 472 free((char *) p->defn); 473 if (!*defn) 474 p->defn = null; 475 else 476 p->defn = xstrdup(defn); 477 p->type = MACRTYPE; 478 } 479 480 /* 481 * dodefn - push back a quoted definition of 482 * the given name. 483 */ 484 void 485 dodefn(name) 486 char *name; 487 { 488 register ndptr p; 489 490 if ((p = lookup(name)) != nil && p->defn != null) { 491 putback(rquote); 492 pbstr(p->defn); 493 putback(lquote); 494 } 495 } 496 497 /* 498 * dopushdef - install a definition in the hash table 499 * without removing a previous definition. Since 500 * each new entry is entered in *front* of the 501 * hash bucket, it hides a previous definition from 502 * lookup. 503 */ 504 void 505 dopushdef(name, defn) 506 register char *name; 507 register char *defn; 508 { 509 register ndptr p; 510 511 if (!*name) 512 errx(1, "null definition"); 513 if (STREQ(name, defn)) 514 errx(1, "%s: recursive definition", name); 515 p = addent(name); 516 if (!*defn) 517 p->defn = null; 518 else 519 p->defn = xstrdup(defn); 520 p->type = MACRTYPE; 521 } 522 523 /* 524 * dodumpdef - dump the specified definitions in the hash 525 * table to stderr. If nothing is specified, the entire 526 * hash table is dumped. 527 */ 528 void 529 dodump(argv, argc) 530 register char *argv[]; 531 register int argc; 532 { 533 register int n; 534 ndptr p; 535 536 if (argc > 2) { 537 for (n = 2; n < argc; n++) 538 if ((p = lookup(argv[n])) != nil) 539 fprintf(stderr, dumpfmt, p->name, 540 p->defn); 541 } 542 else { 543 for (n = 0; n < HASHSIZE; n++) 544 for (p = hashtab[n]; p != nil; p = p->nxtptr) 545 fprintf(stderr, dumpfmt, p->name, 546 p->defn); 547 } 548 } 549 550 /* 551 * doifelse - select one of two alternatives - loop. 552 */ 553 void 554 doifelse(argv, argc) 555 register char *argv[]; 556 register int argc; 557 { 558 cycle { 559 if (STREQ(argv[2], argv[3])) 560 pbstr(argv[4]); 561 else if (argc == 6) 562 pbstr(argv[5]); 563 else if (argc > 6) { 564 argv += 3; 565 argc -= 3; 566 continue; 567 } 568 break; 569 } 570 } 571 572 /* 573 * doinclude - include a given file. 574 */ 575 int 576 doincl(ifile) 577 char *ifile; 578 { 579 if (ilevel + 1 == MAXINP) 580 errx(1, "too many include files"); 581 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 582 ilevel++; 583 bbase[ilevel] = bufbase = bp; 584 return (1); 585 } 586 else 587 return (0); 588 } 589 590 #ifdef EXTENDED 591 /* 592 * dopaste - include a given file without any 593 * macro processing. 594 */ 595 int 596 dopaste(pfile) 597 char *pfile; 598 { 599 FILE *pf; 600 register int c; 601 602 if ((pf = fopen(pfile, "r")) != NULL) { 603 while ((c = getc(pf)) != EOF) 604 putc(c, active); 605 (void) fclose(pf); 606 return (1); 607 } 608 else 609 return (0); 610 } 611 #endif 612 613 /* 614 * dochq - change quote characters 615 */ 616 void 617 dochq(argv, argc) 618 register char *argv[]; 619 register int argc; 620 { 621 if (argc > 2) { 622 if (*argv[2]) 623 lquote = *argv[2]; 624 else 625 lquote = LQUOTE; 626 if (argc > 3) { 627 if (*argv[3]) 628 rquote = *argv[3]; 629 else 630 rquote = RQUOTE; 631 } 632 else 633 rquote = lquote; 634 } 635 else { 636 lquote = LQUOTE; 637 rquote = RQUOTE; 638 } 639 } 640 641 /* 642 * dochc - change comment characters 643 */ 644 void 645 dochc(argv, argc) 646 register char *argv[]; 647 register int argc; 648 { 649 if (argc > 2) { 650 if (*argv[2]) 651 scommt = *argv[2]; 652 if (argc > 3) { 653 if (*argv[3]) 654 ecommt = *argv[3]; 655 } 656 else 657 ecommt = ECOMMT; 658 } 659 else { 660 scommt = SCOMMT; 661 ecommt = ECOMMT; 662 } 663 } 664 665 /* 666 * dodivert - divert the output to a temporary file 667 */ 668 void 669 dodiv(n) 670 register int n; 671 { 672 oindex = n; 673 if (n < 0 || n >= MAXOUT) 674 n = 0; /* bitbucket */ 675 if (outfile[n] == NULL) { 676 m4temp[UNIQUE] = n + '0'; 677 if ((outfile[n] = fopen(m4temp, "w")) == NULL) 678 errx(1, "%s: cannot divert", m4temp); 679 } 680 active = outfile[n]; 681 } 682 683 /* 684 * doundivert - undivert a specified output, or all 685 * other outputs, in numerical order. 686 */ 687 void 688 doundiv(argv, argc) 689 register char *argv[]; 690 register int argc; 691 { 692 register int ind; 693 register int n; 694 695 if (argc > 2) { 696 for (ind = 2; ind < argc; ind++) { 697 n = atoi(argv[ind]); 698 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 699 getdiv(n); 700 701 } 702 } 703 else 704 for (n = 1; n < MAXOUT; n++) 705 if (outfile[n] != NULL) 706 getdiv(n); 707 } 708 709 /* 710 * dosub - select substring 711 */ 712 void 713 dosub(argv, argc) 714 register char *argv[]; 715 register int argc; 716 { 717 register unsigned char *ap, *fc, *k; 718 register int nc; 719 720 if (argc < 5) 721 nc = MAXTOK; 722 else 723 #ifdef EXPR 724 nc = expr(argv[4]); 725 #else 726 nc = atoi(argv[4]); 727 #endif 728 ap = argv[2]; /* target string */ 729 #ifdef EXPR 730 fc = ap + expr(argv[3]); /* first char */ 731 #else 732 fc = ap + atoi(argv[3]); /* first char */ 733 #endif 734 if (fc >= ap && fc < ap + strlen(ap)) 735 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 736 putback(*k); 737 } 738 739 /* 740 * map: 741 * map every character of s1 that is specified in from 742 * into s3 and replace in s. (source s1 remains untouched) 743 * 744 * This is a standard implementation of map(s,from,to) function of ICON 745 * language. Within mapvec, we replace every character of "from" with 746 * the corresponding character in "to". If "to" is shorter than "from", 747 * than the corresponding entries are null, which means that those 748 * characters dissapear altogether. Furthermore, imagine 749 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 750 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 751 * ultimately maps to `*'. In order to achieve this effect in an efficient 752 * manner (i.e. without multiple passes over the destination string), we 753 * loop over mapvec, starting with the initial source character. if the 754 * character value (dch) in this location is different than the source 755 * character (sch), sch becomes dch, once again to index into mapvec, until 756 * the character value stabilizes (i.e. sch = dch, in other words 757 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 758 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 759 * end, we restore mapvec* back to normal where mapvec[n] == n for 760 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 761 * about 5 times faster than any algorithm that makes multiple passes over 762 * destination string. 763 */ 764 void 765 map(dest, src, from, to) 766 register char *dest; 767 register char *src; 768 register char *from; 769 register char *to; 770 { 771 register char *tmp; 772 register char sch, dch; 773 static char mapvec[128] = { 774 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 775 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 776 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 777 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 778 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 779 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 780 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 781 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 782 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 783 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 784 120, 121, 122, 123, 124, 125, 126, 127 785 }; 786 787 if (*src) { 788 tmp = from; 789 /* 790 * create a mapping between "from" and 791 * "to" 792 */ 793 while (*from) 794 mapvec[*from++] = (*to) ? *to++ : (char) 0; 795 796 while (*src) { 797 sch = *src++; 798 dch = mapvec[sch]; 799 while (dch != sch) { 800 sch = dch; 801 dch = mapvec[sch]; 802 } 803 if (*dest = dch) 804 dest++; 805 } 806 /* 807 * restore all the changed characters 808 */ 809 while (*tmp) { 810 mapvec[*tmp] = *tmp; 811 tmp++; 812 } 813 } 814 *dest = (char) 0; 815 } 816