Annotation of src/usr.bin/m4/eval.c, Revision 1.22
1.22 ! espie 1: /* $OpenBSD: eval.c,v 1.21 1999/11/30 22:19:50 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.22 ! espie 44: static char rcsid[] = "$OpenBSD: eval.c,v 1.21 1999/11/30 22:19:50 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:
400: default:
1.12 espie 401: errx(1, "eval: major botch.");
1.1 deraadt 402: break;
403: }
404: }
405:
406: char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
407:
408: /*
409: * expand - user-defined macro expansion
410: */
411: void
412: expand(argv, argc)
1.20 espie 413: const char *argv[];
1.17 espie 414: int argc;
1.1 deraadt 415: {
1.20 espie 416: const char *t;
417: const char *p;
1.17 espie 418: int n;
419: int argno;
1.1 deraadt 420:
421: t = argv[0]; /* defn string as a whole */
422: p = t;
423: while (*p)
424: p++;
425: p--; /* last character of defn */
426: while (p > t) {
427: if (*(p - 1) != ARGFLAG)
428: putback(*p);
429: else {
430: switch (*p) {
431:
432: case '#':
433: pbnum(argc - 2);
434: break;
435: case '0':
436: case '1':
437: case '2':
438: case '3':
439: case '4':
440: case '5':
441: case '6':
442: case '7':
443: case '8':
444: case '9':
445: if ((argno = *p - '0') < argc - 1)
446: pbstr(argv[argno + 1]);
447: break;
448: case '*':
449: for (n = argc - 1; n > 2; n--) {
450: pbstr(argv[n]);
1.7 millert 451: putback(COMMA);
1.1 deraadt 452: }
453: pbstr(argv[2]);
454: break;
1.7 millert 455: case '@':
456: for (n = argc - 1; n > 2; n--) {
457: pbstr(rquote);
458: pbstr(argv[n]);
459: pbstr(lquote);
460: putback(COMMA);
461: }
462: pbstr(rquote);
463: pbstr(argv[2]);
464: pbstr(lquote);
465: break;
1.1 deraadt 466: default:
467: putback(*p);
468: putback('$');
469: break;
470: }
471: p--;
472: }
473: p--;
474: }
475: if (p == t) /* do last character */
476: putback(*p);
477: }
478:
479: /*
480: * dodefine - install definition in the table
481: */
482: void
483: dodefine(name, defn)
1.20 espie 484: const char *name;
485: const char *defn;
1.1 deraadt 486: {
1.17 espie 487: ndptr p;
1.1 deraadt 488:
489: if (!*name)
1.12 espie 490: errx(1, "null definition.");
1.1 deraadt 491: if ((p = lookup(name)) == nil)
492: p = addent(name);
493: else if (p->defn != null)
494: free((char *) p->defn);
495: if (!*defn)
496: p->defn = null;
497: else
498: p->defn = xstrdup(defn);
499: p->type = MACRTYPE;
1.22 ! espie 500: if (STREQ(name, defn))
! 501: p->type |= RECDEF;
1.1 deraadt 502: }
503:
504: /*
505: * dodefn - push back a quoted definition of
506: * the given name.
507: */
1.20 espie 508: static void
1.1 deraadt 509: dodefn(name)
1.20 espie 510: const char *name;
1.1 deraadt 511: {
1.17 espie 512: ndptr p;
1.1 deraadt 513:
514: if ((p = lookup(name)) != nil && p->defn != null) {
1.10 deraadt 515: pbstr(rquote);
1.1 deraadt 516: pbstr(p->defn);
1.10 deraadt 517: pbstr(lquote);
1.1 deraadt 518: }
519: }
520:
521: /*
522: * dopushdef - install a definition in the hash table
523: * without removing a previous definition. Since
524: * each new entry is entered in *front* of the
525: * hash bucket, it hides a previous definition from
526: * lookup.
527: */
1.20 espie 528: static void
1.1 deraadt 529: dopushdef(name, defn)
1.20 espie 530: const char *name;
531: const char *defn;
1.1 deraadt 532: {
1.17 espie 533: ndptr p;
1.1 deraadt 534:
535: if (!*name)
1.12 espie 536: errx(1, "null definition");
1.1 deraadt 537: p = addent(name);
538: if (!*defn)
539: p->defn = null;
540: else
541: p->defn = xstrdup(defn);
542: p->type = MACRTYPE;
1.22 ! espie 543: if (STREQ(name, defn))
! 544: p->type |= RECDEF;
1.1 deraadt 545: }
546:
547: /*
548: * dodumpdef - dump the specified definitions in the hash
549: * table to stderr. If nothing is specified, the entire
550: * hash table is dumped.
551: */
1.20 espie 552: static void
1.1 deraadt 553: dodump(argv, argc)
1.20 espie 554: const char *argv[];
1.17 espie 555: int argc;
1.1 deraadt 556: {
1.17 espie 557: int n;
1.1 deraadt 558: ndptr p;
559:
560: if (argc > 2) {
561: for (n = 2; n < argc; n++)
562: if ((p = lookup(argv[n])) != nil)
563: fprintf(stderr, dumpfmt, p->name,
564: p->defn);
1.8 deraadt 565: } else {
1.1 deraadt 566: for (n = 0; n < HASHSIZE; n++)
567: for (p = hashtab[n]; p != nil; p = p->nxtptr)
568: fprintf(stderr, dumpfmt, p->name,
569: p->defn);
570: }
571: }
572:
573: /*
574: * doifelse - select one of two alternatives - loop.
575: */
1.20 espie 576: static void
1.1 deraadt 577: doifelse(argv, argc)
1.20 espie 578: const char *argv[];
1.17 espie 579: int argc;
1.1 deraadt 580: {
581: cycle {
582: if (STREQ(argv[2], argv[3]))
583: pbstr(argv[4]);
584: else if (argc == 6)
585: pbstr(argv[5]);
586: else if (argc > 6) {
587: argv += 3;
588: argc -= 3;
589: continue;
590: }
591: break;
592: }
593: }
594:
595: /*
596: * doinclude - include a given file.
597: */
1.20 espie 598: static int
1.1 deraadt 599: doincl(ifile)
1.20 espie 600: const char *ifile;
1.1 deraadt 601: {
602: if (ilevel + 1 == MAXINP)
1.12 espie 603: errx(1, "too many include files.");
1.15 espie 604: if ((infile[ilevel + 1] = fopen_trypath(ifile)) != NULL) {
1.1 deraadt 605: ilevel++;
606: bbase[ilevel] = bufbase = bp;
607: return (1);
1.8 deraadt 608: } else
1.1 deraadt 609: return (0);
610: }
611:
612: #ifdef EXTENDED
613: /*
614: * dopaste - include a given file without any
615: * macro processing.
616: */
1.20 espie 617: static int
1.1 deraadt 618: dopaste(pfile)
1.20 espie 619: const char *pfile;
1.1 deraadt 620: {
621: FILE *pf;
1.17 espie 622: int c;
1.1 deraadt 623:
624: if ((pf = fopen(pfile, "r")) != NULL) {
625: while ((c = getc(pf)) != EOF)
626: putc(c, active);
627: (void) fclose(pf);
628: return (1);
1.8 deraadt 629: } else
1.1 deraadt 630: return (0);
631: }
632: #endif
633:
634: /*
635: * dochq - change quote characters
636: */
1.20 espie 637: static void
1.1 deraadt 638: dochq(argv, argc)
1.20 espie 639: const char *argv[];
1.17 espie 640: int argc;
1.1 deraadt 641: {
642: if (argc > 2) {
1.9 deraadt 643: if (*argv[2])
1.21 espie 644: strlcpy(lquote, argv[2], sizeof(lquote));
1.9 deraadt 645: else {
646: lquote[0] = LQUOTE;
1.14 espie 647: lquote[1] = EOS;
1.9 deraadt 648: }
1.1 deraadt 649: if (argc > 3) {
650: if (*argv[3])
1.21 espie 651: strlcpy(rquote, argv[3], sizeof(rquote));
1.8 deraadt 652: } else
1.2 deraadt 653: strcpy(rquote, lquote);
1.8 deraadt 654: } else {
1.14 espie 655: lquote[0] = LQUOTE, lquote[1] = EOS;
656: rquote[0] = RQUOTE, rquote[1] = EOS;
1.1 deraadt 657: }
658: }
659:
660: /*
661: * dochc - change comment characters
662: */
1.20 espie 663: static void
1.1 deraadt 664: dochc(argv, argc)
1.20 espie 665: const char *argv[];
1.17 espie 666: int argc;
1.1 deraadt 667: {
668: if (argc > 2) {
669: if (*argv[2])
1.21 espie 670: strlcpy(scommt, argv[2], sizeof(scommt));
1.1 deraadt 671: if (argc > 3) {
672: if (*argv[3])
1.21 espie 673: strlcpy(ecommt, argv[3], sizeof(ecommt));
1.1 deraadt 674: }
675: else
1.14 espie 676: ecommt[0] = ECOMMT, ecommt[1] = EOS;
1.1 deraadt 677: }
678: else {
1.14 espie 679: scommt[0] = SCOMMT, scommt[1] = EOS;
680: ecommt[0] = ECOMMT, ecommt[1] = EOS;
1.1 deraadt 681: }
682: }
683:
684: /*
685: * dodivert - divert the output to a temporary file
686: */
1.20 espie 687: static void
1.1 deraadt 688: dodiv(n)
1.17 espie 689: int n;
1.1 deraadt 690: {
1.6 millert 691: int fd;
692:
1.8 deraadt 693: oindex = n;
1.1 deraadt 694: if (n < 0 || n >= MAXOUT)
695: n = 0; /* bitbucket */
696: if (outfile[n] == NULL) {
1.13 espie 697: char fname[] = _PATH_DIVNAME;
698:
699: if ((fd = mkstemp(fname)) < 0 ||
700: (outfile[n] = fdopen(fd, "w+")) == NULL)
701: err(1, "%s: cannot divert", fname);
702: if (unlink(fname) == -1)
703: err(1, "%s: cannot unlink", fname);
1.1 deraadt 704: }
705: active = outfile[n];
706: }
707:
708: /*
709: * doundivert - undivert a specified output, or all
710: * other outputs, in numerical order.
711: */
1.20 espie 712: static void
1.1 deraadt 713: doundiv(argv, argc)
1.20 espie 714: const char *argv[];
1.17 espie 715: int argc;
1.1 deraadt 716: {
1.17 espie 717: int ind;
718: int n;
1.1 deraadt 719:
720: if (argc > 2) {
721: for (ind = 2; ind < argc; ind++) {
722: n = atoi(argv[ind]);
723: if (n > 0 && n < MAXOUT && outfile[n] != NULL)
724: getdiv(n);
725:
726: }
727: }
728: else
729: for (n = 1; n < MAXOUT; n++)
730: if (outfile[n] != NULL)
731: getdiv(n);
732: }
733:
734: /*
735: * dosub - select substring
736: */
1.20 espie 737: static void
1.1 deraadt 738: dosub(argv, argc)
1.20 espie 739: const char *argv[];
1.17 espie 740: int argc;
1.1 deraadt 741: {
1.20 espie 742: const char *ap, *fc, *k;
1.17 espie 743: int nc;
1.1 deraadt 744:
745: if (argc < 5)
746: nc = MAXTOK;
747: else
748: #ifdef EXPR
749: nc = expr(argv[4]);
750: #else
751: nc = atoi(argv[4]);
752: #endif
753: ap = argv[2]; /* target string */
754: #ifdef EXPR
755: fc = ap + expr(argv[3]); /* first char */
756: #else
757: fc = ap + atoi(argv[3]); /* first char */
758: #endif
759: if (fc >= ap && fc < ap + strlen(ap))
760: for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
761: putback(*k);
762: }
763:
764: /*
765: * map:
766: * map every character of s1 that is specified in from
767: * into s3 and replace in s. (source s1 remains untouched)
768: *
769: * This is a standard implementation of map(s,from,to) function of ICON
770: * language. Within mapvec, we replace every character of "from" with
771: * the corresponding character in "to". If "to" is shorter than "from",
772: * than the corresponding entries are null, which means that those
773: * characters dissapear altogether. Furthermore, imagine
774: * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
775: * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
776: * ultimately maps to `*'. In order to achieve this effect in an efficient
777: * manner (i.e. without multiple passes over the destination string), we
778: * loop over mapvec, starting with the initial source character. if the
779: * character value (dch) in this location is different than the source
780: * character (sch), sch becomes dch, once again to index into mapvec, until
781: * the character value stabilizes (i.e. sch = dch, in other words
782: * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
783: * character, it will stabilize, since mapvec[0] == 0 at all times. At the
784: * end, we restore mapvec* back to normal where mapvec[n] == n for
785: * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
786: * about 5 times faster than any algorithm that makes multiple passes over
787: * destination string.
788: */
1.20 espie 789: static void
1.1 deraadt 790: map(dest, src, from, to)
1.17 espie 791: char *dest;
1.20 espie 792: const char *src;
793: const char *from;
794: const char *to;
1.1 deraadt 795: {
1.20 espie 796: const char *tmp;
1.19 espie 797: unsigned char sch, dch;
798: static unsigned char mapvec[256] = {
799: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
800: 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
801: 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
802: 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
803: 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
804: 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
805: 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
806: 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
807: 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
808: 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
809: 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
810: 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
811: 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
812: 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
813: 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
814: 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
815: 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
816: 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
1.1 deraadt 817: };
818:
819: if (*src) {
820: tmp = from;
821: /*
822: * create a mapping between "from" and
823: * "to"
824: */
825: while (*from)
1.19 espie 826: mapvec[(unsigned char)(*from++)] = (*to) ?
827: (unsigned char)(*to++) : 0;
1.1 deraadt 828:
829: while (*src) {
1.19 espie 830: sch = (unsigned char)(*src++);
1.1 deraadt 831: dch = mapvec[sch];
832: while (dch != sch) {
833: sch = dch;
834: dch = mapvec[sch];
835: }
1.19 espie 836: if ((*dest = (char)dch))
1.1 deraadt 837: dest++;
838: }
839: /*
840: * restore all the changed characters
841: */
842: while (*tmp) {
1.19 espie 843: mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1.1 deraadt 844: tmp++;
845: }
846: }
1.19 espie 847: *dest = '\0';
1.1 deraadt 848: }