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