1 | /*
|
---|
2 | * serv.c
|
---|
3 | * Facility: m4 macro processor
|
---|
4 | * by: oz
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "mdef.h"
|
---|
8 | #include "extr.h"
|
---|
9 |
|
---|
10 | char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
|
---|
11 |
|
---|
12 | /*
|
---|
13 | * expand - user-defined macro expansion
|
---|
14 | *
|
---|
15 | */
|
---|
16 | void expand(argv, argc)
|
---|
17 | register char *argv[];
|
---|
18 | register int argc;
|
---|
19 | {
|
---|
20 | register char *t;
|
---|
21 | register char *p;
|
---|
22 | register int n;
|
---|
23 | register int argno;
|
---|
24 |
|
---|
25 | t = argv[0]; /* defn string as a whole */
|
---|
26 | p = t;
|
---|
27 | while (*p)
|
---|
28 | p++;
|
---|
29 | p--; /* last character of defn */
|
---|
30 | while (p > t) {
|
---|
31 | if (*(p-1) != ARGFLAG)
|
---|
32 | putback(*p);
|
---|
33 | else {
|
---|
34 | switch (*p) {
|
---|
35 |
|
---|
36 | case '#':
|
---|
37 | pbnum(argc-2);
|
---|
38 | break;
|
---|
39 | case '0':
|
---|
40 | case '1':
|
---|
41 | case '2':
|
---|
42 | case '3':
|
---|
43 | case '4':
|
---|
44 | case '5':
|
---|
45 | case '6':
|
---|
46 | case '7':
|
---|
47 | case '8':
|
---|
48 | case '9':
|
---|
49 | if ((argno = *p - '0') < argc-1)
|
---|
50 | pbstr(argv[argno+1]);
|
---|
51 | break;
|
---|
52 | case '*':
|
---|
53 | for (n = argc - 1; n > 2; n--) {
|
---|
54 | pbstr(argv[n]);
|
---|
55 | putback(',');
|
---|
56 | }
|
---|
57 | pbstr(argv[2]);
|
---|
58 | break;
|
---|
59 | default :
|
---|
60 | putback(*p);
|
---|
61 | break;
|
---|
62 | }
|
---|
63 | p--;
|
---|
64 | }
|
---|
65 | p--;
|
---|
66 | }
|
---|
67 | if (p == t) /* do last character */
|
---|
68 | putback(*p);
|
---|
69 | }
|
---|
70 |
|
---|
71 | /*
|
---|
72 | * dodefine - install definition in the table
|
---|
73 | *
|
---|
74 | */
|
---|
75 | void dodefine(name, defn)
|
---|
76 | register char *name;
|
---|
77 | register char *defn;
|
---|
78 | {
|
---|
79 | register ndptr p;
|
---|
80 |
|
---|
81 | if (!*name)
|
---|
82 | error("m4: null definition.");
|
---|
83 | if (strcmp(name, defn) == 0)
|
---|
84 | error("m4: recursive definition.");
|
---|
85 | if ((p = lookup(name)) == nil)
|
---|
86 | p = addent(name);
|
---|
87 | else if (p->defn != null)
|
---|
88 | free(p->defn);
|
---|
89 | if (!*defn)
|
---|
90 | p->defn = null;
|
---|
91 | else
|
---|
92 | p->defn = strsave(defn);
|
---|
93 | p->type = MACRTYPE;
|
---|
94 | }
|
---|
95 |
|
---|
96 | /*
|
---|
97 | * dodefn - push back a quoted definition of
|
---|
98 | * the given name.
|
---|
99 | */
|
---|
100 |
|
---|
101 | void dodefn(name)
|
---|
102 | char *name;
|
---|
103 | {
|
---|
104 | register ndptr p;
|
---|
105 |
|
---|
106 | if ((p = lookup(name)) != nil && p->defn != null) {
|
---|
107 | putback(rquote);
|
---|
108 | pbstr(p->defn);
|
---|
109 | putback(lquote);
|
---|
110 | }
|
---|
111 | }
|
---|
112 |
|
---|
113 | /*
|
---|
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
|
---|
118 | * lookup.
|
---|
119 | */
|
---|
120 | void dopushdef(name, defn)
|
---|
121 | register char *name;
|
---|
122 | register char *defn;
|
---|
123 | {
|
---|
124 | register ndptr p;
|
---|
125 |
|
---|
126 | if (!*name)
|
---|
127 | error("m4: null definition");
|
---|
128 | if (strcmp(name, defn) == 0)
|
---|
129 | error("m4: recursive definition.");
|
---|
130 | p = addent(name);
|
---|
131 | if (!*defn)
|
---|
132 | p->defn = null;
|
---|
133 | else
|
---|
134 | p->defn = strsave(defn);
|
---|
135 | p->type = MACRTYPE;
|
---|
136 | }
|
---|
137 |
|
---|
138 | /*
|
---|
139 | * dodumpdef - dump the specified definitions in the hash
|
---|
140 | * table to stderr. If nothing is specified, the entire
|
---|
141 | * hash table is dumped.
|
---|
142 | *
|
---|
143 | */
|
---|
144 | void dodump(argv, argc)
|
---|
145 | register char *argv[];
|
---|
146 | register int argc;
|
---|
147 | {
|
---|
148 | register int n;
|
---|
149 | ndptr p;
|
---|
150 |
|
---|
151 | if (argc > 2) {
|
---|
152 | for (n = 2; n < argc; n++)
|
---|
153 | if ((p = lookup(argv[n])) != nil)
|
---|
154 | fprintf(stderr, dumpfmt, p->name,
|
---|
155 | p->defn);
|
---|
156 | }
|
---|
157 | else {
|
---|
158 | for (n = 0; n < HASHSIZE; n++)
|
---|
159 | for (p = hashtab[n]; p != nil; p = p->nxtptr)
|
---|
160 | fprintf(stderr, dumpfmt, p->name,
|
---|
161 | p->defn);
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | /*
|
---|
166 | * doifelse - select one of two alternatives - loop.
|
---|
167 | *
|
---|
168 | */
|
---|
169 | void doifelse(argv,argc)
|
---|
170 | register char *argv[];
|
---|
171 | register int argc;
|
---|
172 | {
|
---|
173 | cycle {
|
---|
174 | if (strcmp(argv[2], argv[3]) == 0)
|
---|
175 | pbstr(argv[4]);
|
---|
176 | else if (argc == 6)
|
---|
177 | pbstr(argv[5]);
|
---|
178 | else if (argc > 6) {
|
---|
179 | argv += 3;
|
---|
180 | argc -= 3;
|
---|
181 | continue;
|
---|
182 | }
|
---|
183 | break;
|
---|
184 | }
|
---|
185 | }
|
---|
186 |
|
---|
187 | /*
|
---|
188 | * doinclude - include a given file.
|
---|
189 | *
|
---|
190 | */
|
---|
191 | int doincl(ifile)
|
---|
192 | char *ifile;
|
---|
193 | {
|
---|
194 | if (ilevel+1 == MAXINP)
|
---|
195 | error("m4: too many include files.");
|
---|
196 | if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
|
---|
197 | ilevel++;
|
---|
198 | return (1);
|
---|
199 | }
|
---|
200 | else
|
---|
201 | return (0);
|
---|
202 | }
|
---|
203 |
|
---|
204 | #ifdef EXTENDED
|
---|
205 | /*
|
---|
206 | * dopaste - include a given file without any
|
---|
207 | * macro processing.
|
---|
208 | */
|
---|
209 | int dopaste(pfile)
|
---|
210 | char *pfile;
|
---|
211 | {
|
---|
212 | FILE *pf;
|
---|
213 | register int c;
|
---|
214 |
|
---|
215 | if ((pf = fopen(pfile, "r")) != NULL) {
|
---|
216 | while((c = getc(pf)) != EOF)
|
---|
217 | putc(c, active);
|
---|
218 | (void) fclose(pf);
|
---|
219 | return(1);
|
---|
220 | }
|
---|
221 | else
|
---|
222 | return(0);
|
---|
223 | }
|
---|
224 | #endif
|
---|
225 |
|
---|
226 | /*
|
---|
227 | * dochq - change quote characters
|
---|
228 | *
|
---|
229 | */
|
---|
230 | void dochq(argv, argc)
|
---|
231 | register char *argv[];
|
---|
232 | register int argc;
|
---|
233 | {
|
---|
234 | if (argc > 2) {
|
---|
235 | if (*argv[2])
|
---|
236 | lquote = *argv[2];
|
---|
237 | if (argc > 3) {
|
---|
238 | if (*argv[3])
|
---|
239 | rquote = *argv[3];
|
---|
240 | }
|
---|
241 | else
|
---|
242 | rquote = lquote;
|
---|
243 | }
|
---|
244 | else {
|
---|
245 | lquote = LQUOTE;
|
---|
246 | rquote = RQUOTE;
|
---|
247 | }
|
---|
248 | }
|
---|
249 |
|
---|
250 | /*
|
---|
251 | * dochc - change comment characters
|
---|
252 | *
|
---|
253 | */
|
---|
254 | void dochc(argv, argc)
|
---|
255 | register char *argv[];
|
---|
256 | register int argc;
|
---|
257 | {
|
---|
258 | if (argc > 2) {
|
---|
259 | if (*argv[2])
|
---|
260 | scommt = *argv[2];
|
---|
261 | if (argc > 3) {
|
---|
262 | if (*argv[3])
|
---|
263 | ecommt = *argv[3];
|
---|
264 | }
|
---|
265 | else
|
---|
266 | ecommt = ECOMMT;
|
---|
267 | }
|
---|
268 | else {
|
---|
269 | scommt = SCOMMT;
|
---|
270 | ecommt = ECOMMT;
|
---|
271 | }
|
---|
272 | }
|
---|
273 |
|
---|
274 | /*
|
---|
275 | * dodivert - divert the output to a temporary file
|
---|
276 | *
|
---|
277 | */
|
---|
278 | void dodiv(n)
|
---|
279 | register int n;
|
---|
280 | {
|
---|
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.");
|
---|
287 | }
|
---|
288 | oindex = n;
|
---|
289 | active = outfile[n];
|
---|
290 | }
|
---|
291 |
|
---|
292 | /*
|
---|
293 | * doundivert - undivert a specified output, or all
|
---|
294 | * other outputs, in numerical order.
|
---|
295 | */
|
---|
296 | void doundiv(argv, argc)
|
---|
297 | register char *argv[];
|
---|
298 | register int argc;
|
---|
299 | {
|
---|
300 | register int ind;
|
---|
301 | register int n;
|
---|
302 |
|
---|
303 | if (argc > 2) {
|
---|
304 | for (ind = 2; ind < argc; ind++) {
|
---|
305 | n = atoi(argv[ind]);
|
---|
306 | if (n > 0 && n < MAXOUT && outfile[n] != NULL)
|
---|
307 | getdiv(n);
|
---|
308 |
|
---|
309 | }
|
---|
310 | }
|
---|
311 | else
|
---|
312 | for (n = 1; n < MAXOUT; n++)
|
---|
313 | if (outfile[n] != NULL)
|
---|
314 | getdiv(n);
|
---|
315 | }
|
---|
316 |
|
---|
317 | /*
|
---|
318 | * dosub - select substring
|
---|
319 | *
|
---|
320 | */
|
---|
321 | void dosub (argv, argc)
|
---|
322 | register char *argv[];
|
---|
323 | register int argc;
|
---|
324 | {
|
---|
325 | register char *ap, *fc, *k;
|
---|
326 | register int nc;
|
---|
327 |
|
---|
328 | if (argc < 5)
|
---|
329 | nc = MAXTOK;
|
---|
330 | else
|
---|
331 | #ifdef EXPR
|
---|
332 | nc = expr(argv[4]);
|
---|
333 | #else
|
---|
334 | nc = atoi(argv[4]);
|
---|
335 | #endif
|
---|
336 | ap = argv[2]; /* target string */
|
---|
337 | #ifdef EXPR
|
---|
338 | fc = ap + expr(argv[3]); /* first char */
|
---|
339 | #else
|
---|
340 | fc = ap + atoi(argv[3]); /* first char */
|
---|
341 | #endif
|
---|
342 | if (fc >= ap && fc < ap+strlen(ap))
|
---|
343 | for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
|
---|
344 | putback(*k);
|
---|
345 | }
|
---|
346 |
|
---|
347 | /*
|
---|
348 | * map:
|
---|
349 | * map every character of s1 that is specified in from
|
---|
350 | * into s3 and replace in s. (source s1 remains untouched)
|
---|
351 | *
|
---|
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.
|
---|
371 | *
|
---|
372 | */
|
---|
373 |
|
---|
374 | void map(dest,src,from,to)
|
---|
375 | register char *dest;
|
---|
376 | register char *src;
|
---|
377 | register char *from;
|
---|
378 | register char *to;
|
---|
379 | {
|
---|
380 | register char *tmp;
|
---|
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
|
---|
394 | };
|
---|
395 |
|
---|
396 | if (*src) {
|
---|
397 | tmp = from;
|
---|
398 | /*
|
---|
399 | * create a mapping between "from" and "to"
|
---|
400 | */
|
---|
401 | while (*from)
|
---|
402 | mapvec[*from++] = (*to) ? *to++ : (char) 0;
|
---|
403 |
|
---|
404 | while (*src) {
|
---|
405 | sch = *src++;
|
---|
406 | dch = mapvec[sch];
|
---|
407 | while (dch != sch) {
|
---|
408 | sch = dch;
|
---|
409 | dch = mapvec[sch];
|
---|
410 | }
|
---|
411 | if (*dest = dch)
|
---|
412 | dest++;
|
---|
413 | }
|
---|
414 | /*
|
---|
415 | * restore all the changed characters
|
---|
416 | */
|
---|
417 | while (*tmp) {
|
---|
418 | mapvec[*tmp] = *tmp;
|
---|
419 | tmp++;
|
---|
420 | }
|
---|
421 | }
|
---|
422 | *dest = (char) 0;
|
---|
423 | }
|
---|