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