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