source: trunk/minix/commands/m4/serv.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.3 KB
Line 
1/*
2 * serv.c
3 * Facility: m4 macro processor
4 * by: oz
5 */
6
7#include "mdef.h"
8#include "extr.h"
9
10char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
11
12/*
13 * expand - user-defined macro expansion
14 *
15 */
16void expand(argv, argc)
17register char *argv[];
18register 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 */
75void dodefine(name, defn)
76register char *name;
77register 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
101void dodefn(name)
102char *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 */
120void dopushdef(name, defn)
121register char *name;
122register 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 */
144void dodump(argv, argc)
145register char *argv[];
146register 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 */
169void doifelse(argv,argc)
170register char *argv[];
171register 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 */
191int doincl(ifile)
192char *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 */
209int dopaste(pfile)
210char *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 */
230void dochq(argv, argc)
231register char *argv[];
232register 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 */
254void dochc(argv, argc)
255register char *argv[];
256register 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 */
278void dodiv(n)
279register 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 */
296void doundiv(argv, argc)
297register char *argv[];
298register 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 */
321void dosub (argv, argc)
322register char *argv[];
323register 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
374void map(dest,src,from,to)
375register char *dest;
376register char *src;
377register char *from;
378register 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}
Note: See TracBrowser for help on using the repository browser.