2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93";
43 * Facility: m4 macro processor
47 #include <sys/types.h>
56 #include "pathnames.h"
59 * eval - evaluate built-in macros.
60 * argc - number of elements in argv.
61 * argv - element vector :
62 * argv[0] = definition of a user
63 * macro or nil if built-in.
64 * argv[1] = name of the macro or
66 * argv[2] = parameters to user-defined
67 * . macro or built-in.
70 * Note that the minimum value for argc is 3. A call in the form
71 * of macro-or-builtin() will result in:
73 * argv[1] = macro-or-builtin
79 register char *argv[];
84 static int sysval = 0;
87 printf("argc = %d\n", argc);
88 for (n = 0; n < argc; n++)
89 printf("argv[%d] = %s\n", n, argv[n]);
92 * if argc == 3 and argv[2] is null, then we
93 * have macro-or-builtin() type call. We adjust
94 * argc to avoid further checking..
96 if (argc == 3 && !*(argv[2]))
99 switch (td & ~STATIC) {
103 dodefine(argv[2], (argc > 3) ? argv[3] : null);
108 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
117 * doexpr - evaluate arithmetic
121 pbnum(expr(argv[2]));
126 doifelse(argv, argc);
131 * doifdef - select one of two
132 * alternatives based on the existence of
136 if (lookup(argv[2]) != nil)
145 * dolen - find the length of the
149 pbnum((argc > 2) ? strlen(argv[2]) : 0);
154 * doincr - increment the value of the
158 pbnum(atoi(argv[2]) + 1);
163 * dodecr - decrement the value of the
167 pbnum(atoi(argv[2]) - 1);
172 * dosys - execute system command
175 sysval = system(argv[2]);
180 * dosysval - return value of the last
189 if (!doincl(argv[2]))
190 oops("%s: %s", argv[2], strerror(errno));
195 (void) doincl(argv[2]);
200 if (!dopaste(argv[2]))
201 oops("%s: %s", argv[2], strerror(errno));
206 (void) dopaste(argv[2]);
219 * dosub - select substring
228 * doshift - push back all arguments
229 * except the first one (i.e. skip
233 for (n = argc - 1; n > 3; n--) {
246 if (argc > 2 && (n = atoi(argv[2])) != 0)
260 * dodivnum - return the number of
261 * current output diversion
268 * doundefine - undefine a previously
269 * defined macro(s) or m4 keyword(s).
272 for (n = 2; n < argc; n++)
273 remhash(argv[n], ALL);
278 * dopopdef - remove the topmost
279 * definitions of macro(s) or m4
283 for (n = 2; n < argc; n++)
284 remhash(argv[n], TOP);
289 * dotemp - create a temporary file
292 pbstr(mktemp(argv[2]));
297 * dotranslit - replace all characters in
298 * the source string that appears in the
299 * "from" string with the corresponding
300 * characters in the "to" string.
305 map(temp, argv[2], argv[3], argv[4]);
307 map(temp, argv[2], argv[3], null);
316 * doindex - find the index of the second
317 * argument string in the first argument
318 * string. -1 if not present.
320 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
325 * doerrp - print the arguments to stderr
329 for (n = 2; n < argc; n++)
330 fprintf(stderr, "%s ", argv[n]);
331 fprintf(stderr, "\n");
337 * dodnl - eat-up-to and including
340 while ((c = gpbc()) != '\n' && c != EOF)
346 * dom4wrap - set up for
347 * wrap-up/wind-down activity
349 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
354 * doexit - immediate exit from m4.
356 exit((argc > 2) ? atoi(argv[2]) : 0);
361 for (n = 2; n < argc; n++)
366 oops("%s: major botch.", "eval");
371 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
374 * expand - user-defined macro expansion
378 register char *argv[];
386 t = argv[0]; /* defn string as a whole */
390 p--; /* last character of defn */
392 if (*(p - 1) != ARGFLAG)
410 if ((argno = *p - '0') < argc - 1)
411 pbstr(argv[argno + 1]);
414 for (n = argc - 1; n > 2; n--) {
429 if (p == t) /* do last character */
434 * dodefine - install definition in the table
444 oops("null definition.");
445 if (STREQ(name, defn))
446 oops("%s: recursive definition.", name);
447 if ((p = lookup(name)) == nil)
449 else if (p->defn != null)
450 free((char *) p->defn);
454 p->defn = xstrdup(defn);
459 * dodefn - push back a quoted definition of
468 if ((p = lookup(name)) != nil && p->defn != null) {
476 * dopushdef - install a definition in the hash table
477 * without removing a previous definition. Since
478 * each new entry is entered in *front* of the
479 * hash bucket, it hides a previous definition from
483 dopushdef(name, defn)
490 oops("null definition");
491 if (STREQ(name, defn))
492 oops("%s: recursive definition.", name);
497 p->defn = xstrdup(defn);
502 * dodumpdef - dump the specified definitions in the hash
503 * table to stderr. If nothing is specified, the entire
504 * hash table is dumped.
508 register char *argv[];
515 for (n = 2; n < argc; n++)
516 if ((p = lookup(argv[n])) != nil)
517 fprintf(stderr, dumpfmt, p->name,
521 for (n = 0; n < HASHSIZE; n++)
522 for (p = hashtab[n]; p != nil; p = p->nxtptr)
523 fprintf(stderr, dumpfmt, p->name,
529 * doifelse - select one of two alternatives - loop.
533 register char *argv[];
537 if (STREQ(argv[2], argv[3]))
551 * doinclude - include a given file.
557 if (ilevel + 1 == MAXINP)
558 oops("too many include files.");
559 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
561 bbase[ilevel] = bufbase = bp;
570 * dopaste - include a given file without any
580 if ((pf = fopen(pfile, "r")) != NULL) {
581 while ((c = getc(pf)) != EOF)
592 * dochq - change quote characters
596 register char *argv[];
616 * dochc - change comment characters
620 register char *argv[];
640 * dodivert - divert the output to a temporary file
646 if (n < 0 || n >= MAXOUT)
647 n = 0; /* bitbucket */
648 if (outfile[n] == NULL) {
649 m4temp[UNIQUE] = n + '0';
650 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
651 oops("%s: cannot divert.", m4temp);
658 * doundivert - undivert a specified output, or all
659 * other outputs, in numerical order.
663 register char *argv[];
670 for (ind = 2; ind < argc; ind++) {
672 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
678 for (n = 1; n < MAXOUT; n++)
679 if (outfile[n] != NULL)
684 * dosub - select substring
688 register char *argv[];
691 register char *ap, *fc, *k;
702 ap = argv[2]; /* target string */
704 fc = ap + expr(argv[3]); /* first char */
706 fc = ap + atoi(argv[3]); /* first char */
708 if (fc >= ap && fc < ap + strlen(ap))
709 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
715 * map every character of s1 that is specified in from
716 * into s3 and replace in s. (source s1 remains untouched)
718 * This is a standard implementation of map(s,from,to) function of ICON
719 * language. Within mapvec, we replace every character of "from" with
720 * the corresponding character in "to". If "to" is shorter than "from",
721 * than the corresponding entries are null, which means that those
722 * characters dissapear altogether. Furthermore, imagine
723 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
724 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
725 * ultimately maps to `*'. In order to achieve this effect in an efficient
726 * manner (i.e. without multiple passes over the destination string), we
727 * loop over mapvec, starting with the initial source character. if the
728 * character value (dch) in this location is different than the source
729 * character (sch), sch becomes dch, once again to index into mapvec, until
730 * the character value stabilizes (i.e. sch = dch, in other words
731 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
732 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
733 * end, we restore mapvec* back to normal where mapvec[n] == n for
734 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
735 * about 5 times faster than any algorithm that makes multiple passes over
736 * destination string.
739 map(dest, src, from, to)
746 register char sch, dch;
747 static char mapvec[128] = {
748 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
749 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
750 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
751 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
752 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
753 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
754 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
755 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
756 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
757 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
758 120, 121, 122, 123, 124, 125, 126, 127
764 * create a mapping between "from" and
768 mapvec[*from++] = (*to) ? *to++ : (char) 0;
781 * restore all the changed characters