1 /* $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $ */
2 /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * @(#)eval.c 8.2 (Berkeley) 4/27/95
40 * $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $
41 * $FreeBSD: src/usr.bin/m4/eval.c,v 1.10.2.5 2002/07/15 02:06:15 jmallett Exp $
42 * $DragonFly: src/usr.bin/m4/eval.c,v 1.2 2003/06/17 04:29:28 dillon Exp $
47 * Facility: m4 macro processor
51 #include <sys/types.h>
63 #include "pathnames.h"
65 #define BUILTIN_MARKER "__builtin_"
67 static void dodefn(const char *);
68 static void dopushdef(const char *, const char *);
69 static void dodump(const char *[], int);
70 static void dotrace(const char *[], int, int);
71 static void doifelse(const char *[], int);
72 static int doincl(const char *);
73 static int dopaste(const char *);
74 static void gnu_dochq(const char *[], int);
75 static void dochq(const char *[], int);
76 static void gnu_dochc(const char *[], int);
77 static void dochc(const char *[], int);
78 static void dodiv(int);
79 static void doundiv(const char *[], int);
80 static void dosub(const char *[], int);
81 static void map(char *, const char *, const char *, const char *);
82 static const char *handledash(char *, char *, const char *);
83 static void expand_builtin(const char *[], int, int);
84 static void expand_macro(const char *[], int);
85 static void dump_one_def(ndptr);
87 unsigned long expansion_id;
90 * eval - eval all macros and builtins calls
91 * argc - number of elements in argv.
92 * argv - element vector :
93 * argv[0] = definition of a user
94 * macro or nil if built-in.
95 * argv[1] = name of the macro or
97 * argv[2] = parameters to user-defined
98 * . macro or built-in.
101 * A call in the form of macro-or-builtin() will result in:
103 * argv[1] = macro-or-builtin
106 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
109 eval(const char *argv[], int argc, int td)
115 errx(1, "%s at line %lu: expanding recursive definition for %s",
116 CURRENT_NAME, CURRENT_LINE, argv[1]);
117 if (traced_macros && is_traced(argv[1]))
118 mark = trace(argv, argc, infile+ilevel);
120 expand_macro(argv, argc);
122 expand_builtin(argv, argc, td);
128 * expand_builtin - evaluate built-in macros.
131 expand_builtin(const char *argv[], int argc, int td)
135 static int sysval = 0;
138 printf("argc = %d\n", argc);
139 for (n = 0; n < argc; n++)
140 printf("argv[%d] = %s\n", n, argv[n]);
145 * if argc == 3 and argv[2] is null, then we
146 * have macro-or-builtin() type call. We adjust
147 * argc to avoid further checking..
151 if (argc == 3 && !*(argv[2]))
154 switch (td & TYPEMASK) {
158 dodefine(argv[2], (argc > 3) ? argv[3] : null);
163 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
171 dotrace(argv, argc, 1);
175 dotrace(argv, argc, 0);
180 * doexpr - evaluate arithmetic
184 pbnum(expr(argv[2]));
189 doifelse(argv, argc);
194 * doifdef - select one of two
195 * alternatives based on the existence of
199 if (lookup(argv[2]) != nil)
208 * dolen - find the length of the
211 pbnum((argc > 2) ? strlen(argv[2]) : 0);
216 * doincr - increment the value of the
220 pbnum(atoi(argv[2]) + 1);
225 * dodecr - decrement the value of the
229 pbnum(atoi(argv[2]) - 1);
234 * dosys - execute system command
237 sysval = system(argv[2]);
242 * dosysval - return value of the last
255 if (!doincl(argv[2]))
256 err(1, "%s at line %lu: include(%s)",
257 CURRENT_NAME, CURRENT_LINE, argv[2]);
262 (void) doincl(argv[2]);
267 if (!dopaste(argv[2]))
268 err(1, "%s at line %lu: paste(%s)",
269 CURRENT_NAME, CURRENT_LINE, argv[2]);
274 (void) dopaste(argv[2]);
293 * dosub - select substring
302 * doshift - push back all arguments
303 * except the first one (i.e. skip
307 for (n = argc - 1; n > 3; n--) {
320 if (argc > 2 && (n = atoi(argv[2])) != 0)
334 * dodivnum - return the number of
335 * current output diversion
342 * doundefine - undefine a previously
343 * defined macro(s) or m4 keyword(s).
346 for (n = 2; n < argc; n++)
347 remhash(argv[n], ALL);
352 * dopopdef - remove the topmost
353 * definitions of macro(s) or m4
357 for (n = 2; n < argc; n++)
358 remhash(argv[n], TOP);
363 * dotemp - create a temporary file
369 temp = xstrdup(argv[2]);
374 "%s at line %lu: couldn't make temp file %s",
375 CURRENT_NAME, CURRENT_LINE, argv[2]);
384 * dotranslit - replace all characters in
385 * the source string that appears in the
386 * "from" string with the corresponding
387 * characters in the "to" string.
392 temp = xalloc(strlen(argv[2])+1);
394 map(temp, argv[2], argv[3], argv[4]);
396 map(temp, argv[2], argv[3], null);
405 * doindex - find the index of the second
406 * argument string in the first argument
407 * string. -1 if not present.
409 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
414 * doerrp - print the arguments to stderr
418 for (n = 2; n < argc; n++)
419 fprintf(stderr, "%s ", argv[n]);
420 fprintf(stderr, "\n");
426 * dodnl - eat-up-to and including
429 while ((c = gpbc()) != '\n' && c != EOF)
435 * dom4wrap - set up for
436 * wrap-up/wind-down activity
438 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
443 * doexit - immediate exit from m4.
446 exit((argc > 2) ? atoi(argv[2]) : 0);
451 for (n = 2; n < argc; n++)
455 case INDIRTYPE: /* Indirect call */
460 case BUILTINTYPE: /* Builtins only */
462 dobuiltin(argv, argc);
467 dopatsubst(argv, argc);
471 doregexp(argv, argc);
474 doprintlineno(infile+ilevel);
477 doprintfilename(infile+ilevel);
485 errx(1, "%s at line %lu: eval: major botch.",
486 CURRENT_NAME, CURRENT_LINE);
492 * expand_macro - user-defined macro expansion
495 expand_macro(const char *argv[], int argc)
502 t = argv[0]; /* defn string as a whole */
506 p--; /* last character of defn */
508 if (*(p - 1) != ARGFLAG)
526 if ((argno = *p - '0') < argc - 1)
527 pbstr(argv[argno + 1]);
531 for (n = argc - 1; n > 2; n--) {
540 for (n = argc - 1; n > 2; n--) {
560 if (p == t) /* do last character */
565 * dodefine - install definition in the table
568 dodefine(const char *name, const char *defn)
574 errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
576 if ((p = lookup(name)) == nil)
578 else if (p->defn != null)
579 free((char *) p->defn);
580 if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
581 n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
583 p->type = n & TYPEMASK;
584 if ((n & NOARGS) == 0)
586 p->defn = xstrdup(null);
591 p->defn = xstrdup(null);
593 p->defn = xstrdup(defn);
595 if (STREQ(name, defn))
600 * dodefn - push back a quoted definition of
604 dodefn(const char *name)
609 if ((p = lookup(name)) != nil) {
610 if (p->defn != null) {
614 } else if ((real = builtin_realname(p->type)) != NULL) {
616 pbstr(BUILTIN_MARKER);
622 * dopushdef - install a definition in the hash table
623 * without removing a previous definition. Since
624 * each new entry is entered in *front* of the
625 * hash bucket, it hides a previous definition from
629 dopushdef(const char *name, const char *defn)
634 errx(1, "%s at line %lu: null definition", CURRENT_NAME,
638 p->defn = xstrdup(null);
640 p->defn = xstrdup(defn);
642 if (STREQ(name, defn))
647 * dump_one_def - dump the specified definition.
650 dump_one_def(ndptr p)
655 if ((p->type & TYPEMASK) == MACRTYPE)
656 fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
658 real = builtin_realname(p->type);
661 fprintf(traceout, "%s:\t<%s>\n", p->name, real);
664 fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
668 * dodumpdef - dump the specified definitions in the hash
669 * table to stderr. If nothing is specified, the entire
670 * hash table is dumped.
673 dodump(const char *argv[], int argc)
679 for (n = 2; n < argc; n++)
680 if ((p = lookup(argv[n])) != nil)
683 for (n = 0; n < HASHSIZE; n++)
684 for (p = hashtab[n]; p != nil; p = p->nxtptr)
690 * dotrace - mark some macros as traced/untraced depending upon on.
693 dotrace(const char *argv[], int argc, int on)
698 for (n = 2; n < argc; n++)
699 mark_traced(argv[n], on);
701 mark_traced(NULL, on);
705 * doifelse - select one of two alternatives - loop.
708 doifelse(const char *argv[], int argc)
711 if (STREQ(argv[2], argv[3]))
725 * doinclude - include a given file.
728 doincl(const char *ifile)
730 if (ilevel + 1 == MAXINP)
731 errx(1, "%s at line %lu: too many include files.",
732 CURRENT_NAME, CURRENT_LINE);
733 if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
735 if ((inname[ilevel] = strdup(ifile)) == NULL)
737 inlineno[ilevel] = 1;
738 bbase[ilevel] = bufbase = bp;
747 * dopaste - include a given file without any
751 dopaste(const char *pfile)
756 if ((pf = fopen(pfile, "r")) != NULL) {
757 fprintf(active, "#line 1 \"%s\"\n", pfile);
758 while ((c = getc(pf)) != EOF)
769 gnu_dochq(const char *argv[], int ac)
771 /* In gnu-m4 mode, the only way to restore quotes is to have no
772 * arguments at all. */
774 lquote[0] = LQUOTE, lquote[1] = EOS;
775 rquote[0] = RQUOTE, rquote[1] = EOS;
777 strlcpy(lquote, argv[2], sizeof(lquote));
779 strlcpy(rquote, argv[3], sizeof(rquote));
786 * dochq - change quote characters
789 dochq(const char *argv[], int argc)
793 strlcpy(lquote, argv[2], sizeof(lquote));
800 strlcpy(rquote, argv[3], sizeof(rquote));
802 strcpy(rquote, lquote);
804 lquote[0] = LQUOTE, lquote[1] = EOS;
805 rquote[0] = RQUOTE, rquote[1] = EOS;
810 gnu_dochc(const char *argv[], int ac)
812 /* In gnu-m4 mode, no arguments mean no comment
813 * arguments at all. */
819 strlcpy(scommt, argv[2], sizeof(scommt));
821 scommt[0] = SCOMMT, scommt[1] = EOS;
822 if(ac > 3 && *argv[3])
823 strlcpy(ecommt, argv[3], sizeof(ecommt));
825 ecommt[0] = ECOMMT, ecommt[1] = EOS;
829 * dochc - change comment characters
832 dochc(const char *argv[], int argc)
836 strlcpy(scommt, argv[2], sizeof(scommt));
839 strlcpy(ecommt, argv[3], sizeof(ecommt));
842 ecommt[0] = ECOMMT, ecommt[1] = EOS;
845 scommt[0] = SCOMMT, scommt[1] = EOS;
846 ecommt[0] = ECOMMT, ecommt[1] = EOS;
851 * dodivert - divert the output to a temporary file
863 n = 0; /* bitbucket */
867 n = 0; /* bitbucket */
868 if (outfile[n] == NULL) {
869 char fname[] = _PATH_DIVNAME;
871 if ((fd = mkstemp(fname)) < 0 ||
872 (outfile[n] = fdopen(fd, "w+")) == NULL)
873 err(1, "%s: cannot divert", fname);
874 if (unlink(fname) == -1)
875 err(1, "%s: cannot unlink", fname);
881 * doundivert - undivert a specified output, or all
882 * other outputs, in numerical order.
885 doundiv(const char *argv[], int argc)
891 for (ind = 2; ind < argc; ind++) {
893 if (n > 0 && n < maxout && outfile[n] != NULL)
899 for (n = 1; n < maxout; n++)
900 if (outfile[n] != NULL)
905 * dosub - select substring
908 dosub(const char *argv[], int argc)
910 const char *ap, *fc, *k;
913 ap = argv[2]; /* target string */
915 fc = ap + expr(argv[3]); /* first char */
917 fc = ap + atoi(argv[3]); /* first char */
922 nc = min(nc, expr(argv[4]));
924 nc = min(nc, atoi(argv[4]));
926 if (fc >= ap && fc < ap + strlen(ap))
927 for (k = fc + nc - 1; k >= fc; k--)
933 * map every character of s1 that is specified in from
934 * into s3 and replace in s. (source s1 remains untouched)
936 * This is a standard implementation of map(s,from,to) function of ICON
937 * language. Within mapvec, we replace every character of "from" with
938 * the corresponding character in "to". If "to" is shorter than "from",
939 * than the corresponding entries are null, which means that those
940 * characters dissapear altogether. Furthermore, imagine
941 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
942 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
943 * ultimately maps to `*'. In order to achieve this effect in an efficient
944 * manner (i.e. without multiple passes over the destination string), we
945 * loop over mapvec, starting with the initial source character. if the
946 * character value (dch) in this location is different than the source
947 * character (sch), sch becomes dch, once again to index into mapvec, until
948 * the character value stabilizes (i.e. sch = dch, in other words
949 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
950 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
951 * end, we restore mapvec* back to normal where mapvec[n] == n for
952 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
953 * about 5 times faster than any algorithm that makes multiple passes over
954 * destination string.
957 map(char *dest, const char *src, const char *from, const char *to)
960 unsigned char sch, dch;
961 static char frombis[257];
962 static char tobis[257];
963 static unsigned char mapvec[256] = {
964 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
965 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
966 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
967 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
968 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
969 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
970 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
971 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
972 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
973 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
974 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
975 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
976 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
977 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
978 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
979 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
980 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
981 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
987 * expand character ranges on the fly
989 from = handledash(frombis, frombis + 256, from);
990 to = handledash(tobis, tobis + 256, to);
994 * create a mapping between "from" and
998 mapvec[(unsigned char)(*from++)] = (*to) ?
999 (unsigned char)(*to++) : 0;
1002 sch = (unsigned char)(*src++);
1004 while (dch != sch) {
1008 if ((*dest = (char)dch))
1012 * restore all the changed characters
1015 mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1025 * use buffer to copy the src string, expanding character ranges
1029 handledash(char *buffer, char *end, const char *src)
1035 if (src[1] == '-' && src[2]) {
1037 for (i = (unsigned char)src[0];
1038 i <= (unsigned char)src[2]; i++) {