eval.c revision 1590
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
23 *
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
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 6/6/93";
39#endif /* not lint */
40
41/*
42 * eval.c
43 * Facility: m4 macro processor
44 * by: oz
45 */
46
47#include <sys/types.h>
48#include <errno.h>
49#include <unistd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include "mdef.h"
54#include "stdd.h"
55#include "extern.h"
56#include "pathnames.h"
57
58/*
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
65 *				  built-in.
66 *			argv[2] = parameters to user-defined
67 *			   .	  macro or built-in.
68 *			   .
69 *
70 * Note that the minimum value for argc is 3. A call in the form
71 * of macro-or-builtin() will result in:
72 *			argv[0] = nullstr
73 *			argv[1] = macro-or-builtin
74 *			argv[2] = nullstr
75 */
76
77void
78eval(argv, argc, td)
79register char *argv[];
80register int argc;
81register int td;
82{
83	register int c, n;
84	static int sysval = 0;
85
86#ifdef DEBUG
87	printf("argc = %d\n", argc);
88	for (n = 0; n < argc; n++)
89		printf("argv[%d] = %s\n", n, argv[n]);
90#endif
91 /*
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..
95  */
96	if (argc == 3 && !*(argv[2]))
97		argc--;
98
99	switch (td & ~STATIC) {
100
101	case DEFITYPE:
102		if (argc > 2)
103			dodefine(argv[2], (argc > 3) ? argv[3] : null);
104		break;
105
106	case PUSDTYPE:
107		if (argc > 2)
108			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
109		break;
110
111	case DUMPTYPE:
112		dodump(argv, argc);
113		break;
114
115	case EXPRTYPE:
116	/*
117	 * doexpr - evaluate arithmetic
118	 * expression
119	 */
120		if (argc > 2)
121			pbnum(expr(argv[2]));
122		break;
123
124	case IFELTYPE:
125		if (argc > 4)
126			doifelse(argv, argc);
127		break;
128
129	case IFDFTYPE:
130	/*
131	 * doifdef - select one of two
132	 * alternatives based on the existence of
133	 * another definition
134	 */
135		if (argc > 3) {
136			if (lookup(argv[2]) != nil)
137				pbstr(argv[3]);
138			else if (argc > 4)
139				pbstr(argv[4]);
140		}
141		break;
142
143	case LENGTYPE:
144	/*
145	 * dolen - find the length of the
146	 * argument
147	 */
148		if (argc > 2)
149			pbnum((argc > 2) ? strlen(argv[2]) : 0);
150		break;
151
152	case INCRTYPE:
153	/*
154	 * doincr - increment the value of the
155	 * argument
156	 */
157		if (argc > 2)
158			pbnum(atoi(argv[2]) + 1);
159		break;
160
161	case DECRTYPE:
162	/*
163	 * dodecr - decrement the value of the
164	 * argument
165	 */
166		if (argc > 2)
167			pbnum(atoi(argv[2]) - 1);
168		break;
169
170	case SYSCTYPE:
171	/*
172	 * dosys - execute system command
173	 */
174		if (argc > 2)
175			sysval = system(argv[2]);
176		break;
177
178	case SYSVTYPE:
179	/*
180	 * dosysval - return value of the last
181	 * system call.
182	 *
183	 */
184		pbnum(sysval);
185		break;
186
187	case INCLTYPE:
188		if (argc > 2)
189			if (!doincl(argv[2]))
190				oops("%s: %s", argv[2], strerror(errno));
191		break;
192
193	case SINCTYPE:
194		if (argc > 2)
195			(void) doincl(argv[2]);
196		break;
197#ifdef EXTENDED
198	case PASTTYPE:
199		if (argc > 2)
200			if (!dopaste(argv[2]))
201				oops("%s: %s", argv[2], strerror(errno));
202		break;
203
204	case SPASTYPE:
205		if (argc > 2)
206			(void) dopaste(argv[2]);
207		break;
208#endif
209	case CHNQTYPE:
210		dochq(argv, argc);
211		break;
212
213	case CHNCTYPE:
214		dochc(argv, argc);
215		break;
216
217	case SUBSTYPE:
218	/*
219	 * dosub - select substring
220	 *
221	 */
222		if (argc > 3)
223			dosub(argv, argc);
224		break;
225
226	case SHIFTYPE:
227	/*
228	 * doshift - push back all arguments
229	 * except the first one (i.e. skip
230	 * argv[2])
231	 */
232		if (argc > 3) {
233			for (n = argc - 1; n > 3; n--) {
234				putback(rquote);
235				pbstr(argv[n]);
236				putback(lquote);
237				putback(',');
238			}
239			putback(rquote);
240			pbstr(argv[3]);
241			putback(lquote);
242		}
243		break;
244
245	case DIVRTYPE:
246		if (argc > 2 && (n = atoi(argv[2])) != 0)
247			dodiv(n);
248		else {
249			active = stdout;
250			oindex = 0;
251		}
252		break;
253
254	case UNDVTYPE:
255		doundiv(argv, argc);
256		break;
257
258	case DIVNTYPE:
259	/*
260	 * dodivnum - return the number of
261	 * current output diversion
262	 */
263		pbnum(oindex);
264		break;
265
266	case UNDFTYPE:
267	/*
268	 * doundefine - undefine a previously
269	 * defined macro(s) or m4 keyword(s).
270	 */
271		if (argc > 2)
272			for (n = 2; n < argc; n++)
273				remhash(argv[n], ALL);
274		break;
275
276	case POPDTYPE:
277	/*
278	 * dopopdef - remove the topmost
279	 * definitions of macro(s) or m4
280	 * keyword(s).
281	 */
282		if (argc > 2)
283			for (n = 2; n < argc; n++)
284				remhash(argv[n], TOP);
285		break;
286
287	case MKTMTYPE:
288	/*
289	 * dotemp - create a temporary file
290	 */
291		if (argc > 2)
292			pbstr(mktemp(argv[2]));
293		break;
294
295	case TRNLTYPE:
296	/*
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.
301	 */
302		if (argc > 3) {
303			char temp[MAXTOK];
304			if (argc > 4)
305				map(temp, argv[2], argv[3], argv[4]);
306			else
307				map(temp, argv[2], argv[3], null);
308			pbstr(temp);
309		}
310		else if (argc > 2)
311			pbstr(argv[2]);
312		break;
313
314	case INDXTYPE:
315	/*
316	 * doindex - find the index of the second
317	 * argument string in the first argument
318	 * string. -1 if not present.
319	 */
320		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
321		break;
322
323	case ERRPTYPE:
324	/*
325	 * doerrp - print the arguments to stderr
326	 * file
327	 */
328		if (argc > 2) {
329			for (n = 2; n < argc; n++)
330				fprintf(stderr, "%s ", argv[n]);
331			fprintf(stderr, "\n");
332		}
333		break;
334
335	case DNLNTYPE:
336	/*
337	 * dodnl - eat-up-to and including
338	 * newline
339	 */
340		while ((c = gpbc()) != '\n' && c != EOF)
341			;
342		break;
343
344	case M4WRTYPE:
345	/*
346	 * dom4wrap - set up for
347	 * wrap-up/wind-down activity
348	 */
349		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
350		break;
351
352	case EXITTYPE:
353	/*
354	 * doexit - immediate exit from m4.
355	 */
356		exit((argc > 2) ? atoi(argv[2]) : 0);
357		break;
358
359	case DEFNTYPE:
360		if (argc > 2)
361			for (n = 2; n < argc; n++)
362				dodefn(argv[n]);
363		break;
364
365	default:
366		oops("%s: major botch.", "eval");
367		break;
368	}
369}
370
371char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
372
373/*
374 * expand - user-defined macro expansion
375 */
376void
377expand(argv, argc)
378register char *argv[];
379register int argc;
380{
381	register char *t;
382	register char *p;
383	register int n;
384	register int argno;
385
386	t = argv[0];		       /* defn string as a whole */
387	p = t;
388	while (*p)
389		p++;
390	p--;			       /* last character of defn */
391	while (p > t) {
392		if (*(p - 1) != ARGFLAG)
393			putback(*p);
394		else {
395			switch (*p) {
396
397			case '#':
398				pbnum(argc - 2);
399				break;
400			case '0':
401			case '1':
402			case '2':
403			case '3':
404			case '4':
405			case '5':
406			case '6':
407			case '7':
408			case '8':
409			case '9':
410				if ((argno = *p - '0') < argc - 1)
411					pbstr(argv[argno + 1]);
412				break;
413			case '*':
414				for (n = argc - 1; n > 2; n--) {
415					pbstr(argv[n]);
416					putback(',');
417				}
418				pbstr(argv[2]);
419				break;
420			default:
421				putback(*p);
422				putback('$');
423				break;
424			}
425			p--;
426		}
427		p--;
428	}
429	if (p == t)		       /* do last character */
430		putback(*p);
431}
432
433/*
434 * dodefine - install definition in the table
435 */
436void
437dodefine(name, defn)
438register char *name;
439register char *defn;
440{
441	register ndptr p;
442
443	if (!*name)
444		oops("null definition.");
445	if (STREQ(name, defn))
446		oops("%s: recursive definition.", name);
447	if ((p = lookup(name)) == nil)
448		p = addent(name);
449	else if (p->defn != null)
450		free((char *) p->defn);
451	if (!*defn)
452		p->defn = null;
453	else
454		p->defn = xstrdup(defn);
455	p->type = MACRTYPE;
456}
457
458/*
459 * dodefn - push back a quoted definition of
460 *      the given name.
461 */
462void
463dodefn(name)
464char *name;
465{
466	register ndptr p;
467
468	if ((p = lookup(name)) != nil && p->defn != null) {
469		putback(rquote);
470		pbstr(p->defn);
471		putback(lquote);
472	}
473}
474
475/*
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
480 *      lookup.
481 */
482void
483dopushdef(name, defn)
484register char *name;
485register char *defn;
486{
487	register ndptr p;
488
489	if (!*name)
490		oops("null definition");
491	if (STREQ(name, defn))
492		oops("%s: recursive definition.", name);
493	p = addent(name);
494	if (!*defn)
495		p->defn = null;
496	else
497		p->defn = xstrdup(defn);
498	p->type = MACRTYPE;
499}
500
501/*
502 * dodumpdef - dump the specified definitions in the hash
503 *      table to stderr. If nothing is specified, the entire
504 *      hash table is dumped.
505 */
506void
507dodump(argv, argc)
508register char *argv[];
509register int argc;
510{
511	register int n;
512	ndptr p;
513
514	if (argc > 2) {
515		for (n = 2; n < argc; n++)
516			if ((p = lookup(argv[n])) != nil)
517				fprintf(stderr, dumpfmt, p->name,
518					p->defn);
519	}
520	else {
521		for (n = 0; n < HASHSIZE; n++)
522			for (p = hashtab[n]; p != nil; p = p->nxtptr)
523				fprintf(stderr, dumpfmt, p->name,
524					p->defn);
525	}
526}
527
528/*
529 * doifelse - select one of two alternatives - loop.
530 */
531void
532doifelse(argv, argc)
533register char *argv[];
534register int argc;
535{
536	cycle {
537		if (STREQ(argv[2], argv[3]))
538			pbstr(argv[4]);
539		else if (argc == 6)
540			pbstr(argv[5]);
541		else if (argc > 6) {
542			argv += 3;
543			argc -= 3;
544			continue;
545		}
546		break;
547	}
548}
549
550/*
551 * doinclude - include a given file.
552 */
553int
554doincl(ifile)
555char *ifile;
556{
557	if (ilevel + 1 == MAXINP)
558		oops("too many include files.");
559	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
560		ilevel++;
561		bbase[ilevel] = bufbase = bp;
562		return (1);
563	}
564	else
565		return (0);
566}
567
568#ifdef EXTENDED
569/*
570 * dopaste - include a given file without any
571 *           macro processing.
572 */
573int
574dopaste(pfile)
575char *pfile;
576{
577	FILE *pf;
578	register int c;
579
580	if ((pf = fopen(pfile, "r")) != NULL) {
581		while ((c = getc(pf)) != EOF)
582			putc(c, active);
583		(void) fclose(pf);
584		return (1);
585	}
586	else
587		return (0);
588}
589#endif
590
591/*
592 * dochq - change quote characters
593 */
594void
595dochq(argv, argc)
596register char *argv[];
597register int argc;
598{
599	if (argc > 2) {
600		if (*argv[2])
601			lquote = *argv[2];
602		if (argc > 3) {
603			if (*argv[3])
604				rquote = *argv[3];
605		}
606		else
607			rquote = lquote;
608	}
609	else {
610		lquote = LQUOTE;
611		rquote = RQUOTE;
612	}
613}
614
615/*
616 * dochc - change comment characters
617 */
618void
619dochc(argv, argc)
620register char *argv[];
621register int argc;
622{
623	if (argc > 2) {
624		if (*argv[2])
625			scommt = *argv[2];
626		if (argc > 3) {
627			if (*argv[3])
628				ecommt = *argv[3];
629		}
630		else
631			ecommt = ECOMMT;
632	}
633	else {
634		scommt = SCOMMT;
635		ecommt = ECOMMT;
636	}
637}
638
639/*
640 * dodivert - divert the output to a temporary file
641 */
642void
643dodiv(n)
644register int n;
645{
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);
652	}
653	oindex = n;
654	active = outfile[n];
655}
656
657/*
658 * doundivert - undivert a specified output, or all
659 *              other outputs, in numerical order.
660 */
661void
662doundiv(argv, argc)
663register char *argv[];
664register int argc;
665{
666	register int ind;
667	register int n;
668
669	if (argc > 2) {
670		for (ind = 2; ind < argc; ind++) {
671			n = atoi(argv[ind]);
672			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
673				getdiv(n);
674
675		}
676	}
677	else
678		for (n = 1; n < MAXOUT; n++)
679			if (outfile[n] != NULL)
680				getdiv(n);
681}
682
683/*
684 * dosub - select substring
685 */
686void
687dosub(argv, argc)
688register char *argv[];
689register int argc;
690{
691	register char *ap, *fc, *k;
692	register int nc;
693
694	if (argc < 5)
695		nc = MAXTOK;
696	else
697#ifdef EXPR
698		nc = expr(argv[4]);
699#else
700		nc = atoi(argv[4]);
701#endif
702	ap = argv[2];		       /* target string */
703#ifdef EXPR
704	fc = ap + expr(argv[3]);       /* first char */
705#else
706	fc = ap + atoi(argv[3]);       /* first char */
707#endif
708	if (fc >= ap && fc < ap + strlen(ap))
709		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
710			putback(*k);
711}
712
713/*
714 * map:
715 * map every character of s1 that is specified in from
716 * into s3 and replace in s. (source s1 remains untouched)
717 *
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.
737 */
738void
739map(dest, src, from, to)
740register char *dest;
741register char *src;
742register char *from;
743register char *to;
744{
745	register char *tmp;
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
759	};
760
761	if (*src) {
762		tmp = from;
763	/*
764	 * create a mapping between "from" and
765	 * "to"
766	 */
767		while (*from)
768			mapvec[*from++] = (*to) ? *to++ : (char) 0;
769
770		while (*src) {
771			sch = *src++;
772			dch = mapvec[sch];
773			while (dch != sch) {
774				sch = dch;
775				dch = mapvec[sch];
776			}
777			if (*dest = dch)
778				dest++;
779		}
780	/*
781	 * restore all the changed characters
782	 */
783		while (*tmp) {
784			mapvec[*tmp] = *tmp;
785			tmp++;
786		}
787	}
788	*dest = (char) 0;
789}
790