xref: /freebsd/usr.bin/m4/eval.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
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
38 static 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 
77 void
78 eval(argv, argc, td)
79 register char *argv[];
80 register int argc;
81 register 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 		killdiv();
360 		exit((argc > 2) ? atoi(argv[2]) : 0);
361 		break;
362 
363 	case DEFNTYPE:
364 		if (argc > 2)
365 			for (n = 2; n < argc; n++)
366 				dodefn(argv[n]);
367 		break;
368 
369 	default:
370 		oops("%s: major botch.", "eval");
371 		break;
372 	}
373 }
374 
375 char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
376 
377 /*
378  * expand - user-defined macro expansion
379  */
380 void
381 expand(argv, argc)
382 register char *argv[];
383 register int argc;
384 {
385 	register unsigned char *t;
386 	register unsigned char *p;
387 	register int n;
388 	register int argno;
389 
390 	t = argv[0];		       /* defn string as a whole */
391 	p = t;
392 	while (*p)
393 		p++;
394 	p--;			       /* last character of defn */
395 	while (p > t) {
396 		if (*(p - 1) != ARGFLAG)
397 			putback(*p);
398 		else {
399 			switch (*p) {
400 
401 			case '#':
402 				pbnum(argc - 2);
403 				break;
404 			case '0':
405 			case '1':
406 			case '2':
407 			case '3':
408 			case '4':
409 			case '5':
410 			case '6':
411 			case '7':
412 			case '8':
413 			case '9':
414 				if ((argno = *p - '0') < argc - 1)
415 					pbstr(argv[argno + 1]);
416 				break;
417 			case '*':
418 				for (n = argc - 1; n > 2; n--) {
419 					pbstr(argv[n]);
420 					putback(',');
421 				}
422 				pbstr(argv[2]);
423 				break;
424 			default:
425 				putback(*p);
426 				putback('$');
427 				break;
428 			}
429 			p--;
430 		}
431 		p--;
432 	}
433 	if (p == t)		       /* do last character */
434 		putback(*p);
435 }
436 
437 /*
438  * dodefine - install definition in the table
439  */
440 void
441 dodefine(name, defn)
442 register char *name;
443 register char *defn;
444 {
445 	register ndptr p;
446 
447 	if (!*name)
448 		oops("null definition.");
449 	if (STREQ(name, defn))
450 		oops("%s: recursive definition.", name);
451 	if ((p = lookup(name)) == nil)
452 		p = addent(name);
453 	else if (p->defn != null)
454 		free((char *) p->defn);
455 	if (!*defn)
456 		p->defn = null;
457 	else
458 		p->defn = xstrdup(defn);
459 	p->type = MACRTYPE;
460 }
461 
462 /*
463  * dodefn - push back a quoted definition of
464  *      the given name.
465  */
466 void
467 dodefn(name)
468 char *name;
469 {
470 	register ndptr p;
471 
472 	if ((p = lookup(name)) != nil && p->defn != null) {
473 		putback(rquote);
474 		pbstr(p->defn);
475 		putback(lquote);
476 	}
477 }
478 
479 /*
480  * dopushdef - install a definition in the hash table
481  *      without removing a previous definition. Since
482  *      each new entry is entered in *front* of the
483  *      hash bucket, it hides a previous definition from
484  *      lookup.
485  */
486 void
487 dopushdef(name, defn)
488 register char *name;
489 register char *defn;
490 {
491 	register ndptr p;
492 
493 	if (!*name)
494 		oops("null definition");
495 	if (STREQ(name, defn))
496 		oops("%s: recursive definition.", name);
497 	p = addent(name);
498 	if (!*defn)
499 		p->defn = null;
500 	else
501 		p->defn = xstrdup(defn);
502 	p->type = MACRTYPE;
503 }
504 
505 /*
506  * dodumpdef - dump the specified definitions in the hash
507  *      table to stderr. If nothing is specified, the entire
508  *      hash table is dumped.
509  */
510 void
511 dodump(argv, argc)
512 register char *argv[];
513 register int argc;
514 {
515 	register int n;
516 	ndptr p;
517 
518 	if (argc > 2) {
519 		for (n = 2; n < argc; n++)
520 			if ((p = lookup(argv[n])) != nil)
521 				fprintf(stderr, dumpfmt, p->name,
522 					p->defn);
523 	}
524 	else {
525 		for (n = 0; n < HASHSIZE; n++)
526 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
527 				fprintf(stderr, dumpfmt, p->name,
528 					p->defn);
529 	}
530 }
531 
532 /*
533  * doifelse - select one of two alternatives - loop.
534  */
535 void
536 doifelse(argv, argc)
537 register char *argv[];
538 register int argc;
539 {
540 	cycle {
541 		if (STREQ(argv[2], argv[3]))
542 			pbstr(argv[4]);
543 		else if (argc == 6)
544 			pbstr(argv[5]);
545 		else if (argc > 6) {
546 			argv += 3;
547 			argc -= 3;
548 			continue;
549 		}
550 		break;
551 	}
552 }
553 
554 /*
555  * doinclude - include a given file.
556  */
557 int
558 doincl(ifile)
559 char *ifile;
560 {
561 	if (ilevel + 1 == MAXINP)
562 		oops("too many include files.");
563 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
564 		ilevel++;
565 		bbase[ilevel] = bufbase = bp;
566 		return (1);
567 	}
568 	else
569 		return (0);
570 }
571 
572 #ifdef EXTENDED
573 /*
574  * dopaste - include a given file without any
575  *           macro processing.
576  */
577 int
578 dopaste(pfile)
579 char *pfile;
580 {
581 	FILE *pf;
582 	register int c;
583 
584 	if ((pf = fopen(pfile, "r")) != NULL) {
585 		while ((c = getc(pf)) != EOF)
586 			putc(c, active);
587 		(void) fclose(pf);
588 		return (1);
589 	}
590 	else
591 		return (0);
592 }
593 #endif
594 
595 /*
596  * dochq - change quote characters
597  */
598 void
599 dochq(argv, argc)
600 register char *argv[];
601 register int argc;
602 {
603 	if (argc > 2) {
604 		if (*argv[2])
605 			lquote = *argv[2];
606 		if (argc > 3) {
607 			if (*argv[3])
608 				rquote = *argv[3];
609 		}
610 		else
611 			rquote = lquote;
612 	}
613 	else {
614 		lquote = LQUOTE;
615 		rquote = RQUOTE;
616 	}
617 }
618 
619 /*
620  * dochc - change comment characters
621  */
622 void
623 dochc(argv, argc)
624 register char *argv[];
625 register int argc;
626 {
627 	if (argc > 2) {
628 		if (*argv[2])
629 			scommt = *argv[2];
630 		if (argc > 3) {
631 			if (*argv[3])
632 				ecommt = *argv[3];
633 		}
634 		else
635 			ecommt = ECOMMT;
636 	}
637 	else {
638 		scommt = SCOMMT;
639 		ecommt = ECOMMT;
640 	}
641 }
642 
643 /*
644  * dodivert - divert the output to a temporary file
645  */
646 void
647 dodiv(n)
648 register int n;
649 {
650 	if (n < 0 || n >= MAXOUT)
651 		n = 0;		       /* bitbucket */
652 	if (outfile[n] == NULL) {
653 		m4temp[UNIQUE] = n + '0';
654 		if ((outfile[n] = fopen(m4temp, "w")) == NULL)
655 			oops("%s: cannot divert.", m4temp);
656 	}
657 	oindex = n;
658 	active = outfile[n];
659 }
660 
661 /*
662  * doundivert - undivert a specified output, or all
663  *              other outputs, in numerical order.
664  */
665 void
666 doundiv(argv, argc)
667 register char *argv[];
668 register int argc;
669 {
670 	register int ind;
671 	register int n;
672 
673 	if (argc > 2) {
674 		for (ind = 2; ind < argc; ind++) {
675 			n = atoi(argv[ind]);
676 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
677 				getdiv(n);
678 
679 		}
680 	}
681 	else
682 		for (n = 1; n < MAXOUT; n++)
683 			if (outfile[n] != NULL)
684 				getdiv(n);
685 }
686 
687 /*
688  * dosub - select substring
689  */
690 void
691 dosub(argv, argc)
692 register char *argv[];
693 register int argc;
694 {
695 	register unsigned char *ap, *fc, *k;
696 	register int nc;
697 
698 	if (argc < 5)
699 		nc = MAXTOK;
700 	else
701 #ifdef EXPR
702 		nc = expr(argv[4]);
703 #else
704 		nc = atoi(argv[4]);
705 #endif
706 	ap = argv[2];		       /* target string */
707 #ifdef EXPR
708 	fc = ap + expr(argv[3]);       /* first char */
709 #else
710 	fc = ap + atoi(argv[3]);       /* first char */
711 #endif
712 	if (fc >= ap && fc < ap + strlen(ap))
713 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
714 			putback(*k);
715 }
716 
717 /*
718  * map:
719  * map every character of s1 that is specified in from
720  * into s3 and replace in s. (source s1 remains untouched)
721  *
722  * This is a standard implementation of map(s,from,to) function of ICON
723  * language. Within mapvec, we replace every character of "from" with
724  * the corresponding character in "to". If "to" is shorter than "from",
725  * than the corresponding entries are null, which means that those
726  * characters dissapear altogether. Furthermore, imagine
727  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
728  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
729  * ultimately maps to `*'. In order to achieve this effect in an efficient
730  * manner (i.e. without multiple passes over the destination string), we
731  * loop over mapvec, starting with the initial source character. if the
732  * character value (dch) in this location is different than the source
733  * character (sch), sch becomes dch, once again to index into mapvec, until
734  * the character value stabilizes (i.e. sch = dch, in other words
735  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
736  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
737  * end, we restore mapvec* back to normal where mapvec[n] == n for
738  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
739  * about 5 times faster than any algorithm that makes multiple passes over
740  * destination string.
741  */
742 void
743 map(dest, src, from, to)
744 register char *dest;
745 register char *src;
746 register char *from;
747 register char *to;
748 {
749 	register char *tmp;
750 	register char sch, dch;
751 	static char mapvec[128] = {
752 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
753 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
754 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
755 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
756 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
757 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
758 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
759 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
760 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
761 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
762 		120, 121, 122, 123, 124, 125, 126, 127
763 	};
764 
765 	if (*src) {
766 		tmp = from;
767 	/*
768 	 * create a mapping between "from" and
769 	 * "to"
770 	 */
771 		while (*from)
772 			mapvec[*from++] = (*to) ? *to++ : (char) 0;
773 
774 		while (*src) {
775 			sch = *src++;
776 			dch = mapvec[sch];
777 			while (dch != sch) {
778 				sch = dch;
779 				dch = mapvec[sch];
780 			}
781 			if (*dest = dch)
782 				dest++;
783 		}
784 	/*
785 	 * restore all the changed characters
786 	 */
787 		while (*tmp) {
788 			mapvec[*tmp] = *tmp;
789 			tmp++;
790 		}
791 	}
792 	*dest = (char) 0;
793 }
794