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