]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/m4/eval.c
BSD 4.4 Lite Usr.bin Sources
[FreeBSD/FreeBSD.git] / usr.bin / m4 / eval.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ozan Yigit at York University.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 static char sccsid[] = "@(#)eval.c      8.1 (Berkeley) 6/6/93";
39 #endif /* not lint */
40
41 /*
42  * eval.c
43  * Facility: m4 macro processor
44  * by: oz
45  */
46
47 #include <sys/types.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "mdef.h"
54 #include "stdd.h"
55 #include "extern.h"
56 #include "pathnames.h"
57
58 /*
59  * eval - evaluate built-in macros.
60  *        argc - number of elements in argv.
61  *        argv - element vector :
62  *                      argv[0] = definition of a user
63  *                                macro or nil if built-in.
64  *                      argv[1] = name of the macro or
65  *                                built-in.
66  *                      argv[2] = parameters to user-defined
67  *                         .      macro or built-in.
68  *                         .
69  *
70  * Note that the minimum value for argc is 3. A call in the form
71  * of macro-or-builtin() will result in:
72  *                      argv[0] = nullstr
73  *                      argv[1] = macro-or-builtin
74  *                      argv[2] = nullstr
75  */
76
77 void
78 eval(argv, argc, td)
79 register char *argv[];
80 register int argc;
81 register int td;
82 {
83         register int c, n;
84         static int sysval = 0;
85
86 #ifdef DEBUG
87         printf("argc = %d\n", argc);
88         for (n = 0; n < argc; n++)
89                 printf("argv[%d] = %s\n", n, argv[n]);
90 #endif
91  /*
92   * if argc == 3 and argv[2] is null, then we
93   * have macro-or-builtin() type call. We adjust
94   * argc to avoid further checking..
95   */
96         if (argc == 3 && !*(argv[2]))
97                 argc--;
98
99         switch (td & ~STATIC) {
100
101         case DEFITYPE:
102                 if (argc > 2)
103                         dodefine(argv[2], (argc > 3) ? argv[3] : null);
104                 break;
105
106         case PUSDTYPE:
107                 if (argc > 2)
108                         dopushdef(argv[2], (argc > 3) ? argv[3] : null);
109                 break;
110
111         case DUMPTYPE:
112                 dodump(argv, argc);
113                 break;
114
115         case EXPRTYPE:
116         /*
117          * doexpr - evaluate arithmetic
118          * expression
119          */
120                 if (argc > 2)
121                         pbnum(expr(argv[2]));
122                 break;
123
124         case IFELTYPE:
125                 if (argc > 4)
126                         doifelse(argv, argc);
127                 break;
128
129         case IFDFTYPE:
130         /*
131          * doifdef - select one of two
132          * alternatives based on the existence of
133          * another definition
134          */
135                 if (argc > 3) {
136                         if (lookup(argv[2]) != nil)
137                                 pbstr(argv[3]);
138                         else if (argc > 4)
139                                 pbstr(argv[4]);
140                 }
141                 break;
142
143         case LENGTYPE:
144         /*
145          * dolen - find the length of the
146          * argument
147          */
148                 if (argc > 2)
149                         pbnum((argc > 2) ? strlen(argv[2]) : 0);
150                 break;
151
152         case INCRTYPE:
153         /*
154          * doincr - increment the value of the
155          * argument
156          */
157                 if (argc > 2)
158                         pbnum(atoi(argv[2]) + 1);
159                 break;
160
161         case DECRTYPE:
162         /*
163          * dodecr - decrement the value of the
164          * argument
165          */
166                 if (argc > 2)
167                         pbnum(atoi(argv[2]) - 1);
168                 break;
169
170         case SYSCTYPE:
171         /*
172          * dosys - execute system command
173          */
174                 if (argc > 2)
175                         sysval = system(argv[2]);
176                 break;
177
178         case SYSVTYPE:
179         /*
180          * dosysval - return value of the last
181          * system call.
182          * 
183          */
184                 pbnum(sysval);
185                 break;
186
187         case INCLTYPE:
188                 if (argc > 2)
189                         if (!doincl(argv[2]))
190                                 oops("%s: %s", argv[2], strerror(errno));
191                 break;
192
193         case SINCTYPE:
194                 if (argc > 2)
195                         (void) doincl(argv[2]);
196                 break;
197 #ifdef EXTENDED
198         case PASTTYPE:
199                 if (argc > 2)
200                         if (!dopaste(argv[2]))
201                                 oops("%s: %s", argv[2], strerror(errno));
202                 break;
203
204         case SPASTYPE:
205                 if (argc > 2)
206                         (void) dopaste(argv[2]);
207                 break;
208 #endif
209         case CHNQTYPE:
210                 dochq(argv, argc);
211                 break;
212
213         case CHNCTYPE:
214                 dochc(argv, argc);
215                 break;
216
217         case SUBSTYPE:
218         /*
219          * dosub - select substring
220          * 
221          */
222                 if (argc > 3)
223                         dosub(argv, argc);
224                 break;
225
226         case SHIFTYPE:
227         /*
228          * doshift - push back all arguments
229          * except the first one (i.e. skip
230          * argv[2])
231          */
232                 if (argc > 3) {
233                         for (n = argc - 1; n > 3; n--) {
234                                 putback(rquote);
235                                 pbstr(argv[n]);
236                                 putback(lquote);
237                                 putback(',');
238                         }
239                         putback(rquote);
240                         pbstr(argv[3]);
241                         putback(lquote);
242                 }
243                 break;
244
245         case DIVRTYPE:
246                 if (argc > 2 && (n = atoi(argv[2])) != 0)
247                         dodiv(n);
248                 else {
249                         active = stdout;
250                         oindex = 0;
251                 }
252                 break;
253
254         case UNDVTYPE:
255                 doundiv(argv, argc);
256                 break;
257
258         case DIVNTYPE:
259         /*
260          * dodivnum - return the number of
261          * current output diversion
262          */
263                 pbnum(oindex);
264                 break;
265
266         case UNDFTYPE:
267         /*
268          * doundefine - undefine a previously
269          * defined macro(s) or m4 keyword(s).
270          */
271                 if (argc > 2)
272                         for (n = 2; n < argc; n++)
273                                 remhash(argv[n], ALL);
274                 break;
275
276         case POPDTYPE:
277         /*
278          * dopopdef - remove the topmost
279          * definitions of macro(s) or m4
280          * keyword(s).
281          */
282                 if (argc > 2)
283                         for (n = 2; n < argc; n++)
284                                 remhash(argv[n], TOP);
285                 break;
286
287         case MKTMTYPE:
288         /*
289          * dotemp - create a temporary file
290          */
291                 if (argc > 2)
292                         pbstr(mktemp(argv[2]));
293                 break;
294
295         case TRNLTYPE:
296         /*
297          * dotranslit - replace all characters in
298          * the source string that appears in the
299          * "from" string with the corresponding
300          * characters in the "to" string.
301          */
302                 if (argc > 3) {
303                         char temp[MAXTOK];
304                         if (argc > 4)
305                                 map(temp, argv[2], argv[3], argv[4]);
306                         else
307                                 map(temp, argv[2], argv[3], null);
308                         pbstr(temp);
309                 }
310                 else if (argc > 2)
311                         pbstr(argv[2]);
312                 break;
313
314         case INDXTYPE:
315         /*
316          * doindex - find the index of the second
317          * argument string in the first argument
318          * string. -1 if not present.
319          */
320                 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
321                 break;
322
323         case ERRPTYPE:
324         /*
325          * doerrp - print the arguments to stderr
326          * file
327          */
328                 if (argc > 2) {
329                         for (n = 2; n < argc; n++)
330                                 fprintf(stderr, "%s ", argv[n]);
331                         fprintf(stderr, "\n");
332                 }
333                 break;
334
335         case DNLNTYPE:
336         /*
337          * dodnl - eat-up-to and including
338          * newline
339          */
340                 while ((c = gpbc()) != '\n' && c != EOF)
341                         ;
342                 break;
343
344         case M4WRTYPE:
345         /*
346          * dom4wrap - set up for
347          * wrap-up/wind-down activity
348          */
349                 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
350                 break;
351
352         case EXITTYPE:
353         /*
354          * doexit - immediate exit from m4.
355          */
356                 exit((argc > 2) ? atoi(argv[2]) : 0);
357                 break;
358
359         case DEFNTYPE:
360                 if (argc > 2)
361                         for (n = 2; n < argc; n++)
362                                 dodefn(argv[n]);
363                 break;
364
365         default:
366                 oops("%s: major botch.", "eval");
367                 break;
368         }
369 }
370
371 char *dumpfmt = "`%s'\t`%s'\n";        /* format string for dumpdef   */
372
373 /*
374  * expand - user-defined macro expansion
375  */
376 void
377 expand(argv, argc)
378 register char *argv[];
379 register int argc;
380 {
381         register char *t;
382         register char *p;
383         register int n;
384         register int argno;
385
386         t = argv[0];                   /* defn string as a whole */
387         p = t;
388         while (*p)
389                 p++;
390         p--;                           /* last character of defn */
391         while (p > t) {
392                 if (*(p - 1) != ARGFLAG)
393                         putback(*p);
394                 else {
395                         switch (*p) {
396
397                         case '#':
398                                 pbnum(argc - 2);
399                                 break;
400                         case '0':
401                         case '1':
402                         case '2':
403                         case '3':
404                         case '4':
405                         case '5':
406                         case '6':
407                         case '7':
408                         case '8':
409                         case '9':
410                                 if ((argno = *p - '0') < argc - 1)
411                                         pbstr(argv[argno + 1]);
412                                 break;
413                         case '*':
414                                 for (n = argc - 1; n > 2; n--) {
415                                         pbstr(argv[n]);
416                                         putback(',');
417                                 }
418                                 pbstr(argv[2]);
419                                 break;
420                         default:
421                                 putback(*p);
422                                 putback('$');
423                                 break;
424                         }
425                         p--;
426                 }
427                 p--;
428         }
429         if (p == t)                    /* do last character */
430                 putback(*p);
431 }
432
433 /*
434  * dodefine - install definition in the table
435  */
436 void
437 dodefine(name, defn)
438 register char *name;
439 register char *defn;
440 {
441         register ndptr p;
442
443         if (!*name)
444                 oops("null definition.");
445         if (STREQ(name, defn))
446                 oops("%s: recursive definition.", name);
447         if ((p = lookup(name)) == nil)
448                 p = addent(name);
449         else if (p->defn != null)
450                 free((char *) p->defn);
451         if (!*defn)
452                 p->defn = null;
453         else
454                 p->defn = xstrdup(defn);
455         p->type = MACRTYPE;
456 }
457
458 /*
459  * dodefn - push back a quoted definition of
460  *      the given name.
461  */
462 void
463 dodefn(name)
464 char *name;
465 {
466         register ndptr p;
467
468         if ((p = lookup(name)) != nil && p->defn != null) {
469                 putback(rquote);
470                 pbstr(p->defn);
471                 putback(lquote);
472         }
473 }
474
475 /*
476  * dopushdef - install a definition in the hash table
477  *      without removing a previous definition. Since
478  *      each new entry is entered in *front* of the
479  *      hash bucket, it hides a previous definition from
480  *      lookup.
481  */
482 void
483 dopushdef(name, defn)
484 register char *name;
485 register char *defn;
486 {
487         register ndptr p;
488
489         if (!*name)
490                 oops("null definition");
491         if (STREQ(name, defn))
492                 oops("%s: recursive definition.", name);
493         p = addent(name);
494         if (!*defn)
495                 p->defn = null;
496         else
497                 p->defn = xstrdup(defn);
498         p->type = MACRTYPE;
499 }
500
501 /*
502  * dodumpdef - dump the specified definitions in the hash
503  *      table to stderr. If nothing is specified, the entire
504  *      hash table is dumped.
505  */
506 void
507 dodump(argv, argc)
508 register char *argv[];
509 register int argc;
510 {
511         register int n;
512         ndptr p;
513
514         if (argc > 2) {
515                 for (n = 2; n < argc; n++)
516                         if ((p = lookup(argv[n])) != nil)
517                                 fprintf(stderr, dumpfmt, p->name,
518                                         p->defn);
519         }
520         else {
521                 for (n = 0; n < HASHSIZE; n++)
522                         for (p = hashtab[n]; p != nil; p = p->nxtptr)
523                                 fprintf(stderr, dumpfmt, p->name,
524                                         p->defn);
525         }
526 }
527
528 /*
529  * doifelse - select one of two alternatives - loop.
530  */
531 void
532 doifelse(argv, argc)
533 register char *argv[];
534 register int argc;
535 {
536         cycle {
537                 if (STREQ(argv[2], argv[3]))
538                         pbstr(argv[4]);
539                 else if (argc == 6)
540                         pbstr(argv[5]);
541                 else if (argc > 6) {
542                         argv += 3;
543                         argc -= 3;
544                         continue;
545                 }
546                 break;
547         }
548 }
549
550 /*
551  * doinclude - include a given file.
552  */
553 int
554 doincl(ifile)
555 char *ifile;
556 {
557         if (ilevel + 1 == MAXINP)
558                 oops("too many include files.");
559         if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
560                 ilevel++;
561                 bbase[ilevel] = bufbase = bp;
562                 return (1);
563         }
564         else
565                 return (0);
566 }
567
568 #ifdef EXTENDED
569 /*
570  * dopaste - include a given file without any
571  *           macro processing.
572  */
573 int
574 dopaste(pfile)
575 char *pfile;
576 {
577         FILE *pf;
578         register int c;
579
580         if ((pf = fopen(pfile, "r")) != NULL) {
581                 while ((c = getc(pf)) != EOF)
582                         putc(c, active);
583                 (void) fclose(pf);
584                 return (1);
585         }
586         else
587                 return (0);
588 }
589 #endif
590
591 /*
592  * dochq - change quote characters
593  */
594 void
595 dochq(argv, argc)
596 register char *argv[];
597 register int argc;
598 {
599         if (argc > 2) {
600                 if (*argv[2])
601                         lquote = *argv[2];
602                 if (argc > 3) {
603                         if (*argv[3])
604                                 rquote = *argv[3];
605                 }
606                 else
607                         rquote = lquote;
608         }
609         else {
610                 lquote = LQUOTE;
611                 rquote = RQUOTE;
612         }
613 }
614
615 /*
616  * dochc - change comment characters
617  */
618 void
619 dochc(argv, argc)
620 register char *argv[];
621 register int argc;
622 {
623         if (argc > 2) {
624                 if (*argv[2])
625                         scommt = *argv[2];
626                 if (argc > 3) {
627                         if (*argv[3])
628                                 ecommt = *argv[3];
629                 }
630                 else
631                         ecommt = ECOMMT;
632         }
633         else {
634                 scommt = SCOMMT;
635                 ecommt = ECOMMT;
636         }
637 }
638
639 /*
640  * dodivert - divert the output to a temporary file
641  */
642 void
643 dodiv(n)
644 register int n;
645 {
646         if (n < 0 || n >= MAXOUT)
647                 n = 0;                 /* bitbucket */
648         if (outfile[n] == NULL) {
649                 m4temp[UNIQUE] = n + '0';
650                 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
651                         oops("%s: cannot divert.", m4temp);
652         }
653         oindex = n;
654         active = outfile[n];
655 }
656
657 /*
658  * doundivert - undivert a specified output, or all
659  *              other outputs, in numerical order.
660  */
661 void
662 doundiv(argv, argc)
663 register char *argv[];
664 register int argc;
665 {
666         register int ind;
667         register int n;
668
669         if (argc > 2) {
670                 for (ind = 2; ind < argc; ind++) {
671                         n = atoi(argv[ind]);
672                         if (n > 0 && n < MAXOUT && outfile[n] != NULL)
673                                 getdiv(n);
674
675                 }
676         }
677         else
678                 for (n = 1; n < MAXOUT; n++)
679                         if (outfile[n] != NULL)
680                                 getdiv(n);
681 }
682
683 /*
684  * dosub - select substring
685  */
686 void
687 dosub(argv, argc)
688 register char *argv[];
689 register int argc;
690 {
691         register char *ap, *fc, *k;
692         register int nc;
693
694         if (argc < 5)
695                 nc = MAXTOK;
696         else
697 #ifdef EXPR
698                 nc = expr(argv[4]);
699 #else
700                 nc = atoi(argv[4]);
701 #endif
702         ap = argv[2];                  /* target string */
703 #ifdef EXPR
704         fc = ap + expr(argv[3]);       /* first char */
705 #else
706         fc = ap + atoi(argv[3]);       /* first char */
707 #endif
708         if (fc >= ap && fc < ap + strlen(ap))
709                 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
710                         putback(*k);
711 }
712
713 /*
714  * map:
715  * map every character of s1 that is specified in from
716  * into s3 and replace in s. (source s1 remains untouched)
717  *
718  * This is a standard implementation of map(s,from,to) function of ICON
719  * language. Within mapvec, we replace every character of "from" with
720  * the corresponding character in "to". If "to" is shorter than "from",
721  * than the corresponding entries are null, which means that those
722  * characters dissapear altogether. Furthermore, imagine
723  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
724  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
725  * ultimately maps to `*'. In order to achieve this effect in an efficient
726  * manner (i.e. without multiple passes over the destination string), we
727  * loop over mapvec, starting with the initial source character. if the
728  * character value (dch) in this location is different than the source
729  * character (sch), sch becomes dch, once again to index into mapvec, until
730  * the character value stabilizes (i.e. sch = dch, in other words
731  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
732  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
733  * end, we restore mapvec* back to normal where mapvec[n] == n for
734  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
735  * about 5 times faster than any algorithm that makes multiple passes over
736  * destination string.
737  */
738 void
739 map(dest, src, from, to)
740 register char *dest;
741 register char *src;
742 register char *from;
743 register char *to;
744 {
745         register char *tmp;
746         register char sch, dch;
747         static char mapvec[128] = {
748                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
749                 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
750                 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
751                 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
752                 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
753                 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
754                 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
755                 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
756                 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
757                 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
758                 120, 121, 122, 123, 124, 125, 126, 127
759         };
760
761         if (*src) {
762                 tmp = from;
763         /*
764          * create a mapping between "from" and
765          * "to"
766          */
767                 while (*from)
768                         mapvec[*from++] = (*to) ? *to++ : (char) 0;
769
770                 while (*src) {
771                         sch = *src++;
772                         dch = mapvec[sch];
773                         while (dch != sch) {
774                                 sch = dch;
775                                 dch = mapvec[sch];
776                         }
777                         if (*dest = dch)
778                                 dest++;
779                 }
780         /*
781          * restore all the changed characters
782          */
783                 while (*tmp) {
784                         mapvec[*tmp] = *tmp;
785                         tmp++;
786                 }
787         }
788         *dest = (char) 0;
789 }