3 * Facility: m4 macro processor
10 extern ndptr
lookup();
11 extern ndptr
addent();
12 extern char *strsave();
14 char *dumpfmt
= "`%s'\t`%s'\n"; /* format string for dumpdef */
17 * expand - user-defined macro expansion
21 register char *argv
[];
29 t
= argv
[0]; /* defn string as a whole */
33 p
--; /* last character of defn */
35 if (*(p
-1) != ARGFLAG
)
53 if ((argno
= *p
- '0') < argc
-1)
57 for (n
= argc
- 1; n
> 2; n
--) {
71 if (p
== t
) /* do last character */
76 * dodefine - install definition in the table
86 error("m4: null definition.");
87 if (strcmp(name
, defn
) == 0)
88 error("m4: recursive definition.");
89 if ((p
= lookup(name
)) == nil
)
91 else if (p
->defn
!= null
)
96 p
->defn
= strsave(defn
);
101 * dodefn - push back a quoted definition of
110 if ((p
= lookup(name
)) != nil
&& p
->defn
!= null
) {
118 * dopushdef - install a definition in the hash table
119 * without removing a previous definition. Since
120 * each new entry is entered in *front* of the
121 * hash bucket, it hides a previous definition from
124 dopushdef(name
, defn
)
131 error("m4: null definition");
132 if (strcmp(name
, defn
) == 0)
133 error("m4: recursive definition.");
138 p
->defn
= strsave(defn
);
143 * dodumpdef - dump the specified definitions in the hash
144 * table to stderr. If nothing is specified, the entire
145 * hash table is dumped.
149 register char *argv
[];
156 for (n
= 2; n
< argc
; n
++)
157 if ((p
= lookup(argv
[n
])) != nil
)
158 fprintf(stderr
, dumpfmt
, p
->name
,
162 for (n
= 0; n
< HASHSIZE
; n
++)
163 for (p
= hashtab
[n
]; p
!= nil
; p
= p
->nxtptr
)
164 fprintf(stderr
, dumpfmt
, p
->name
,
170 * doifelse - select one of two alternatives - loop.
174 register char *argv
[];
178 if (strcmp(argv
[2], argv
[3]) == 0)
192 * doinclude - include a given file.
198 if (ilevel
+1 == MAXINP
)
199 error("m4: too many include files.");
200 if ((infile
[ilevel
+1] = fopen(ifile
, "r")) != NULL
) {
210 * dopaste - include a given file without any
219 if ((pf
= fopen(pfile
, "r")) != NULL
) {
220 while((c
= getc(pf
)) != EOF
)
231 * dochq - change quote characters
235 register char *argv
[];
255 * dochc - change comment characters
259 register char *argv
[];
279 * dodivert - divert the output to a temporary file
285 if (n
< 0 || n
>= MAXOUT
)
286 n
= 0; /* bitbucket */
287 if (outfile
[n
] == NULL
) {
288 m4temp
[UNIQUE
] = n
+ '0';
289 if ((outfile
[n
] = fopen(m4temp
, "w")) == NULL
)
290 error("m4: cannot divert.");
297 * doundivert - undivert a specified output, or all
298 * other outputs, in numerical order.
301 register char *argv
[];
308 for (ind
= 2; ind
< argc
; ind
++) {
310 if (n
> 0 && n
< MAXOUT
&& outfile
[n
] != NULL
)
316 for (n
= 1; n
< MAXOUT
; n
++)
317 if (outfile
[n
] != NULL
)
322 * dosub - select substring
326 register char *argv
[];
329 register char *ap
, *fc
, *k
;
340 ap
= argv
[2]; /* target string */
342 fc
= ap
+ expr(argv
[3]); /* first char */
344 fc
= ap
+ atoi(argv
[3]); /* first char */
346 if (fc
>= ap
&& fc
< ap
+strlen(ap
))
347 for (k
= fc
+min(nc
,strlen(fc
))-1; k
>= fc
; k
--)
353 * map every character of s1 that is specified in from
354 * into s3 and replace in s. (source s1 remains untouched)
356 * This is a standard implementation of map(s,from,to) function of ICON
357 * language. Within mapvec, we replace every character of "from" with
358 * the corresponding character in "to". If "to" is shorter than "from",
359 * than the corresponding entries are null, which means that those
360 * characters dissapear altogether. Furthermore, imagine
361 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
362 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
363 * ultimately maps to `*'. In order to achieve this effect in an efficient
364 * manner (i.e. without multiple passes over the destination string), we
365 * loop over mapvec, starting with the initial source character. if the
366 * character value (dch) in this location is different than the source
367 * character (sch), sch becomes dch, once again to index into mapvec, until
368 * the character value stabilizes (i.e. sch = dch, in other words
369 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
370 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
371 * end, we restore mapvec* back to normal where mapvec[n] == n for
372 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
373 * about 5 times faster than any algorithm that makes multiple passes over
374 * destination string.
378 map(dest
,src
,from
,to
)
385 register char sch
, dch
;
386 static char mapvec
[128] = {
387 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
388 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
389 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
390 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
391 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
392 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
393 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
394 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
395 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
396 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
397 120, 121, 122, 123, 124, 125, 126, 127
403 * create a mapping between "from" and "to"
406 mapvec
[*from
++] = (*to
) ? *to
++ : (char) 0;
419 * restore all the changed characters