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