eval.c revision 1.13 1 /* $NetBSD: eval.c,v 1.13 2000/10/17 18:51:32 jdolecek 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.13 2000/10/17 18:51:32 jdolecek 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 const 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