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