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