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