eval.c revision 1.4 1 /* $NetBSD: eval.c,v 1.4 1995/09/28 05:37:28 tls 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.4 1995/09/28 05:37:28 tls 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 for (n = argc - 1; n > 3; n--) {
240 putback(rquote);
241 pbstr(argv[n]);
242 putback(lquote);
243 putback(',');
244 }
245 putback(rquote);
246 pbstr(argv[3]);
247 putback(lquote);
248 }
249 break;
250
251 case DIVRTYPE:
252 if (argc > 2 && (n = atoi(argv[2])) != 0)
253 dodiv(n);
254 else {
255 active = stdout;
256 oindex = 0;
257 }
258 break;
259
260 case UNDVTYPE:
261 doundiv(argv, argc);
262 break;
263
264 case DIVNTYPE:
265 /*
266 * dodivnum - return the number of
267 * current output diversion
268 */
269 pbnum(oindex);
270 break;
271
272 case UNDFTYPE:
273 /*
274 * doundefine - undefine a previously
275 * defined macro(s) or m4 keyword(s).
276 */
277 if (argc > 2)
278 for (n = 2; n < argc; n++)
279 remhash(argv[n], ALL);
280 break;
281
282 case POPDTYPE:
283 /*
284 * dopopdef - remove the topmost
285 * definitions of macro(s) or m4
286 * keyword(s).
287 */
288 if (argc > 2)
289 for (n = 2; n < argc; n++)
290 remhash(argv[n], TOP);
291 break;
292
293 case MKTMTYPE:
294 /*
295 * dotemp - create a temporary file
296 */
297 if (argc > 2)
298 pbstr(mktemp(argv[2]));
299 break;
300
301 case TRNLTYPE:
302 /*
303 * dotranslit - replace all characters in
304 * the source string that appears in the
305 * "from" string with the corresponding
306 * characters in the "to" string.
307 */
308 if (argc > 3) {
309 char temp[MAXTOK];
310 if (argc > 4)
311 map(temp, argv[2], argv[3], argv[4]);
312 else
313 map(temp, argv[2], argv[3], null);
314 pbstr(temp);
315 }
316 else if (argc > 2)
317 pbstr(argv[2]);
318 break;
319
320 case INDXTYPE:
321 /*
322 * doindex - find the index of the second
323 * argument string in the first argument
324 * string. -1 if not present.
325 */
326 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
327 break;
328
329 case ERRPTYPE:
330 /*
331 * doerrp - print the arguments to stderr
332 * file
333 */
334 if (argc > 2) {
335 for (n = 2; n < argc; n++)
336 fprintf(stderr, "%s ", argv[n]);
337 fprintf(stderr, "\n");
338 }
339 break;
340
341 case DNLNTYPE:
342 /*
343 * dodnl - eat-up-to and including
344 * newline
345 */
346 while ((c = gpbc()) != '\n' && c != EOF)
347 ;
348 break;
349
350 case M4WRTYPE:
351 /*
352 * dom4wrap - set up for
353 * wrap-up/wind-down activity
354 */
355 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
356 break;
357
358 case EXITTYPE:
359 /*
360 * doexit - immediate exit from m4.
361 */
362 killdiv();
363 exit((argc > 2) ? atoi(argv[2]) : 0);
364 break;
365
366 case DEFNTYPE:
367 if (argc > 2)
368 for (n = 2; n < argc; n++)
369 dodefn(argv[n]);
370 break;
371
372 default:
373 oops("%s: major botch.", "eval");
374 break;
375 }
376 }
377
378 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
379
380 /*
381 * expand - user-defined macro expansion
382 */
383 void
384 expand(argv, argc)
385 register char *argv[];
386 register int argc;
387 {
388 register char *t;
389 register char *p;
390 register int n;
391 register int argno;
392
393 t = argv[0]; /* defn string as a whole */
394 p = t;
395 while (*p)
396 p++;
397 p--; /* last character of defn */
398 while (p > t) {
399 if (*(p - 1) != ARGFLAG)
400 putback(*p);
401 else {
402 switch (*p) {
403
404 case '#':
405 pbnum(argc - 2);
406 break;
407 case '0':
408 case '1':
409 case '2':
410 case '3':
411 case '4':
412 case '5':
413 case '6':
414 case '7':
415 case '8':
416 case '9':
417 if ((argno = *p - '0') < argc - 1)
418 pbstr(argv[argno + 1]);
419 break;
420 case '*':
421 for (n = argc - 1; n > 2; n--) {
422 pbstr(argv[n]);
423 putback(',');
424 }
425 pbstr(argv[2]);
426 break;
427 default:
428 putback(*p);
429 putback('$');
430 break;
431 }
432 p--;
433 }
434 p--;
435 }
436 if (p == t) /* do last character */
437 putback(*p);
438 }
439
440 /*
441 * dodefine - install definition in the table
442 */
443 void
444 dodefine(name, defn)
445 register char *name;
446 register char *defn;
447 {
448 register ndptr p;
449
450 if (!*name)
451 oops("null definition.");
452 if (STREQ(name, defn))
453 oops("%s: recursive definition.", name);
454 if ((p = lookup(name)) == nil)
455 p = addent(name);
456 else if (p->defn != null)
457 free((char *) p->defn);
458 if (!*defn)
459 p->defn = null;
460 else
461 p->defn = xstrdup(defn);
462 p->type = MACRTYPE;
463 }
464
465 /*
466 * dodefn - push back a quoted definition of
467 * the given name.
468 */
469 void
470 dodefn(name)
471 char *name;
472 {
473 register ndptr p;
474
475 if ((p = lookup(name)) != nil && p->defn != null) {
476 putback(rquote);
477 pbstr(p->defn);
478 putback(lquote);
479 }
480 }
481
482 /*
483 * dopushdef - install a definition in the hash table
484 * without removing a previous definition. Since
485 * each new entry is entered in *front* of the
486 * hash bucket, it hides a previous definition from
487 * lookup.
488 */
489 void
490 dopushdef(name, defn)
491 register char *name;
492 register char *defn;
493 {
494 register ndptr p;
495
496 if (!*name)
497 oops("null definition");
498 if (STREQ(name, defn))
499 oops("%s: recursive definition.", name);
500 p = addent(name);
501 if (!*defn)
502 p->defn = null;
503 else
504 p->defn = xstrdup(defn);
505 p->type = MACRTYPE;
506 }
507
508 /*
509 * dodumpdef - dump the specified definitions in the hash
510 * table to stderr. If nothing is specified, the entire
511 * hash table is dumped.
512 */
513 void
514 dodump(argv, argc)
515 register char *argv[];
516 register int argc;
517 {
518 register int n;
519 ndptr p;
520
521 if (argc > 2) {
522 for (n = 2; n < argc; n++)
523 if ((p = lookup(argv[n])) != nil)
524 fprintf(stderr, dumpfmt, p->name,
525 p->defn);
526 }
527 else {
528 for (n = 0; n < HASHSIZE; n++)
529 for (p = hashtab[n]; p != nil; p = p->nxtptr)
530 fprintf(stderr, dumpfmt, p->name,
531 p->defn);
532 }
533 }
534
535 /*
536 * doifelse - select one of two alternatives - loop.
537 */
538 void
539 doifelse(argv, argc)
540 register char *argv[];
541 register int argc;
542 {
543 cycle {
544 if (STREQ(argv[2], argv[3]))
545 pbstr(argv[4]);
546 else if (argc == 6)
547 pbstr(argv[5]);
548 else if (argc > 6) {
549 argv += 3;
550 argc -= 3;
551 continue;
552 }
553 break;
554 }
555 }
556
557 /*
558 * doinclude - include a given file.
559 */
560 int
561 doincl(ifile)
562 char *ifile;
563 {
564 if (ilevel + 1 == MAXINP)
565 oops("too many include files.");
566 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
567 ilevel++;
568 bbase[ilevel] = bufbase = bp;
569 return (1);
570 }
571 else
572 return (0);
573 }
574
575 #ifdef EXTENDED
576 /*
577 * dopaste - include a given file without any
578 * macro processing.
579 */
580 int
581 dopaste(pfile)
582 char *pfile;
583 {
584 FILE *pf;
585 register int c;
586
587 if ((pf = fopen(pfile, "r")) != NULL) {
588 while ((c = getc(pf)) != EOF)
589 putc(c, active);
590 (void) fclose(pf);
591 return (1);
592 }
593 else
594 return (0);
595 }
596 #endif
597
598 /*
599 * dochq - change quote characters
600 */
601 void
602 dochq(argv, argc)
603 register char *argv[];
604 register int argc;
605 {
606 if (argc > 2) {
607 if (*argv[2])
608 lquote = *argv[2];
609 if (argc > 3) {
610 if (*argv[3])
611 rquote = *argv[3];
612 }
613 else
614 rquote = lquote;
615 }
616 else {
617 lquote = LQUOTE;
618 rquote = RQUOTE;
619 }
620 }
621
622 /*
623 * dochc - change comment characters
624 */
625 void
626 dochc(argv, argc)
627 register char *argv[];
628 register int argc;
629 {
630 if (argc > 2) {
631 if (*argv[2])
632 scommt = *argv[2];
633 if (argc > 3) {
634 if (*argv[3])
635 ecommt = *argv[3];
636 }
637 else
638 ecommt = ECOMMT;
639 }
640 else {
641 scommt = SCOMMT;
642 ecommt = ECOMMT;
643 }
644 }
645
646 /*
647 * dodivert - divert the output to a temporary file
648 */
649 void
650 dodiv(n)
651 register int n;
652 {
653 if (n < 0 || n >= MAXOUT)
654 n = 0; /* bitbucket */
655 if (outfile[n] == NULL) {
656 m4temp[UNIQUE] = n + '0';
657 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
658 oops("%s: cannot divert.", m4temp);
659 }
660 oindex = n;
661 active = outfile[n];
662 }
663
664 /*
665 * doundivert - undivert a specified output, or all
666 * other outputs, in numerical order.
667 */
668 void
669 doundiv(argv, argc)
670 register char *argv[];
671 register int argc;
672 {
673 register int ind;
674 register int n;
675
676 if (argc > 2) {
677 for (ind = 2; ind < argc; ind++) {
678 n = atoi(argv[ind]);
679 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
680 getdiv(n);
681
682 }
683 }
684 else
685 for (n = 1; n < MAXOUT; n++)
686 if (outfile[n] != NULL)
687 getdiv(n);
688 }
689
690 /*
691 * dosub - select substring
692 */
693 void
694 dosub(argv, argc)
695 register char *argv[];
696 register int argc;
697 {
698 register char *ap, *fc, *k;
699 register int nc;
700
701 if (argc < 5)
702 nc = MAXTOK;
703 else
704 #ifdef EXPR
705 nc = expr(argv[4]);
706 #else
707 nc = atoi(argv[4]);
708 #endif
709 ap = argv[2]; /* target string */
710 #ifdef EXPR
711 fc = ap + expr(argv[3]); /* first char */
712 #else
713 fc = ap + atoi(argv[3]); /* first char */
714 #endif
715 if (fc >= ap && fc < ap + strlen(ap))
716 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
717 putback(*k);
718 }
719
720 /*
721 * map:
722 * map every character of s1 that is specified in from
723 * into s3 and replace in s. (source s1 remains untouched)
724 *
725 * This is a standard implementation of map(s,from,to) function of ICON
726 * language. Within mapvec, we replace every character of "from" with
727 * the corresponding character in "to". If "to" is shorter than "from",
728 * than the corresponding entries are null, which means that those
729 * characters dissapear altogether. Furthermore, imagine
730 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
731 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
732 * ultimately maps to `*'. In order to achieve this effect in an efficient
733 * manner (i.e. without multiple passes over the destination string), we
734 * loop over mapvec, starting with the initial source character. if the
735 * character value (dch) in this location is different than the source
736 * character (sch), sch becomes dch, once again to index into mapvec, until
737 * the character value stabilizes (i.e. sch = dch, in other words
738 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
739 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
740 * end, we restore mapvec* back to normal where mapvec[n] == n for
741 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
742 * about 5 times faster than any algorithm that makes multiple passes over
743 * destination string.
744 */
745 void
746 map(dest, src, from, to)
747 register char *dest;
748 register char *src;
749 register char *from;
750 register char *to;
751 {
752 register char *tmp;
753 register char sch, dch;
754 static char mapvec[128] = {
755 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
756 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
757 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
758 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
759 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
760 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
761 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
762 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
763 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
764 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
765 120, 121, 122, 123, 124, 125, 126, 127
766 };
767
768 if (*src) {
769 tmp = from;
770 /*
771 * create a mapping between "from" and
772 * "to"
773 */
774 while (*from)
775 mapvec[*from++] = (*to) ? *to++ : (char) 0;
776
777 while (*src) {
778 sch = *src++;
779 dch = mapvec[sch];
780 while (dch != sch) {
781 sch = dch;
782 dch = mapvec[sch];
783 }
784 if (*dest = dch)
785 dest++;
786 }
787 /*
788 * restore all the changed characters
789 */
790 while (*tmp) {
791 mapvec[*tmp] = *tmp;
792 tmp++;
793 }
794 }
795 *dest = (char) 0;
796 }
797