]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/m4/eval.c
This commit was generated by cvs2svn to compensate for changes in r56230,
[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 #if 0
39 static char sccsid[] = "@(#)eval.c      8.1 (Berkeley) 6/6/93";
40 #endif
41 static const char rcsid[] =
42   "$FreeBSD$";
43 #endif /* not lint */
44
45 /*
46  * eval.c
47  * Facility: m4 macro processor
48  * by: oz
49  */
50
51 #include <sys/types.h>
52 #include <err.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include "mdef.h"
58 #include "stdd.h"
59 #include "extern.h"
60 #include "pathnames.h"
61
62 /*
63  * eval - evaluate built-in macros.
64  *        argc - number of elements in argv.
65  *        argv - element vector :
66  *                      argv[0] = definition of a user
67  *                                macro or nil if built-in.
68  *                      argv[1] = name of the macro or
69  *                                built-in.
70  *                      argv[2] = parameters to user-defined
71  *                         .      macro or built-in.
72  *                         .
73  *
74  * Note that the minimum value for argc is 3. A call in the form
75  * of macro-or-builtin() will result in:
76  *                      argv[0] = nullstr
77  *                      argv[1] = macro-or-builtin
78  *                      argv[2] = nullstr
79  */
80
81 void
82 eval(argv, argc, td)
83 register char *argv[];
84 register int argc;
85 register int td;
86 {
87         register int c, n;
88         static int sysval = 0;
89
90 #ifdef DEBUG
91         printf("argc = %d\n", argc);
92         for (n = 0; n < argc; n++)
93                 printf("argv[%d] = %s\n", n, argv[n]);
94 #endif
95  /*
96   * if argc == 3 and argv[2] is null, then we
97   * have macro-or-builtin() type call. We adjust
98   * argc to avoid further checking..
99   */
100         if (argc == 3 && !*(argv[2]))
101                 argc--;
102
103         switch (td & ~STATIC) {
104
105         case DEFITYPE:
106                 if (argc > 2)
107                         dodefine(argv[2], (argc > 3) ? argv[3] : null);
108                 break;
109
110         case PUSDTYPE:
111                 if (argc > 2)
112                         dopushdef(argv[2], (argc > 3) ? argv[3] : null);
113                 break;
114
115         case DUMPTYPE:
116                 dodump(argv, argc);
117                 break;
118
119         case EXPRTYPE:
120         /*
121          * doexpr - evaluate arithmetic
122          * expression
123          */
124                 if (argc > 2)
125                         pbnum(expr(argv[2]));
126                 break;
127
128         case IFELTYPE:
129                 if (argc > 4)
130                         doifelse(argv, argc);
131                 break;
132
133         case IFDFTYPE:
134         /*
135          * doifdef - select one of two
136          * alternatives based on the existence of
137          * another definition
138          */
139                 if (argc > 3) {
140                         if (lookup(argv[2]) != nil)
141                                 pbstr(argv[3]);
142                         else if (argc > 4)
143                                 pbstr(argv[4]);
144                 }
145                 break;
146
147         case LENGTYPE:
148         /*
149          * dolen - find the length of the
150          * argument
151          */
152                 if (argc > 2)
153                         pbnum((argc > 2) ? strlen(argv[2]) : 0);
154                 break;
155
156         case INCRTYPE:
157         /*
158          * doincr - increment the value of the
159          * argument
160          */
161                 if (argc > 2)
162                         pbnum(atoi(argv[2]) + 1);
163                 break;
164
165         case DECRTYPE:
166         /*
167          * dodecr - decrement the value of the
168          * argument
169          */
170                 if (argc > 2)
171                         pbnum(atoi(argv[2]) - 1);
172                 break;
173
174         case SYSCTYPE:
175         /*
176          * dosys - execute system command
177          */
178                 /* Make sure m4 output is NOT interrupted */
179                 fflush(stdout);
180                 fflush(stderr);
181                 if (argc > 2)
182                         sysval = system(argv[2]);
183                 break;
184
185         case SYSVTYPE:
186         /*
187          * dosysval - return value of the last
188          * system call.
189          *
190          */
191                 pbnum(sysval);
192                 break;
193
194         case INCLTYPE:
195                 if (argc > 2)
196                         if (!doincl(argv[2]))
197                                 err(1, "%s", argv[2]);
198                 break;
199
200         case SINCTYPE:
201                 if (argc > 2)
202                         (void) doincl(argv[2]);
203                 break;
204 #ifdef EXTENDED
205         case PASTTYPE:
206                 if (argc > 2)
207                         if (!dopaste(argv[2]))
208                                 err(1, "%s", argv[2]);
209                 break;
210
211         case SPASTYPE:
212                 if (argc > 2)
213                         (void) dopaste(argv[2]);
214                 break;
215 #endif
216         case CHNQTYPE:
217                 dochq(argv, argc);
218                 break;
219
220         case CHNCTYPE:
221                 dochc(argv, argc);
222                 break;
223
224         case SUBSTYPE:
225         /*
226          * dosub - select substring
227          *
228          */
229                 if (argc > 3)
230                         dosub(argv, argc);
231                 break;
232
233         case SHIFTYPE:
234         /*
235          * doshift - push back all arguments
236          * except the first one (i.e. skip
237          * argv[2])
238          */
239                 if (argc > 3) {
240                         for (n = argc - 1; n > 3; n--) {
241                                 putback(rquote);
242                                 pbstr(argv[n]);
243                                 putback(lquote);
244                                 putback(',');
245                         }
246                         putback(rquote);
247                         pbstr(argv[3]);
248                         putback(lquote);
249                 }
250                 break;
251
252         case DIVRTYPE:
253                 if (argc > 2 && (n = atoi(argv[2])) != 0)
254                         dodiv(n);
255                 else {
256                         active = stdout;
257                         oindex = 0;
258                 }
259                 break;
260
261         case UNDVTYPE:
262                 doundiv(argv, argc);
263                 break;
264
265         case DIVNTYPE:
266         /*
267          * dodivnum - return the number of
268          * current output diversion
269          */
270                 pbnum(oindex);
271                 break;
272
273         case UNDFTYPE:
274         /*
275          * doundefine - undefine a previously
276          * defined macro(s) or m4 keyword(s).
277          */
278                 if (argc > 2)
279                         for (n = 2; n < argc; n++)
280                                 remhash(argv[n], ALL);
281                 break;
282
283         case POPDTYPE:
284         /*
285          * dopopdef - remove the topmost
286          * definitions of macro(s) or m4
287          * keyword(s).
288          */
289                 if (argc > 2)
290                         for (n = 2; n < argc; n++)
291                                 remhash(argv[n], TOP);
292                 break;
293
294         case MKTMTYPE:
295         /*
296          * dotemp - create a temporary file
297          */
298                 if (argc > 2)
299                         pbstr(mktemp(argv[2]));
300                 break;
301
302         case TRNLTYPE:
303         /*
304          * dotranslit - replace all characters in
305          * the source string that appears in the
306          * "from" string with the corresponding
307          * characters in the "to" string.
308          */
309                 if (argc > 3) {
310                         char temp[STRSPMAX+1];
311                         if (argc > 4)
312                                 map(temp, argv[2], argv[3], argv[4]);
313                         else
314                                 map(temp, argv[2], argv[3], null);
315                         pbstr(temp);
316                 }
317                 else if (argc > 2)
318                         pbstr(argv[2]);
319                 break;
320
321         case INDXTYPE:
322         /*
323          * doindex - find the index of the second
324          * argument string in the first argument
325          * string. -1 if not present.
326          */
327                 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
328                 break;
329
330         case ERRPTYPE:
331         /*
332          * doerrp - print the arguments to stderr
333          * file
334          */
335                 if (argc > 2) {
336                         for (n = 2; n < argc; n++)
337                                 fprintf(stderr, "%s ", argv[n]);
338                         fprintf(stderr, "\n");
339                 }
340                 break;
341
342         case DNLNTYPE:
343         /*
344          * dodnl - eat-up-to and including
345          * newline
346          */
347                 while ((c = gpbc()) != '\n' && c != EOF)
348                         ;
349                 break;
350
351         case M4WRTYPE:
352         /*
353          * dom4wrap - set up for
354          * wrap-up/wind-down activity
355          */
356                 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
357                 break;
358
359         case EXITTYPE:
360         /*
361          * doexit - immediate exit from m4.
362          */
363                 killdiv();
364                 exit((argc > 2) ? atoi(argv[2]) : 0);
365                 break;
366
367         case DEFNTYPE:
368                 if (argc > 2)
369                         for (n = 2; n < argc; n++)
370                                 dodefn(argv[n]);
371                 break;
372
373         case MACRTYPE:
374                 pbstr("");
375                 break;
376
377         default:
378                 errx(1, "eval: major botch");
379                 break;
380         }
381 }
382
383 char *dumpfmt = "`%s'\t`%s'\n";        /* format string for dumpdef   */
384
385 /*
386  * expand - user-defined macro expansion
387  */
388 void
389 expand(argv, argc)
390 register char *argv[];
391 register int argc;
392 {
393         register unsigned char *t;
394         register unsigned char *p;
395         register int n;
396         register int argno;
397
398         t = argv[0];                   /* defn string as a whole */
399         p = t;
400         while (*p)
401                 p++;
402         p--;                           /* last character of defn */
403         while (p > t) {
404                 if (*(p - 1) != ARGFLAG)
405                         putback(*p);
406                 else {
407                         switch (*p) {
408
409                         case '#':
410                                 pbnum(argc - 2);
411                                 break;
412                         case '0':
413                         case '1':
414                         case '2':
415                         case '3':
416                         case '4':
417                         case '5':
418                         case '6':
419                         case '7':
420                         case '8':
421                         case '9':
422                                 if ((argno = *p - '0') < argc - 1)
423                                         pbstr(argv[argno + 1]);
424                                 break;
425                         case '*':
426                                 for (n = argc - 1; n > 2; n--) {
427                                         pbstr(argv[n]);
428                                         putback(',');
429                                 }
430                                 pbstr(argv[2]);
431                                 break;
432                         case '@':
433                                 for( n = argc - 1; n >= 2; n-- )
434                                 {
435                                         putback(rquote);
436                                         pbstr(argv[n]);
437                                         putback(lquote);
438                                         if( n > 2 )
439                                                 putback(',');
440                                 }
441                                 break;
442                         default:
443                                 putback(*p);
444                                 putback('$');
445                                 break;
446                         }
447                         p--;
448                 }
449                 p--;
450         }
451         if (p == t)                    /* do last character */
452                 putback(*p);
453 }
454
455 /*
456  * dodefine - install definition in the table
457  */
458 void
459 dodefine(name, defn)
460 register char *name;
461 register char *defn;
462 {
463         register ndptr p;
464
465         if (!*name)
466                 errx(1, "null definition");
467         if (STREQ(name, defn))
468                 errx(1, "%s: recursive definition", name);
469         if ((p = lookup(name)) == nil)
470                 p = addent(name);
471         else if (p->defn != null)
472                 free((char *) p->defn);
473         if (!*defn)
474                 p->defn = null;
475         else
476                 p->defn = xstrdup(defn);
477         p->type = MACRTYPE;
478 }
479
480 /*
481  * dodefn - push back a quoted definition of
482  *      the given name.
483  */
484 void
485 dodefn(name)
486 char *name;
487 {
488         register ndptr p;
489
490         if ((p = lookup(name)) != nil && p->defn != null) {
491                 putback(rquote);
492                 pbstr(p->defn);
493                 putback(lquote);
494         }
495 }
496
497 /*
498  * dopushdef - install a definition in the hash table
499  *      without removing a previous definition. Since
500  *      each new entry is entered in *front* of the
501  *      hash bucket, it hides a previous definition from
502  *      lookup.
503  */
504 void
505 dopushdef(name, defn)
506 register char *name;
507 register char *defn;
508 {
509         register ndptr p;
510
511         if (!*name)
512                 errx(1, "null definition");
513         if (STREQ(name, defn))
514                 errx(1, "%s: recursive definition", name);
515         p = addent(name);
516         if (!*defn)
517                 p->defn = null;
518         else
519                 p->defn = xstrdup(defn);
520         p->type = MACRTYPE;
521 }
522
523 /*
524  * dodumpdef - dump the specified definitions in the hash
525  *      table to stderr. If nothing is specified, the entire
526  *      hash table is dumped.
527  */
528 void
529 dodump(argv, argc)
530 register char *argv[];
531 register int argc;
532 {
533         register int n;
534         ndptr p;
535
536         if (argc > 2) {
537                 for (n = 2; n < argc; n++)
538                         if ((p = lookup(argv[n])) != nil)
539                                 fprintf(stderr, dumpfmt, p->name,
540                                         p->defn);
541         }
542         else {
543                 for (n = 0; n < HASHSIZE; n++)
544                         for (p = hashtab[n]; p != nil; p = p->nxtptr)
545                                 fprintf(stderr, dumpfmt, p->name,
546                                         p->defn);
547         }
548 }
549
550 /*
551  * doifelse - select one of two alternatives - loop.
552  */
553 void
554 doifelse(argv, argc)
555 register char *argv[];
556 register int argc;
557 {
558         cycle {
559                 if (STREQ(argv[2], argv[3]))
560                         pbstr(argv[4]);
561                 else if (argc == 6)
562                         pbstr(argv[5]);
563                 else if (argc > 6) {
564                         argv += 3;
565                         argc -= 3;
566                         continue;
567                 }
568                 break;
569         }
570 }
571
572 /*
573  * doinclude - include a given file.
574  */
575 int
576 doincl(ifile)
577 char *ifile;
578 {
579         if (ilevel + 1 == MAXINP)
580                 errx(1, "too many include files");
581         if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
582                 ilevel++;
583                 bbase[ilevel] = bufbase = bp;
584                 return (1);
585         }
586         else
587                 return (0);
588 }
589
590 #ifdef EXTENDED
591 /*
592  * dopaste - include a given file without any
593  *           macro processing.
594  */
595 int
596 dopaste(pfile)
597 char *pfile;
598 {
599         FILE *pf;
600         register int c;
601
602         if ((pf = fopen(pfile, "r")) != NULL) {
603                 while ((c = getc(pf)) != EOF)
604                         putc(c, active);
605                 (void) fclose(pf);
606                 return (1);
607         }
608         else
609                 return (0);
610 }
611 #endif
612
613 /*
614  * dochq - change quote characters
615  */
616 void
617 dochq(argv, argc)
618 register char *argv[];
619 register int argc;
620 {
621         if (argc > 2) {
622                 if (*argv[2])
623                         lquote = *argv[2];
624                 else
625                         lquote = LQUOTE;
626                 if (argc > 3) {
627                         if (*argv[3])
628                                 rquote = *argv[3];
629                         else
630                                 rquote = RQUOTE;
631                 }
632                 else
633                         rquote = lquote;
634         }
635         else {
636                 lquote = LQUOTE;
637                 rquote = RQUOTE;
638         }
639 }
640
641 /*
642  * dochc - change comment characters
643  */
644 void
645 dochc(argv, argc)
646 register char *argv[];
647 register int argc;
648 {
649         if (argc > 2) {
650                 if (*argv[2])
651                         scommt = *argv[2];
652                 if (argc > 3) {
653                         if (*argv[3])
654                                 ecommt = *argv[3];
655                 }
656                 else
657                         ecommt = ECOMMT;
658         }
659         else {
660                 scommt = SCOMMT;
661                 ecommt = ECOMMT;
662         }
663 }
664
665 /*
666  * dodivert - divert the output to a temporary file
667  */
668 void
669 dodiv(n)
670 register int n;
671 {
672         oindex = n;
673         if (n < 0 || n >= MAXOUT)
674                 n = 0;                 /* bitbucket */
675         if (outfile[n] == NULL) {
676                 m4temp[UNIQUE] = n + '0';
677                 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
678                         errx(1, "%s: cannot divert", m4temp);
679         }
680         active = outfile[n];
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 register char *argv[];
690 register int argc;
691 {
692         register int ind;
693         register 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 register char *argv[];
715 register int argc;
716 {
717         register unsigned char *ap, *fc, *k;
718         register 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 register char *dest;
767 register char *src;
768 register char *from;
769 register char *to;
770 {
771         register char *tmp;
772         register 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[*from++] = (*to) ? *to++ : (char) 0;
795
796                 while (*src) {
797                         sch = *src++;
798                         dch = mapvec[sch];
799                         while (dch != sch) {
800                                 sch = dch;
801                                 dch = mapvec[sch];
802                         }
803                         if (*dest = dch)
804                                 dest++;
805                 }
806         /*
807          * restore all the changed characters
808          */
809                 while (*tmp) {
810                         mapvec[*tmp] = *tmp;
811                         tmp++;
812                 }
813         }
814         *dest = (char) 0;
815 }