This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
integrate changes#2978,2979 from mainline
[perl5.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];
51   char TokenBuffer[TOKENBUFFERSIZE];
52   int LineBufferLength, TempLength, DummyVariable, LineBufferLoop;
53   int TokenBufferLoop, ConfigSubLoop, GotIt;
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     /* Right. Go looking for $s. */
201     for(LineBufferLoop = 0; LineBufferLoop < LineBufferLength;
202         LineBufferLoop++) {
203       /* Did we find one? */
204       if ('$' != LineBuffer[LineBufferLoop]) {
205         /* Nope, spit out the value */
206         putchar(LineBuffer[LineBufferLoop]);
207       } else {
208         /* Yes, we did. Is it escaped? */
209         if ((LineBufferLoop > 0) && ('\\' == LineBuffer[LineBufferLoop -
210                                                        1])) {
211           /* Yup. Spit it out */
212           putchar(LineBuffer[LineBufferLoop]);
213         } else {
214          /* Nope. Go grab us a token */
215           TokenBufferLoop = 0;
216           /* Advance to the next character in the input stream */
217           LineBufferLoop++;
218           while((LineBufferLoop < LineBufferLength) &&
219                 ((isalnum(LineBuffer[LineBufferLoop]) || ('_' ==
220                                                           LineBuffer[LineBufferLoop])))) {
221             TokenBuffer[TokenBufferLoop] = LineBuffer[LineBufferLoop];
222             LineBufferLoop++;
223             TokenBufferLoop++;
224           }
225
226           /* Trailing null on the token buffer */
227           TokenBuffer[TokenBufferLoop] = '\0';
228
229           /* Back the line buffer pointer up one */
230           LineBufferLoop--;
231           
232           /* Right, we're done grabbing a token. Check to make sure we got */
233           /* something */
234           if (TokenBufferLoop) {
235             /* Well, we do. Run through all the tokens we've got in the */
236             /* ConfigSub array and see if any match */
237             GotIt = 0;
238             for(ConfigSubLoop = 0; ConfigSubLoop < ConfigSubCount;
239                 ConfigSubLoop++) {
240               if (!strcmp(TokenBuffer, ConfigSub[ConfigSubLoop].Tag)) {
241                 GotIt = 1;
242                 printf("%s", ConfigSub[ConfigSubLoop].Value);
243                 break;
244               }
245             }
246
247             /* Did we find something? If not, spit out what was in our */
248             /* buffer */
249             if (!GotIt) {
250               printf("$%s", TokenBuffer);
251             }
252             
253           } else {
254             /* Just a bare $. Spit it out */
255             putchar('$');
256           }       
257         }
258       }
259     }
260     
261     /* We're all done. Spit out an EOL */
262     printf("\n");
263     
264     
265   }
266   
267   /* Close the files */
268   fclose(ConfigSH);
269   fclose(Config_H);
270 }
271
272 void
273 tilde_sub(char LineBuffer[], Translate TildeSub[], int TildeSubCount)
274 {
275   char TempBuffer[LINEBUFFERSIZE], TempTilde[TOKENBUFFERSIZE];
276   int TildeLoop, InTilde, CopiedBufferLength, TildeBufferLength, k, GotIt;
277   int TempLength;
278   InTilde = 0;
279   CopiedBufferLength = 0;
280   TildeBufferLength = 0;
281   TempLength = strlen(LineBuffer);
282
283   /* Grovel over our input looking for ~foo~ constructs */
284   for(TildeLoop = 0; TildeLoop < TempLength; TildeLoop++) {
285     /* Are we in a tilde? */
286     if (InTilde) {
287       /* Yup. Is the current character a tilde? */
288       if (LineBuffer[TildeLoop] == '~') {
289         /* Yup. That means we're ready to do a substitution */
290         InTilde = 0;
291         GotIt = 0;
292         /* Trailing null */
293         TempTilde[TildeBufferLength] = '\0';
294         for( k=0; k < TildeSubCount; k++) {
295           if (!strcmp(TildeSub[k].Tag, TempTilde)) {
296             GotIt = 1;
297             /* Tack on the trailing null to the main buffer */
298             TempBuffer[CopiedBufferLength] = '\0';
299             /* Copy the tilde substitution over */
300             strcat(TempBuffer, TildeSub[k].Value);
301             CopiedBufferLength = strlen(TempBuffer);
302           }
303         }
304         
305         /* Did we find anything? */
306         if (GotIt == 0) {
307           /* Guess not. Copy the whole thing out verbatim */
308           TempBuffer[CopiedBufferLength] = '\0';
309           TempBuffer[CopiedBufferLength++] = '~';
310           TempBuffer[CopiedBufferLength] = '\0';
311           strcat(TempBuffer, TempTilde);
312           strcat(TempBuffer, "~");
313           CopiedBufferLength = strlen(TempBuffer);
314         }
315         
316       } else {
317         /* 'Kay, not a tilde. Is it a word character? */
318         if (isalnum(LineBuffer[TildeLoop]) || (LineBuffer[TildeLoop] =
319                                               '-') ||
320             (LineBuffer[TildeLoop] == '-')) {
321           TempTilde[TildeBufferLength++] = LineBuffer[TildeLoop];
322         } else {
323           /* No, it's not a tilde character. For shame! We've got a */
324           /* bogus token. Copy a ~ into the output buffer, then append */
325           /* whatever we've got in our token buffer */
326           TempBuffer[CopiedBufferLength++] = '~';
327           TempBuffer[CopiedBufferLength] = '\0';
328           TempTilde[TildeBufferLength] = '\0';
329           strcat(TempBuffer, TempTilde);
330           CopiedBufferLength += TildeBufferLength;
331           InTilde = 0;
332         }
333       }
334     } else {
335       /* We're not in a tilde. Do we want to be? */
336       if (LineBuffer[TildeLoop] == '~') {
337         /* Guess so */
338         InTilde = 1;
339         TildeBufferLength = 0;
340       } else {
341         /* Nope. Copy the character to the output buffer */
342         TempBuffer[CopiedBufferLength++] = LineBuffer[TildeLoop];
343       }
344     }
345   }
346   
347   /* Out of the loop. First, double-check to see if there was anything */
348   /* pending. */
349   if (InTilde) {
350     /* bogus token. Copy a ~ into the output buffer, then append */
351     /* whatever we've got in our token buffer */
352     TempBuffer[CopiedBufferLength++] = '~';
353     TempBuffer[CopiedBufferLength] = '\0';
354     TempTilde[TildeBufferLength] = '\0';
355     strcat(TempBuffer, TempTilde);
356     CopiedBufferLength += TildeBufferLength;
357   } else {
358     /* Nope, nothing pensing. Tack on a \0 */
359     TempBuffer[CopiedBufferLength] = '\0';
360   }
361
362   /* Okay, we're done. Copy the temp buffer back into the line buffer */
363   strcpy(LineBuffer, TempBuffer);
364
365 }
366