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