eval.c revision 24901
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 38static 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 77void 78eval(argv, argc, td) 79register char *argv[]; 80register int argc; 81register 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 375char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 376 377/* 378 * expand - user-defined macro expansion 379 */ 380void 381expand(argv, argc) 382register char *argv[]; 383register 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 case '@': 425 for( n = argc - 1; n >= 2; n-- ) 426 { 427 putback(rquote); 428 pbstr(argv[n]); 429 putback(lquote); 430 if( n > 2 ) 431 putback(','); 432 } 433 break; 434 default: 435 putback(*p); 436 putback('$'); 437 break; 438 } 439 p--; 440 } 441 p--; 442 } 443 if (p == t) /* do last character */ 444 putback(*p); 445} 446 447/* 448 * dodefine - install definition in the table 449 */ 450void 451dodefine(name, defn) 452register char *name; 453register char *defn; 454{ 455 register ndptr p; 456 457 if (!*name) 458 oops("null definition."); 459 if (STREQ(name, defn)) 460 oops("%s: recursive definition.", name); 461 if ((p = lookup(name)) == nil) 462 p = addent(name); 463 else if (p->defn != null) 464 free((char *) p->defn); 465 if (!*defn) 466 p->defn = null; 467 else 468 p->defn = xstrdup(defn); 469 p->type = MACRTYPE; 470} 471 472/* 473 * dodefn - push back a quoted definition of 474 * the given name. 475 */ 476void 477dodefn(name) 478char *name; 479{ 480 register ndptr p; 481 482 if ((p = lookup(name)) != nil && p->defn != null) { 483 putback(rquote); 484 pbstr(p->defn); 485 putback(lquote); 486 } 487} 488 489/* 490 * dopushdef - install a definition in the hash table 491 * without removing a previous definition. Since 492 * each new entry is entered in *front* of the 493 * hash bucket, it hides a previous definition from 494 * lookup. 495 */ 496void 497dopushdef(name, defn) 498register char *name; 499register char *defn; 500{ 501 register ndptr p; 502 503 if (!*name) 504 oops("null definition"); 505 if (STREQ(name, defn)) 506 oops("%s: recursive definition.", name); 507 p = addent(name); 508 if (!*defn) 509 p->defn = null; 510 else 511 p->defn = xstrdup(defn); 512 p->type = MACRTYPE; 513} 514 515/* 516 * dodumpdef - dump the specified definitions in the hash 517 * table to stderr. If nothing is specified, the entire 518 * hash table is dumped. 519 */ 520void 521dodump(argv, argc) 522register char *argv[]; 523register int argc; 524{ 525 register int n; 526 ndptr p; 527 528 if (argc > 2) { 529 for (n = 2; n < argc; n++) 530 if ((p = lookup(argv[n])) != nil) 531 fprintf(stderr, dumpfmt, p->name, 532 p->defn); 533 } 534 else { 535 for (n = 0; n < HASHSIZE; n++) 536 for (p = hashtab[n]; p != nil; p = p->nxtptr) 537 fprintf(stderr, dumpfmt, p->name, 538 p->defn); 539 } 540} 541 542/* 543 * doifelse - select one of two alternatives - loop. 544 */ 545void 546doifelse(argv, argc) 547register char *argv[]; 548register int argc; 549{ 550 cycle { 551 if (STREQ(argv[2], argv[3])) 552 pbstr(argv[4]); 553 else if (argc == 6) 554 pbstr(argv[5]); 555 else if (argc > 6) { 556 argv += 3; 557 argc -= 3; 558 continue; 559 } 560 break; 561 } 562} 563 564/* 565 * doinclude - include a given file. 566 */ 567int 568doincl(ifile) 569char *ifile; 570{ 571 if (ilevel + 1 == MAXINP) 572 oops("too many include files."); 573 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 574 ilevel++; 575 bbase[ilevel] = bufbase = bp; 576 return (1); 577 } 578 else 579 return (0); 580} 581 582#ifdef EXTENDED 583/* 584 * dopaste - include a given file without any 585 * macro processing. 586 */ 587int 588dopaste(pfile) 589char *pfile; 590{ 591 FILE *pf; 592 register int c; 593 594 if ((pf = fopen(pfile, "r")) != NULL) { 595 while ((c = getc(pf)) != EOF) 596 putc(c, active); 597 (void) fclose(pf); 598 return (1); 599 } 600 else 601 return (0); 602} 603#endif 604 605/* 606 * dochq - change quote characters 607 */ 608void 609dochq(argv, argc) 610register char *argv[]; 611register int argc; 612{ 613 if (argc > 2) { 614 if (*argv[2]) 615 lquote = *argv[2]; 616 if (argc > 3) { 617 if (*argv[3]) 618 rquote = *argv[3]; 619 } 620 else 621 rquote = lquote; 622 } 623 else { 624 lquote = LQUOTE; 625 rquote = RQUOTE; 626 } 627} 628 629/* 630 * dochc - change comment characters 631 */ 632void 633dochc(argv, argc) 634register char *argv[]; 635register int argc; 636{ 637 if (argc > 2) { 638 if (*argv[2]) 639 scommt = *argv[2]; 640 if (argc > 3) { 641 if (*argv[3]) 642 ecommt = *argv[3]; 643 } 644 else 645 ecommt = ECOMMT; 646 } 647 else { 648 scommt = SCOMMT; 649 ecommt = ECOMMT; 650 } 651} 652 653/* 654 * dodivert - divert the output to a temporary file 655 */ 656void 657dodiv(n) 658register int n; 659{ 660 if (n < 0 || n >= MAXOUT) 661 n = 0; /* bitbucket */ 662 if (outfile[n] == NULL) { 663 m4temp[UNIQUE] = n + '0'; 664 if ((outfile[n] = fopen(m4temp, "w")) == NULL) 665 oops("%s: cannot divert.", m4temp); 666 } 667 oindex = n; 668 active = outfile[n]; 669} 670 671/* 672 * doundivert - undivert a specified output, or all 673 * other outputs, in numerical order. 674 */ 675void 676doundiv(argv, argc) 677register char *argv[]; 678register int argc; 679{ 680 register int ind; 681 register int n; 682 683 if (argc > 2) { 684 for (ind = 2; ind < argc; ind++) { 685 n = atoi(argv[ind]); 686 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 687 getdiv(n); 688 689 } 690 } 691 else 692 for (n = 1; n < MAXOUT; n++) 693 if (outfile[n] != NULL) 694 getdiv(n); 695} 696 697/* 698 * dosub - select substring 699 */ 700void 701dosub(argv, argc) 702register char *argv[]; 703register int argc; 704{ 705 register unsigned char *ap, *fc, *k; 706 register int nc; 707 708 if (argc < 5) 709 nc = MAXTOK; 710 else 711#ifdef EXPR 712 nc = expr(argv[4]); 713#else 714 nc = atoi(argv[4]); 715#endif 716 ap = argv[2]; /* target string */ 717#ifdef EXPR 718 fc = ap + expr(argv[3]); /* first char */ 719#else 720 fc = ap + atoi(argv[3]); /* first char */ 721#endif 722 if (fc >= ap && fc < ap + strlen(ap)) 723 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 724 putback(*k); 725} 726 727/* 728 * map: 729 * map every character of s1 that is specified in from 730 * into s3 and replace in s. (source s1 remains untouched) 731 * 732 * This is a standard implementation of map(s,from,to) function of ICON 733 * language. Within mapvec, we replace every character of "from" with 734 * the corresponding character in "to". If "to" is shorter than "from", 735 * than the corresponding entries are null, which means that those 736 * characters dissapear altogether. Furthermore, imagine 737 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 738 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 739 * ultimately maps to `*'. In order to achieve this effect in an efficient 740 * manner (i.e. without multiple passes over the destination string), we 741 * loop over mapvec, starting with the initial source character. if the 742 * character value (dch) in this location is different than the source 743 * character (sch), sch becomes dch, once again to index into mapvec, until 744 * the character value stabilizes (i.e. sch = dch, in other words 745 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 746 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 747 * end, we restore mapvec* back to normal where mapvec[n] == n for 748 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 749 * about 5 times faster than any algorithm that makes multiple passes over 750 * destination string. 751 */ 752void 753map(dest, src, from, to) 754register char *dest; 755register char *src; 756register char *from; 757register char *to; 758{ 759 register char *tmp; 760 register char sch, dch; 761 static char mapvec[128] = { 762 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 763 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 764 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 765 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 766 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 767 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 768 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 769 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 770 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 771 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 772 120, 121, 122, 123, 124, 125, 126, 127 773 }; 774 775 if (*src) { 776 tmp = from; 777 /* 778 * create a mapping between "from" and 779 * "to" 780 */ 781 while (*from) 782 mapvec[*from++] = (*to) ? *to++ : (char) 0; 783 784 while (*src) { 785 sch = *src++; 786 dch = mapvec[sch]; 787 while (dch != sch) { 788 sch = dch; 789 dch = mapvec[sch]; 790 } 791 if (*dest = dch) 792 dest++; 793 } 794 /* 795 * restore all the changed characters 796 */ 797 while (*tmp) { 798 mapvec[*tmp] = *tmp; 799 tmp++; 800 } 801 } 802 *dest = (char) 0; 803} 804