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 [-f file] [foo=bar [baz=xyzzy [...]]] >config.h 8 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. 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> 23 #include <unistd.h> 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 */ 35 #define LINEBUFFERSIZE 1024 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 { 50 int c, i; 51 char *ifile = NULL; 52 char WorkString[LINEBUFFERSIZE]; 53 FILE *ConfigSH, *Config_H, *Extra_Subs; 54 char LineBuffer[LINEBUFFERSIZE], *TempValue, *StartTilde, *EndTilde; 55 char SecondaryLineBuffer[LINEBUFFERSIZE], OutBuf[LINEBUFFERSIZE]; 56 char TokenBuffer[TOKENBUFFERSIZE]; 57 int LineBufferLength, TempLength, DummyVariable, LineBufferLoop; 58 int TokenBufferLoop, ConfigSubLoop, GotIt, OutBufPos; 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) { 67 printf("Usage: munchconfig config.sh config_h.sh [-f file] [foo=bar [baz=xyzzy [...]]]\n"); 68 exit(EXIT_FAILURE); 69 } 70 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 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 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 101 /* Any tag/value pairs on the command line? */ 102 if (argc > optind) { 103 for (i=optind; i < argc && argv[i]; i++) { 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 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 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 177 /* Check to see if there's a trailing ' or ". If not, add a newline to 178 the buffer and grab another line. */ 179 TempLength = strlen(TempValue); 180 while ((TempValue[TempLength-1] != '\'') && 181 (TempValue[TempLength-1] != '"')) { 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 249 OutBufPos = 0; 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 */ 256 OutBuf[OutBufPos++] = LineBuffer[LineBufferLoop]; 257 } else { 258 /* Yes, we did. Is it escaped? */ 259 if ((LineBufferLoop > 0) && ('\\' == LineBuffer[LineBufferLoop - 260 1])) { 261 /* Yup. Spit it out */ 262 OutBuf[OutBufPos++] = LineBuffer[LineBufferLoop]; 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)) { 291 char *cp = ConfigSub[ConfigSubLoop].Value; 292 GotIt = 1; 293 while (*cp) OutBuf[OutBufPos++] = *(cp++); 294 break; 295 } 296 } 297 298 /* Did we find something? If not, spit out what was in our */ 299 /* buffer */ 300 if (!GotIt) { 301 char *cp = TokenBuffer; 302 OutBuf[OutBufPos++] = '$'; 303 while (*cp) OutBuf[OutBufPos++] = *(cp++); 304 } 305 306 } else { 307 /* Just a bare $. Spit it out */ 308 OutBuf[OutBufPos++] = '$'; 309 } 310 } 311 } 312 } 313 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 } 344 } 345 346 /* Close the files */ 347 fclose(ConfigSH); 348 fclose(Config_H); 349 if (ifile) fclose(Extra_Subs); 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? */ 398 if (isalnum(LineBuffer[TildeLoop]) || 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 446