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