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