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