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