1 /* $NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg 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 #include <sys/cdefs.h> 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 43 #else 44 __RCSID("$NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 /* 49 * eval.c 50 * Facility: m4 macro processor 51 * by: oz 52 */ 53 54 #include <sys/types.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <unistd.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include "mdef.h" 62 #include "stdd.h" 63 #include "extern.h" 64 #include "pathnames.h" 65 66 /* 67 * eval - evaluate built-in macros. 68 * argc - number of elements in argv. 69 * argv - element vector : 70 * argv[0] = definition of a user 71 * macro or nil if built-in. 72 * argv[1] = name of the macro or 73 * built-in. 74 * argv[2] = parameters to user-defined 75 * . macro or built-in. 76 * . 77 * 78 * Note that the minimum value for argc is 3. A call in the form 79 * of macro-or-builtin() will result in: 80 * argv[0] = nullstr 81 * argv[1] = macro-or-builtin 82 * argv[2] = nullstr 83 */ 84 85 void 86 eval(argv, argc, td) 87 char *argv[]; 88 int argc; 89 int td; 90 { 91 int c, n; 92 static int sysval = 0; 93 94 #ifdef DEBUG 95 printf("argc = %d\n", argc); 96 for (n = 0; n < argc; n++) 97 printf("argv[%d] = %s\n", n, argv[n]); 98 #endif 99 /* 100 * if argc == 3 and argv[2] is null, then we 101 * have macro-or-builtin() type call. We adjust 102 * argc to avoid further checking.. 103 */ 104 if (argc == 3 && !*(argv[2])) 105 argc--; 106 107 switch (td & ~STATIC) { 108 109 case DEFITYPE: 110 if (argc > 2) 111 dodefine(argv[2], (argc > 3) ? argv[3] : null); 112 break; 113 114 case PUSDTYPE: 115 if (argc > 2) 116 dopushdef(argv[2], (argc > 3) ? argv[3] : null); 117 break; 118 119 case DUMPTYPE: 120 dodump(argv, argc); 121 break; 122 123 case EXPRTYPE: 124 /* 125 * doexpr - evaluate arithmetic 126 * expression 127 */ 128 if (argc > 2) 129 pbnum(expr(argv[2])); 130 break; 131 132 case IFELTYPE: 133 if (argc > 4) 134 doifelse(argv, argc); 135 break; 136 137 case IFDFTYPE: 138 /* 139 * doifdef - select one of two 140 * alternatives based on the existence of 141 * another definition 142 */ 143 if (argc > 3) { 144 if (lookup(argv[2]) != nil) 145 pbstr(argv[3]); 146 else if (argc > 4) 147 pbstr(argv[4]); 148 } 149 break; 150 151 case LENGTYPE: 152 /* 153 * dolen - find the length of the 154 * argument 155 */ 156 if (argc > 2) 157 pbnum((argc > 2) ? strlen(argv[2]) : 0); 158 break; 159 160 case INCRTYPE: 161 /* 162 * doincr - increment the value of the 163 * argument 164 */ 165 if (argc > 2) 166 pbnum(atoi(argv[2]) + 1); 167 break; 168 169 case DECRTYPE: 170 /* 171 * dodecr - decrement the value of the 172 * argument 173 */ 174 if (argc > 2) 175 pbnum(atoi(argv[2]) - 1); 176 break; 177 178 case SYSCTYPE: 179 /* 180 * dosys - execute system command 181 */ 182 if (argc > 2) 183 sysval = system(argv[2]); 184 break; 185 186 case SYSVTYPE: 187 /* 188 * dosysval - return value of the last 189 * system call. 190 * 191 */ 192 pbnum(sysval); 193 break; 194 195 case INCLTYPE: 196 if (argc > 2) 197 if (!doincl(argv[2])) 198 err(1, "%s", argv[2]); 199 break; 200 201 case SINCTYPE: 202 if (argc > 2) 203 (void) doincl(argv[2]); 204 break; 205 #ifdef EXTENDED 206 case PASTTYPE: 207 if (argc > 2) 208 if (!dopaste(argv[2])) 209 err(1, "%s", argv[2]); 210 break; 211 212 case SPASTYPE: 213 if (argc > 2) 214 (void) dopaste(argv[2]); 215 break; 216 #endif 217 case CHNQTYPE: 218 dochq(argv, argc); 219 break; 220 221 case CHNCTYPE: 222 dochc(argv, argc); 223 break; 224 225 case SUBSTYPE: 226 /* 227 * dosub - select substring 228 * 229 */ 230 if (argc > 3) 231 dosub(argv, argc); 232 break; 233 234 case SHIFTYPE: 235 /* 236 * doshift - push back all arguments 237 * except the first one (i.e. skip 238 * argv[2]) 239 */ 240 if (argc > 3) { 241 for (n = argc - 1; n > 3; n--) { 242 pbstr(rquote); 243 pbstr(argv[n]); 244 pbstr(lquote); 245 putback(COMMA); 246 } 247 pbstr(rquote); 248 pbstr(argv[3]); 249 pbstr(lquote); 250 } 251 break; 252 253 case DIVRTYPE: 254 if (argc > 2 && (n = atoi(argv[2])) != 0) 255 dodiv(n); 256 else { 257 active = stdout; 258 oindex = 0; 259 } 260 break; 261 262 case UNDVTYPE: 263 doundiv(argv, argc); 264 break; 265 266 case DIVNTYPE: 267 /* 268 * dodivnum - return the number of 269 * current output diversion 270 */ 271 pbnum(oindex); 272 break; 273 274 case UNDFTYPE: 275 /* 276 * doundefine - undefine a previously 277 * defined macro(s) or m4 keyword(s). 278 */ 279 if (argc > 2) 280 for (n = 2; n < argc; n++) 281 remhash(argv[n], ALL); 282 break; 283 284 case POPDTYPE: 285 /* 286 * dopopdef - remove the topmost 287 * definitions of macro(s) or m4 288 * keyword(s). 289 */ 290 if (argc > 2) 291 for (n = 2; n < argc; n++) 292 remhash(argv[n], TOP); 293 break; 294 295 case MKTMTYPE: 296 /* 297 * dotemp - create a temporary file 298 */ 299 if (argc > 2) { 300 int fd; 301 302 fd = mkstemp(argv[2]); 303 if (fd == -1) 304 err(1, "mkstemp failed"); 305 close(fd); 306 pbstr(argv[2]); 307 } 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 errx(1, "eval: major botch"); 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 char *argv[]; 395 int argc; 396 { 397 char *t; 398 char *p; 399 int n; 400 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 char *name; 466 char *defn; 467 { 468 ndptr p; 469 470 if (!*name) 471 errx(1, "null definition"); 472 if (STREQ(name, defn)) 473 errx(1, "%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 ndptr p; 494 495 if ((p = lookup(name)) != nil && p->defn != null) { 496 pbstr(rquote); 497 pbstr(p->defn); 498 pbstr(lquote); 499 } 500 } 501 502 /* 503 * dopushdef - install a definition in the hash table 504 * without removing a previous definition. Since 505 * each new entry is entered in *front* of the 506 * hash bucket, it hides a previous definition from 507 * lookup. 508 */ 509 void 510 dopushdef(name, defn) 511 char *name; 512 char *defn; 513 { 514 ndptr p; 515 516 if (!*name) 517 errx(1, "null definition"); 518 if (STREQ(name, defn)) 519 errx(1, "%s: recursive definition", name); 520 p = addent(name); 521 if (!*defn) 522 p->defn = null; 523 else 524 p->defn = xstrdup(defn); 525 p->type = MACRTYPE; 526 } 527 528 /* 529 * dodumpdef - dump the specified definitions in the hash 530 * table to stderr. If nothing is specified, the entire 531 * hash table is dumped. 532 */ 533 void 534 dodump(argv, argc) 535 char *argv[]; 536 int argc; 537 { 538 int n; 539 ndptr p; 540 541 if (argc > 2) { 542 for (n = 2; n < argc; n++) 543 if ((p = lookup(argv[n])) != nil) 544 fprintf(stderr, dumpfmt, p->name, 545 p->defn); 546 } 547 else { 548 for (n = 0; n < HASHSIZE; n++) 549 for (p = hashtab[n]; p != nil; p = p->nxtptr) 550 fprintf(stderr, dumpfmt, p->name, 551 p->defn); 552 } 553 } 554 555 /* 556 * doifelse - select one of two alternatives - loop. 557 */ 558 void 559 doifelse(argv, argc) 560 char *argv[]; 561 int argc; 562 { 563 cycle { 564 if (STREQ(argv[2], argv[3])) 565 pbstr(argv[4]); 566 else if (argc == 6) 567 pbstr(argv[5]); 568 else if (argc > 6) { 569 argv += 3; 570 argc -= 3; 571 continue; 572 } 573 break; 574 } 575 } 576 577 /* 578 * doinclude - include a given file. 579 */ 580 int 581 doincl(ifile) 582 char *ifile; 583 { 584 if (ilevel + 1 == MAXINP) 585 errx(1, "too many include files"); 586 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 587 ilevel++; 588 bbase[ilevel] = bufbase = bp; 589 return (1); 590 } 591 else 592 return (0); 593 } 594 595 #ifdef EXTENDED 596 /* 597 * dopaste - include a given file without any 598 * macro processing. 599 */ 600 int 601 dopaste(pfile) 602 char *pfile; 603 { 604 FILE *pf; 605 int c; 606 607 if ((pf = fopen(pfile, "r")) != NULL) { 608 while ((c = getc(pf)) != EOF) 609 putc(c, active); 610 (void) fclose(pf); 611 return (1); 612 } 613 else 614 return (0); 615 } 616 #endif 617 618 /* 619 * dochq - change quote characters 620 */ 621 void 622 dochq(argv, argc) 623 char *argv[]; 624 int argc; 625 { 626 if (argc > 2) { 627 if (*argv[2]) 628 strncpy(lquote, argv[2], MAXCCHARS); 629 if (argc > 3) { 630 if (*argv[3]) 631 strncpy(rquote, argv[3], MAXCCHARS); 632 } 633 else 634 strcpy(rquote, lquote); 635 } 636 else { 637 lquote[0] = LQUOTE, lquote[1] = '\0'; 638 rquote[0] = RQUOTE, rquote[1] = '\0'; 639 } 640 } 641 642 /* 643 * dochc - change comment characters 644 */ 645 void 646 dochc(argv, argc) 647 char *argv[]; 648 int argc; 649 { 650 if (argc > 2) { 651 if (*argv[2]) 652 strncpy(scommt, argv[2], MAXCCHARS); 653 if (argc > 3) { 654 if (*argv[3]) 655 strncpy(ecommt, argv[3], MAXCCHARS); 656 } 657 else 658 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 659 } 660 else { 661 scommt[0] = SCOMMT, scommt[1] = '\0'; 662 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 663 } 664 } 665 666 /* 667 * dodivert - divert the output to a temporary file 668 */ 669 void 670 dodiv(n) 671 int n; 672 { 673 int tempfilenum; 674 675 /* 676 * direct output to the appropriate temporary file (the bit 677 * bucket, if out of range). 678 */ 679 tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n; 680 681 if (outfile[tempfilenum] == NULL) { 682 m4temp[UNIQUE] = tempfilenum + '0'; 683 if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL) 684 err(1, "%s: cannot divert", m4temp); 685 } 686 oindex = n; 687 active = outfile[tempfilenum]; 688 } 689 690 /* 691 * doundivert - undivert a specified output, or all 692 * other outputs, in numerical order. 693 */ 694 void 695 doundiv(argv, argc) 696 char *argv[]; 697 int argc; 698 { 699 int ind; 700 int n; 701 702 if (argc > 2) { 703 for (ind = 2; ind < argc; ind++) { 704 n = atoi(argv[ind]); 705 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 706 getdiv(n); 707 708 } 709 } 710 else 711 for (n = 1; n < MAXOUT; n++) 712 if (outfile[n] != NULL) 713 getdiv(n); 714 } 715 716 /* 717 * dosub - select substring 718 */ 719 void 720 dosub(argv, argc) 721 char *argv[]; 722 int argc; 723 { 724 char *ap, *fc, *k; 725 int nc; 726 727 if (argc < 5) 728 nc = MAXTOK; 729 else 730 #ifdef EXPR 731 nc = expr(argv[4]); 732 #else 733 nc = atoi(argv[4]); 734 #endif 735 ap = argv[2]; /* target string */ 736 #ifdef EXPR 737 fc = ap + expr(argv[3]); /* first char */ 738 #else 739 fc = ap + atoi(argv[3]); /* first char */ 740 #endif 741 if (fc >= ap && fc < ap + strlen(ap)) 742 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 743 putback(*k); 744 } 745 746 /* 747 * map: 748 * map every character of s1 that is specified in from 749 * into s3 and replace in s. (source s1 remains untouched) 750 * 751 * This is a standard implementation of map(s,from,to) function of ICON 752 * language. Within mapvec, we replace every character of "from" with 753 * the corresponding character in "to". If "to" is shorter than "from", 754 * than the corresponding entries are null, which means that those 755 * characters dissapear altogether. Furthermore, imagine 756 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 757 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 758 * ultimately maps to `*'. In order to achieve this effect in an efficient 759 * manner (i.e. without multiple passes over the destination string), we 760 * loop over mapvec, starting with the initial source character. if the 761 * character value (dch) in this location is different than the source 762 * character (sch), sch becomes dch, once again to index into mapvec, until 763 * the character value stabilizes (i.e. sch = dch, in other words 764 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 765 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 766 * end, we restore mapvec* back to normal where mapvec[n] == n for 767 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 768 * about 5 times faster than any algorithm that makes multiple passes over 769 * destination string. 770 */ 771 void 772 map(dest, src, from, to) 773 char *dest; 774 char *src; 775 char *from; 776 char *to; 777 { 778 char *tmp; 779 char sch, dch; 780 static char mapvec[128] = { 781 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 782 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 783 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 784 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 785 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 786 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 787 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 788 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 789 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 790 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 791 120, 121, 122, 123, 124, 125, 126, 127 792 }; 793 794 if (*src) { 795 tmp = from; 796 /* 797 * create a mapping between "from" and 798 * "to" 799 */ 800 while (*from) 801 mapvec[(int)*from++] = (*to) ? *to++ : (char) 0; 802 803 while (*src) { 804 sch = *src++; 805 dch = mapvec[(int)sch]; 806 while (dch != sch) { 807 sch = dch; 808 dch = mapvec[(int)sch]; 809 } 810 if ((*dest = dch) != 0) 811 dest++; 812 } 813 /* 814 * restore all the changed characters 815 */ 816 while (*tmp) { 817 mapvec[(int)*tmp] = *tmp; 818 tmp++; 819 } 820 } 821 *dest = (char) 0; 822 } 823