Commit | Line | Data |
97abc6ad |
1 | /* munchconfig.c |
2 | |
3 | A very, very (very!) simple program to process a config_h.sh file on |
4 | non-unix systems. |
5 | |
6 | usage: |
b8df70f4 |
7 | munchconfig config.sh config_h.sh [-f file] [foo=bar [baz=xyzzy [...]]] >config.h |
97abc6ad |
8 | |
b8df70f4 |
9 | which is to say, it takes as its first parameter a config.sh (or |
10 | equivalent), as its second a config_h.sh (or equivalent), an optional file |
11 | containing tag=value pairs (one on each line), and an optional list of |
12 | tag=value pairs on the command line. |
97abc6ad |
13 | |
14 | It spits the processed config.h out to STDOUT. |
15 | |
16 | */ |
17 | |
18 | #include <stdio.h> |
19 | #include <errno.h> |
20 | #include <stdlib.h> |
21 | #include <string.h> |
22 | #include <ctype.h> |
b8df70f4 |
23 | #include <unistd.h> |
97abc6ad |
24 | |
25 | /* The failure code to exit with */ |
26 | #ifndef EXIT_FAILURE |
27 | #ifdef VMS |
28 | #define EXIT_FAILURE 0 |
29 | #else |
30 | #define EXIT_FAILURE -1 |
31 | #endif |
32 | #endif |
33 | |
34 | /* The biggest line we can read in from a file */ |
e43aec62 |
35 | #define LINEBUFFERSIZE 1024 |
97abc6ad |
36 | #define NUMTILDESUBS 30 |
37 | #define NUMCONFIGSUBS 1000 |
38 | #define TOKENBUFFERSIZE 80 |
39 | |
40 | typedef struct { |
41 | char Tag[TOKENBUFFERSIZE]; |
42 | char Value[512]; |
43 | } Translate; |
44 | |
45 | void tilde_sub(char [], Translate [], int); |
46 | |
47 | int |
48 | main(int argc, char *argv[]) |
49 | { |
b8df70f4 |
50 | int c, i; |
51 | char *ifile = NULL; |
52 | char WorkString[LINEBUFFERSIZE]; |
53 | FILE *ConfigSH, *Config_H, *Extra_Subs; |
97abc6ad |
54 | char LineBuffer[LINEBUFFERSIZE], *TempValue, *StartTilde, *EndTilde; |
cc391245 |
55 | char SecondaryLineBuffer[LINEBUFFERSIZE], OutBuf[LINEBUFFERSIZE]; |
97abc6ad |
56 | char TokenBuffer[TOKENBUFFERSIZE]; |
57 | int LineBufferLength, TempLength, DummyVariable, LineBufferLoop; |
cc391245 |
58 | int TokenBufferLoop, ConfigSubLoop, GotIt, OutBufPos; |
97abc6ad |
59 | Translate TildeSub[NUMTILDESUBS]; /* Holds the tilde (~FOO~) */ |
60 | /* substitutions */ |
61 | Translate ConfigSub[NUMCONFIGSUBS]; /* Holds the substitutions from */ |
62 | /* config.sh */ |
63 | int TildeSubCount = 0, ConfigSubCount = 0; /* # of tilde substitutions */ |
64 | /* and config substitutions, */ |
65 | /* respectively */ |
66 | if (argc < 3) { |
b8df70f4 |
67 | printf("Usage: munchconfig config.sh config_h.sh [-f file] [foo=bar [baz=xyzzy [...]]]\n"); |
97abc6ad |
68 | exit(EXIT_FAILURE); |
69 | } |
70 | |
b8df70f4 |
71 | optind = 3; /* skip config.sh and config_h.sh */ |
72 | while ((c = getopt(argc, argv, "f:")) != -1) { |
73 | switch (c) { |
74 | case 'f': |
75 | ifile = optarg; |
76 | break; |
77 | case ':': |
78 | fprintf(stderr, "Option -%c requires an operand\n", optopt); |
79 | break; |
80 | case '?': |
81 | fprintf(stderr,"Unrecognised option: -%c\n", optopt); |
82 | } |
83 | } |
84 | |
97abc6ad |
85 | /* First, open the input files */ |
86 | if (NULL == (ConfigSH = fopen(argv[1], "r"))) { |
87 | printf("Error %i trying to open config.sh file %s\n", errno, argv[1]); |
88 | exit(EXIT_FAILURE); |
89 | } |
90 | |
91 | if (NULL == (Config_H = fopen(argv[2], "r"))) { |
92 | printf("Error %i trying to open config_h.sh file %s\n", errno, argv[2]); |
93 | exit(EXIT_FAILURE); |
94 | } |
95 | |
b8df70f4 |
96 | if (ifile != NULL && NULL == (Extra_Subs = fopen(ifile, "r"))) { |
97 | printf("Error %i trying to open extra substitutions file %s\n", errno, ifile); |
98 | exit(EXIT_FAILURE); |
99 | } |
100 | |
97abc6ad |
101 | /* Any tag/value pairs on the command line? */ |
b8df70f4 |
102 | if (argc > optind) { |
103 | for (i=optind; i < argc && argv[i]; i++) { |
97abc6ad |
104 | /* Local copy */ |
105 | strcpy(WorkString, argv[i]); |
106 | /* Stick a NULL over the = */ |
107 | TempValue = strchr(WorkString, '='); |
108 | *TempValue++ = '\0'; |
109 | |
110 | /* Copy the tag and value into the holding array */ |
111 | strcpy(TildeSub[TildeSubCount].Tag, WorkString); |
112 | strcpy(TildeSub[TildeSubCount].Value, TempValue); |
113 | TildeSubCount++; |
114 | } |
115 | } |
116 | |
b8df70f4 |
117 | /* Now read in the tag/value pairs from the extra substitutions file, if any */ |
118 | while(ifile && fgets(LineBuffer, LINEBUFFERSIZE - 1, Extra_Subs)) { |
119 | /* Force a trailing null, just in case */ |
120 | LineBuffer[LINEBUFFERSIZE - 1] = '\0'; |
121 | LineBufferLength = strlen(LineBuffer); |
122 | |
123 | /* Chop trailing control characters */ |
124 | while((LineBufferLength > 0) && (LineBuffer[LineBufferLength-1] < ' ')) { |
125 | LineBuffer[LineBufferLength - 1] = '\0'; |
126 | LineBufferLength--; |
127 | } |
128 | |
129 | /* If it's empty, then try again */ |
130 | if (!*LineBuffer) |
131 | continue; |
132 | |
133 | /* Local copy */ |
134 | strcpy(WorkString, LineBuffer); |
135 | /* Stick a NULL over the = */ |
136 | TempValue = strchr(WorkString, '='); |
137 | *TempValue++ = '\0'; |
138 | |
139 | /* Copy the tag and value into the holding array */ |
140 | strcpy(TildeSub[TildeSubCount].Tag, WorkString); |
141 | strcpy(TildeSub[TildeSubCount].Value, TempValue); |
142 | TildeSubCount++; |
143 | } |
144 | |
145 | |
97abc6ad |
146 | /* Now read in the config.sh file. */ |
147 | while(fgets(LineBuffer, LINEBUFFERSIZE - 1, ConfigSH)) { |
148 | /* Force a trailing null, just in case */ |
149 | LineBuffer[LINEBUFFERSIZE - 1] = '\0'; |
150 | |
151 | LineBufferLength = strlen(LineBuffer); |
152 | |
153 | /* Chop trailing control characters */ |
154 | while((LineBufferLength > 0) && (LineBuffer[LineBufferLength-1] < ' ')) { |
155 | LineBuffer[LineBufferLength - 1] = '\0'; |
156 | LineBufferLength--; |
157 | } |
158 | |
159 | /* If it's empty, then try again */ |
160 | if (!*LineBuffer) |
161 | continue; |
162 | |
163 | /* If the line begins with a '#' or ' ', skip */ |
164 | if ((LineBuffer[0] == ' ') || (LineBuffer[0] == '#')) |
165 | continue; |
166 | |
167 | /* We've got something. Guess we need to actually handle it */ |
168 | /* Do the tilde substitution */ |
169 | tilde_sub(LineBuffer, TildeSub, TildeSubCount); |
170 | |
171 | /* Stick a NULL over the = */ |
172 | TempValue = strchr(LineBuffer, '='); |
173 | *TempValue++ = '\0'; |
174 | /* And another over the leading ', which better be there */ |
175 | *TempValue++ = '\0'; |
176 | |
b6e4eeb2 |
177 | /* Check to see if there's a trailing ' or ". If not, add a newline to |
178 | the buffer and grab another line. */ |
97abc6ad |
179 | TempLength = strlen(TempValue); |
b6e4eeb2 |
180 | while ((TempValue[TempLength-1] != '\'') && |
181 | (TempValue[TempLength-1] != '"')) { |
97abc6ad |
182 | fgets(SecondaryLineBuffer, LINEBUFFERSIZE - 1, ConfigSH); |
183 | /* Force a trailing null, just in case */ |
184 | SecondaryLineBuffer[LINEBUFFERSIZE - 1] = '\0'; |
185 | /* Go substitute */ |
186 | tilde_sub(SecondaryLineBuffer, TildeSub, TildeSubCount); |
187 | /* Tack a nweline on the end of our primary buffer */ |
188 | strcat(TempValue, "\n"); |
189 | /* Concat the new line we just read */ |
190 | strcat(TempValue, SecondaryLineBuffer); |
191 | |
192 | /* Refigure the length */ |
193 | TempLength = strlen(TempValue); |
194 | |
195 | /* Chop trailing control characters */ |
196 | while((TempLength > 0) && (TempValue[TempLength-1] < ' ')) { |
197 | TempValue[TempLength - 1] = '\0'; |
198 | TempLength--; |
199 | } |
200 | } |
201 | |
202 | /* And finally one over the trailing ' */ |
203 | TempValue[TempLength-1] = '\0'; |
204 | |
205 | /* Is there even anything left? */ |
206 | if(*TempValue) { |
207 | /* Copy the tag over */ |
208 | strcpy(ConfigSub[ConfigSubCount].Tag, LineBuffer); |
209 | /* Copy the value over */ |
210 | strcpy(ConfigSub[ConfigSubCount].Value, TempValue); |
211 | |
212 | /* Up the count */ |
213 | ConfigSubCount++; |
214 | |
215 | } |
216 | } |
217 | |
218 | /* Okay, we've read in all the substititions from our config.sh */ |
219 | /* equivalent. Read in the config_h.sh equiv and start the substitution */ |
220 | |
221 | /* First, eat all the lines until we get to one with !GROK!THIS! in it */ |
222 | while(!strstr(fgets(LineBuffer, LINEBUFFERSIZE, Config_H), |
223 | "!GROK!THIS!")) { |
224 | |
225 | /* Dummy statement to shut up any compiler that'll whine about an empty */ |
226 | /* loop */ |
227 | DummyVariable++; |
228 | } |
229 | |
230 | /* Right, we've read all the lines through the first one with !GROK!THIS! */ |
231 | /* in it. That gets us through the beginning stuff. Now start in earnest */ |
232 | /* with our translations, which run until we get to another !GROK!THIS! */ |
233 | while(!strstr(fgets(LineBuffer, LINEBUFFERSIZE, Config_H), |
234 | "!GROK!THIS!")) { |
235 | /* Force a trailing null, just in case */ |
236 | LineBuffer[LINEBUFFERSIZE - 1] = '\0'; |
237 | |
238 | /* Tilde Substitute */ |
239 | tilde_sub(LineBuffer, TildeSub, TildeSubCount); |
240 | |
241 | LineBufferLength = strlen(LineBuffer); |
242 | |
243 | /* Chop trailing control characters */ |
244 | while((LineBufferLength > 0) && (LineBuffer[LineBufferLength-1] < ' ')) { |
245 | LineBuffer[LineBufferLength - 1] = '\0'; |
246 | LineBufferLength--; |
247 | } |
248 | |
cc391245 |
249 | OutBufPos = 0; |
97abc6ad |
250 | /* Right. Go looking for $s. */ |
251 | for(LineBufferLoop = 0; LineBufferLoop < LineBufferLength; |
252 | LineBufferLoop++) { |
253 | /* Did we find one? */ |
254 | if ('$' != LineBuffer[LineBufferLoop]) { |
255 | /* Nope, spit out the value */ |
cc391245 |
256 | OutBuf[OutBufPos++] = LineBuffer[LineBufferLoop]; |
97abc6ad |
257 | } else { |
258 | /* Yes, we did. Is it escaped? */ |
259 | if ((LineBufferLoop > 0) && ('\\' == LineBuffer[LineBufferLoop - |
260 | 1])) { |
261 | /* Yup. Spit it out */ |
cc391245 |
262 | OutBuf[OutBufPos++] = LineBuffer[LineBufferLoop]; |
97abc6ad |
263 | } else { |
264 | /* Nope. Go grab us a token */ |
265 | TokenBufferLoop = 0; |
266 | /* Advance to the next character in the input stream */ |
267 | LineBufferLoop++; |
268 | while((LineBufferLoop < LineBufferLength) && |
269 | ((isalnum(LineBuffer[LineBufferLoop]) || ('_' == |
270 | LineBuffer[LineBufferLoop])))) { |
271 | TokenBuffer[TokenBufferLoop] = LineBuffer[LineBufferLoop]; |
272 | LineBufferLoop++; |
273 | TokenBufferLoop++; |
274 | } |
275 | |
276 | /* Trailing null on the token buffer */ |
277 | TokenBuffer[TokenBufferLoop] = '\0'; |
278 | |
279 | /* Back the line buffer pointer up one */ |
280 | LineBufferLoop--; |
281 | |
282 | /* Right, we're done grabbing a token. Check to make sure we got */ |
283 | /* something */ |
284 | if (TokenBufferLoop) { |
285 | /* Well, we do. Run through all the tokens we've got in the */ |
286 | /* ConfigSub array and see if any match */ |
287 | GotIt = 0; |
288 | for(ConfigSubLoop = 0; ConfigSubLoop < ConfigSubCount; |
289 | ConfigSubLoop++) { |
290 | if (!strcmp(TokenBuffer, ConfigSub[ConfigSubLoop].Tag)) { |
cc391245 |
291 | char *cp = ConfigSub[ConfigSubLoop].Value; |
292 | GotIt = 1; |
293 | while (*cp) OutBuf[OutBufPos++] = *(cp++); |
97abc6ad |
294 | break; |
295 | } |
296 | } |
297 | |
298 | /* Did we find something? If not, spit out what was in our */ |
299 | /* buffer */ |
300 | if (!GotIt) { |
cc391245 |
301 | char *cp = TokenBuffer; |
302 | OutBuf[OutBufPos++] = '$'; |
303 | while (*cp) OutBuf[OutBufPos++] = *(cp++); |
97abc6ad |
304 | } |
305 | |
306 | } else { |
307 | /* Just a bare $. Spit it out */ |
cc391245 |
308 | OutBuf[OutBufPos++] = '$'; |
97abc6ad |
309 | } |
310 | } |
311 | } |
312 | } |
313 | |
cc391245 |
314 | /* If we've created an #undef line, make sure we don't output anthing |
315 | * after the "#undef FOO" besides comments. We could do this as we |
316 | * go by recognizing the #undef as it goes by, and thus avoid another |
317 | * use of a fixed-length buffer, but this is simpler. |
318 | */ |
319 | if (!strncmp(OutBuf,"#undef",6)) { |
320 | char *cp = OutBuf; |
321 | int i, incomment = 0; |
322 | LineBufferLoop = 0; |
323 | OutBuf[OutBufPos] = '\0'; |
324 | for (i = 0; i <= 1; i++) { |
325 | while (!isspace(*cp)) LineBuffer[LineBufferLoop++] = *(cp++); |
326 | while ( isspace(*cp)) LineBuffer[LineBufferLoop++] = *(cp++); |
327 | } |
328 | while (*cp) { |
329 | while (isspace(*cp)) LineBuffer[LineBufferLoop++] = *(cp++); |
330 | if (!incomment && *cp == '/' && *(cp+1) == '*') incomment = 1; |
331 | while (*cp && !isspace(*cp)) { |
332 | if (incomment) LineBuffer[LineBufferLoop++] = *cp; |
333 | cp++; |
334 | } |
335 | if (incomment && *cp == '*' && *(cp+1) == '/') incomment = 0; |
336 | } |
337 | LineBuffer[LineBufferLoop] = '\0'; |
338 | puts(LineBuffer); |
339 | } |
340 | else { |
341 | OutBuf[OutBufPos] = '\0'; |
342 | puts(OutBuf); |
343 | } |
97abc6ad |
344 | } |
345 | |
346 | /* Close the files */ |
347 | fclose(ConfigSH); |
348 | fclose(Config_H); |
b8df70f4 |
349 | if (ifile) fclose(Extra_Subs); |
97abc6ad |
350 | } |
351 | |
352 | void |
353 | tilde_sub(char LineBuffer[], Translate TildeSub[], int TildeSubCount) |
354 | { |
355 | char TempBuffer[LINEBUFFERSIZE], TempTilde[TOKENBUFFERSIZE]; |
356 | int TildeLoop, InTilde, CopiedBufferLength, TildeBufferLength, k, GotIt; |
357 | int TempLength; |
358 | InTilde = 0; |
359 | CopiedBufferLength = 0; |
360 | TildeBufferLength = 0; |
361 | TempLength = strlen(LineBuffer); |
362 | |
363 | /* Grovel over our input looking for ~foo~ constructs */ |
364 | for(TildeLoop = 0; TildeLoop < TempLength; TildeLoop++) { |
365 | /* Are we in a tilde? */ |
366 | if (InTilde) { |
367 | /* Yup. Is the current character a tilde? */ |
368 | if (LineBuffer[TildeLoop] == '~') { |
369 | /* Yup. That means we're ready to do a substitution */ |
370 | InTilde = 0; |
371 | GotIt = 0; |
372 | /* Trailing null */ |
373 | TempTilde[TildeBufferLength] = '\0'; |
374 | for( k=0; k < TildeSubCount; k++) { |
375 | if (!strcmp(TildeSub[k].Tag, TempTilde)) { |
376 | GotIt = 1; |
377 | /* Tack on the trailing null to the main buffer */ |
378 | TempBuffer[CopiedBufferLength] = '\0'; |
379 | /* Copy the tilde substitution over */ |
380 | strcat(TempBuffer, TildeSub[k].Value); |
381 | CopiedBufferLength = strlen(TempBuffer); |
382 | } |
383 | } |
384 | |
385 | /* Did we find anything? */ |
386 | if (GotIt == 0) { |
387 | /* Guess not. Copy the whole thing out verbatim */ |
388 | TempBuffer[CopiedBufferLength] = '\0'; |
389 | TempBuffer[CopiedBufferLength++] = '~'; |
390 | TempBuffer[CopiedBufferLength] = '\0'; |
391 | strcat(TempBuffer, TempTilde); |
392 | strcat(TempBuffer, "~"); |
393 | CopiedBufferLength = strlen(TempBuffer); |
394 | } |
395 | |
396 | } else { |
397 | /* 'Kay, not a tilde. Is it a word character? */ |
154545c7 |
398 | if (isalnum(LineBuffer[TildeLoop]) || |
97abc6ad |
399 | (LineBuffer[TildeLoop] == '-')) { |
400 | TempTilde[TildeBufferLength++] = LineBuffer[TildeLoop]; |
401 | } else { |
402 | /* No, it's not a tilde character. For shame! We've got a */ |
403 | /* bogus token. Copy a ~ into the output buffer, then append */ |
404 | /* whatever we've got in our token buffer */ |
405 | TempBuffer[CopiedBufferLength++] = '~'; |
406 | TempBuffer[CopiedBufferLength] = '\0'; |
407 | TempTilde[TildeBufferLength] = '\0'; |
408 | strcat(TempBuffer, TempTilde); |
409 | CopiedBufferLength += TildeBufferLength; |
410 | InTilde = 0; |
411 | } |
412 | } |
413 | } else { |
414 | /* We're not in a tilde. Do we want to be? */ |
415 | if (LineBuffer[TildeLoop] == '~') { |
416 | /* Guess so */ |
417 | InTilde = 1; |
418 | TildeBufferLength = 0; |
419 | } else { |
420 | /* Nope. Copy the character to the output buffer */ |
421 | TempBuffer[CopiedBufferLength++] = LineBuffer[TildeLoop]; |
422 | } |
423 | } |
424 | } |
425 | |
426 | /* Out of the loop. First, double-check to see if there was anything */ |
427 | /* pending. */ |
428 | if (InTilde) { |
429 | /* bogus token. Copy a ~ into the output buffer, then append */ |
430 | /* whatever we've got in our token buffer */ |
431 | TempBuffer[CopiedBufferLength++] = '~'; |
432 | TempBuffer[CopiedBufferLength] = '\0'; |
433 | TempTilde[TildeBufferLength] = '\0'; |
434 | strcat(TempBuffer, TempTilde); |
435 | CopiedBufferLength += TildeBufferLength; |
436 | } else { |
437 | /* Nope, nothing pensing. Tack on a \0 */ |
438 | TempBuffer[CopiedBufferLength] = '\0'; |
439 | } |
440 | |
441 | /* Okay, we're done. Copy the temp buffer back into the line buffer */ |
442 | strcpy(LineBuffer, TempBuffer); |
443 | |
444 | } |
445 | |