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