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