improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / m4 / serv.c
blob2dc6a029233a82e26b70106871188bfcb2caa740
1 /*
2 * serv.c
3 * Facility: m4 macro processor
4 * by: oz
5 */
7 #include "mdef.h"
8 #include "extr.h"
10 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
13 * expand - user-defined macro expansion
16 void expand(argv, argc)
17 register char *argv[];
18 register int argc;
20 register char *t;
21 register char *p;
22 register int n;
23 register int argno;
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) {
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(',');
57 pbstr(argv[2]);
58 break;
59 default :
60 putback(*p);
61 break;
63 p--;
65 p--;
67 if (p == t) /* do last character */
68 putback(*p);
72 * dodefine - install definition in the table
75 void dodefine(name, defn)
76 register char *name;
77 register char *defn;
79 register ndptr p;
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;
97 * dodefn - push back a quoted definition of
98 * the given name.
101 void dodefn(name)
102 char *name;
104 register ndptr p;
106 if ((p = lookup(name)) != nil && p->defn != null) {
107 putback(rquote);
108 pbstr(p->defn);
109 putback(lquote);
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.
120 void dopushdef(name, defn)
121 register char *name;
122 register char *defn;
124 register ndptr p;
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;
139 * dodumpdef - dump the specified definitions in the hash
140 * table to stderr. If nothing is specified, the entire
141 * hash table is dumped.
144 void dodump(argv, argc)
145 register char *argv[];
146 register int argc;
148 register int n;
149 ndptr p;
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);
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);
166 * doifelse - select one of two alternatives - loop.
169 void doifelse(argv,argc)
170 register char *argv[];
171 register int argc;
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;
183 break;
188 * doinclude - include a given file.
191 int doincl(ifile)
192 char *ifile;
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);
200 else
201 return (0);
204 #ifdef EXTENDED
206 * dopaste - include a given file without any
207 * macro processing.
209 int dopaste(pfile)
210 char *pfile;
212 FILE *pf;
213 register int c;
215 if ((pf = fopen(pfile, "r")) != NULL) {
216 while((c = getc(pf)) != EOF)
217 putc(c, active);
218 (void) fclose(pf);
219 return(1);
221 else
222 return(0);
224 #endif
227 * dochq - change quote characters
230 void dochq(argv, argc)
231 register char *argv[];
232 register int argc;
234 if (argc > 2) {
235 if (*argv[2])
236 lquote = *argv[2];
237 if (argc > 3) {
238 if (*argv[3])
239 rquote = *argv[3];
241 else
242 rquote = lquote;
244 else {
245 lquote = LQUOTE;
246 rquote = RQUOTE;
251 * dochc - change comment characters
254 void dochc(argv, argc)
255 register char *argv[];
256 register int argc;
258 if (argc > 2) {
259 if (*argv[2])
260 scommt = *argv[2];
261 if (argc > 3) {
262 if (*argv[3])
263 ecommt = *argv[3];
265 else
266 ecommt = ECOMMT;
268 else {
269 scommt = SCOMMT;
270 ecommt = ECOMMT;
275 * dodivert - divert the output to a temporary file
278 void dodiv(n)
279 register int n;
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.");
288 oindex = n;
289 active = outfile[n];
293 * doundivert - undivert a specified output, or all
294 * other outputs, in numerical order.
296 void doundiv(argv, argc)
297 register char *argv[];
298 register int argc;
300 register int ind;
301 register int n;
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);
311 else
312 for (n = 1; n < MAXOUT; n++)
313 if (outfile[n] != NULL)
314 getdiv(n);
318 * dosub - select substring
321 void dosub (argv, argc)
322 register char *argv[];
323 register int argc;
325 register char *ap, *fc, *k;
326 register int nc;
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);
348 * map:
349 * map every character of s1 that is specified in from
350 * into s3 and replace in s. (source s1 remains untouched)
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.
374 void map(dest,src,from,to)
375 register char *dest;
376 register char *src;
377 register char *from;
378 register char *to;
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
396 if (*src) {
397 tmp = from;
399 * create a mapping between "from" and "to"
401 while (*from)
402 mapvec[*from++] = (*to) ? *to++ : (char) 0;
404 while (*src) {
405 sch = *src++;
406 dch = mapvec[sch];
407 while (dch != sch) {
408 sch = dch;
409 dch = mapvec[sch];
411 if (*dest = dch)
412 dest++;
415 * restore all the changed characters
417 while (*tmp) {
418 mapvec[*tmp] = *tmp;
419 tmp++;
422 *dest = (char) 0;