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