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