386BSD 0.1 development
[unix-history] / usr / src / usr.bin / m4 / serv.c
CommitLineData
88bb73f0
WJ
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)serv.c 5.3 (Berkeley) 2/26/91";
39#endif /* not lint */
40
41/*
42 * serv.c
43 * Facility: m4 macro processor
44 * by: oz
45 */
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include "mdef.h"
51#include "extr.h"
52#include "pathnames.h"
53
54extern ndptr lookup();
55extern ndptr addent();
56
57char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
58
59/*
60 * expand - user-defined macro expansion
61 *
62 */
63expand(argv, argc)
64register char *argv[];
65register int argc;
66{
67 register char *t;
68 register char *p;
69 register int n;
70 register int argno;
71
72 t = argv[0]; /* defn string as a whole */
73 p = t;
74 while (*p)
75 p++;
76 p--; /* last character of defn */
77 while (p > t) {
78 if (*(p-1) != ARGFLAG)
79 putback(*p);
80 else {
81 switch (*p) {
82
83 case '#':
84 pbnum(argc-2);
85 break;
86 case '0':
87 case '1':
88 case '2':
89 case '3':
90 case '4':
91 case '5':
92 case '6':
93 case '7':
94 case '8':
95 case '9':
96 if ((argno = *p - '0') < argc-1)
97 pbstr(argv[argno+1]);
98 break;
99 case '*':
100 for (n = argc - 1; n > 2; n--) {
101 pbstr(argv[n]);
102 putback(',');
103 }
104 pbstr(argv[2]);
105 break;
106 default :
107 putback(*p);
108 break;
109 }
110 p--;
111 }
112 p--;
113 }
114 if (p == t) /* do last character */
115 putback(*p);
116}
117
118/*
119 * dodefine - install definition in the table
120 *
121 */
122dodefine(name, defn)
123register char *name;
124register char *defn;
125{
126 register ndptr p;
127
128 if (!*name)
129 error("m4: null definition.");
130 if (strcmp(name, defn) == 0)
131 error("m4: recursive definition.");
132 if ((p = lookup(name)) == nil)
133 p = addent(name);
134 else if (p->defn != null)
135 free(p->defn);
136 if (!*defn)
137 p->defn = null;
138 else
139 p->defn = strdup(defn);
140 p->type = MACRTYPE;
141}
142
143/*
144 * dodefn - push back a quoted definition of
145 * the given name.
146 */
147
148dodefn(name)
149char *name;
150{
151 register ndptr p;
152
153 if ((p = lookup(name)) != nil && p->defn != null) {
154 putback(rquote);
155 pbstr(p->defn);
156 putback(lquote);
157 }
158}
159
160/*
161 * dopushdef - install a definition in the hash table
162 * without removing a previous definition. Since
163 * each new entry is entered in *front* of the
164 * hash bucket, it hides a previous definition from
165 * lookup.
166 */
167dopushdef(name, defn)
168register char *name;
169register char *defn;
170{
171 register ndptr p;
172
173 if (!*name)
174 error("m4: null definition");
175 if (strcmp(name, defn) == 0)
176 error("m4: recursive definition.");
177 p = addent(name);
178 if (!*defn)
179 p->defn = null;
180 else
181 p->defn = strdup(defn);
182 p->type = MACRTYPE;
183}
184
185/*
186 * dodumpdef - dump the specified definitions in the hash
187 * table to stderr. If nothing is specified, the entire
188 * hash table is dumped.
189 *
190 */
191dodump(argv, argc)
192register char *argv[];
193register int argc;
194{
195 register int n;
196 ndptr p;
197
198 if (argc > 2) {
199 for (n = 2; n < argc; n++)
200 if ((p = lookup(argv[n])) != nil)
201 fprintf(stderr, dumpfmt, p->name,
202 p->defn);
203 }
204 else {
205 for (n = 0; n < HASHSIZE; n++)
206 for (p = hashtab[n]; p != nil; p = p->nxtptr)
207 fprintf(stderr, dumpfmt, p->name,
208 p->defn);
209 }
210}
211
212/*
213 * doifelse - select one of two alternatives - loop.
214 *
215 */
216doifelse(argv,argc)
217register char *argv[];
218register int argc;
219{
220 cycle {
221 if (strcmp(argv[2], argv[3]) == 0)
222 pbstr(argv[4]);
223 else if (argc == 6)
224 pbstr(argv[5]);
225 else if (argc > 6) {
226 argv += 3;
227 argc -= 3;
228 continue;
229 }
230 break;
231 }
232}
233
234/*
235 * doinclude - include a given file.
236 *
237 */
238doincl(ifile)
239char *ifile;
240{
241 if (ilevel+1 == MAXINP)
242 error("m4: too many include files.");
243 if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
244 ilevel++;
245 return (1);
246 }
247 else
248 return (0);
249}
250
251#ifdef EXTENDED
252/*
253 * dopaste - include a given file without any
254 * macro processing.
255 */
256dopaste(pfile)
257char *pfile;
258{
259 FILE *pf;
260 register int c;
261
262 if ((pf = fopen(pfile, "r")) != NULL) {
263 while((c = getc(pf)) != EOF)
264 putc(c, active);
265 (void) fclose(pf);
266 return(1);
267 }
268 else
269 return(0);
270}
271#endif
272
273/*
274 * dochq - change quote characters
275 *
276 */
277dochq(argv, argc)
278register char *argv[];
279register int argc;
280{
281 if (argc > 2) {
282 if (*argv[2])
283 lquote = *argv[2];
284 if (argc > 3) {
285 if (*argv[3])
286 rquote = *argv[3];
287 }
288 else
289 rquote = lquote;
290 }
291 else {
292 lquote = LQUOTE;
293 rquote = RQUOTE;
294 }
295}
296
297/*
298 * dochc - change comment characters
299 *
300 */
301dochc(argv, argc)
302register char *argv[];
303register int argc;
304{
305 if (argc > 2) {
306 if (*argv[2])
307 scommt = *argv[2];
308 if (argc > 3) {
309 if (*argv[3])
310 ecommt = *argv[3];
311 }
312 else
313 ecommt = ECOMMT;
314 }
315 else {
316 scommt = SCOMMT;
317 ecommt = ECOMMT;
318 }
319}
320
321/*
322 * dodivert - divert the output to a temporary file
323 *
324 */
325dodiv(n)
326register int n;
327{
328 if (n < 0 || n >= MAXOUT)
329 n = 0; /* bitbucket */
330 if (outfile[n] == NULL) {
331 m4temp[UNIQUE] = n + '0';
332 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
333 error("m4: cannot divert.");
334 }
335 oindex = n;
336 active = outfile[n];
337}
338
339/*
340 * doundivert - undivert a specified output, or all
341 * other outputs, in numerical order.
342 */
343doundiv(argv, argc)
344register char *argv[];
345register int argc;
346{
347 register int ind;
348 register int n;
349
350 if (argc > 2) {
351 for (ind = 2; ind < argc; ind++) {
352 n = atoi(argv[ind]);
353 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
354 getdiv(n);
355
356 }
357 }
358 else
359 for (n = 1; n < MAXOUT; n++)
360 if (outfile[n] != NULL)
361 getdiv(n);
362}
363
364/*
365 * dosub - select substring
366 *
367 */
368dosub (argv, argc)
369register char *argv[];
370register int argc;
371{
372 register char *ap, *fc, *k;
373 register int nc;
374
375 if (argc < 5)
376 nc = MAXTOK;
377 else
378#ifdef EXPR
379 nc = expr(argv[4]);
380#else
381 nc = atoi(argv[4]);
382#endif
383 ap = argv[2]; /* target string */
384#ifdef EXPR
385 fc = ap + expr(argv[3]); /* first char */
386#else
387 fc = ap + atoi(argv[3]); /* first char */
388#endif
389 if (fc >= ap && fc < ap+strlen(ap))
390 for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
391 putback(*k);
392}
393
394/*
395 * map:
396 * map every character of s1 that is specified in from
397 * into s3 and replace in s. (source s1 remains untouched)
398 *
399 * This is a standard implementation of map(s,from,to) function of ICON
400 * language. Within mapvec, we replace every character of "from" with
401 * the corresponding character in "to". If "to" is shorter than "from",
402 * than the corresponding entries are null, which means that those
403 * characters dissapear altogether. Furthermore, imagine
404 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
405 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
406 * ultimately maps to `*'. In order to achieve this effect in an efficient
407 * manner (i.e. without multiple passes over the destination string), we
408 * loop over mapvec, starting with the initial source character. if the
409 * character value (dch) in this location is different than the source
410 * character (sch), sch becomes dch, once again to index into mapvec, until
411 * the character value stabilizes (i.e. sch = dch, in other words
412 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
413 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
414 * end, we restore mapvec* back to normal where mapvec[n] == n for
415 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
416 * about 5 times faster than any algorithm that makes multiple passes over
417 * destination string.
418 *
419 */
420
421map(dest,src,from,to)
422register char *dest;
423register char *src;
424register char *from;
425register char *to;
426{
427 register char *tmp;
428 register char sch, dch;
429 static char mapvec[128] = {
430 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
431 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
432 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
433 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
434 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
435 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
436 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
437 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
438 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
439 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
440 120, 121, 122, 123, 124, 125, 126, 127
441 };
442
443 if (*src) {
444 tmp = from;
445 /*
446 * create a mapping between "from" and "to"
447 */
448 while (*from)
449 mapvec[*from++] = (*to) ? *to++ : (char) 0;
450
451 while (*src) {
452 sch = *src++;
453 dch = mapvec[sch];
454 while (dch != sch) {
455 sch = dch;
456 dch = mapvec[sch];
457 }
458 if (*dest = dch)
459 dest++;
460 }
461 /*
462 * restore all the changed characters
463 */
464 while (*tmp) {
465 mapvec[*tmp] = *tmp;
466 tmp++;
467 }
468 }
469 *dest = (char) 0;
470}