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