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