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