* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)serv.c 5.3 (Berkeley) 2/26/91";
* Facility: m4 macro processor
char *dumpfmt
= "`%s'\t`%s'\n"; /* format string for dumpdef */
* expand - user-defined macro expansion
t
= argv
[0]; /* defn string as a whole */
p
--; /* last character of defn */
if ((argno
= *p
- '0') < argc
-1)
for (n
= argc
- 1; n
> 2; n
--) {
if (p
== t
) /* do last character */
* dodefine - install definition in the table
error("m4: null definition.");
if (strcmp(name
, defn
) == 0)
error("m4: recursive definition.");
if ((p
= lookup(name
)) == nil
)
else if (p
->defn
!= null
)
* dodefn - push back a quoted definition of
if ((p
= lookup(name
)) != nil
&& p
->defn
!= null
) {
* dopushdef - install a definition in the hash table
* without removing a previous definition. Since
* each new entry is entered in *front* of the
* hash bucket, it hides a previous definition from
error("m4: null definition");
if (strcmp(name
, defn
) == 0)
error("m4: recursive definition.");
* dodumpdef - dump the specified definitions in the hash
* table to stderr. If nothing is specified, the entire
for (n
= 2; n
< argc
; n
++)
if ((p
= lookup(argv
[n
])) != nil
)
fprintf(stderr
, dumpfmt
, p
->name
,
for (n
= 0; n
< HASHSIZE
; n
++)
for (p
= hashtab
[n
]; p
!= nil
; p
= p
->nxtptr
)
fprintf(stderr
, dumpfmt
, p
->name
,
* doifelse - select one of two alternatives - loop.
if (strcmp(argv
[2], argv
[3]) == 0)
* doinclude - include a given file.
error("m4: too many include files.");
if ((infile
[ilevel
+1] = fopen(ifile
, "r")) != NULL
) {
* dopaste - include a given file without any
if ((pf
= fopen(pfile
, "r")) != NULL
) {
while((c
= getc(pf
)) != EOF
)
* dochq - change quote characters
* dochc - change comment characters
* dodivert - divert the output to a temporary file
if (n
< 0 || n
>= MAXOUT
)
if (outfile
[n
] == NULL
) {
m4temp
[UNIQUE
] = n
+ '0';
if ((outfile
[n
] = fopen(m4temp
, "w")) == NULL
)
error("m4: cannot divert.");
* doundivert - undivert a specified output, or all
* other outputs, in numerical order.
for (ind
= 2; ind
< argc
; ind
++) {
if (n
> 0 && n
< MAXOUT
&& outfile
[n
] != NULL
)
for (n
= 1; n
< MAXOUT
; n
++)
* dosub - select substring
register char *ap
, *fc
, *k
;
ap
= argv
[2]; /* target string */
fc
= ap
+ expr(argv
[3]); /* first char */
fc
= ap
+ atoi(argv
[3]); /* first char */
if (fc
>= ap
&& fc
< ap
+strlen(ap
))
for (k
= fc
+min(nc
,strlen(fc
))-1; k
>= fc
; k
--)
* map every character of s1 that is specified in from
* into s3 and replace in s. (source s1 remains untouched)
* This is a standard implementation of map(s,from,to) function of ICON
* language. Within mapvec, we replace every character of "from" with
* the corresponding character in "to". If "to" is shorter than "from",
* than the corresponding entries are null, which means that those
* characters dissapear altogether. Furthermore, imagine
* map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
* `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
* ultimately maps to `*'. In order to achieve this effect in an efficient
* manner (i.e. without multiple passes over the destination string), we
* loop over mapvec, starting with the initial source character. if the
* character value (dch) in this location is different than the source
* character (sch), sch becomes dch, once again to index into mapvec, until
* the character value stabilizes (i.e. sch = dch, in other words
* mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
* character, it will stabilize, since mapvec[0] == 0 at all times. At the
* end, we restore mapvec* back to normal where mapvec[n] == n for
* 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
* about 5 times faster than any algorithm that makes multiple passes over
static char mapvec
[128] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127
* create a mapping between "from" and "to"
mapvec
[*from
++] = (*to
) ? *to
++ : (char) 0;
* restore all the changed characters