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