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