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