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