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