This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
A configuration system for VMS perl
[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 '. If not, add a newline to the */
129     /* buffer and grab another line. */
130     TempLength = strlen(TempValue);
131     while (TempValue[TempLength-1] != '\'') {
132       fgets(SecondaryLineBuffer, LINEBUFFERSIZE - 1, ConfigSH);
133       /* Force a trailing null, just in case */
134       SecondaryLineBuffer[LINEBUFFERSIZE - 1] = '\0';
135       /* Go substitute */
136       tilde_sub(SecondaryLineBuffer, TildeSub, TildeSubCount);
137       /* Tack a nweline on the end of our primary buffer */
138       strcat(TempValue, "\n");
139       /* Concat the new line we just read */
140       strcat(TempValue, SecondaryLineBuffer);
141
142       /* Refigure the length */
143       TempLength = strlen(TempValue);
144       
145       /* Chop trailing control characters */
146       while((TempLength > 0) && (TempValue[TempLength-1] < ' ')) {
147         TempValue[TempLength - 1] = '\0';
148         TempLength--;
149       }
150     }
151     
152     /* And finally one over the trailing ' */
153     TempValue[TempLength-1] = '\0';
154
155     /* Is there even anything left? */
156     if(*TempValue) {
157       /* Copy the tag over */
158       strcpy(ConfigSub[ConfigSubCount].Tag, LineBuffer);
159       /* Copy the value over */
160       strcpy(ConfigSub[ConfigSubCount].Value, TempValue);
161
162       /* Up the count */
163       ConfigSubCount++;
164
165     }
166   }
167
168   /* Okay, we've read in all the substititions from our config.sh */
169   /* equivalent. Read in the config_h.sh equiv and start the substitution */
170   
171   /* First, eat all the lines until we get to one with !GROK!THIS! in it */
172   while(!strstr(fgets(LineBuffer, LINEBUFFERSIZE, Config_H),
173                 "!GROK!THIS!")) {
174
175     /* Dummy statement to shut up any compiler that'll whine about an empty */
176     /* loop */
177     DummyVariable++;
178   }
179
180   /* Right, we've read all the lines through the first one with !GROK!THIS! */
181   /* in it. That gets us through the beginning stuff. Now start in earnest */
182   /* with our translations, which run until we get to another !GROK!THIS! */
183   while(!strstr(fgets(LineBuffer, LINEBUFFERSIZE, Config_H),
184                 "!GROK!THIS!")) {
185     /* Force a trailing null, just in case */
186     LineBuffer[LINEBUFFERSIZE - 1] = '\0';
187     
188     /* Tilde Substitute */
189     tilde_sub(LineBuffer, TildeSub, TildeSubCount);
190
191     LineBufferLength = strlen(LineBuffer);
192     
193     /* Chop trailing control characters */
194     while((LineBufferLength > 0) && (LineBuffer[LineBufferLength-1] < ' ')) {
195       LineBuffer[LineBufferLength - 1] = '\0';
196       LineBufferLength--;
197     }
198
199     /* Right. Go looking for $s. */
200     for(LineBufferLoop = 0; LineBufferLoop < LineBufferLength;
201         LineBufferLoop++) {
202       /* Did we find one? */
203       if ('$' != LineBuffer[LineBufferLoop]) {
204         /* Nope, spit out the value */
205         putchar(LineBuffer[LineBufferLoop]);
206       } else {
207         /* Yes, we did. Is it escaped? */
208         if ((LineBufferLoop > 0) && ('\\' == LineBuffer[LineBufferLoop -
209                                                        1])) {
210           /* Yup. Spit it out */
211           putchar(LineBuffer[LineBufferLoop]);
212         } else {
213          /* Nope. Go grab us a token */
214           TokenBufferLoop = 0;
215           /* Advance to the next character in the input stream */
216           LineBufferLoop++;
217           while((LineBufferLoop < LineBufferLength) &&
218                 ((isalnum(LineBuffer[LineBufferLoop]) || ('_' ==
219                                                           LineBuffer[LineBufferLoop])))) {
220             TokenBuffer[TokenBufferLoop] = LineBuffer[LineBufferLoop];
221             LineBufferLoop++;
222             TokenBufferLoop++;
223           }
224
225           /* Trailing null on the token buffer */
226           TokenBuffer[TokenBufferLoop] = '\0';
227
228           /* Back the line buffer pointer up one */
229           LineBufferLoop--;
230           
231           /* Right, we're done grabbing a token. Check to make sure we got */
232           /* something */
233           if (TokenBufferLoop) {
234             /* Well, we do. Run through all the tokens we've got in the */
235             /* ConfigSub array and see if any match */
236             GotIt = 0;
237             for(ConfigSubLoop = 0; ConfigSubLoop < ConfigSubCount;
238                 ConfigSubLoop++) {
239               if (!strcmp(TokenBuffer, ConfigSub[ConfigSubLoop].Tag)) {
240                 GotIt = 1;
241                 printf("%s", ConfigSub[ConfigSubLoop].Value);
242                 break;
243               }
244             }
245
246             /* Did we find something? If not, spit out what was in our */
247             /* buffer */
248             if (!GotIt) {
249               printf("$%s", TokenBuffer);
250             }
251             
252           } else {
253             /* Just a bare $. Spit it out */
254             putchar('$');
255           }       
256         }
257       }
258     }
259     
260     /* We're all done. Spit out an EOL */
261     printf("\n");
262     
263     
264   }
265   
266   /* Close the files */
267   fclose(ConfigSH);
268   fclose(Config_H);
269 }
270
271 void
272 tilde_sub(char LineBuffer[], Translate TildeSub[], int TildeSubCount)
273 {
274   char TempBuffer[LINEBUFFERSIZE], TempTilde[TOKENBUFFERSIZE];
275   int TildeLoop, InTilde, CopiedBufferLength, TildeBufferLength, k, GotIt;
276   int TempLength;
277   InTilde = 0;
278   CopiedBufferLength = 0;
279   TildeBufferLength = 0;
280   TempLength = strlen(LineBuffer);
281
282   /* Grovel over our input looking for ~foo~ constructs */
283   for(TildeLoop = 0; TildeLoop < TempLength; TildeLoop++) {
284     /* Are we in a tilde? */
285     if (InTilde) {
286       /* Yup. Is the current character a tilde? */
287       if (LineBuffer[TildeLoop] == '~') {
288         /* Yup. That means we're ready to do a substitution */
289         InTilde = 0;
290         GotIt = 0;
291         /* Trailing null */
292         TempTilde[TildeBufferLength] = '\0';
293         for( k=0; k < TildeSubCount; k++) {
294           if (!strcmp(TildeSub[k].Tag, TempTilde)) {
295             GotIt = 1;
296             /* Tack on the trailing null to the main buffer */
297             TempBuffer[CopiedBufferLength] = '\0';
298             /* Copy the tilde substitution over */
299             strcat(TempBuffer, TildeSub[k].Value);
300             CopiedBufferLength = strlen(TempBuffer);
301           }
302         }
303         
304         /* Did we find anything? */
305         if (GotIt == 0) {
306           /* Guess not. Copy the whole thing out verbatim */
307           TempBuffer[CopiedBufferLength] = '\0';
308           TempBuffer[CopiedBufferLength++] = '~';
309           TempBuffer[CopiedBufferLength] = '\0';
310           strcat(TempBuffer, TempTilde);
311           strcat(TempBuffer, "~");
312           CopiedBufferLength = strlen(TempBuffer);
313         }
314         
315       } else {
316         /* 'Kay, not a tilde. Is it a word character? */
317         if (isalnum(LineBuffer[TildeLoop]) || (LineBuffer[TildeLoop] =
318                                               '-') ||
319             (LineBuffer[TildeLoop] == '-')) {
320           TempTilde[TildeBufferLength++] = LineBuffer[TildeLoop];
321         } else {
322           /* No, it's not a tilde character. For shame! We've got a */
323           /* bogus token. Copy a ~ into the output buffer, then append */
324           /* whatever we've got in our token buffer */
325           TempBuffer[CopiedBufferLength++] = '~';
326           TempBuffer[CopiedBufferLength] = '\0';
327           TempTilde[TildeBufferLength] = '\0';
328           strcat(TempBuffer, TempTilde);
329           CopiedBufferLength += TildeBufferLength;
330           InTilde = 0;
331         }
332       }
333     } else {
334       /* We're not in a tilde. Do we want to be? */
335       if (LineBuffer[TildeLoop] == '~') {
336         /* Guess so */
337         InTilde = 1;
338         TildeBufferLength = 0;
339       } else {
340         /* Nope. Copy the character to the output buffer */
341         TempBuffer[CopiedBufferLength++] = LineBuffer[TildeLoop];
342       }
343     }
344   }
345   
346   /* Out of the loop. First, double-check to see if there was anything */
347   /* pending. */
348   if (InTilde) {
349     /* bogus token. Copy a ~ into the output buffer, then append */
350     /* whatever we've got in our token buffer */
351     TempBuffer[CopiedBufferLength++] = '~';
352     TempBuffer[CopiedBufferLength] = '\0';
353     TempTilde[TildeBufferLength] = '\0';
354     strcat(TempBuffer, TempTilde);
355     CopiedBufferLength += TildeBufferLength;
356   } else {
357     /* Nope, nothing pensing. Tack on a \0 */
358     TempBuffer[CopiedBufferLength] = '\0';
359   }
360
361   /* Okay, we're done. Copy the temp buffer back into the line buffer */
362   strcpy(LineBuffer, TempBuffer);
363
364 }
365