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