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