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