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