dec729919988fe111ad2f40d616431008d3ef031
[openafs.git] / src / mpp / mpp.c
1 /*
2  *      (C) Copyright 10/17/86 by Carnegie Mellon University
3  */
4 #include <stdio.h>
5 #include <unistd.h>
6
7 extern char *malloc();
8
9 #define maxinputdepth   16
10 #define maxlinesize     1024
11 #define macrohashsize   1023
12 #define macronamesize   32
13 #define maxnestdepth    128
14
15 #define inline  xxinline
16
17 struct nest {
18     int status;
19 };
20
21 struct file {
22     char *name;
23     FILE *stream;
24     int lineno;
25 };
26
27 struct macro {
28     struct macro *next;
29     enum macromode { rdwr, rdonly } mode;
30     char *name;
31     char *value;
32 };
33
34 static stripcomments = 0;
35 static specialchar = '%';
36 static struct nest nests[maxnestdepth];
37 static struct nest *nestp = &nests[0];
38 static struct nest *lastnestp = &nests[maxnestdepth - 1];
39
40 static struct file files[maxinputdepth];
41 static struct file *lastfilep = &files[maxinputdepth - 1];
42 static struct file *filep = &files[0];
43
44 static char inline[maxlinesize];
45 static char outline[maxlinesize];
46 static struct macro *macrohashtable[macrohashsize];
47
48 static
49 error(a0, a1)
50      char *a0, *a1;
51 {
52     fprintf(stderr, a0, a1);
53     putc('\n', stderr);
54     exit(1);
55 }
56
57 static
58 fileerror(a0, a1)
59      char *a0, *a1;
60 {
61     fprintf(stderr, "%s; line %d: ", filep->name, filep->lineno);
62     error(a0, a1);
63 }
64
65 static char *
66 strsav(s)
67      char *s;
68 {
69     char *p;
70
71     if ((p = malloc(strlen(s) + 1)) == NULL)
72         error("Out of Memory");
73     strcpy(p, s);
74     return p;
75 }
76
77 static struct macro **
78 macrolookup(name)
79      char *name;
80 {
81     register struct macro **mpp, *mp;
82     register char *cp;
83     register unsigned hv;
84
85     for (cp = name, hv = 0; *cp; hv += *cp++);
86     mpp = &macrohashtable[hv % macrohashsize];
87     while ((mp = *mpp) && strcmp(mp->name, name))
88         mpp = &mp->next;
89     return mpp;
90 }
91
92 static
93 macroundefine(name)
94      char *name;
95 {
96     register struct macro **mpp, *mp;
97
98     mpp = macrolookup(name);
99     if (mp = *mpp) {
100         *mpp = mp->next;
101         free(mp->value);
102         free(mp->name);
103         free(mp);
104     }
105 }
106
107 static
108 macrodefine(name, value, mode)
109      char *name;
110      char *value;
111      enum macromode mode;
112 {
113     register struct macro **mpp, *mp;
114
115     mpp = macrolookup(name);
116     if (mp = *mpp) {
117         if (mp->mode == rdonly)
118             return;
119         free(mp->value);
120     } else {
121         if ((mp = (struct macro *)malloc(sizeof(struct macro))) == 0)
122             error("Out of memory");
123         mp->name = strsav(name);
124         mp->next = 0;
125         *mpp = mp;
126     }
127     mp->mode = mode;
128     mp->value = strsav(value);
129 }
130
131
132 static char *
133 macroexpand(dst, src)
134      register char *dst, *src;
135 {
136     char name[macronamesize];
137     register char *np;
138     register struct macro *mp;
139
140     while (*src) {
141         if (*src != '$') {
142             *dst++ = *src++;
143             continue;
144         }
145         src++;
146         if (*src == '$') {
147             *dst++ = '$';
148             src++;
149             continue;
150         }
151         np = name;
152         if (*src == '{' || *src == '(') {
153             src++;
154             while (*src) {
155                 if (*src == '}' || *src == ')') {
156                     src++;
157                     break;
158                 }
159                 if (np >= &name[macronamesize])
160                     src++;
161                 else
162                     *np++ = *src++;
163             }
164         } else {
165             *np++ = *src++;
166         }
167         *np = 0;
168         if (mp = *macrolookup(name))
169             dst = macroexpand(dst, mp->value);
170     }
171     *dst = 0;
172     return dst;
173 }
174
175
176
177 static
178 readline(line)
179      char *line;
180 {
181     while (filep >= &files[0]) {
182         filep->lineno++;
183         if (fgets(line, maxlinesize, filep->stream) != NULL)
184             return -1;
185         if (fclose(filep->stream) == EOF)
186             error("Error closing %s", filep->name);
187         free(filep->name);
188         if (filep == &files[0])
189             return 0;
190         filep--;
191     }
192     return 0;
193 }
194
195 static
196 writeline(line)
197      char *line;
198 {
199     fputs(line, stdout);
200 }
201
202
203 static
204 directive(what)
205      char *what;
206 {
207     char *arg[3], *cp;
208     int n;
209
210     if (*what++ != specialchar)
211         return nestp->status;
212     if (cp = strrchr(what, '\n'))
213         *cp = 0;
214     for (n = 0; n < 2; n++) {
215         while (*what == ' ' || *what == '\t')
216             what++;
217         arg[n] = what;
218         while (*what != ' ' && *what != '\t' && *what != 0)
219             what++;
220         if (*what)
221             *what++ = 0;
222     }
223     while (*what == ' ' || *what == '\t')
224         what++;
225     arg[2] = what;
226     if (strcmp(arg[0], "ifdef") == 0) {
227         if (nestp == lastnestp)
228             fileerror("If Depth overflow");
229         if (nestp->status == 2 || nestp->status == 1) {
230             nestp++;
231             nestp->status = 2;
232             return 1;
233         }
234         nestp++;
235         nestp->status = (*macrolookup(arg[1])) ? 0 : 1;
236         return 1;
237     }
238     if (strcmp(arg[0], "ifndef") == 0) {
239         if (nestp == lastnestp)
240             fileerror("If Depth overflow");
241         if (nestp->status == 2 || nestp->status == 1) {
242             nestp++;
243             nestp->status = 2;
244             return 1;
245         }
246         nestp++;
247         nestp->status = (*macrolookup(arg[1])) ? 1 : 0;
248         return 1;
249     }
250     if (strcmp(arg[0], "else") == 0) {
251         if (nestp->status == 2)
252             return 1;
253         if (nestp == &nests[0])
254             fileerror("If less else");
255         nestp->status = nestp->status ? 0 : 1;
256         return 1;
257     }
258     if (strcmp(arg[0], "endif") == 0) {
259         if (nestp == &nests[0])
260             fileerror("If less endif");
261         nestp--;
262         return 1;
263     }
264     if (nestp->status)
265         return 1;
266     if (strcmp(arg[0], "include") == 0) {
267         if (filep == lastfilep)
268             fileerror("Include file overflow");
269         filep++;
270         if ((filep->stream = fopen(arg[1], "r")) == NULL) {
271             filep--;
272             fileerror("Can't open %s", arg[1]);
273         }
274         filep->name = strsav(arg[1]);
275         filep->lineno = 0;
276         return 1;
277     }
278     if (strcmp(arg[0], "define") == 0) {
279         macrodefine(arg[1], arg[2], rdwr);
280         return 1;
281     }
282     if (strcmp(arg[0], "undef") == 0) {
283         macroundefine(arg[1]);
284         return 1;
285     }
286     fileerror("Unknown directive %s", arg[0]);
287 }
288
289 expandfile(name)
290      char *name;
291 {
292     if (strcmp(name, "-") == 0) {
293         filep->stream = stdin;
294         filep->name = strsav("(stdin)");
295     } else {
296         if ((filep->stream = fopen(name, "r")) == NULL) {
297             fileerror("Can't open %s", name);
298             exit(1);
299         }
300         filep->name = strsav(name);
301     }
302     filep->lineno = 0;
303     while (readline(inline)) {
304         if (stripcomments) {
305             char *cp;
306             for (cp = inline; *cp != 0 && *cp != '#'; cp++)
307                 continue;
308             *cp = 0;
309             if (cp == inline)
310                 continue;
311         }
312         (void)macroexpand(outline, inline);
313         if (directive(outline))
314             continue;
315         writeline(outline);
316     }
317 }
318
319 static
320 usage()
321 {
322     fprintf(stderr, "Usage: mpp [-cC][-s][-Dname=value][-Uname][-][files]\n");
323     exit(1);
324 }
325
326 #include "AFS_component_version_number.c"
327
328 main(argc, argv)
329      int argc;
330      char **argv;
331 {
332     argv++, argc--;
333     if (argc == 0)
334         usage();
335     while (argc > 0) {
336         if (**argv == '-') {
337             if (strcmp(*argv, "-s") == 0) {
338                 stripcomments++;
339                 argv++, argc--;
340                 continue;
341             }
342             if (strncmp(*argv, "-c", sizeof("-c") - 1) == 0) {
343                 specialchar = argv[0][sizeof("-c")];
344                 argv++, argc--;
345                 continue;
346             }
347             if (strncmp(*argv, "-U", sizeof("-U") - 1) == 0) {
348                 macroundefine(&argv[0][sizeof("-U")]);
349                 argv++, argc--;
350                 continue;
351             }
352             if (strncmp(*argv, "-D", sizeof("-D") - 1) == 0) {
353                 char *cp, *cp2;
354
355                 cp = &argv[0][sizeof("-D") - 1];
356                 if (cp2 = strrchr(cp, '='))
357                     *cp2++ = 0;
358                 if (cp2 == 0)
359                     cp2 = "";
360                 macrodefine(cp, cp2, rdonly);
361                 argv++, argc--;
362                 continue;
363             }
364             if (strcmp(*argv, "-"))
365                 usage();
366         }
367         expandfile(*argv);
368         argv++, argc--;
369     }
370     exit(0);
371 }