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