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