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