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