143d6cbb6Sbostic /*
2494f5ecfSbostic * Copyright (c) 1989, 1993
3494f5ecfSbostic * The Regents of the University of California. All rights reserved.
443d6cbb6Sbostic *
543d6cbb6Sbostic * This code is derived from software contributed to Berkeley by
6a435ab37Sbostic * Ozan Yigit at York University.
743d6cbb6Sbostic *
8799620b5Sbostic * %sccs.include.redist.c%
943d6cbb6Sbostic */
1043d6cbb6Sbostic
1143d6cbb6Sbostic #ifndef lint
12*b043d314Sbostic static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 04/27/95";
1343d6cbb6Sbostic #endif /* not lint */
1443d6cbb6Sbostic
1543d6cbb6Sbostic /*
1643d6cbb6Sbostic * eval.c
1743d6cbb6Sbostic * Facility: m4 macro processor
1843d6cbb6Sbostic * by: oz
1943d6cbb6Sbostic */
2043d6cbb6Sbostic
21d3eef09bSbostic #include <sys/types.h>
22d3eef09bSbostic #include <errno.h>
23935903d7Sbostic #include <unistd.h>
24935903d7Sbostic #include <stdio.h>
25935903d7Sbostic #include <stdlib.h>
26935903d7Sbostic #include <string.h>
2743d6cbb6Sbostic #include "mdef.h"
28d3eef09bSbostic #include "stdd.h"
29d3eef09bSbostic #include "extern.h"
30d3eef09bSbostic #include "pathnames.h"
3143d6cbb6Sbostic
3243d6cbb6Sbostic /*
3343d6cbb6Sbostic * eval - evaluate built-in macros.
3443d6cbb6Sbostic * argc - number of elements in argv.
3543d6cbb6Sbostic * argv - element vector :
3643d6cbb6Sbostic * argv[0] = definition of a user
3743d6cbb6Sbostic * macro or nil if built-in.
3843d6cbb6Sbostic * argv[1] = name of the macro or
3943d6cbb6Sbostic * built-in.
4043d6cbb6Sbostic * argv[2] = parameters to user-defined
4143d6cbb6Sbostic * . macro or built-in.
4243d6cbb6Sbostic * .
4343d6cbb6Sbostic *
4443d6cbb6Sbostic * Note that the minimum value for argc is 3. A call in the form
4543d6cbb6Sbostic * of macro-or-builtin() will result in:
4643d6cbb6Sbostic * argv[0] = nullstr
4743d6cbb6Sbostic * argv[1] = macro-or-builtin
4843d6cbb6Sbostic * argv[2] = nullstr
4943d6cbb6Sbostic */
5043d6cbb6Sbostic
51d3eef09bSbostic void
eval(argv,argc,td)5243d6cbb6Sbostic eval(argv, argc, td)
5343d6cbb6Sbostic register char *argv[];
5443d6cbb6Sbostic register int argc;
5543d6cbb6Sbostic register int td;
5643d6cbb6Sbostic {
5743d6cbb6Sbostic register int c, n;
58d3eef09bSbostic static int sysval = 0;
5943d6cbb6Sbostic
6043d6cbb6Sbostic #ifdef DEBUG
6143d6cbb6Sbostic printf("argc = %d\n", argc);
6243d6cbb6Sbostic for (n = 0; n < argc; n++)
6343d6cbb6Sbostic printf("argv[%d] = %s\n", n, argv[n]);
6443d6cbb6Sbostic #endif
6543d6cbb6Sbostic /*
66d3eef09bSbostic * if argc == 3 and argv[2] is null, then we
67d3eef09bSbostic * have macro-or-builtin() type call. We adjust
68d3eef09bSbostic * argc to avoid further checking..
6943d6cbb6Sbostic */
7043d6cbb6Sbostic if (argc == 3 && !*(argv[2]))
7143d6cbb6Sbostic argc--;
7243d6cbb6Sbostic
7343d6cbb6Sbostic switch (td & ~STATIC) {
7443d6cbb6Sbostic
7543d6cbb6Sbostic case DEFITYPE:
7643d6cbb6Sbostic if (argc > 2)
7743d6cbb6Sbostic dodefine(argv[2], (argc > 3) ? argv[3] : null);
7843d6cbb6Sbostic break;
7943d6cbb6Sbostic
8043d6cbb6Sbostic case PUSDTYPE:
8143d6cbb6Sbostic if (argc > 2)
8243d6cbb6Sbostic dopushdef(argv[2], (argc > 3) ? argv[3] : null);
8343d6cbb6Sbostic break;
8443d6cbb6Sbostic
8543d6cbb6Sbostic case DUMPTYPE:
8643d6cbb6Sbostic dodump(argv, argc);
8743d6cbb6Sbostic break;
8843d6cbb6Sbostic
8943d6cbb6Sbostic case EXPRTYPE:
9043d6cbb6Sbostic /*
91d3eef09bSbostic * doexpr - evaluate arithmetic
92d3eef09bSbostic * expression
9343d6cbb6Sbostic */
9443d6cbb6Sbostic if (argc > 2)
9543d6cbb6Sbostic pbnum(expr(argv[2]));
9643d6cbb6Sbostic break;
9743d6cbb6Sbostic
9843d6cbb6Sbostic case IFELTYPE:
9943d6cbb6Sbostic if (argc > 4)
10043d6cbb6Sbostic doifelse(argv, argc);
10143d6cbb6Sbostic break;
10243d6cbb6Sbostic
10343d6cbb6Sbostic case IFDFTYPE:
10443d6cbb6Sbostic /*
105d3eef09bSbostic * doifdef - select one of two
106d3eef09bSbostic * alternatives based on the existence of
107d3eef09bSbostic * another definition
10843d6cbb6Sbostic */
10943d6cbb6Sbostic if (argc > 3) {
11043d6cbb6Sbostic if (lookup(argv[2]) != nil)
11143d6cbb6Sbostic pbstr(argv[3]);
11243d6cbb6Sbostic else if (argc > 4)
11343d6cbb6Sbostic pbstr(argv[4]);
11443d6cbb6Sbostic }
11543d6cbb6Sbostic break;
11643d6cbb6Sbostic
11743d6cbb6Sbostic case LENGTYPE:
11843d6cbb6Sbostic /*
119d3eef09bSbostic * dolen - find the length of the
120d3eef09bSbostic * argument
12143d6cbb6Sbostic */
12243d6cbb6Sbostic if (argc > 2)
12343d6cbb6Sbostic pbnum((argc > 2) ? strlen(argv[2]) : 0);
12443d6cbb6Sbostic break;
12543d6cbb6Sbostic
12643d6cbb6Sbostic case INCRTYPE:
12743d6cbb6Sbostic /*
128d3eef09bSbostic * doincr - increment the value of the
129d3eef09bSbostic * argument
13043d6cbb6Sbostic */
13143d6cbb6Sbostic if (argc > 2)
13243d6cbb6Sbostic pbnum(atoi(argv[2]) + 1);
13343d6cbb6Sbostic break;
13443d6cbb6Sbostic
13543d6cbb6Sbostic case DECRTYPE:
13643d6cbb6Sbostic /*
137d3eef09bSbostic * dodecr - decrement the value of the
138d3eef09bSbostic * argument
13943d6cbb6Sbostic */
14043d6cbb6Sbostic if (argc > 2)
14143d6cbb6Sbostic pbnum(atoi(argv[2]) - 1);
14243d6cbb6Sbostic break;
14343d6cbb6Sbostic
14443d6cbb6Sbostic case SYSCTYPE:
14543d6cbb6Sbostic /*
14643d6cbb6Sbostic * dosys - execute system command
14743d6cbb6Sbostic */
14843d6cbb6Sbostic if (argc > 2)
14943d6cbb6Sbostic sysval = system(argv[2]);
15043d6cbb6Sbostic break;
15143d6cbb6Sbostic
15243d6cbb6Sbostic case SYSVTYPE:
15343d6cbb6Sbostic /*
154d3eef09bSbostic * dosysval - return value of the last
155d3eef09bSbostic * system call.
15643d6cbb6Sbostic *
15743d6cbb6Sbostic */
15843d6cbb6Sbostic pbnum(sysval);
15943d6cbb6Sbostic break;
16043d6cbb6Sbostic
16143d6cbb6Sbostic case INCLTYPE:
16243d6cbb6Sbostic if (argc > 2)
163d3eef09bSbostic if (!doincl(argv[2]))
164d3eef09bSbostic oops("%s: %s", argv[2], strerror(errno));
16543d6cbb6Sbostic break;
16643d6cbb6Sbostic
16743d6cbb6Sbostic case SINCTYPE:
16843d6cbb6Sbostic if (argc > 2)
16943d6cbb6Sbostic (void) doincl(argv[2]);
17043d6cbb6Sbostic break;
17143d6cbb6Sbostic #ifdef EXTENDED
17243d6cbb6Sbostic case PASTTYPE:
17343d6cbb6Sbostic if (argc > 2)
174d3eef09bSbostic if (!dopaste(argv[2]))
175d3eef09bSbostic oops("%s: %s", argv[2], strerror(errno));
17643d6cbb6Sbostic break;
17743d6cbb6Sbostic
17843d6cbb6Sbostic case SPASTYPE:
17943d6cbb6Sbostic if (argc > 2)
18043d6cbb6Sbostic (void) dopaste(argv[2]);
18143d6cbb6Sbostic break;
18243d6cbb6Sbostic #endif
18343d6cbb6Sbostic case CHNQTYPE:
18443d6cbb6Sbostic dochq(argv, argc);
18543d6cbb6Sbostic break;
18643d6cbb6Sbostic
18743d6cbb6Sbostic case CHNCTYPE:
18843d6cbb6Sbostic dochc(argv, argc);
18943d6cbb6Sbostic break;
19043d6cbb6Sbostic
19143d6cbb6Sbostic case SUBSTYPE:
19243d6cbb6Sbostic /*
19343d6cbb6Sbostic * dosub - select substring
19443d6cbb6Sbostic *
19543d6cbb6Sbostic */
19643d6cbb6Sbostic if (argc > 3)
19743d6cbb6Sbostic dosub(argv, argc);
19843d6cbb6Sbostic break;
19943d6cbb6Sbostic
20043d6cbb6Sbostic case SHIFTYPE:
20143d6cbb6Sbostic /*
202d3eef09bSbostic * doshift - push back all arguments
203d3eef09bSbostic * except the first one (i.e. skip
204d3eef09bSbostic * argv[2])
20543d6cbb6Sbostic */
20643d6cbb6Sbostic if (argc > 3) {
20743d6cbb6Sbostic for (n = argc - 1; n > 3; n--) {
20843d6cbb6Sbostic putback(rquote);
20943d6cbb6Sbostic pbstr(argv[n]);
21043d6cbb6Sbostic putback(lquote);
21143d6cbb6Sbostic putback(',');
21243d6cbb6Sbostic }
21343d6cbb6Sbostic putback(rquote);
21443d6cbb6Sbostic pbstr(argv[3]);
21543d6cbb6Sbostic putback(lquote);
21643d6cbb6Sbostic }
21743d6cbb6Sbostic break;
21843d6cbb6Sbostic
21943d6cbb6Sbostic case DIVRTYPE:
22043d6cbb6Sbostic if (argc > 2 && (n = atoi(argv[2])) != 0)
22143d6cbb6Sbostic dodiv(n);
22243d6cbb6Sbostic else {
22343d6cbb6Sbostic active = stdout;
22443d6cbb6Sbostic oindex = 0;
22543d6cbb6Sbostic }
22643d6cbb6Sbostic break;
22743d6cbb6Sbostic
22843d6cbb6Sbostic case UNDVTYPE:
22943d6cbb6Sbostic doundiv(argv, argc);
23043d6cbb6Sbostic break;
23143d6cbb6Sbostic
23243d6cbb6Sbostic case DIVNTYPE:
23343d6cbb6Sbostic /*
234d3eef09bSbostic * dodivnum - return the number of
235d3eef09bSbostic * current output diversion
23643d6cbb6Sbostic */
23743d6cbb6Sbostic pbnum(oindex);
23843d6cbb6Sbostic break;
23943d6cbb6Sbostic
24043d6cbb6Sbostic case UNDFTYPE:
24143d6cbb6Sbostic /*
242d3eef09bSbostic * doundefine - undefine a previously
243d3eef09bSbostic * defined macro(s) or m4 keyword(s).
24443d6cbb6Sbostic */
24543d6cbb6Sbostic if (argc > 2)
24643d6cbb6Sbostic for (n = 2; n < argc; n++)
24743d6cbb6Sbostic remhash(argv[n], ALL);
24843d6cbb6Sbostic break;
24943d6cbb6Sbostic
25043d6cbb6Sbostic case POPDTYPE:
25143d6cbb6Sbostic /*
252d3eef09bSbostic * dopopdef - remove the topmost
253d3eef09bSbostic * definitions of macro(s) or m4
254d3eef09bSbostic * keyword(s).
25543d6cbb6Sbostic */
25643d6cbb6Sbostic if (argc > 2)
25743d6cbb6Sbostic for (n = 2; n < argc; n++)
25843d6cbb6Sbostic remhash(argv[n], TOP);
25943d6cbb6Sbostic break;
26043d6cbb6Sbostic
26143d6cbb6Sbostic case MKTMTYPE:
26243d6cbb6Sbostic /*
26343d6cbb6Sbostic * dotemp - create a temporary file
26443d6cbb6Sbostic */
26543d6cbb6Sbostic if (argc > 2)
26643d6cbb6Sbostic pbstr(mktemp(argv[2]));
26743d6cbb6Sbostic break;
26843d6cbb6Sbostic
26943d6cbb6Sbostic case TRNLTYPE:
27043d6cbb6Sbostic /*
271d3eef09bSbostic * dotranslit - replace all characters in
272d3eef09bSbostic * the source string that appears in the
273d3eef09bSbostic * "from" string with the corresponding
27443d6cbb6Sbostic * characters in the "to" string.
27543d6cbb6Sbostic */
27643d6cbb6Sbostic if (argc > 3) {
27743d6cbb6Sbostic char temp[MAXTOK];
27843d6cbb6Sbostic if (argc > 4)
27943d6cbb6Sbostic map(temp, argv[2], argv[3], argv[4]);
28043d6cbb6Sbostic else
28143d6cbb6Sbostic map(temp, argv[2], argv[3], null);
28243d6cbb6Sbostic pbstr(temp);
28343d6cbb6Sbostic }
284d3eef09bSbostic else if (argc > 2)
28543d6cbb6Sbostic pbstr(argv[2]);
28643d6cbb6Sbostic break;
28743d6cbb6Sbostic
28843d6cbb6Sbostic case INDXTYPE:
28943d6cbb6Sbostic /*
290d3eef09bSbostic * doindex - find the index of the second
291d3eef09bSbostic * argument string in the first argument
292d3eef09bSbostic * string. -1 if not present.
29343d6cbb6Sbostic */
29443d6cbb6Sbostic pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
29543d6cbb6Sbostic break;
29643d6cbb6Sbostic
29743d6cbb6Sbostic case ERRPTYPE:
29843d6cbb6Sbostic /*
299d3eef09bSbostic * doerrp - print the arguments to stderr
300d3eef09bSbostic * file
30143d6cbb6Sbostic */
30243d6cbb6Sbostic if (argc > 2) {
30343d6cbb6Sbostic for (n = 2; n < argc; n++)
30443d6cbb6Sbostic fprintf(stderr, "%s ", argv[n]);
30543d6cbb6Sbostic fprintf(stderr, "\n");
30643d6cbb6Sbostic }
30743d6cbb6Sbostic break;
30843d6cbb6Sbostic
30943d6cbb6Sbostic case DNLNTYPE:
31043d6cbb6Sbostic /*
311d3eef09bSbostic * dodnl - eat-up-to and including
312d3eef09bSbostic * newline
31343d6cbb6Sbostic */
31443d6cbb6Sbostic while ((c = gpbc()) != '\n' && c != EOF)
31543d6cbb6Sbostic ;
31643d6cbb6Sbostic break;
31743d6cbb6Sbostic
31843d6cbb6Sbostic case M4WRTYPE:
31943d6cbb6Sbostic /*
320d3eef09bSbostic * dom4wrap - set up for
321d3eef09bSbostic * wrap-up/wind-down activity
32243d6cbb6Sbostic */
323d3eef09bSbostic m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
32443d6cbb6Sbostic break;
32543d6cbb6Sbostic
32643d6cbb6Sbostic case EXITTYPE:
32743d6cbb6Sbostic /*
32843d6cbb6Sbostic * doexit - immediate exit from m4.
32943d6cbb6Sbostic */
330*b043d314Sbostic killdiv();
33143d6cbb6Sbostic exit((argc > 2) ? atoi(argv[2]) : 0);
33243d6cbb6Sbostic break;
33343d6cbb6Sbostic
33443d6cbb6Sbostic case DEFNTYPE:
33543d6cbb6Sbostic if (argc > 2)
33643d6cbb6Sbostic for (n = 2; n < argc; n++)
33743d6cbb6Sbostic dodefn(argv[n]);
33843d6cbb6Sbostic break;
33943d6cbb6Sbostic
34043d6cbb6Sbostic default:
341d3eef09bSbostic oops("%s: major botch.", "eval");
34243d6cbb6Sbostic break;
34343d6cbb6Sbostic }
34443d6cbb6Sbostic }
345d3eef09bSbostic
346d3eef09bSbostic char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
347d3eef09bSbostic
348d3eef09bSbostic /*
349d3eef09bSbostic * expand - user-defined macro expansion
350d3eef09bSbostic */
351d3eef09bSbostic void
expand(argv,argc)352d3eef09bSbostic expand(argv, argc)
353d3eef09bSbostic register char *argv[];
354d3eef09bSbostic register int argc;
355d3eef09bSbostic {
356d3eef09bSbostic register char *t;
357d3eef09bSbostic register char *p;
358d3eef09bSbostic register int n;
359d3eef09bSbostic register int argno;
360d3eef09bSbostic
361d3eef09bSbostic t = argv[0]; /* defn string as a whole */
362d3eef09bSbostic p = t;
363d3eef09bSbostic while (*p)
364d3eef09bSbostic p++;
365d3eef09bSbostic p--; /* last character of defn */
366d3eef09bSbostic while (p > t) {
367d3eef09bSbostic if (*(p - 1) != ARGFLAG)
368d3eef09bSbostic putback(*p);
369d3eef09bSbostic else {
370d3eef09bSbostic switch (*p) {
371d3eef09bSbostic
372d3eef09bSbostic case '#':
373d3eef09bSbostic pbnum(argc - 2);
374d3eef09bSbostic break;
375d3eef09bSbostic case '0':
376d3eef09bSbostic case '1':
377d3eef09bSbostic case '2':
378d3eef09bSbostic case '3':
379d3eef09bSbostic case '4':
380d3eef09bSbostic case '5':
381d3eef09bSbostic case '6':
382d3eef09bSbostic case '7':
383d3eef09bSbostic case '8':
384d3eef09bSbostic case '9':
385d3eef09bSbostic if ((argno = *p - '0') < argc - 1)
386d3eef09bSbostic pbstr(argv[argno + 1]);
387d3eef09bSbostic break;
388d3eef09bSbostic case '*':
389d3eef09bSbostic for (n = argc - 1; n > 2; n--) {
390d3eef09bSbostic pbstr(argv[n]);
391d3eef09bSbostic putback(',');
392d3eef09bSbostic }
393d3eef09bSbostic pbstr(argv[2]);
394d3eef09bSbostic break;
395d3eef09bSbostic default:
396d3eef09bSbostic putback(*p);
3978a657776Sbostic putback('$');
398d3eef09bSbostic break;
399d3eef09bSbostic }
400d3eef09bSbostic p--;
401d3eef09bSbostic }
402d3eef09bSbostic p--;
403d3eef09bSbostic }
404d3eef09bSbostic if (p == t) /* do last character */
405d3eef09bSbostic putback(*p);
406d3eef09bSbostic }
407d3eef09bSbostic
408d3eef09bSbostic /*
409d3eef09bSbostic * dodefine - install definition in the table
410d3eef09bSbostic */
411d3eef09bSbostic void
dodefine(name,defn)412d3eef09bSbostic dodefine(name, defn)
413d3eef09bSbostic register char *name;
414d3eef09bSbostic register char *defn;
415d3eef09bSbostic {
416d3eef09bSbostic register ndptr p;
417d3eef09bSbostic
418d3eef09bSbostic if (!*name)
419d3eef09bSbostic oops("null definition.");
420d3eef09bSbostic if (STREQ(name, defn))
421d3eef09bSbostic oops("%s: recursive definition.", name);
422d3eef09bSbostic if ((p = lookup(name)) == nil)
423d3eef09bSbostic p = addent(name);
424d3eef09bSbostic else if (p->defn != null)
425d3eef09bSbostic free((char *) p->defn);
426d3eef09bSbostic if (!*defn)
427d3eef09bSbostic p->defn = null;
428d3eef09bSbostic else
429d3eef09bSbostic p->defn = xstrdup(defn);
430d3eef09bSbostic p->type = MACRTYPE;
431d3eef09bSbostic }
432d3eef09bSbostic
433d3eef09bSbostic /*
434d3eef09bSbostic * dodefn - push back a quoted definition of
435d3eef09bSbostic * the given name.
436d3eef09bSbostic */
437d3eef09bSbostic void
dodefn(name)438d3eef09bSbostic dodefn(name)
439d3eef09bSbostic char *name;
440d3eef09bSbostic {
441d3eef09bSbostic register ndptr p;
442d3eef09bSbostic
443d3eef09bSbostic if ((p = lookup(name)) != nil && p->defn != null) {
444d3eef09bSbostic putback(rquote);
445d3eef09bSbostic pbstr(p->defn);
446d3eef09bSbostic putback(lquote);
447d3eef09bSbostic }
448d3eef09bSbostic }
449d3eef09bSbostic
450d3eef09bSbostic /*
451d3eef09bSbostic * dopushdef - install a definition in the hash table
452d3eef09bSbostic * without removing a previous definition. Since
453d3eef09bSbostic * each new entry is entered in *front* of the
454d3eef09bSbostic * hash bucket, it hides a previous definition from
455d3eef09bSbostic * lookup.
456d3eef09bSbostic */
457d3eef09bSbostic void
dopushdef(name,defn)458d3eef09bSbostic dopushdef(name, defn)
459d3eef09bSbostic register char *name;
460d3eef09bSbostic register char *defn;
461d3eef09bSbostic {
462d3eef09bSbostic register ndptr p;
463d3eef09bSbostic
464d3eef09bSbostic if (!*name)
465d3eef09bSbostic oops("null definition");
466d3eef09bSbostic if (STREQ(name, defn))
467d3eef09bSbostic oops("%s: recursive definition.", name);
468d3eef09bSbostic p = addent(name);
469d3eef09bSbostic if (!*defn)
470d3eef09bSbostic p->defn = null;
471d3eef09bSbostic else
472d3eef09bSbostic p->defn = xstrdup(defn);
473d3eef09bSbostic p->type = MACRTYPE;
474d3eef09bSbostic }
475d3eef09bSbostic
476d3eef09bSbostic /*
477d3eef09bSbostic * dodumpdef - dump the specified definitions in the hash
478d3eef09bSbostic * table to stderr. If nothing is specified, the entire
479d3eef09bSbostic * hash table is dumped.
480d3eef09bSbostic */
481d3eef09bSbostic void
dodump(argv,argc)482d3eef09bSbostic dodump(argv, argc)
483d3eef09bSbostic register char *argv[];
484d3eef09bSbostic register int argc;
485d3eef09bSbostic {
486d3eef09bSbostic register int n;
487d3eef09bSbostic ndptr p;
488d3eef09bSbostic
489d3eef09bSbostic if (argc > 2) {
490d3eef09bSbostic for (n = 2; n < argc; n++)
491d3eef09bSbostic if ((p = lookup(argv[n])) != nil)
492d3eef09bSbostic fprintf(stderr, dumpfmt, p->name,
493d3eef09bSbostic p->defn);
494d3eef09bSbostic }
495d3eef09bSbostic else {
496d3eef09bSbostic for (n = 0; n < HASHSIZE; n++)
497d3eef09bSbostic for (p = hashtab[n]; p != nil; p = p->nxtptr)
498d3eef09bSbostic fprintf(stderr, dumpfmt, p->name,
499d3eef09bSbostic p->defn);
500d3eef09bSbostic }
501d3eef09bSbostic }
502d3eef09bSbostic
503d3eef09bSbostic /*
504d3eef09bSbostic * doifelse - select one of two alternatives - loop.
505d3eef09bSbostic */
506d3eef09bSbostic void
doifelse(argv,argc)507d3eef09bSbostic doifelse(argv, argc)
508d3eef09bSbostic register char *argv[];
509d3eef09bSbostic register int argc;
510d3eef09bSbostic {
511d3eef09bSbostic cycle {
512d3eef09bSbostic if (STREQ(argv[2], argv[3]))
513d3eef09bSbostic pbstr(argv[4]);
514d3eef09bSbostic else if (argc == 6)
515d3eef09bSbostic pbstr(argv[5]);
516d3eef09bSbostic else if (argc > 6) {
517d3eef09bSbostic argv += 3;
518d3eef09bSbostic argc -= 3;
519d3eef09bSbostic continue;
520d3eef09bSbostic }
521d3eef09bSbostic break;
522d3eef09bSbostic }
523d3eef09bSbostic }
524d3eef09bSbostic
525d3eef09bSbostic /*
526d3eef09bSbostic * doinclude - include a given file.
527d3eef09bSbostic */
528d3eef09bSbostic int
doincl(ifile)529d3eef09bSbostic doincl(ifile)
530d3eef09bSbostic char *ifile;
531d3eef09bSbostic {
532d3eef09bSbostic if (ilevel + 1 == MAXINP)
533d3eef09bSbostic oops("too many include files.");
534d3eef09bSbostic if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
535d3eef09bSbostic ilevel++;
536c22b2b5fSeric bbase[ilevel] = bufbase = bp;
537d3eef09bSbostic return (1);
538d3eef09bSbostic }
539d3eef09bSbostic else
540d3eef09bSbostic return (0);
541d3eef09bSbostic }
542d3eef09bSbostic
543d3eef09bSbostic #ifdef EXTENDED
544d3eef09bSbostic /*
545d3eef09bSbostic * dopaste - include a given file without any
546d3eef09bSbostic * macro processing.
547d3eef09bSbostic */
548d3eef09bSbostic int
dopaste(pfile)549d3eef09bSbostic dopaste(pfile)
550d3eef09bSbostic char *pfile;
551d3eef09bSbostic {
552d3eef09bSbostic FILE *pf;
553d3eef09bSbostic register int c;
554d3eef09bSbostic
555d3eef09bSbostic if ((pf = fopen(pfile, "r")) != NULL) {
556d3eef09bSbostic while ((c = getc(pf)) != EOF)
557d3eef09bSbostic putc(c, active);
558d3eef09bSbostic (void) fclose(pf);
559d3eef09bSbostic return (1);
560d3eef09bSbostic }
561d3eef09bSbostic else
562d3eef09bSbostic return (0);
563d3eef09bSbostic }
564d3eef09bSbostic #endif
565d3eef09bSbostic
566d3eef09bSbostic /*
567d3eef09bSbostic * dochq - change quote characters
568d3eef09bSbostic */
569d3eef09bSbostic void
dochq(argv,argc)570d3eef09bSbostic dochq(argv, argc)
571d3eef09bSbostic register char *argv[];
572d3eef09bSbostic register int argc;
573d3eef09bSbostic {
574d3eef09bSbostic if (argc > 2) {
575d3eef09bSbostic if (*argv[2])
576d3eef09bSbostic lquote = *argv[2];
577d3eef09bSbostic if (argc > 3) {
578d3eef09bSbostic if (*argv[3])
579d3eef09bSbostic rquote = *argv[3];
580d3eef09bSbostic }
581d3eef09bSbostic else
582d3eef09bSbostic rquote = lquote;
583d3eef09bSbostic }
584d3eef09bSbostic else {
585d3eef09bSbostic lquote = LQUOTE;
586d3eef09bSbostic rquote = RQUOTE;
587d3eef09bSbostic }
588d3eef09bSbostic }
589d3eef09bSbostic
590d3eef09bSbostic /*
591d3eef09bSbostic * dochc - change comment characters
592d3eef09bSbostic */
593d3eef09bSbostic void
dochc(argv,argc)594d3eef09bSbostic dochc(argv, argc)
595d3eef09bSbostic register char *argv[];
596d3eef09bSbostic register int argc;
597d3eef09bSbostic {
598d3eef09bSbostic if (argc > 2) {
599d3eef09bSbostic if (*argv[2])
600d3eef09bSbostic scommt = *argv[2];
601d3eef09bSbostic if (argc > 3) {
602d3eef09bSbostic if (*argv[3])
603d3eef09bSbostic ecommt = *argv[3];
604d3eef09bSbostic }
605d3eef09bSbostic else
606d3eef09bSbostic ecommt = ECOMMT;
607d3eef09bSbostic }
608d3eef09bSbostic else {
609d3eef09bSbostic scommt = SCOMMT;
610d3eef09bSbostic ecommt = ECOMMT;
611d3eef09bSbostic }
612d3eef09bSbostic }
613d3eef09bSbostic
614d3eef09bSbostic /*
615d3eef09bSbostic * dodivert - divert the output to a temporary file
616d3eef09bSbostic */
617d3eef09bSbostic void
dodiv(n)618d3eef09bSbostic dodiv(n)
619d3eef09bSbostic register int n;
620d3eef09bSbostic {
621d3eef09bSbostic if (n < 0 || n >= MAXOUT)
622d3eef09bSbostic n = 0; /* bitbucket */
623d3eef09bSbostic if (outfile[n] == NULL) {
624d3eef09bSbostic m4temp[UNIQUE] = n + '0';
625d3eef09bSbostic if ((outfile[n] = fopen(m4temp, "w")) == NULL)
626d3eef09bSbostic oops("%s: cannot divert.", m4temp);
627d3eef09bSbostic }
628d3eef09bSbostic oindex = n;
629d3eef09bSbostic active = outfile[n];
630d3eef09bSbostic }
631d3eef09bSbostic
632d3eef09bSbostic /*
633d3eef09bSbostic * doundivert - undivert a specified output, or all
634d3eef09bSbostic * other outputs, in numerical order.
635d3eef09bSbostic */
636d3eef09bSbostic void
doundiv(argv,argc)637d3eef09bSbostic doundiv(argv, argc)
638d3eef09bSbostic register char *argv[];
639d3eef09bSbostic register int argc;
640d3eef09bSbostic {
641d3eef09bSbostic register int ind;
642d3eef09bSbostic register int n;
643d3eef09bSbostic
644d3eef09bSbostic if (argc > 2) {
645d3eef09bSbostic for (ind = 2; ind < argc; ind++) {
646d3eef09bSbostic n = atoi(argv[ind]);
647d3eef09bSbostic if (n > 0 && n < MAXOUT && outfile[n] != NULL)
648d3eef09bSbostic getdiv(n);
649d3eef09bSbostic
650d3eef09bSbostic }
651d3eef09bSbostic }
652d3eef09bSbostic else
653d3eef09bSbostic for (n = 1; n < MAXOUT; n++)
654d3eef09bSbostic if (outfile[n] != NULL)
655d3eef09bSbostic getdiv(n);
656d3eef09bSbostic }
657d3eef09bSbostic
658d3eef09bSbostic /*
659d3eef09bSbostic * dosub - select substring
660d3eef09bSbostic */
661d3eef09bSbostic void
dosub(argv,argc)662d3eef09bSbostic dosub(argv, argc)
663d3eef09bSbostic register char *argv[];
664d3eef09bSbostic register int argc;
665d3eef09bSbostic {
666d3eef09bSbostic register char *ap, *fc, *k;
667d3eef09bSbostic register int nc;
668d3eef09bSbostic
669d3eef09bSbostic if (argc < 5)
670d3eef09bSbostic nc = MAXTOK;
671d3eef09bSbostic else
672d3eef09bSbostic #ifdef EXPR
673d3eef09bSbostic nc = expr(argv[4]);
674d3eef09bSbostic #else
675d3eef09bSbostic nc = atoi(argv[4]);
676d3eef09bSbostic #endif
677d3eef09bSbostic ap = argv[2]; /* target string */
678d3eef09bSbostic #ifdef EXPR
679d3eef09bSbostic fc = ap + expr(argv[3]); /* first char */
680d3eef09bSbostic #else
681d3eef09bSbostic fc = ap + atoi(argv[3]); /* first char */
682d3eef09bSbostic #endif
683d3eef09bSbostic if (fc >= ap && fc < ap + strlen(ap))
684d3eef09bSbostic for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
685d3eef09bSbostic putback(*k);
686d3eef09bSbostic }
687d3eef09bSbostic
688d3eef09bSbostic /*
689d3eef09bSbostic * map:
690d3eef09bSbostic * map every character of s1 that is specified in from
691d3eef09bSbostic * into s3 and replace in s. (source s1 remains untouched)
692d3eef09bSbostic *
693d3eef09bSbostic * This is a standard implementation of map(s,from,to) function of ICON
694d3eef09bSbostic * language. Within mapvec, we replace every character of "from" with
695d3eef09bSbostic * the corresponding character in "to". If "to" is shorter than "from",
696d3eef09bSbostic * than the corresponding entries are null, which means that those
697d3eef09bSbostic * characters dissapear altogether. Furthermore, imagine
698d3eef09bSbostic * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
699d3eef09bSbostic * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
700d3eef09bSbostic * ultimately maps to `*'. In order to achieve this effect in an efficient
701d3eef09bSbostic * manner (i.e. without multiple passes over the destination string), we
702d3eef09bSbostic * loop over mapvec, starting with the initial source character. if the
703d3eef09bSbostic * character value (dch) in this location is different than the source
704d3eef09bSbostic * character (sch), sch becomes dch, once again to index into mapvec, until
705d3eef09bSbostic * the character value stabilizes (i.e. sch = dch, in other words
706d3eef09bSbostic * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
707d3eef09bSbostic * character, it will stabilize, since mapvec[0] == 0 at all times. At the
708d3eef09bSbostic * end, we restore mapvec* back to normal where mapvec[n] == n for
709d3eef09bSbostic * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
710d3eef09bSbostic * about 5 times faster than any algorithm that makes multiple passes over
711d3eef09bSbostic * destination string.
712d3eef09bSbostic */
713d3eef09bSbostic void
map(dest,src,from,to)714d3eef09bSbostic map(dest, src, from, to)
715d3eef09bSbostic register char *dest;
716d3eef09bSbostic register char *src;
717d3eef09bSbostic register char *from;
718d3eef09bSbostic register char *to;
719d3eef09bSbostic {
720d3eef09bSbostic register char *tmp;
721d3eef09bSbostic register char sch, dch;
722d3eef09bSbostic static char mapvec[128] = {
723d3eef09bSbostic 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
724d3eef09bSbostic 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
725d3eef09bSbostic 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
726d3eef09bSbostic 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
727d3eef09bSbostic 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
728d3eef09bSbostic 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
729d3eef09bSbostic 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
730d3eef09bSbostic 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
731d3eef09bSbostic 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
732d3eef09bSbostic 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
733d3eef09bSbostic 120, 121, 122, 123, 124, 125, 126, 127
734d3eef09bSbostic };
735d3eef09bSbostic
736d3eef09bSbostic if (*src) {
737d3eef09bSbostic tmp = from;
738d3eef09bSbostic /*
739d3eef09bSbostic * create a mapping between "from" and
740d3eef09bSbostic * "to"
741d3eef09bSbostic */
742d3eef09bSbostic while (*from)
743d3eef09bSbostic mapvec[*from++] = (*to) ? *to++ : (char) 0;
744d3eef09bSbostic
745d3eef09bSbostic while (*src) {
746d3eef09bSbostic sch = *src++;
747d3eef09bSbostic dch = mapvec[sch];
748d3eef09bSbostic while (dch != sch) {
749d3eef09bSbostic sch = dch;
750d3eef09bSbostic dch = mapvec[sch];
751d3eef09bSbostic }
752d3eef09bSbostic if (*dest = dch)
753d3eef09bSbostic dest++;
754d3eef09bSbostic }
755d3eef09bSbostic /*
756d3eef09bSbostic * restore all the changed characters
757d3eef09bSbostic */
758d3eef09bSbostic while (*tmp) {
759d3eef09bSbostic mapvec[*tmp] = *tmp;
760d3eef09bSbostic tmp++;
761d3eef09bSbostic }
762d3eef09bSbostic }
763d3eef09bSbostic *dest = (char) 0;
764d3eef09bSbostic }
765