3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
10 * This code is derived from software contributed to Berkeley by
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 static char sccsid[] = "@(#)serv.c 5.4 (Berkeley) 1/21/94";
48 * Facility: m4 macro processor
57 #include "pathnames.h"
59 extern ndptr lookup();
60 extern ndptr addent();
62 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
65 * expand - user-defined macro expansion
69 register char *argv[];
77 t = argv[0]; /* defn string as a whole */
81 p--; /* last character of defn */
83 if (*(p-1) != ARGFLAG)
101 if ((argno = *p - '0') < argc-1)
102 pbstr(argv[argno+1]);
105 for (n = argc - 1; n > 2; n--) {
119 if (p == t) /* do last character */
124 * dodefine - install definition in the table
134 error("m4: null definition.");
135 if (strcmp(name, defn) == 0)
136 error("m4: recursive definition.");
137 if ((p = lookup(name)) == nil)
139 else if (p->defn != null)
144 p->defn = strdup(defn);
149 * dodefn - push back a quoted definition of
158 if ((p = lookup(name)) != nil && p->defn != null) {
166 * dopushdef - install a definition in the hash table
167 * without removing a previous definition. Since
168 * each new entry is entered in *front* of the
169 * hash bucket, it hides a previous definition from
172 dopushdef(name, defn)
179 error("m4: null definition");
180 if (strcmp(name, defn) == 0)
181 error("m4: recursive definition.");
186 p->defn = strdup(defn);
191 * dodumpdef - dump the specified definitions in the hash
192 * table to stderr. If nothing is specified, the entire
193 * hash table is dumped.
197 register char *argv[];
204 for (n = 2; n < argc; n++)
205 if ((p = lookup(argv[n])) != nil)
206 fprintf(stderr, dumpfmt, p->name,
210 for (n = 0; n < HASHSIZE; n++)
211 for (p = hashtab[n]; p != nil; p = p->nxtptr)
212 fprintf(stderr, dumpfmt, p->name,
218 * doifelse - select one of two alternatives - loop.
222 register char *argv[];
226 if (strcmp(argv[2], argv[3]) == 0)
240 * doinclude - include a given file.
246 if (ilevel+1 == MAXINP)
247 error("m4: too many include files.");
248 if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
258 * dopaste - include a given file without any
267 if ((pf = fopen(pfile, "r")) != NULL) {
268 while((c = getc(pf)) != EOF)
279 * dochq - change quote characters
283 register char *argv[];
303 * dochc - change comment characters
307 register char *argv[];
327 * dodivert - divert the output to a temporary file
333 if (n < 0 || n >= MAXOUT)
334 n = 0; /* bitbucket */
335 if (outfile[n] == NULL) {
336 m4temp[UNIQUE] = n + '0';
337 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
338 error("m4: cannot divert.");
345 * doundivert - undivert a specified output, or all
346 * other outputs, in numerical order.
349 register char *argv[];
356 for (ind = 2; ind < argc; ind++) {
358 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
364 for (n = 1; n < MAXOUT; n++)
365 if (outfile[n] != NULL)
370 * dosub - select substring
374 register char *argv[];
377 register char *ap, *fc, *k;
388 ap = argv[2]; /* target string */
390 fc = ap + expr(argv[3]); /* first char */
392 fc = ap + atoi(argv[3]); /* first char */
394 if (fc >= ap && fc < ap+strlen(ap))
395 for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
401 * map every character of s1 that is specified in from
402 * into s3 and replace in s. (source s1 remains untouched)
404 * This is a standard implementation of map(s,from,to) function of ICON
405 * language. Within mapvec, we replace every character of "from" with
406 * the corresponding character in "to". If "to" is shorter than "from",
407 * than the corresponding entries are null, which means that those
408 * characters dissapear altogether. Furthermore, imagine
409 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
410 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
411 * ultimately maps to `*'. In order to achieve this effect in an efficient
412 * manner (i.e. without multiple passes over the destination string), we
413 * loop over mapvec, starting with the initial source character. if the
414 * character value (dch) in this location is different than the source
415 * character (sch), sch becomes dch, once again to index into mapvec, until
416 * the character value stabilizes (i.e. sch = dch, in other words
417 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
418 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
419 * end, we restore mapvec* back to normal where mapvec[n] == n for
420 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
421 * about 5 times faster than any algorithm that makes multiple passes over
422 * destination string.
426 map(dest,src,from,to)
433 register char sch, dch;
434 static char mapvec[128] = {
435 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
436 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
437 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
438 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
439 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
440 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
441 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
442 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
443 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
444 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
445 120, 121, 122, 123, 124, 125, 126, 127
451 * create a mapping between "from" and "to"
454 mapvec[*from++] = (*to) ? *to++ : (char) 0;
467 * restore all the changed characters