1 /* $NetBSD: eval.c,v 1.19 2004/07/06 13:19:42 mycroft 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. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #if HAVE_NBTOOL_CONFIG_H 37 #include "nbtool_config.h" 38 #endif 39 40 #include <sys/cdefs.h> 41 #if defined(__RCSID) && !defined(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.19 2004/07/06 13:19:42 mycroft 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 <errno.h> 57 #include <fcntl.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <stddef.h> 61 #include <string.h> 62 #include "mdef.h" 63 #include "stdd.h" 64 #include "extern.h" 65 #include "pathnames.h" 66 67 #define BUILTIN_MARKER "__builtin_" 68 69 static void dodefn __P((const char *)); 70 static void dopushdef __P((const char *, const char *)); 71 static void dodump __P((const char *[], int)); 72 static void dotrace __P((const char *[], int, int)); 73 static void doifelse __P((const char *[], int)); 74 static int doincl __P((const char *)); 75 static int dopaste __P((const char *)); 76 static void gnu_dochq __P((const char *[], int)); 77 static void dochq __P((const char *[], int)); 78 static void gnu_dochc __P((const char *[], int)); 79 static void dochc __P((const char *[], int)); 80 static void dodiv __P((int)); 81 static void doundiv __P((const char *[], int)); 82 static void dosub __P((const char *[], int)); 83 static void map __P((char *, const char *, const char *, const char *)); 84 static const char *handledash __P((char *, char *, const char *)); 85 static void expand_builtin __P((const char *[], int, int)); 86 static void expand_macro __P((const char *[], int)); 87 static void dump_one_def __P((ndptr)); 88 89 unsigned long expansion_id; 90 91 /* 92 * eval - eval all macros and builtins calls 93 * argc - number of elements in argv. 94 * argv - element vector : 95 * argv[0] = definition of a user 96 * macro or nil if built-in. 97 * argv[1] = name of the macro or 98 * built-in. 99 * argv[2] = parameters to user-defined 100 * . macro or built-in. 101 * . 102 * 103 * A call in the form of macro-or-builtin() will result in: 104 * argv[0] = nullstr 105 * argv[1] = macro-or-builtin 106 * argv[2] = nullstr 107 * 108 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 109 */ 110 void 111 eval(argv, argc, td) 112 const char *argv[]; 113 int argc; 114 int td; 115 { 116 ssize_t mark = -1; 117 118 expansion_id++; 119 if (td & RECDEF) 120 errx(1, "%s at line %lu: expanding recursive definition for %s", 121 CURRENT_NAME, CURRENT_LINE, argv[1]); 122 if (traced_macros && is_traced(argv[1])) 123 mark = trace(argv, argc, infile+ilevel); 124 if (td == MACRTYPE) 125 expand_macro(argv, argc); 126 else 127 expand_builtin(argv, argc, td); 128 if (mark != -1) 129 finish_trace(mark); 130 } 131 132 /* 133 * expand_builtin - evaluate built-in macros. 134 */ 135 void 136 expand_builtin(argv, argc, td) 137 const char *argv[]; 138 int argc; 139 int td; 140 { 141 int c, n; 142 int ac; 143 static int sysval = 0; 144 145 #ifdef DEBUG 146 printf("argc = %d\n", argc); 147 for (n = 0; n < argc; n++) 148 printf("argv[%d] = %s\n", n, argv[n]); 149 #endif 150 151 /* 152 * if argc == 3 and argv[2] is null, then we 153 * have macro-or-builtin() type call. We adjust 154 * argc to avoid further checking.. 155 */ 156 ac = argc; 157 158 if (argc == 3 && !*(argv[2])) 159 argc--; 160 161 switch (td & TYPEMASK) { 162 163 case DEFITYPE: 164 if (argc > 2) 165 dodefine(argv[2], (argc > 3) ? argv[3] : null); 166 break; 167 168 case PUSDTYPE: 169 if (argc > 2) 170 dopushdef(argv[2], (argc > 3) ? argv[3] : null); 171 break; 172 173 case DUMPTYPE: 174 dodump(argv, argc); 175 break; 176 177 case TRACEONTYPE: 178 dotrace(argv, argc, 1); 179 break; 180 181 case TRACEOFFTYPE: 182 dotrace(argv, argc, 0); 183 break; 184 185 case EXPRTYPE: 186 /* 187 * doexpr - evaluate arithmetic 188 * expression 189 */ 190 if (argc > 2) 191 pbnum(expr(argv[2])); 192 break; 193 194 case IFELTYPE: 195 if (argc > 4) 196 doifelse(argv, argc); 197 break; 198 199 case IFDFTYPE: 200 /* 201 * doifdef - select one of two 202 * alternatives based on the existence of 203 * another definition 204 */ 205 if (argc > 3) { 206 if (lookup(argv[2]) != nil) 207 pbstr(argv[3]); 208 else if (argc > 4) 209 pbstr(argv[4]); 210 } 211 break; 212 213 case LENGTYPE: 214 /* 215 * dolen - find the length of the 216 * argument 217 */ 218 pbnum((argc > 2) ? strlen(argv[2]) : 0); 219 break; 220 221 case INCRTYPE: 222 /* 223 * doincr - increment the value of the 224 * argument 225 */ 226 if (argc > 2) 227 pbnum(atoi(argv[2]) + 1); 228 break; 229 230 case DECRTYPE: 231 /* 232 * dodecr - decrement the value of the 233 * argument 234 */ 235 if (argc > 2) 236 pbnum(atoi(argv[2]) - 1); 237 break; 238 239 case SYSCTYPE: 240 /* 241 * dosys - execute system command 242 */ 243 if (argc > 2) 244 sysval = system(argv[2]); 245 break; 246 247 case SYSVTYPE: 248 /* 249 * dosysval - return value of the last 250 * system call. 251 * 252 */ 253 pbnum(sysval); 254 break; 255 256 case ESYSCMDTYPE: 257 if (argc > 2) 258 doesyscmd(argv[2]); 259 break; 260 case INCLTYPE: 261 if (argc > 2) 262 if (!doincl(argv[2])) 263 err(1, "%s at line %lu: include(%s)", 264 CURRENT_NAME, CURRENT_LINE, argv[2]); 265 break; 266 267 case SINCTYPE: 268 if (argc > 2) 269 (void) doincl(argv[2]); 270 break; 271 #ifdef EXTENDED 272 case PASTTYPE: 273 if (argc > 2) 274 if (!dopaste(argv[2])) 275 err(1, "%s at line %lu: paste(%s)", 276 CURRENT_NAME, CURRENT_LINE, argv[2]); 277 break; 278 279 case SPASTYPE: 280 if (argc > 2) 281 (void) dopaste(argv[2]); 282 break; 283 #endif 284 case CHNQTYPE: 285 if (mimic_gnu) 286 gnu_dochq(argv, ac); 287 else 288 dochq(argv, argc); 289 break; 290 291 case CHNCTYPE: 292 if (mimic_gnu) 293 gnu_dochc(argv, ac); 294 else 295 dochc(argv, argc); 296 break; 297 298 case SUBSTYPE: 299 /* 300 * dosub - select substring 301 * 302 */ 303 if (argc > 3) 304 dosub(argv, argc); 305 break; 306 307 case SHIFTYPE: 308 /* 309 * doshift - push back all arguments 310 * except the first one (i.e. skip 311 * argv[2]) 312 */ 313 if (argc > 3) { 314 for (n = argc - 1; n > 3; n--) { 315 pbstr(rquote); 316 pbstr(argv[n]); 317 pbstr(lquote); 318 putback(COMMA); 319 } 320 pbstr(rquote); 321 pbstr(argv[3]); 322 pbstr(lquote); 323 } 324 break; 325 326 case DIVRTYPE: 327 if (argc > 2 && (n = atoi(argv[2])) != 0) 328 dodiv(n); 329 else { 330 active = stdout; 331 oindex = 0; 332 } 333 break; 334 335 case UNDVTYPE: 336 doundiv(argv, argc); 337 break; 338 339 case DIVNTYPE: 340 /* 341 * dodivnum - return the number of 342 * current output diversion 343 */ 344 pbnum(oindex); 345 break; 346 347 case UNDFTYPE: 348 /* 349 * doundefine - undefine a previously 350 * defined macro(s) or m4 keyword(s). 351 */ 352 if (argc > 2) 353 for (n = 2; n < argc; n++) 354 remhash(argv[n], ALL); 355 break; 356 357 case POPDTYPE: 358 /* 359 * dopopdef - remove the topmost 360 * definitions of macro(s) or m4 361 * keyword(s). 362 */ 363 if (argc > 2) 364 for (n = 2; n < argc; n++) 365 remhash(argv[n], TOP); 366 break; 367 368 case MKTMTYPE: 369 /* 370 * dotemp - create a temporary file 371 */ 372 if (argc > 2) { 373 int fd; 374 char *temp; 375 376 temp = xstrdup(argv[2]); 377 378 fd = mkstemp(temp); 379 if (fd == -1) 380 err(1, 381 "%s at line %lu: couldn't make temp file %s", 382 CURRENT_NAME, CURRENT_LINE, argv[2]); 383 close(fd); 384 pbstr(temp); 385 free(temp); 386 } 387 break; 388 389 case TRNLTYPE: 390 /* 391 * dotranslit - replace all characters in 392 * the source string that appears in the 393 * "from" string with the corresponding 394 * characters in the "to" string. 395 */ 396 if (argc > 3) { 397 char temp[STRSPMAX+1]; 398 if (argc > 4) 399 map(temp, argv[2], argv[3], argv[4]); 400 else 401 map(temp, argv[2], argv[3], null); 402 pbstr(temp); 403 } else if (argc > 2) 404 pbstr(argv[2]); 405 break; 406 407 case INDXTYPE: 408 /* 409 * doindex - find the index of the second 410 * argument string in the first argument 411 * string. -1 if not present. 412 */ 413 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 414 break; 415 416 case ERRPTYPE: 417 /* 418 * doerrp - print the arguments to stderr 419 * file 420 */ 421 if (argc > 2) { 422 for (n = 2; n < argc; n++) 423 fprintf(stderr, "%s ", argv[n]); 424 fprintf(stderr, "\n"); 425 } 426 break; 427 428 case DNLNTYPE: 429 /* 430 * dodnl - eat-up-to and including 431 * newline 432 */ 433 while ((c = gpbc()) != '\n' && c != EOF) 434 ; 435 break; 436 437 case M4WRTYPE: 438 /* 439 * dom4wrap - set up for 440 * wrap-up/wind-down activity 441 */ 442 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 443 break; 444 445 case EXITTYPE: 446 /* 447 * doexit - immediate exit from m4. 448 */ 449 killdiv(); 450 exit((argc > 2) ? atoi(argv[2]) : 0); 451 break; 452 453 case DEFNTYPE: 454 if (argc > 2) 455 for (n = 2; n < argc; n++) 456 dodefn(argv[n]); 457 break; 458 459 case INDIRTYPE: /* Indirect call */ 460 if (argc > 2) 461 doindir(argv, argc); 462 break; 463 464 case BUILTINTYPE: /* Builtins only */ 465 if (argc > 2) 466 dobuiltin(argv, argc); 467 break; 468 469 case PATSTYPE: 470 if (argc > 2) 471 dopatsubst(argv, argc); 472 break; 473 case REGEXPTYPE: 474 if (argc > 2) 475 doregexp(argv, argc); 476 break; 477 case LINETYPE: 478 doprintlineno(infile+ilevel); 479 break; 480 case FILENAMETYPE: 481 doprintfilename(infile+ilevel); 482 break; 483 case SELFTYPE: 484 pbstr(rquote); 485 pbstr(argv[1]); 486 pbstr(lquote); 487 break; 488 default: 489 errx(1, "%s at line %lu: eval: major botch.", 490 CURRENT_NAME, CURRENT_LINE); 491 break; 492 } 493 } 494 495 /* 496 * expand_macro - user-defined macro expansion 497 */ 498 void 499 expand_macro(argv, argc) 500 const char *argv[]; 501 int argc; 502 { 503 const char *t; 504 const char *p; 505 int n; 506 int argno; 507 508 t = argv[0]; /* defn string as a whole */ 509 p = t; 510 while (*p) 511 p++; 512 p--; /* last character of defn */ 513 while (p > t) { 514 if (*(p - 1) != ARGFLAG) 515 PUTBACK(*p); 516 else { 517 switch (*p) { 518 519 case '#': 520 pbnum(argc - 2); 521 break; 522 case '0': 523 case '1': 524 case '2': 525 case '3': 526 case '4': 527 case '5': 528 case '6': 529 case '7': 530 case '8': 531 case '9': 532 if ((argno = *p - '0') < argc - 1) 533 pbstr(argv[argno + 1]); 534 break; 535 case '*': 536 if (argc > 2) { 537 for (n = argc - 1; n > 2; n--) { 538 pbstr(argv[n]); 539 putback(COMMA); 540 } 541 pbstr(argv[2]); 542 } 543 break; 544 case '@': 545 if (argc > 2) { 546 for (n = argc - 1; n > 2; n--) { 547 pbstr(rquote); 548 pbstr(argv[n]); 549 pbstr(lquote); 550 putback(COMMA); 551 } 552 pbstr(rquote); 553 pbstr(argv[2]); 554 pbstr(lquote); 555 } 556 break; 557 default: 558 PUTBACK(*p); 559 PUTBACK('$'); 560 break; 561 } 562 p--; 563 } 564 p--; 565 } 566 if (p == t) /* do last character */ 567 PUTBACK(*p); 568 } 569 570 /* 571 * dodefine - install definition in the table 572 */ 573 void 574 dodefine(name, defn) 575 const char *name; 576 const char *defn; 577 { 578 ndptr p; 579 int n; 580 581 if (!*name) 582 errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 583 CURRENT_LINE); 584 if ((p = lookup(name)) == nil) 585 p = addent(name); 586 else if (p->defn != null) 587 free((char *) p->defn); 588 if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { 589 n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); 590 if (n != -1) { 591 p->type = n & TYPEMASK; 592 if ((n & NOARGS) == 0) 593 p->type |= NEEDARGS; 594 p->defn = null; 595 return; 596 } 597 } 598 if (!*defn) 599 p->defn = null; 600 else 601 p->defn = xstrdup(defn); 602 p->type = MACRTYPE; 603 if (STREQ(name, defn)) 604 p->type |= RECDEF; 605 } 606 607 /* 608 * dodefn - push back a quoted definition of 609 * the given name. 610 */ 611 static void 612 dodefn(name) 613 const char *name; 614 { 615 ndptr p; 616 const char *real; 617 618 if ((p = lookup(name)) != nil) { 619 if (p->defn != null) { 620 pbstr(rquote); 621 pbstr(p->defn); 622 pbstr(lquote); 623 } else if ((real = builtin_realname(p->type)) != NULL) { 624 pbstr(real); 625 pbstr(BUILTIN_MARKER); 626 } 627 } 628 } 629 630 /* 631 * dopushdef - install a definition in the hash table 632 * without removing a previous definition. Since 633 * each new entry is entered in *front* of the 634 * hash bucket, it hides a previous definition from 635 * lookup. 636 */ 637 static void 638 dopushdef(name, defn) 639 const char *name; 640 const char *defn; 641 { 642 ndptr p; 643 644 if (!*name) 645 errx(1, "%s at line %lu: null definition", CURRENT_NAME, 646 CURRENT_LINE); 647 p = addent(name); 648 if (!*defn) 649 p->defn = null; 650 else 651 p->defn = xstrdup(defn); 652 p->type = MACRTYPE; 653 if (STREQ(name, defn)) 654 p->type |= RECDEF; 655 } 656 657 /* 658 * dump_one_def - dump the specified definition. 659 */ 660 static void 661 dump_one_def(p) 662 ndptr p; 663 { 664 FILE *out = traceout ? traceout : stderr; 665 const char *real; 666 667 if (mimic_gnu) { 668 if ((p->type & TYPEMASK) == MACRTYPE) 669 fprintf(out, "%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(out, "%s:\t<%s>\n", p->name, real); 675 } 676 } else 677 fprintf(out, "`%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