xref: /netbsd-src/usr.bin/m4/eval.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: eval.c,v 1.10 1997/10/19 04:39:51 lukem 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.10 1997/10/19 04:39:51 lukem 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 			pbstr(mktemp(argv[2]));
301 		break;
302 
303 	case TRNLTYPE:
304 	/*
305 	 * dotranslit - replace all characters in
306 	 * the source string that appears in the
307 	 * "from" string with the corresponding
308 	 * characters in the "to" string.
309 	 */
310 		if (argc > 3) {
311 			char temp[MAXTOK];
312 			if (argc > 4)
313 				map(temp, argv[2], argv[3], argv[4]);
314 			else
315 				map(temp, argv[2], argv[3], null);
316 			pbstr(temp);
317 		}
318 		else if (argc > 2)
319 			pbstr(argv[2]);
320 		break;
321 
322 	case INDXTYPE:
323 	/*
324 	 * doindex - find the index of the second
325 	 * argument string in the first argument
326 	 * string. -1 if not present.
327 	 */
328 		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
329 		break;
330 
331 	case ERRPTYPE:
332 	/*
333 	 * doerrp - print the arguments to stderr
334 	 * file
335 	 */
336 		if (argc > 2) {
337 			for (n = 2; n < argc; n++)
338 				fprintf(stderr, "%s ", argv[n]);
339 			fprintf(stderr, "\n");
340 		}
341 		break;
342 
343 	case DNLNTYPE:
344 	/*
345 	 * dodnl - eat-up-to and including
346 	 * newline
347 	 */
348 		while ((c = gpbc()) != '\n' && c != EOF)
349 			;
350 		break;
351 
352 	case M4WRTYPE:
353 	/*
354 	 * dom4wrap - set up for
355 	 * wrap-up/wind-down activity
356 	 */
357 		m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
358 		break;
359 
360 	case EXITTYPE:
361 	/*
362 	 * doexit - immediate exit from m4.
363 	 */
364 		killdiv();
365 		exit((argc > 2) ? atoi(argv[2]) : 0);
366 		break;
367 
368 	case DEFNTYPE:
369 		if (argc > 2)
370 			for (n = 2; n < argc; n++)
371 				dodefn(argv[n]);
372 		break;
373 
374 	default:
375 		errx(1, "eval: major botch");
376 		break;
377 	}
378 }
379 
380 char *dumpfmt = "`%s'\t`%s'\n";	       /* format string for dumpdef   */
381 
382 /*
383  * expand - user-defined macro expansion
384  */
385 void
386 expand(argv, argc)
387 	char *argv[];
388 	int argc;
389 {
390 	char *t;
391 	char *p;
392 	int n;
393 	int argno;
394 
395 	t = argv[0];		       /* defn string as a whole */
396 	p = t;
397 	while (*p)
398 		p++;
399 	p--;			       /* last character of defn */
400 	while (p > t) {
401 		if (*(p - 1) != ARGFLAG)
402 			putback(*p);
403 		else {
404 			switch (*p) {
405 
406 			case '#':
407 				pbnum(argc - 2);
408 				break;
409 			case '0':
410 			case '1':
411 			case '2':
412 			case '3':
413 			case '4':
414 			case '5':
415 			case '6':
416 			case '7':
417 			case '8':
418 			case '9':
419 				if ((argno = *p - '0') < argc - 1)
420 					pbstr(argv[argno + 1]);
421 				break;
422 			case '*':
423 				for (n = argc - 1; n > 2; n--) {
424 					pbstr(argv[n]);
425 					putback(COMMA);
426 				}
427 				pbstr(argv[2]);
428 				break;
429                         case '@':
430                                 for (n = argc - 1; n > 2; n--) {
431                                         pbstr(rquote);
432                                         pbstr(argv[n]);
433                                         pbstr(lquote);
434 					putback(COMMA);
435                                 }
436 				pbstr(rquote);
437                                 pbstr(argv[2]);
438 				pbstr(lquote);
439                                 break;
440 			default:
441 				putback(*p);
442 				putback('$');
443 				break;
444 			}
445 			p--;
446 		}
447 		p--;
448 	}
449 	if (p == t)		       /* do last character */
450 		putback(*p);
451 }
452 
453 /*
454  * dodefine - install definition in the table
455  */
456 void
457 dodefine(name, defn)
458 	char *name;
459 	char *defn;
460 {
461 	ndptr p;
462 
463 	if (!*name)
464 		errx(1, "null definition");
465 	if (STREQ(name, defn))
466 		errx(1, "%s: recursive definition", name);
467 	if ((p = lookup(name)) == nil)
468 		p = addent(name);
469 	else if (p->defn != null)
470 		free((char *) p->defn);
471 	if (!*defn)
472 		p->defn = null;
473 	else
474 		p->defn = xstrdup(defn);
475 	p->type = MACRTYPE;
476 }
477 
478 /*
479  * dodefn - push back a quoted definition of
480  *      the given name.
481  */
482 void
483 dodefn(name)
484 	char *name;
485 {
486 	ndptr p;
487 
488 	if ((p = lookup(name)) != nil && p->defn != null) {
489 		pbstr(rquote);
490 		pbstr(p->defn);
491 		pbstr(lquote);
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 	char *name;
505 	char *defn;
506 {
507 	ndptr p;
508 
509 	if (!*name)
510 		errx(1, "null definition");
511 	if (STREQ(name, defn))
512 		errx(1, "%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 	char *argv[];
529 	int argc;
530 {
531 	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 	char *argv[];
554 	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 		errx(1, "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 	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 	char *argv[];
617 	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 	char *argv[];
641 	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 	int n;
665 {
666 	int tempfilenum;
667 
668 	/*
669 	 * direct output to the appropriate temporary file (the bit
670 	 * bucket, if out of range).
671 	 */
672 	tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n;
673 
674 	if (outfile[tempfilenum] == NULL) {
675 		m4temp[UNIQUE] = tempfilenum + '0';
676 		if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL)
677 			err(1, "%s: cannot divert", m4temp);
678 	}
679 	oindex = n;
680 	active = outfile[tempfilenum];
681 }
682 
683 /*
684  * doundivert - undivert a specified output, or all
685  *              other outputs, in numerical order.
686  */
687 void
688 doundiv(argv, argc)
689 	char *argv[];
690 	int argc;
691 {
692 	int ind;
693 	int n;
694 
695 	if (argc > 2) {
696 		for (ind = 2; ind < argc; ind++) {
697 			n = atoi(argv[ind]);
698 			if (n > 0 && n < MAXOUT && outfile[n] != NULL)
699 				getdiv(n);
700 
701 		}
702 	}
703 	else
704 		for (n = 1; n < MAXOUT; n++)
705 			if (outfile[n] != NULL)
706 				getdiv(n);
707 }
708 
709 /*
710  * dosub - select substring
711  */
712 void
713 dosub(argv, argc)
714 	char *argv[];
715 	int argc;
716 {
717 	char *ap, *fc, *k;
718 	int nc;
719 
720 	if (argc < 5)
721 		nc = MAXTOK;
722 	else
723 #ifdef EXPR
724 		nc = expr(argv[4]);
725 #else
726 		nc = atoi(argv[4]);
727 #endif
728 	ap = argv[2];		       /* target string */
729 #ifdef EXPR
730 	fc = ap + expr(argv[3]);       /* first char */
731 #else
732 	fc = ap + atoi(argv[3]);       /* first char */
733 #endif
734 	if (fc >= ap && fc < ap + strlen(ap))
735 		for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
736 			putback(*k);
737 }
738 
739 /*
740  * map:
741  * map every character of s1 that is specified in from
742  * into s3 and replace in s. (source s1 remains untouched)
743  *
744  * This is a standard implementation of map(s,from,to) function of ICON
745  * language. Within mapvec, we replace every character of "from" with
746  * the corresponding character in "to". If "to" is shorter than "from",
747  * than the corresponding entries are null, which means that those
748  * characters dissapear altogether. Furthermore, imagine
749  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
750  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
751  * ultimately maps to `*'. In order to achieve this effect in an efficient
752  * manner (i.e. without multiple passes over the destination string), we
753  * loop over mapvec, starting with the initial source character. if the
754  * character value (dch) in this location is different than the source
755  * character (sch), sch becomes dch, once again to index into mapvec, until
756  * the character value stabilizes (i.e. sch = dch, in other words
757  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
758  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
759  * end, we restore mapvec* back to normal where mapvec[n] == n for
760  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
761  * about 5 times faster than any algorithm that makes multiple passes over
762  * destination string.
763  */
764 void
765 map(dest, src, from, to)
766 	char *dest;
767 	char *src;
768 	char *from;
769 	char *to;
770 {
771 	char *tmp;
772 	char sch, dch;
773 	static char mapvec[128] = {
774 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
775 		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
776 		24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
777 		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
778 		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
779 		60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
780 		72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
781 		84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
782 		96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
783 		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
784 		120, 121, 122, 123, 124, 125, 126, 127
785 	};
786 
787 	if (*src) {
788 		tmp = from;
789 	/*
790 	 * create a mapping between "from" and
791 	 * "to"
792 	 */
793 		while (*from)
794 			mapvec[(int)*from++] = (*to) ? *to++ : (char) 0;
795 
796 		while (*src) {
797 			sch = *src++;
798 			dch = mapvec[(int)sch];
799 			while (dch != sch) {
800 				sch = dch;
801 				dch = mapvec[(int)sch];
802 			}
803 			if ((*dest = dch) != 0)
804 				dest++;
805 		}
806 	/*
807 	 * restore all the changed characters
808 	 */
809 		while (*tmp) {
810 			mapvec[(int)*tmp] = *tmp;
811 			tmp++;
812 		}
813 	}
814 	*dest = (char) 0;
815 }
816