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