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