1 /* $NetBSD: eval.c,v 1.9 1997/02/08 23:50:40 cgd 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.9 1997/02/08 23:50:40 cgd 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 pbstr(rquote); 242 pbstr(argv[n]); 243 pbstr(lquote); 244 putback(COMMA); 245 } 246 pbstr(rquote); 247 pbstr(argv[3]); 248 pbstr(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[MAXTOK]; 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 default: 374 oops("%s: major botch.", "eval"); 375 break; 376 } 377 } 378 379 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 380 381 /* 382 * expand - user-defined macro expansion 383 */ 384 void 385 expand(argv, argc) 386 register char *argv[]; 387 register int argc; 388 { 389 register char *t; 390 register char *p; 391 register int n; 392 register int argno; 393 394 t = argv[0]; /* defn string as a whole */ 395 p = t; 396 while (*p) 397 p++; 398 p--; /* last character of defn */ 399 while (p > t) { 400 if (*(p - 1) != ARGFLAG) 401 putback(*p); 402 else { 403 switch (*p) { 404 405 case '#': 406 pbnum(argc - 2); 407 break; 408 case '0': 409 case '1': 410 case '2': 411 case '3': 412 case '4': 413 case '5': 414 case '6': 415 case '7': 416 case '8': 417 case '9': 418 if ((argno = *p - '0') < argc - 1) 419 pbstr(argv[argno + 1]); 420 break; 421 case '*': 422 for (n = argc - 1; n > 2; n--) { 423 pbstr(argv[n]); 424 putback(COMMA); 425 } 426 pbstr(argv[2]); 427 break; 428 case '@': 429 for (n = argc - 1; n > 2; n--) { 430 pbstr(rquote); 431 pbstr(argv[n]); 432 pbstr(lquote); 433 putback(COMMA); 434 } 435 pbstr(rquote); 436 pbstr(argv[2]); 437 pbstr(lquote); 438 break; 439 default: 440 putback(*p); 441 putback('$'); 442 break; 443 } 444 p--; 445 } 446 p--; 447 } 448 if (p == t) /* do last character */ 449 putback(*p); 450 } 451 452 /* 453 * dodefine - install definition in the table 454 */ 455 void 456 dodefine(name, defn) 457 register char *name; 458 register char *defn; 459 { 460 register ndptr p; 461 462 if (!*name) 463 oops("null definition."); 464 if (STREQ(name, defn)) 465 oops("%s: recursive definition.", name); 466 if ((p = lookup(name)) == nil) 467 p = addent(name); 468 else if (p->defn != null) 469 free((char *) p->defn); 470 if (!*defn) 471 p->defn = null; 472 else 473 p->defn = xstrdup(defn); 474 p->type = MACRTYPE; 475 } 476 477 /* 478 * dodefn - push back a quoted definition of 479 * the given name. 480 */ 481 void 482 dodefn(name) 483 char *name; 484 { 485 register ndptr p; 486 487 if ((p = lookup(name)) != nil && p->defn != null) { 488 pbstr(rquote); 489 pbstr(p->defn); 490 pbstr(lquote); 491 } 492 } 493 494 /* 495 * dopushdef - install a definition in the hash table 496 * without removing a previous definition. Since 497 * each new entry is entered in *front* of the 498 * hash bucket, it hides a previous definition from 499 * lookup. 500 */ 501 void 502 dopushdef(name, defn) 503 register char *name; 504 register char *defn; 505 { 506 register ndptr p; 507 508 if (!*name) 509 oops("null definition"); 510 if (STREQ(name, defn)) 511 oops("%s: recursive definition.", name); 512 p = addent(name); 513 if (!*defn) 514 p->defn = null; 515 else 516 p->defn = xstrdup(defn); 517 p->type = MACRTYPE; 518 } 519 520 /* 521 * dodumpdef - dump the specified definitions in the hash 522 * table to stderr. If nothing is specified, the entire 523 * hash table is dumped. 524 */ 525 void 526 dodump(argv, argc) 527 register char *argv[]; 528 register int argc; 529 { 530 register int n; 531 ndptr p; 532 533 if (argc > 2) { 534 for (n = 2; n < argc; n++) 535 if ((p = lookup(argv[n])) != nil) 536 fprintf(stderr, dumpfmt, p->name, 537 p->defn); 538 } 539 else { 540 for (n = 0; n < HASHSIZE; n++) 541 for (p = hashtab[n]; p != nil; p = p->nxtptr) 542 fprintf(stderr, dumpfmt, p->name, 543 p->defn); 544 } 545 } 546 547 /* 548 * doifelse - select one of two alternatives - loop. 549 */ 550 void 551 doifelse(argv, argc) 552 register char *argv[]; 553 register int argc; 554 { 555 cycle { 556 if (STREQ(argv[2], argv[3])) 557 pbstr(argv[4]); 558 else if (argc == 6) 559 pbstr(argv[5]); 560 else if (argc > 6) { 561 argv += 3; 562 argc -= 3; 563 continue; 564 } 565 break; 566 } 567 } 568 569 /* 570 * doinclude - include a given file. 571 */ 572 int 573 doincl(ifile) 574 char *ifile; 575 { 576 if (ilevel + 1 == MAXINP) 577 oops("too many include files."); 578 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 579 ilevel++; 580 bbase[ilevel] = bufbase = bp; 581 return (1); 582 } 583 else 584 return (0); 585 } 586 587 #ifdef EXTENDED 588 /* 589 * dopaste - include a given file without any 590 * macro processing. 591 */ 592 int 593 dopaste(pfile) 594 char *pfile; 595 { 596 FILE *pf; 597 register int c; 598 599 if ((pf = fopen(pfile, "r")) != NULL) { 600 while ((c = getc(pf)) != EOF) 601 putc(c, active); 602 (void) fclose(pf); 603 return (1); 604 } 605 else 606 return (0); 607 } 608 #endif 609 610 /* 611 * dochq - change quote characters 612 */ 613 void 614 dochq(argv, argc) 615 register char *argv[]; 616 register int argc; 617 { 618 if (argc > 2) { 619 if (*argv[2]) 620 strncpy(lquote, argv[2], MAXCCHARS); 621 if (argc > 3) { 622 if (*argv[3]) 623 strncpy(rquote, argv[3], MAXCCHARS); 624 } 625 else 626 strcpy(rquote, lquote); 627 } 628 else { 629 lquote[0] = LQUOTE, lquote[1] = '\0'; 630 rquote[0] = RQUOTE, rquote[1] = '\0'; 631 } 632 } 633 634 /* 635 * dochc - change comment characters 636 */ 637 void 638 dochc(argv, argc) 639 register char *argv[]; 640 register int argc; 641 { 642 if (argc > 2) { 643 if (*argv[2]) 644 strncpy(scommt, argv[2], MAXCCHARS); 645 if (argc > 3) { 646 if (*argv[3]) 647 strncpy(ecommt, argv[3], MAXCCHARS); 648 } 649 else 650 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 651 } 652 else { 653 scommt[0] = SCOMMT, scommt[1] = '\0'; 654 ecommt[0] = ECOMMT, ecommt[1] = '\0'; 655 } 656 } 657 658 /* 659 * dodivert - divert the output to a temporary file 660 */ 661 void 662 dodiv(n) 663 register int n; 664 { 665 int tempfilenum; 666 667 /* 668 * direct output to the appropriate temporary file (the bit 669 * bucket, if out of range). 670 */ 671 tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n; 672 673 if (outfile[tempfilenum] == NULL) { 674 m4temp[UNIQUE] = tempfilenum + '0'; 675 if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL) 676 oops("%s: cannot divert.", m4temp); 677 } 678 oindex = n; 679 active = outfile[tempfilenum]; 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 char *ap, *fc, *k; 717 register int nc; 718 719 if (argc < 5) 720 nc = MAXTOK; 721 else 722 #ifdef EXPR 723 nc = expr(argv[4]); 724 #else 725 nc = atoi(argv[4]); 726 #endif 727 ap = argv[2]; /* target string */ 728 #ifdef EXPR 729 fc = ap + expr(argv[3]); /* first char */ 730 #else 731 fc = ap + atoi(argv[3]); /* first char */ 732 #endif 733 if (fc >= ap && fc < ap + strlen(ap)) 734 for (k = fc + min(nc, strlen(fc)) - 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