1 /* $NetBSD: eval.c,v 1.5 1996/01/13 23:25:23 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.5 1996/01/13 23:25:23 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(','); 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(','); 433 } 434 pbstr(argv[2]); 435 break; 436 default: 437 putback(*p); 438 putback('$'); 439 break; 440 } 441 p--; 442 } 443 p--; 444 } 445 if (p == t) /* do last character */ 446 putback(*p); 447 } 448 449 /* 450 * dodefine - install definition in the table 451 */ 452 void 453 dodefine(name, defn) 454 register char *name; 455 register char *defn; 456 { 457 register ndptr p; 458 459 if (!*name) 460 oops("null definition."); 461 if (STREQ(name, defn)) 462 oops("%s: recursive definition.", name); 463 if ((p = lookup(name)) == nil) 464 p = addent(name); 465 else if (p->defn != null) 466 free((char *) p->defn); 467 if (!*defn) 468 p->defn = null; 469 else 470 p->defn = xstrdup(defn); 471 p->type = MACRTYPE; 472 } 473 474 /* 475 * dodefn - push back a quoted definition of 476 * the given name. 477 */ 478 void 479 dodefn(name) 480 char *name; 481 { 482 register ndptr p; 483 484 if ((p = lookup(name)) != nil && p->defn != null) { 485 int n = strlen(rquote); 486 while (n--) 487 putback(rquote[n]); 488 pbstr(p->defn); 489 n = strlen(lquote); 490 while (n--) 491 putback(lquote[n]); 492 } 493 } 494 495 /* 496 * dopushdef - install a definition in the hash table 497 * without removing a previous definition. Since 498 * each new entry is entered in *front* of the 499 * hash bucket, it hides a previous definition from 500 * lookup. 501 */ 502 void 503 dopushdef(name, defn) 504 register char *name; 505 register char *defn; 506 { 507 register ndptr p; 508 509 if (!*name) 510 oops("null definition"); 511 if (STREQ(name, defn)) 512 oops("%s: recursive definition.", name); 513 p = addent(name); 514 if (!*defn) 515 p->defn = null; 516 else 517 p->defn = xstrdup(defn); 518 p->type = MACRTYPE; 519 } 520 521 /* 522 * dodumpdef - dump the specified definitions in the hash 523 * table to stderr. If nothing is specified, the entire 524 * hash table is dumped. 525 */ 526 void 527 dodump(argv, argc) 528 register char *argv[]; 529 register int argc; 530 { 531 register int n; 532 ndptr p; 533 534 if (argc > 2) { 535 for (n = 2; n < argc; n++) 536 if ((p = lookup(argv[n])) != nil) 537 fprintf(stderr, dumpfmt, p->name, 538 p->defn); 539 } 540 else { 541 for (n = 0; n < HASHSIZE; n++) 542 for (p = hashtab[n]; p != nil; p = p->nxtptr) 543 fprintf(stderr, dumpfmt, p->name, 544 p->defn); 545 } 546 } 547 548 /* 549 * doifelse - select one of two alternatives - loop. 550 */ 551 void 552 doifelse(argv, argc) 553 register char *argv[]; 554 register int argc; 555 { 556 cycle { 557 if (STREQ(argv[2], argv[3])) 558 pbstr(argv[4]); 559 else if (argc == 6) 560 pbstr(argv[5]); 561 else if (argc > 6) { 562 argv += 3; 563 argc -= 3; 564 continue; 565 } 566 break; 567 } 568 } 569 570 /* 571 * doinclude - include a given file. 572 */ 573 int 574 doincl(ifile) 575 char *ifile; 576 { 577 if (ilevel + 1 == MAXINP) 578 oops("too many include files."); 579 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 580 ilevel++; 581 bbase[ilevel] = bufbase = bp; 582 return (1); 583 } 584 else 585 return (0); 586 } 587 588 #ifdef EXTENDED 589 /* 590 * dopaste - include a given file without any 591 * macro processing. 592 */ 593 int 594 dopaste(pfile) 595 char *pfile; 596 { 597 FILE *pf; 598 register int c; 599 600 if ((pf = fopen(pfile, "r")) != NULL) { 601 while ((c = getc(pf)) != EOF) 602 putc(c, active); 603 (void) fclose(pf); 604 return (1); 605 } 606 else 607 return (0); 608 } 609 #endif 610 611 /* 612 * dochq - change quote characters 613 */ 614 void 615 dochq(argv, argc) 616 register char *argv[]; 617 register int argc; 618 { 619 if (argc > 2) { 620 if (*argv[2]) 621 strncpy(lquote, argv[2], MAXCCHARS); 622 if (argc > 3) { 623 if (*argv[3]) 624 strncpy(rquote, argv[3], MAXCCHARS); 625 } 626 else 627 strcpy(rquote, lquote); 628 } 629 else { 630 lquote[0] = LQUOTE, lquote[1] = '\0'; 631 rquote[0] = RQUOTE, rquote[1] = '\0'; 632 } 633 } 634 635 /* 636 * dochc - change comment characters 637 */ 638 void 639 dochc(argv, argc) 640 register char *argv[]; 641 register int argc; 642 { 643 if (argc > 2) { 644 if (*argv[2]) 645 strncpy(scommt, argv[2], MAXCCHARS); 646 if (argc > 3) { 647 if (*argv[3]) 648 strncpy(ecommt, argv[3], MAXCCHARS); 649 } 650 else 651 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 652 } 653 else { 654 scommt[0] = SCOMMT, scommt[1] = '\0'; 655 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 656 } 657 } 658 659 /* 660 * dodivert - divert the output to a temporary file 661 */ 662 void 663 dodiv(n) 664 register int n; 665 { 666 if (n < 0 || n >= MAXOUT) 667 n = 0; /* bitbucket */ 668 if (outfile[n] == NULL) { 669 m4temp[UNIQUE] = n + '0'; 670 if ((outfile[n] = fopen(m4temp, "w")) == NULL) 671 oops("%s: cannot divert.", m4temp); 672 } 673 oindex = n; 674 active = outfile[n]; 675 } 676 677 /* 678 * doundivert - undivert a specified output, or all 679 * other outputs, in numerical order. 680 */ 681 void 682 doundiv(argv, argc) 683 register char *argv[]; 684 register int argc; 685 { 686 register int ind; 687 register int n; 688 689 if (argc > 2) { 690 for (ind = 2; ind < argc; ind++) { 691 n = atoi(argv[ind]); 692 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 693 getdiv(n); 694 695 } 696 } 697 else 698 for (n = 1; n < MAXOUT; n++) 699 if (outfile[n] != NULL) 700 getdiv(n); 701 } 702 703 /* 704 * dosub - select substring 705 */ 706 void 707 dosub(argv, argc) 708 register char *argv[]; 709 register int argc; 710 { 711 register char *ap, *fc, *k; 712 register int nc; 713 714 if (argc < 5) 715 nc = MAXTOK; 716 else 717 #ifdef EXPR 718 nc = expr(argv[4]); 719 #else 720 nc = atoi(argv[4]); 721 #endif 722 ap = argv[2]; /* target string */ 723 #ifdef EXPR 724 fc = ap + expr(argv[3]); /* first char */ 725 #else 726 fc = ap + atoi(argv[3]); /* first char */ 727 #endif 728 if (fc >= ap && fc < ap + strlen(ap)) 729 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 730 putback(*k); 731 } 732 733 /* 734 * map: 735 * map every character of s1 that is specified in from 736 * into s3 and replace in s. (source s1 remains untouched) 737 * 738 * This is a standard implementation of map(s,from,to) function of ICON 739 * language. Within mapvec, we replace every character of "from" with 740 * the corresponding character in "to". If "to" is shorter than "from", 741 * than the corresponding entries are null, which means that those 742 * characters dissapear altogether. Furthermore, imagine 743 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 744 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 745 * ultimately maps to `*'. In order to achieve this effect in an efficient 746 * manner (i.e. without multiple passes over the destination string), we 747 * loop over mapvec, starting with the initial source character. if the 748 * character value (dch) in this location is different than the source 749 * character (sch), sch becomes dch, once again to index into mapvec, until 750 * the character value stabilizes (i.e. sch = dch, in other words 751 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 752 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 753 * end, we restore mapvec* back to normal where mapvec[n] == n for 754 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 755 * about 5 times faster than any algorithm that makes multiple passes over 756 * destination string. 757 */ 758 void 759 map(dest, src, from, to) 760 register char *dest; 761 register char *src; 762 register char *from; 763 register char *to; 764 { 765 register char *tmp; 766 register char sch, dch; 767 static char mapvec[128] = { 768 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 769 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 770 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 771 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 772 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 773 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 774 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 775 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 776 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 777 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 778 120, 121, 122, 123, 124, 125, 126, 127 779 }; 780 781 if (*src) { 782 tmp = from; 783 /* 784 * create a mapping between "from" and 785 * "to" 786 */ 787 while (*from) 788 mapvec[*from++] = (*to) ? *to++ : (char) 0; 789 790 while (*src) { 791 sch = *src++; 792 dch = mapvec[sch]; 793 while (dch != sch) { 794 sch = dch; 795 dch = mapvec[sch]; 796 } 797 if (*dest = dch) 798 dest++; 799 } 800 /* 801 * restore all the changed characters 802 */ 803 while (*tmp) { 804 mapvec[*tmp] = *tmp; 805 tmp++; 806 } 807 } 808 *dest = (char) 0; 809 } 810