1 /* $NetBSD: eval.c,v 1.14 2001/11/14 06:16:08 tv Exp $ */ 2 /* $OpenBSD: eval.c,v 1.41 2001/10/10 23:25:31 espie Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Ozan Yigit at York University. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 #ifndef lint 42 #if 0 43 static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 44 #else 45 __RCSID("$NetBSD: eval.c,v 1.14 2001/11/14 06:16:08 tv Exp $"); 46 #endif 47 #endif /* not lint */ 48 49 /* 50 * eval.c 51 * Facility: m4 macro processor 52 * by: oz 53 */ 54 55 #include <sys/types.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <stddef.h> 62 #include <string.h> 63 #include "mdef.h" 64 #include "stdd.h" 65 #include "extern.h" 66 #include "pathnames.h" 67 68 #define BUILTIN_MARKER "__builtin_" 69 70 static void dodefn __P((const char *)); 71 static void dopushdef __P((const char *, const char *)); 72 static void dodump __P((const char *[], int)); 73 static void dotrace __P((const char *[], int, int)); 74 static void doifelse __P((const char *[], int)); 75 static int doincl __P((const char *)); 76 static int dopaste __P((const char *)); 77 static void gnu_dochq __P((const char *[], int)); 78 static void dochq __P((const char *[], int)); 79 static void gnu_dochc __P((const char *[], int)); 80 static void dochc __P((const char *[], int)); 81 static void dodiv __P((int)); 82 static void doundiv __P((const char *[], int)); 83 static void dosub __P((const char *[], int)); 84 static void map __P((char *, const char *, const char *, const char *)); 85 static const char *handledash __P((char *, char *, const char *)); 86 static void expand_builtin __P((const char *[], int, int)); 87 static void expand_macro __P((const char *[], int)); 88 static void dump_one_def __P((ndptr)); 89 90 unsigned long expansion_id; 91 92 /* 93 * eval - eval all macros and builtins calls 94 * argc - number of elements in argv. 95 * argv - element vector : 96 * argv[0] = definition of a user 97 * macro or nil if built-in. 98 * argv[1] = name of the macro or 99 * built-in. 100 * argv[2] = parameters to user-defined 101 * . macro or built-in. 102 * . 103 * 104 * A call in the form of macro-or-builtin() will result in: 105 * argv[0] = nullstr 106 * argv[1] = macro-or-builtin 107 * argv[2] = nullstr 108 * 109 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 110 */ 111 void 112 eval(argv, argc, td) 113 const char *argv[]; 114 int argc; 115 int td; 116 { 117 ssize_t mark = -1; 118 119 expansion_id++; 120 if (td & RECDEF) 121 errx(1, "%s at line %lu: expanding recursive definition for %s", 122 CURRENT_NAME, CURRENT_LINE, argv[1]); 123 if (traced_macros && is_traced(argv[1])) 124 mark = trace(argv, argc, infile+ilevel); 125 if (td == MACRTYPE) 126 expand_macro(argv, argc); 127 else 128 expand_builtin(argv, argc, td); 129 if (mark != -1) 130 finish_trace(mark); 131 } 132 133 /* 134 * expand_builtin - evaluate built-in macros. 135 */ 136 void 137 expand_builtin(argv, argc, td) 138 const char *argv[]; 139 int argc; 140 int td; 141 { 142 int c, n; 143 int ac; 144 static int sysval = 0; 145 146 #ifdef DEBUG 147 printf("argc = %d\n", argc); 148 for (n = 0; n < argc; n++) 149 printf("argv[%d] = %s\n", n, argv[n]); 150 #endif 151 152 /* 153 * if argc == 3 and argv[2] is null, then we 154 * have macro-or-builtin() type call. We adjust 155 * argc to avoid further checking.. 156 */ 157 ac = argc; 158 159 if (argc == 3 && !*(argv[2])) 160 argc--; 161 162 switch (td & TYPEMASK) { 163 164 case DEFITYPE: 165 if (argc > 2) 166 dodefine(argv[2], (argc > 3) ? argv[3] : null); 167 break; 168 169 case PUSDTYPE: 170 if (argc > 2) 171 dopushdef(argv[2], (argc > 3) ? argv[3] : null); 172 break; 173 174 case DUMPTYPE: 175 dodump(argv, argc); 176 break; 177 178 case TRACEONTYPE: 179 dotrace(argv, argc, 1); 180 break; 181 182 case TRACEOFFTYPE: 183 dotrace(argv, argc, 0); 184 break; 185 186 case EXPRTYPE: 187 /* 188 * doexpr - evaluate arithmetic 189 * expression 190 */ 191 if (argc > 2) 192 pbnum(expr(argv[2])); 193 break; 194 195 case IFELTYPE: 196 if (argc > 4) 197 doifelse(argv, argc); 198 break; 199 200 case IFDFTYPE: 201 /* 202 * doifdef - select one of two 203 * alternatives based on the existence of 204 * another definition 205 */ 206 if (argc > 3) { 207 if (lookup(argv[2]) != nil) 208 pbstr(argv[3]); 209 else if (argc > 4) 210 pbstr(argv[4]); 211 } 212 break; 213 214 case LENGTYPE: 215 /* 216 * dolen - find the length of the 217 * argument 218 */ 219 pbnum((argc > 2) ? strlen(argv[2]) : 0); 220 break; 221 222 case INCRTYPE: 223 /* 224 * doincr - increment the value of the 225 * argument 226 */ 227 if (argc > 2) 228 pbnum(atoi(argv[2]) + 1); 229 break; 230 231 case DECRTYPE: 232 /* 233 * dodecr - decrement the value of the 234 * argument 235 */ 236 if (argc > 2) 237 pbnum(atoi(argv[2]) - 1); 238 break; 239 240 case SYSCTYPE: 241 /* 242 * dosys - execute system command 243 */ 244 if (argc > 2) 245 sysval = system(argv[2]); 246 break; 247 248 case SYSVTYPE: 249 /* 250 * dosysval - return value of the last 251 * system call. 252 * 253 */ 254 pbnum(sysval); 255 break; 256 257 case ESYSCMDTYPE: 258 if (argc > 2) 259 doesyscmd(argv[2]); 260 break; 261 case INCLTYPE: 262 if (argc > 2) 263 if (!doincl(argv[2])) 264 err(1, "%s at line %lu: include(%s)", 265 CURRENT_NAME, CURRENT_LINE, argv[2]); 266 break; 267 268 case SINCTYPE: 269 if (argc > 2) 270 (void) doincl(argv[2]); 271 break; 272 #ifdef EXTENDED 273 case PASTTYPE: 274 if (argc > 2) 275 if (!dopaste(argv[2])) 276 err(1, "%s at line %lu: paste(%s)", 277 CURRENT_NAME, CURRENT_LINE, argv[2]); 278 break; 279 280 case SPASTYPE: 281 if (argc > 2) 282 (void) dopaste(argv[2]); 283 break; 284 #endif 285 case CHNQTYPE: 286 if (mimic_gnu) 287 gnu_dochq(argv, ac); 288 else 289 dochq(argv, argc); 290 break; 291 292 case CHNCTYPE: 293 if (mimic_gnu) 294 gnu_dochc(argv, ac); 295 else 296 dochc(argv, argc); 297 break; 298 299 case SUBSTYPE: 300 /* 301 * dosub - select substring 302 * 303 */ 304 if (argc > 3) 305 dosub(argv, argc); 306 break; 307 308 case SHIFTYPE: 309 /* 310 * doshift - push back all arguments 311 * except the first one (i.e. skip 312 * argv[2]) 313 */ 314 if (argc > 3) { 315 for (n = argc - 1; n > 3; n--) { 316 pbstr(rquote); 317 pbstr(argv[n]); 318 pbstr(lquote); 319 putback(COMMA); 320 } 321 pbstr(rquote); 322 pbstr(argv[3]); 323 pbstr(lquote); 324 } 325 break; 326 327 case DIVRTYPE: 328 if (argc > 2 && (n = atoi(argv[2])) != 0) 329 dodiv(n); 330 else { 331 active = stdout; 332 oindex = 0; 333 } 334 break; 335 336 case UNDVTYPE: 337 doundiv(argv, argc); 338 break; 339 340 case DIVNTYPE: 341 /* 342 * dodivnum - return the number of 343 * current output diversion 344 */ 345 pbnum(oindex); 346 break; 347 348 case UNDFTYPE: 349 /* 350 * doundefine - undefine a previously 351 * defined macro(s) or m4 keyword(s). 352 */ 353 if (argc > 2) 354 for (n = 2; n < argc; n++) 355 remhash(argv[n], ALL); 356 break; 357 358 case POPDTYPE: 359 /* 360 * dopopdef - remove the topmost 361 * definitions of macro(s) or m4 362 * keyword(s). 363 */ 364 if (argc > 2) 365 for (n = 2; n < argc; n++) 366 remhash(argv[n], TOP); 367 break; 368 369 case MKTMTYPE: 370 /* 371 * dotemp - create a temporary file 372 */ 373 if (argc > 2) { 374 int fd; 375 char *temp; 376 377 temp = xstrdup(argv[2]); 378 379 fd = mkstemp(temp); 380 if (fd == -1) 381 err(1, 382 "%s at line %lu: couldn't make temp file %s", 383 CURRENT_NAME, CURRENT_LINE, argv[2]); 384 close(fd); 385 pbstr(temp); 386 free(temp); 387 } 388 break; 389 390 case TRNLTYPE: 391 /* 392 * dotranslit - replace all characters in 393 * the source string that appears in the 394 * "from" string with the corresponding 395 * characters in the "to" string. 396 */ 397 if (argc > 3) { 398 char temp[STRSPMAX+1]; 399 if (argc > 4) 400 map(temp, argv[2], argv[3], argv[4]); 401 else 402 map(temp, argv[2], argv[3], null); 403 pbstr(temp); 404 } else if (argc > 2) 405 pbstr(argv[2]); 406 break; 407 408 case INDXTYPE: 409 /* 410 * doindex - find the index of the second 411 * argument string in the first argument 412 * string. -1 if not present. 413 */ 414 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 415 break; 416 417 case ERRPTYPE: 418 /* 419 * doerrp - print the arguments to stderr 420 * file 421 */ 422 if (argc > 2) { 423 for (n = 2; n < argc; n++) 424 fprintf(stderr, "%s ", argv[n]); 425 fprintf(stderr, "\n"); 426 } 427 break; 428 429 case DNLNTYPE: 430 /* 431 * dodnl - eat-up-to and including 432 * newline 433 */ 434 while ((c = gpbc()) != '\n' && c != EOF) 435 ; 436 break; 437 438 case M4WRTYPE: 439 /* 440 * dom4wrap - set up for 441 * wrap-up/wind-down activity 442 */ 443 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 444 break; 445 446 case EXITTYPE: 447 /* 448 * doexit - immediate exit from m4. 449 */ 450 killdiv(); 451 exit((argc > 2) ? atoi(argv[2]) : 0); 452 break; 453 454 case DEFNTYPE: 455 if (argc > 2) 456 for (n = 2; n < argc; n++) 457 dodefn(argv[n]); 458 break; 459 460 case INDIRTYPE: /* Indirect call */ 461 if (argc > 2) 462 doindir(argv, argc); 463 break; 464 465 case BUILTINTYPE: /* Builtins only */ 466 if (argc > 2) 467 dobuiltin(argv, argc); 468 break; 469 470 case PATSTYPE: 471 if (argc > 2) 472 dopatsubst(argv, argc); 473 break; 474 case REGEXPTYPE: 475 if (argc > 2) 476 doregexp(argv, argc); 477 break; 478 case LINETYPE: 479 doprintlineno(infile+ilevel); 480 break; 481 case FILENAMETYPE: 482 doprintfilename(infile+ilevel); 483 break; 484 case SELFTYPE: 485 pbstr(rquote); 486 pbstr(argv[1]); 487 pbstr(lquote); 488 break; 489 default: 490 errx(1, "%s at line %lu: eval: major botch.", 491 CURRENT_NAME, CURRENT_LINE); 492 break; 493 } 494 } 495 496 /* 497 * expand_macro - user-defined macro expansion 498 */ 499 void 500 expand_macro(argv, argc) 501 const char *argv[]; 502 int argc; 503 { 504 const char *t; 505 const char *p; 506 int n; 507 int argno; 508 509 t = argv[0]; /* defn string as a whole */ 510 p = t; 511 while (*p) 512 p++; 513 p--; /* last character of defn */ 514 while (p > t) { 515 if (*(p - 1) != ARGFLAG) 516 PUTBACK(*p); 517 else { 518 switch (*p) { 519 520 case '#': 521 pbnum(argc - 2); 522 break; 523 case '0': 524 case '1': 525 case '2': 526 case '3': 527 case '4': 528 case '5': 529 case '6': 530 case '7': 531 case '8': 532 case '9': 533 if ((argno = *p - '0') < argc - 1) 534 pbstr(argv[argno + 1]); 535 break; 536 case '*': 537 if (argc > 2) { 538 for (n = argc - 1; n > 2; n--) { 539 pbstr(argv[n]); 540 putback(COMMA); 541 } 542 pbstr(argv[2]); 543 } 544 break; 545 case '@': 546 if (argc > 2) { 547 for (n = argc - 1; n > 2; n--) { 548 pbstr(rquote); 549 pbstr(argv[n]); 550 pbstr(lquote); 551 putback(COMMA); 552 } 553 pbstr(rquote); 554 pbstr(argv[2]); 555 pbstr(lquote); 556 } 557 break; 558 default: 559 PUTBACK(*p); 560 PUTBACK('$'); 561 break; 562 } 563 p--; 564 } 565 p--; 566 } 567 if (p == t) /* do last character */ 568 PUTBACK(*p); 569 } 570 571 /* 572 * dodefine - install definition in the table 573 */ 574 void 575 dodefine(name, defn) 576 const char *name; 577 const char *defn; 578 { 579 ndptr p; 580 int n; 581 582 if (!*name) 583 errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 584 CURRENT_LINE); 585 if ((p = lookup(name)) == nil) 586 p = addent(name); 587 else if (p->defn != null) 588 free((char *) p->defn); 589 if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { 590 n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); 591 if (n != -1) { 592 p->type = n & TYPEMASK; 593 if ((n & NOARGS) == 0) 594 p->type |= NEEDARGS; 595 p->defn = null; 596 return; 597 } 598 } 599 if (!*defn) 600 p->defn = null; 601 else 602 p->defn = xstrdup(defn); 603 p->type = MACRTYPE; 604 if (STREQ(name, defn)) 605 p->type |= RECDEF; 606 } 607 608 /* 609 * dodefn - push back a quoted definition of 610 * the given name. 611 */ 612 static void 613 dodefn(name) 614 const char *name; 615 { 616 ndptr p; 617 const char *real; 618 619 if ((p = lookup(name)) != nil) { 620 if (p->defn != null) { 621 pbstr(rquote); 622 pbstr(p->defn); 623 pbstr(lquote); 624 } else if ((real = builtin_realname(p->type)) != NULL) { 625 pbstr(real); 626 pbstr(BUILTIN_MARKER); 627 } 628 } 629 } 630 631 /* 632 * dopushdef - install a definition in the hash table 633 * without removing a previous definition. Since 634 * each new entry is entered in *front* of the 635 * hash bucket, it hides a previous definition from 636 * lookup. 637 */ 638 static void 639 dopushdef(name, defn) 640 const char *name; 641 const char *defn; 642 { 643 ndptr p; 644 645 if (!*name) 646 errx(1, "%s at line %lu: null definition", CURRENT_NAME, 647 CURRENT_LINE); 648 p = addent(name); 649 if (!*defn) 650 p->defn = null; 651 else 652 p->defn = xstrdup(defn); 653 p->type = MACRTYPE; 654 if (STREQ(name, defn)) 655 p->type |= RECDEF; 656 } 657 658 /* 659 * dump_one_def - dump the specified definition. 660 */ 661 static void 662 dump_one_def(p) 663 ndptr p; 664 { 665 const char *real; 666 667 if (mimic_gnu) { 668 if ((p->type & TYPEMASK) == MACRTYPE) 669 fprintf(traceout, "%s:\t%s\n", p->name, p->defn); 670 else { 671 real = builtin_realname(p->type); 672 if (real == NULL) 673 real = null; 674 fprintf(traceout, "%s:\t<%s>\n", p->name, real); 675 } 676 } else 677 fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn); 678 } 679 680 /* 681 * dodumpdef - dump the specified definitions in the hash 682 * table to stderr. If nothing is specified, the entire 683 * hash table is dumped. 684 */ 685 static void 686 dodump(argv, argc) 687 const char *argv[]; 688 int argc; 689 { 690 int n; 691 ndptr p; 692 693 if (argc > 2) { 694 for (n = 2; n < argc; n++) 695 if ((p = lookup(argv[n])) != nil) 696 dump_one_def(p); 697 } else { 698 for (n = 0; n < HASHSIZE; n++) 699 for (p = hashtab[n]; p != nil; p = p->nxtptr) 700 dump_one_def(p); 701 } 702 } 703 704 /* 705 * dotrace - mark some macros as traced/untraced depending upon on. 706 */ 707 static void 708 dotrace(argv, argc, on) 709 const char *argv[]; 710 int argc; 711 int on; 712 { 713 int n; 714 715 if (argc > 2) { 716 for (n = 2; n < argc; n++) 717 mark_traced(argv[n], on); 718 } else 719 mark_traced(NULL, on); 720 } 721 722 /* 723 * doifelse - select one of two alternatives - loop. 724 */ 725 static void 726 doifelse(argv, argc) 727 const char *argv[]; 728 int argc; 729 { 730 cycle { 731 if (STREQ(argv[2], argv[3])) 732 pbstr(argv[4]); 733 else if (argc == 6) 734 pbstr(argv[5]); 735 else if (argc > 6) { 736 argv += 3; 737 argc -= 3; 738 continue; 739 } 740 break; 741 } 742 } 743 744 /* 745 * doinclude - include a given file. 746 */ 747 static int 748 doincl(ifile) 749 const char *ifile; 750 { 751 if (ilevel + 1 == MAXINP) 752 errx(1, "%s at line %lu: too many include files.", 753 CURRENT_NAME, CURRENT_LINE); 754 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 755 ilevel++; 756 bbase[ilevel] = bufbase = bp; 757 return (1); 758 } else 759 return (0); 760 } 761 762 #ifdef EXTENDED 763 /* 764 * dopaste - include a given file without any 765 * macro processing. 766 */ 767 static int 768 dopaste(pfile) 769 const char *pfile; 770 { 771 FILE *pf; 772 int c; 773 774 if ((pf = fopen(pfile, "r")) != NULL) { 775 while ((c = getc(pf)) != EOF) 776 putc(c, active); 777 (void) fclose(pf); 778 return (1); 779 } else 780 return (0); 781 } 782 #endif 783 784 static void 785 gnu_dochq(argv, ac) 786 const char *argv[]; 787 int ac; 788 { 789 /* In gnu-m4 mode, the only way to restore quotes is to have no 790 * arguments at all. */ 791 if (ac == 2) { 792 lquote[0] = LQUOTE, lquote[1] = EOS; 793 rquote[0] = RQUOTE, rquote[1] = EOS; 794 } else { 795 strlcpy(lquote, argv[2], sizeof(lquote)); 796 if(ac > 3) 797 strlcpy(rquote, argv[3], sizeof(rquote)); 798 else 799 rquote[0] = EOS; 800 } 801 } 802 803 /* 804 * dochq - change quote characters 805 */ 806 static void 807 dochq(argv, argc) 808 const char *argv[]; 809 int argc; 810 { 811 if (argc > 2) { 812 if (*argv[2]) 813 strlcpy(lquote, argv[2], sizeof(lquote)); 814 else { 815 lquote[0] = LQUOTE; 816 lquote[1] = EOS; 817 } 818 if (argc > 3) { 819 if (*argv[3]) 820 strlcpy(rquote, argv[3], sizeof(rquote)); 821 } else 822 strcpy(rquote, lquote); 823 } else { 824 lquote[0] = LQUOTE, lquote[1] = EOS; 825 rquote[0] = RQUOTE, rquote[1] = EOS; 826 } 827 } 828 829 static void 830 gnu_dochc(argv, ac) 831 const char *argv[]; 832 int ac; 833 { 834 /* In gnu-m4 mode, no arguments mean no comment 835 * arguments at all. */ 836 if (ac == 2) { 837 scommt[0] = EOS; 838 ecommt[0] = EOS; 839 } else { 840 if (*argv[2]) 841 strlcpy(scommt, argv[2], sizeof(scommt)); 842 else 843 scommt[0] = SCOMMT, scommt[1] = EOS; 844 if(ac > 3 && *argv[3]) 845 strlcpy(ecommt, argv[3], sizeof(ecommt)); 846 else 847 ecommt[0] = ECOMMT, ecommt[1] = EOS; 848 } 849 } 850 /* 851 * dochc - change comment characters 852 */ 853 static void 854 dochc(argv, argc) 855 const char *argv[]; 856 int argc; 857 { 858 if (argc > 2) { 859 if (*argv[2]) 860 strlcpy(scommt, argv[2], sizeof(scommt)); 861 if (argc > 3) { 862 if (*argv[3]) 863 strlcpy(ecommt, argv[3], sizeof(ecommt)); 864 } 865 else 866 ecommt[0] = ECOMMT, ecommt[1] = EOS; 867 } 868 else { 869 scommt[0] = SCOMMT, scommt[1] = EOS; 870 ecommt[0] = ECOMMT, ecommt[1] = EOS; 871 } 872 } 873 874 /* 875 * dodivert - divert the output to a temporary file 876 */ 877 static void 878 dodiv(n) 879 int n; 880 { 881 int fd; 882 883 oindex = n; 884 if (n >= maxout) { 885 if (mimic_gnu) 886 resizedivs(n + 10); 887 else 888 n = 0; /* bitbucket */ 889 } 890 891 if (n < 0) 892 n = 0; /* bitbucket */ 893 if (outfile[n] == NULL) { 894 char fname[] = _PATH_DIVNAME; 895 896 if ((fd = mkstemp(fname)) < 0 || 897 (outfile[n] = fdopen(fd, "w+")) == NULL) 898 err(1, "%s: cannot divert", fname); 899 if (unlink(fname) == -1) 900 err(1, "%s: cannot unlink", fname); 901 } 902 active = outfile[n]; 903 } 904 905 /* 906 * doundivert - undivert a specified output, or all 907 * other outputs, in numerical order. 908 */ 909 static void 910 doundiv(argv, argc) 911 const char *argv[]; 912 int argc; 913 { 914 int ind; 915 int n; 916 917 if (argc > 2) { 918 for (ind = 2; ind < argc; ind++) { 919 n = atoi(argv[ind]); 920 if (n > 0 && n < maxout && outfile[n] != NULL) 921 getdiv(n); 922 923 } 924 } 925 else 926 for (n = 1; n < maxout; n++) 927 if (outfile[n] != NULL) 928 getdiv(n); 929 } 930 931 /* 932 * dosub - select substring 933 */ 934 static void 935 dosub(argv, argc) 936 const char *argv[]; 937 int argc; 938 { 939 const char *ap, *fc, *k; 940 int nc; 941 942 ap = argv[2]; /* target string */ 943 #ifdef EXPR 944 fc = ap + expr(argv[3]); /* first char */ 945 #else 946 fc = ap + atoi(argv[3]); /* first char */ 947 #endif 948 nc = strlen(fc); 949 if (argc >= 5) 950 #ifdef EXPR 951 nc = min(nc, expr(argv[4])); 952 #else 953 nc = min(nc, atoi(argv[4])); 954 #endif 955 if (fc >= ap && fc < ap + strlen(ap)) 956 for (k = fc + nc - 1; k >= fc; k--) 957 putback(*k); 958 } 959 960 /* 961 * map: 962 * map every character of s1 that is specified in from 963 * into s3 and replace in s. (source s1 remains untouched) 964 * 965 * This is a standard implementation of map(s,from,to) function of ICON 966 * language. Within mapvec, we replace every character of "from" with 967 * the corresponding character in "to". If "to" is shorter than "from", 968 * than the corresponding entries are null, which means that those 969 * characters dissapear altogether. Furthermore, imagine 970 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 971 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 972 * ultimately maps to `*'. In order to achieve this effect in an efficient 973 * manner (i.e. without multiple passes over the destination string), we 974 * loop over mapvec, starting with the initial source character. if the 975 * character value (dch) in this location is different than the source 976 * character (sch), sch becomes dch, once again to index into mapvec, until 977 * the character value stabilizes (i.e. sch = dch, in other words 978 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 979 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 980 * end, we restore mapvec* back to normal where mapvec[n] == n for 981 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 982 * about 5 times faster than any algorithm that makes multiple passes over 983 * destination string. 984 */ 985 static void 986 map(dest, src, from, to) 987 char *dest; 988 const char *src; 989 const char *from; 990 const char *to; 991 { 992 const char *tmp; 993 unsigned char sch, dch; 994 static char frombis[257]; 995 static char tobis[257]; 996 static unsigned char mapvec[256] = { 997 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 998 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 999 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 1000 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 1001 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 1002 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 1003 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 1004 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 1005 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 1006 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 1007 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 1008 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 1009 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 1010 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 1011 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 1012 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 1013 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 1014 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 1015 }; 1016 1017 if (*src) { 1018 if (mimic_gnu) { 1019 /* 1020 * expand character ranges on the fly 1021 */ 1022 from = handledash(frombis, frombis + 256, from); 1023 to = handledash(tobis, tobis + 256, to); 1024 } 1025 tmp = from; 1026 /* 1027 * create a mapping between "from" and 1028 * "to" 1029 */ 1030 while (*from) 1031 mapvec[(unsigned char)(*from++)] = (*to) ? 1032 (unsigned char)(*to++) : 0; 1033 1034 while (*src) { 1035 sch = (unsigned char)(*src++); 1036 dch = mapvec[sch]; 1037 while (dch != sch) { 1038 sch = dch; 1039 dch = mapvec[sch]; 1040 } 1041 if ((*dest = (char)dch)) 1042 dest++; 1043 } 1044 /* 1045 * restore all the changed characters 1046 */ 1047 while (*tmp) { 1048 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 1049 tmp++; 1050 } 1051 } 1052 *dest = '\0'; 1053 } 1054 1055 1056 /* 1057 * handledash: 1058 * use buffer to copy the src string, expanding character ranges 1059 * on the way. 1060 */ 1061 static const char * 1062 handledash(buffer, end, src) 1063 char *buffer; 1064 char *end; 1065 const char *src; 1066 { 1067 char *p; 1068 1069 p = buffer; 1070 while(*src) { 1071 if (src[1] == '-' && src[2]) { 1072 unsigned char i; 1073 for (i = (unsigned char)src[0]; 1074 i <= (unsigned char)src[2]; i++) { 1075 *p++ = i; 1076 if (p == end) { 1077 *p = '\0'; 1078 return buffer; 1079 } 1080 } 1081 src += 3; 1082 } else 1083 *p++ = *src++; 1084 if (p == end) 1085 break; 1086 } 1087 *p = '\0'; 1088 return buffer; 1089 } 1090 1091