eval.c revision 27625
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 39static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; 40#endif 41static const char rcsid[] = 42 "$Id$"; 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 81void 82eval(argv, argc, td) 83register char *argv[]; 84register int argc; 85register 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[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 errx(1, "eval: major botch"); 375 break; 376 } 377} 378 379char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 380 381/* 382 * expand - user-defined macro expansion 383 */ 384void 385expand(argv, argc) 386register char *argv[]; 387register 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 */ 454void 455dodefine(name, defn) 456register char *name; 457register 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 */ 480void 481dodefn(name) 482char *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 */ 500void 501dopushdef(name, defn) 502register char *name; 503register 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 */ 524void 525dodump(argv, argc) 526register char *argv[]; 527register 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 */ 549void 550doifelse(argv, argc) 551register char *argv[]; 552register 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 */ 571int 572doincl(ifile) 573char *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 */ 591int 592dopaste(pfile) 593char *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 */ 612void 613dochq(argv, argc) 614register char *argv[]; 615register int argc; 616{ 617 if (argc > 2) { 618 if (*argv[2]) 619 lquote = *argv[2]; 620 if (argc > 3) { 621 if (*argv[3]) 622 rquote = *argv[3]; 623 } 624 else 625 rquote = lquote; 626 } 627 else { 628 lquote = LQUOTE; 629 rquote = RQUOTE; 630 } 631} 632 633/* 634 * dochc - change comment characters 635 */ 636void 637dochc(argv, argc) 638register char *argv[]; 639register int argc; 640{ 641 if (argc > 2) { 642 if (*argv[2]) 643 scommt = *argv[2]; 644 if (argc > 3) { 645 if (*argv[3]) 646 ecommt = *argv[3]; 647 } 648 else 649 ecommt = ECOMMT; 650 } 651 else { 652 scommt = SCOMMT; 653 ecommt = ECOMMT; 654 } 655} 656 657/* 658 * dodivert - divert the output to a temporary file 659 */ 660void 661dodiv(n) 662register int n; 663{ 664 if (n < 0 || n >= MAXOUT) 665 n = 0; /* bitbucket */ 666 if (outfile[n] == NULL) { 667 m4temp[UNIQUE] = n + '0'; 668 if ((outfile[n] = fopen(m4temp, "w")) == NULL) 669 errx(1, "%s: cannot divert", m4temp); 670 } 671 oindex = n; 672 active = outfile[n]; 673} 674 675/* 676 * doundivert - undivert a specified output, or all 677 * other outputs, in numerical order. 678 */ 679void 680doundiv(argv, argc) 681register char *argv[]; 682register int argc; 683{ 684 register int ind; 685 register int n; 686 687 if (argc > 2) { 688 for (ind = 2; ind < argc; ind++) { 689 n = atoi(argv[ind]); 690 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 691 getdiv(n); 692 693 } 694 } 695 else 696 for (n = 1; n < MAXOUT; n++) 697 if (outfile[n] != NULL) 698 getdiv(n); 699} 700 701/* 702 * dosub - select substring 703 */ 704void 705dosub(argv, argc) 706register char *argv[]; 707register int argc; 708{ 709 register unsigned char *ap, *fc, *k; 710 register int nc; 711 712 if (argc < 5) 713 nc = MAXTOK; 714 else 715#ifdef EXPR 716 nc = expr(argv[4]); 717#else 718 nc = atoi(argv[4]); 719#endif 720 ap = argv[2]; /* target string */ 721#ifdef EXPR 722 fc = ap + expr(argv[3]); /* first char */ 723#else 724 fc = ap + atoi(argv[3]); /* first char */ 725#endif 726 if (fc >= ap && fc < ap + strlen(ap)) 727 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 728 putback(*k); 729} 730 731/* 732 * map: 733 * map every character of s1 that is specified in from 734 * into s3 and replace in s. (source s1 remains untouched) 735 * 736 * This is a standard implementation of map(s,from,to) function of ICON 737 * language. Within mapvec, we replace every character of "from" with 738 * the corresponding character in "to". If "to" is shorter than "from", 739 * than the corresponding entries are null, which means that those 740 * characters dissapear altogether. Furthermore, imagine 741 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 742 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 743 * ultimately maps to `*'. In order to achieve this effect in an efficient 744 * manner (i.e. without multiple passes over the destination string), we 745 * loop over mapvec, starting with the initial source character. if the 746 * character value (dch) in this location is different than the source 747 * character (sch), sch becomes dch, once again to index into mapvec, until 748 * the character value stabilizes (i.e. sch = dch, in other words 749 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 750 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 751 * end, we restore mapvec* back to normal where mapvec[n] == n for 752 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 753 * about 5 times faster than any algorithm that makes multiple passes over 754 * destination string. 755 */ 756void 757map(dest, src, from, to) 758register char *dest; 759register char *src; 760register char *from; 761register char *to; 762{ 763 register char *tmp; 764 register char sch, dch; 765 static char mapvec[128] = { 766 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 767 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 768 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 769 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 770 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 771 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 772 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 773 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 774 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 775 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 776 120, 121, 122, 123, 124, 125, 126, 127 777 }; 778 779 if (*src) { 780 tmp = from; 781 /* 782 * create a mapping between "from" and 783 * "to" 784 */ 785 while (*from) 786 mapvec[*from++] = (*to) ? *to++ : (char) 0; 787 788 while (*src) { 789 sch = *src++; 790 dch = mapvec[sch]; 791 while (dch != sch) { 792 sch = dch; 793 dch = mapvec[sch]; 794 } 795 if (*dest = dch) 796 dest++; 797 } 798 /* 799 * restore all the changed characters 800 */ 801 while (*tmp) { 802 mapvec[*tmp] = *tmp; 803 tmp++; 804 } 805 } 806 *dest = (char) 0; 807} 808