xref: /netbsd-src/usr.bin/m4/eval.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg 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 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)eval.c	8.2 (Berkeley) 4/27/95";
43 #else
44 __RCSID("$NetBSD: eval.c,v 1.11 1999/04/20 08:05:51 mrg Exp $");
45 #endif
46 #endif /* not lint */
47 
48 /*
49  * eval.c
50  * Facility: m4 macro processor
51  * by: oz
52  */
53 
54 #include <sys/types.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <unistd.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include "mdef.h"
62 #include "stdd.h"
63 #include "extern.h"
64 #include "pathnames.h"
65 
66 /*
67  * eval - evaluate built-in macros.
68  *	  argc - number of elements in argv.
69  *	  argv - element vector :
70  *			argv[0] = definition of a user
71  *				  macro or nil if built-in.
72  *			argv[1] = name of the macro or
73  *				  built-in.
74  *			argv[2] = parameters to user-defined
75  *			   .	  macro or built-in.
76  *			   .
77  *
78  * Note that the minimum value for argc is 3. A call in the form
79  * of macro-or-builtin() will result in:
80  *			argv[0] = nullstr
81  *			argv[1] = macro-or-builtin
82  *			argv[2] = nullstr
83  */
84 
85 void
86 eval(argv, argc, td)
87 	char *argv[];
88 	int argc;
89 	int td;
90 {
91 	int c, n;
92 	static int sysval = 0;
93 
94 #ifdef DEBUG
95 	printf("argc = %d\n", argc);
96 	for (n = 0; n < argc; n++)
97 		printf("argv[%d] = %s\n", n, argv[n]);
98 #endif
99  /*
100   * if argc == 3 and argv[2] is null, then we
101   * have macro-or-builtin() type call. We adjust
102   * argc to avoid further checking..
103   */
104 	if (argc == 3 && !*(argv[2]))
105 		argc--;
106 
107 	switch (td & ~STATIC) {
108 
109 	case DEFITYPE:
110 		if (argc > 2)
111 			dodefine(argv[2], (argc > 3) ? argv[3] : null);
112 		break;
113 
114 	case PUSDTYPE:
115 		if (argc > 2)
116 			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
117 		break;
118 
119 	case DUMPTYPE:
120 		dodump(argv, argc);
121 		break;
122 
123 	case EXPRTYPE:
124 	/*
125 	 * doexpr - evaluate arithmetic
126 	 * expression
127 	 */
128 		if (argc > 2)
129 			pbnum(expr(argv[2]));
130 		break;
131 
132 	case IFELTYPE:
133 		if (argc > 4)
134 			doifelse(argv, argc);
135 		break;
136 
137 	case IFDFTYPE:
138 	/*
139 	 * doifdef - select one of two
140 	 * alternatives based on the existence of
141 	 * another definition
142 	 */
143 		if (argc > 3) {
144 			if (lookup(argv[2]) != nil)
145 				pbstr(argv[3]);
146 			else if (argc > 4)
147 				pbstr(argv[4]);
148 		}
149 		break;
150 
151 	case LENGTYPE:
152 	/*
153 	 * dolen - find the length of the
154 	 * argument
155 	 */
156 		if (argc > 2)
157 			pbnum((argc > 2) ? strlen(argv[2]) : 0);
158 		break;
159 
160 	case INCRTYPE:
161 	/*
162 	 * doincr - increment the value of the
163 	 * argument
164 	 */
165 		if (argc > 2)
166 			pbnum(atoi(argv[2]) + 1);
167 		break;
168 
169 	case DECRTYPE:
170 	/*
171 	 * dodecr - decrement the value of the
172 	 * argument
173 	 */
174 		if (argc > 2)
175 			pbnum(atoi(argv[2]) - 1);
176 		break;
177 
178 	case SYSCTYPE:
179 	/*
180 	 * dosys - execute system command
181 	 */
182 		if (argc > 2)
183 			sysval = system(argv[2]);
184 		break;
185 
186 	case SYSVTYPE:
187 	/*
188 	 * dosysval - return value of the last
189 	 * system call.
190 	 *
191 	 */
192 		pbnum(sysval);
193 		break;
194 
195 	case INCLTYPE:
196 		if (argc > 2)
197 			if (!doincl(argv[2]))
198 				err(1, "%s", argv[2]);
199 		break;
200 
201 	case SINCTYPE:
202 		if (argc > 2)
203 			(void) doincl(argv[2]);
204 		break;
205 #ifdef EXTENDED
206 	case PASTTYPE:
207 		if (argc > 2)
208 			if (!dopaste(argv[2]))
209 				err(1, "%s", argv[2]);
210 		break;
211 
212 	case SPASTYPE:
213 		if (argc > 2)
214 			(void) dopaste(argv[2]);
215 		break;
216 #endif
217 	case CHNQTYPE:
218 		dochq(argv, argc);
219 		break;
220 
221 	case CHNCTYPE:
222 		dochc(argv, argc);
223 		break;
224 
225 	case SUBSTYPE:
226 	/*
227 	 * dosub - select substring
228 	 *
229 	 */
230 		if (argc > 3)
231 			dosub(argv, argc);
232 		break;
233 
234 	case SHIFTYPE:
235 	/*
236 	 * doshift - push back all arguments
237 	 * except the first one (i.e. skip
238 	 * argv[2])
239 	 */
240 		if (argc > 3) {
241 			for (n = argc - 1; n > 3; n--) {
242 				pbstr(rquote);
243 				pbstr(argv[n]);
244 				pbstr(lquote);
245 				putback(COMMA);
246 			}
247 			pbstr(rquote);
248 			pbstr(argv[3]);
249 			pbstr(lquote);
250 		}
251 		break;
252 
253 	case DIVRTYPE:
254 		if (argc > 2 && (n = atoi(argv[2])) != 0)
255 			dodiv(n);
256 		else {
257 			active = stdout;
258 			oindex = 0;
259 		}
260 		break;
261 
262 	case UNDVTYPE:
263 		doundiv(argv, argc);
264 		break;
265 
266 	case DIVNTYPE:
267 	/*
268 	 * dodivnum - return the number of
269 	 * current output diversion
270 	 */
271 		pbnum(oindex);
272 		break;
273 
274 	case UNDFTYPE:
275 	/*
276 	 * doundefine - undefine a previously
277 	 * defined macro(s) or m4 keyword(s).
278 	 */
279 		if (argc > 2)
280 			for (n = 2; n < argc; n++)
281 				remhash(argv[n], ALL);
282 		break;
283 
284 	case POPDTYPE:
285 	/*
286 	 * dopopdef - remove the topmost
287 	 * definitions of macro(s) or m4
288 	 * keyword(s).
289 	 */
290 		if (argc > 2)
291 			for (n = 2; n < argc; n++)
292 				remhash(argv[n], TOP);
293 		break;
294 
295 	case MKTMTYPE:
296 	/*
297 	 * dotemp - create a temporary file
298 	 */
299 		if (argc > 2) {
300 			int fd;
301 
302 			fd = mkstemp(argv[2]);
303 			if (fd == -1)
304 				err(1, "mkstemp failed");
305 			close(fd);
306 			pbstr(argv[2]);
307 		}
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 		errx(1, "eval: major botch");
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 	char *argv[];
395 	int argc;
396 {
397 	char *t;
398 	char *p;
399 	int n;
400 	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 	char *name;
466 	char *defn;
467 {
468 	ndptr p;
469 
470 	if (!*name)
471 		errx(1, "null definition");
472 	if (STREQ(name, defn))
473 		errx(1, "%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 	ndptr p;
494 
495 	if ((p = lookup(name)) != nil && p->defn != null) {
496 		pbstr(rquote);
497 		pbstr(p->defn);
498 		pbstr(lquote);
499 	}
500 }
501 
502 /*
503  * dopushdef - install a definition in the hash table
504  *      without removing a previous definition. Since
505  *      each new entry is entered in *front* of the
506  *      hash bucket, it hides a previous definition from
507  *      lookup.
508  */
509 void
510 dopushdef(name, defn)
511 	char *name;
512 	char *defn;
513 {
514 	ndptr p;
515 
516 	if (!*name)
517 		errx(1, "null definition");
518 	if (STREQ(name, defn))
519 		errx(1, "%s: recursive definition", name);
520 	p = addent(name);
521 	if (!*defn)
522 		p->defn = null;
523 	else
524 		p->defn = xstrdup(defn);
525 	p->type = MACRTYPE;
526 }
527 
528 /*
529  * dodumpdef - dump the specified definitions in the hash
530  *      table to stderr. If nothing is specified, the entire
531  *      hash table is dumped.
532  */
533 void
534 dodump(argv, argc)
535 	char *argv[];
536 	int argc;
537 {
538 	int n;
539 	ndptr p;
540 
541 	if (argc > 2) {
542 		for (n = 2; n < argc; n++)
543 			if ((p = lookup(argv[n])) != nil)
544 				fprintf(stderr, dumpfmt, p->name,
545 					p->defn);
546 	}
547 	else {
548 		for (n = 0; n < HASHSIZE; n++)
549 			for (p = hashtab[n]; p != nil; p = p->nxtptr)
550 				fprintf(stderr, dumpfmt, p->name,
551 					p->defn);
552 	}
553 }
554 
555 /*
556  * doifelse - select one of two alternatives - loop.
557  */
558 void
559 doifelse(argv, argc)
560 	char *argv[];
561 	int argc;
562 {
563 	cycle {
564 		if (STREQ(argv[2], argv[3]))
565 			pbstr(argv[4]);
566 		else if (argc == 6)
567 			pbstr(argv[5]);
568 		else if (argc > 6) {
569 			argv += 3;
570 			argc -= 3;
571 			continue;
572 		}
573 		break;
574 	}
575 }
576 
577 /*
578  * doinclude - include a given file.
579  */
580 int
581 doincl(ifile)
582 	char *ifile;
583 {
584 	if (ilevel + 1 == MAXINP)
585 		errx(1, "too many include files");
586 	if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
587 		ilevel++;
588 		bbase[ilevel] = bufbase = bp;
589 		return (1);
590 	}
591 	else
592 		return (0);
593 }
594 
595 #ifdef EXTENDED
596 /*
597  * dopaste - include a given file without any
598  *           macro processing.
599  */
600 int
601 dopaste(pfile)
602 	char *pfile;
603 {
604 	FILE *pf;
605 	int c;
606 
607 	if ((pf = fopen(pfile, "r")) != NULL) {
608 		while ((c = getc(pf)) != EOF)
609 			putc(c, active);
610 		(void) fclose(pf);
611 		return (1);
612 	}
613 	else
614 		return (0);
615 }
616 #endif
617 
618 /*
619  * dochq - change quote characters
620  */
621 void
622 dochq(argv, argc)
623 	char *argv[];
624 	int argc;
625 {
626 	if (argc > 2) {
627 		if (*argv[2])
628 			strncpy(lquote, argv[2], MAXCCHARS);
629 		if (argc > 3) {
630 			if (*argv[3])
631 				strncpy(rquote, argv[3], MAXCCHARS);
632 		}
633 		else
634 			strcpy(rquote, lquote);
635 	}
636 	else {
637 		lquote[0] = LQUOTE, lquote[1] = '\0';
638 		rquote[0] = RQUOTE, rquote[1] = '\0';
639 	}
640 }
641 
642 /*
643  * dochc - change comment characters
644  */
645 void
646 dochc(argv, argc)
647 	char *argv[];
648 	int argc;
649 {
650 	if (argc > 2) {
651 		if (*argv[2])
652 			strncpy(scommt, argv[2], MAXCCHARS);
653 		if (argc > 3) {
654 			if (*argv[3])
655 				strncpy(ecommt, argv[3], MAXCCHARS);
656 		}
657 		else
658 			ecommt[0] = ECOMMT, ecommt[1] = '\0';
659 	}
660 	else {
661 		scommt[0] = SCOMMT, scommt[1] = '\0';
662 		ecommt[0] = ECOMMT, ecommt[1] = '\0';
663 	}
664 }
665 
666 /*
667  * dodivert - divert the output to a temporary file
668  */
669 void
670 dodiv(n)
671 	int n;
672 {
673 	int tempfilenum;
674 
675 	/*
676 	 * direct output to the appropriate temporary file (the bit
677 	 * bucket, if out of range).
678 	 */
679 	tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n;
680 
681 	if (outfile[tempfilenum] == NULL) {
682 		m4temp[UNIQUE] = tempfilenum + '0';
683 		if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL)
684 			err(1, "%s: cannot divert", m4temp);
685 	}
686 	oindex = n;
687 	active = outfile[tempfilenum];
688 }
689 
690 /*
691  * doundivert - undivert a specified output, or all
692  *              other outputs, in numerical order.
693  */
694 void
695 doundiv(argv, argc)
696 	char *argv[];
697 	int argc;
698 {
699 	int ind;
700 	int n;
701 
702 	if (argc > 2) {
703 		for (ind = 2; ind < argc; ind++) {
704 			n = atoi(argv[ind]);
705 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
706 				getdiv(n);
707 
708 		}
709 	}
710 	else
711 		for (n = 1; n < MAXOUT; n++)
712 			if (outfile[n] != NULL)
713 				getdiv(n);
714 }
715 
716 /*
717  * dosub - select substring
718  */
719 void
720 dosub(argv, argc)
721 	char *argv[];
722 	int argc;
723 {
724 	char *ap, *fc, *k;
725 	int nc;
726 
727 	if (argc < 5)
728 		nc = MAXTOK;
729 	else
730 #ifdef EXPR
731 		nc = expr(argv[4]);
732 #else
733 		nc = atoi(argv[4]);
734 #endif
735 	ap = argv[2];		       /* target string */
736 #ifdef EXPR
737 	fc = ap + expr(argv[3]);       /* first char */
738 #else
739 	fc = ap + atoi(argv[3]);       /* first char */
740 #endif
741 	if (fc >= ap && fc < ap + strlen(ap))
742 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
743 			putback(*k);
744 }
745 
746 /*
747  * map:
748  * map every character of s1 that is specified in from
749  * into s3 and replace in s. (source s1 remains untouched)
750  *
751  * This is a standard implementation of map(s,from,to) function of ICON
752  * language. Within mapvec, we replace every character of "from" with
753  * the corresponding character in "to". If "to" is shorter than "from",
754  * than the corresponding entries are null, which means that those
755  * characters dissapear altogether. Furthermore, imagine
756  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
757  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
758  * ultimately maps to `*'. In order to achieve this effect in an efficient
759  * manner (i.e. without multiple passes over the destination string), we
760  * loop over mapvec, starting with the initial source character. if the
761  * character value (dch) in this location is different than the source
762  * character (sch), sch becomes dch, once again to index into mapvec, until
763  * the character value stabilizes (i.e. sch = dch, in other words
764  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
765  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
766  * end, we restore mapvec* back to normal where mapvec[n] == n for
767  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
768  * about 5 times faster than any algorithm that makes multiple passes over
769  * destination string.
770  */
771 void
772 map(dest, src, from, to)
773 	char *dest;
774 	char *src;
775 	char *from;
776 	char *to;
777 {
778 	char *tmp;
779 	char sch, dch;
780 	static char mapvec[128] = {
781 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
782 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
783 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
784 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
785 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
786 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
787 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
788 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
789 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
790 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
791 		120, 121, 122, 123, 124, 125, 126, 127
792 	};
793 
794 	if (*src) {
795 		tmp = from;
796 	/*
797 	 * create a mapping between "from" and
798 	 * "to"
799 	 */
800 		while (*from)
801 			mapvec[(int)*from++] = (*to) ? *to++ : (char) 0;
802 
803 		while (*src) {
804 			sch = *src++;
805 			dch = mapvec[(int)sch];
806 			while (dch != sch) {
807 				sch = dch;
808 				dch = mapvec[(int)sch];
809 			}
810 			if ((*dest = dch) != 0)
811 				dest++;
812 		}
813 	/*
814 	 * restore all the changed characters
815 	 */
816 		while (*tmp) {
817 			mapvec[(int)*tmp] = *tmp;
818 			tmp++;
819 		}
820 	}
821 	*dest = (char) 0;
822 }
823