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