1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: Header preprocessor 4 * PURPOSE: Generates header files from other header files 5 * PROGRAMMER; Timo Kreuzer 6 * 7 */ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <stdarg.h> 12 #include <string.h> 13 #include <ctype.h> 14 15 //#define DBG 1 16 17 #if DBG 18 #define trace printf 19 #else 20 #define trace if (0) printf 21 #endif 22 23 typedef struct _DEFINE 24 { 25 struct _DEFINE *pNext; 26 int val; 27 char *pszName; 28 unsigned int cchName; 29 char *pszValue; 30 unsigned int cchValue; 31 char achBuffer[1]; 32 } DEFINE, *PDEFINE; 33 34 DEFINE *gpDefines = 0; 35 int iLine; 36 const char *gpszCurFile; 37 38 char* 39 convert_path(const char* origpath) 40 { 41 char* newpath; 42 int i; 43 44 newpath = strdup(origpath); 45 46 i = 0; 47 while (newpath[i] != 0) 48 { 49 #ifdef UNIX_PATHS 50 if (newpath[i] == '\\') 51 { 52 newpath[i] = '/'; 53 } 54 #else 55 #ifdef DOS_PATHS 56 if (newpath[i] == '/') 57 { 58 newpath[i] = '\\'; 59 } 60 #endif 61 #endif 62 i++; 63 } 64 return newpath; 65 } 66 67 char* 68 GetFolder(const char* pszFullPath) 69 { 70 return "."; 71 } 72 73 void* 74 LoadFile(const char* pszFileName, size_t* pFileSize) 75 { 76 FILE* file; 77 void* pFileData = NULL; 78 int iFileSize; 79 80 trace("Loading file..."); 81 82 file = fopen(pszFileName, "rb"); 83 if (!file) 84 { 85 trace("Could not open file\n"); 86 return NULL; 87 } 88 89 fseek(file, 0L, SEEK_END); 90 iFileSize = ftell(file); 91 fseek(file, 0L, SEEK_SET); 92 *pFileSize = iFileSize; 93 trace("ok. Size is %d\n", iFileSize); 94 95 pFileData = malloc(iFileSize + 1); 96 97 if (pFileData != NULL) 98 { 99 if (iFileSize != fread(pFileData, 1, iFileSize, file)) 100 { 101 free(pFileData); 102 pFileData = NULL; 103 } 104 } 105 else 106 { 107 trace("Could not allocate memory for file\n"); 108 } 109 110 fclose(file); 111 112 return pFileData; 113 } 114 115 116 int 117 error(char *format, ...) 118 { 119 va_list valist; 120 int res; 121 va_start(valist, format); 122 res = vfprintf(stderr, format, valist); 123 va_end(valist); 124 return res; 125 } 126 127 char* 128 GetNextChar(const char *psz) 129 { 130 while (*psz == ' ' || *psz == '\t') psz++; 131 return (char*)psz; 132 } 133 134 char* 135 GetNextLine(char *pszLine) 136 { 137 /* Walk to the end of the line */ 138 while (*pszLine != 13 && *pszLine != 10 && *pszLine != 0) pszLine++; 139 140 /* Skip one CR/LF */ 141 if (pszLine[0] == 13 && pszLine[1] == 10) 142 pszLine += 2; 143 else if (pszLine[0] == 13 || pszLine[0] == 10) 144 pszLine++; 145 146 if (*pszLine == 0) 147 { 148 return 0; 149 } 150 151 return pszLine; 152 } 153 154 int 155 strxlen(const char *psz) 156 { 157 int len = 0; 158 while (isalnum(*psz) || *psz == '_') 159 { 160 psz++; 161 len++; 162 } 163 return len; 164 } 165 166 PDEFINE 167 FindDefine(const char *p, char **pNext) 168 { 169 PDEFINE pDefine; 170 int cchName; 171 172 cchName = strxlen(p); 173 if (pNext) 174 *pNext = (char*)p + cchName; 175 176 /* search for the define in the global list */ 177 pDefine = gpDefines; 178 while (pDefine != 0) 179 { 180 trace("found a define: %s\n", pDefine->pszName); 181 if (pDefine->cchName == cchName) 182 { 183 if (strncmp(p, pDefine->pszName, cchName) == 0) 184 { 185 return pDefine; 186 } 187 } 188 pDefine = pDefine->pNext; 189 } 190 return 0; 191 } 192 193 void 194 WriteLine(char *pchLine, FILE *fileOut) 195 { 196 char *pch, *pchLineEnd, *pchVariable; 197 int len; 198 PDEFINE pDefine; 199 200 pchLineEnd = strchr(pchLine, '\n'); 201 if (pchLineEnd == 0) 202 return; 203 204 len = pchLineEnd - pchLine + 1; 205 206 pch = pchLine; 207 while (len > 0) 208 { 209 /* Check if there is a $ variable in the line */ 210 pchVariable = strchr(pch, '$'); 211 if (pchVariable && (pchVariable < pchLineEnd)) 212 { 213 /* Write all characters up to the $ */ 214 fwrite(pch, 1, pchVariable - pch, fileOut); 215 216 /* Try to find the define */ 217 pDefine = FindDefine(pchVariable + 1, &pch); 218 if (pDefine != 0) 219 { 220 /* We have a define, write the value */ 221 fwrite(pDefine->pszValue, 1, pDefine->cchValue, fileOut); 222 } 223 else 224 { 225 len = strxlen(pchVariable + 1) + 1; 226 error("Could not find variable '%.*s'\n", len, pchVariable); 227 fwrite(pchVariable, 1, pch - pchVariable, fileOut); 228 } 229 230 len = pchLineEnd - pch + 1; 231 } 232 else 233 { 234 fwrite(pch, 1, len, fileOut); 235 break; 236 } 237 } 238 } 239 240 int 241 EvaluateConstant(const char *p, char **pNext) 242 { 243 PDEFINE pDefine; 244 245 pDefine = FindDefine(p, pNext); 246 if (!pDefine) 247 return 0; 248 249 return pDefine->val; 250 } 251 252 int 253 EvaluateExpression(char *pExpression, char **pNext) 254 { 255 char *p, *pstart; 256 int inv, thisval, val = 0; 257 258 trace("evaluating expression\n"); 259 260 pstart = GetNextChar(pExpression); 261 if (*pstart != '(') 262 { 263 error("Parse error: expected '(' \n"); 264 return -1; 265 } 266 267 while (1) 268 { 269 /* Get the start of the real expression */ 270 p = pstart; 271 if ((p[0] == '&' && p[1] == '&') || 272 (p[0] == '|' && p[1] == '|')) 273 { 274 p++; 275 } 276 p = GetNextChar(p + 1); 277 278 /* Check for inversion modifier */ 279 if (*p == '!') 280 { 281 inv = 1; 282 p = GetNextChar(p + 1); 283 } 284 else 285 inv = 0; 286 287 /* Beginning of a new subexpression? */ 288 if (*p == '(') 289 { 290 /* Evaluate subexpression */ 291 thisval = EvaluateExpression(p, &p); 292 } 293 else if (isdigit(*p)) 294 { 295 thisval = strtod(p, &p); 296 trace("found a num: %d\n", thisval); 297 } 298 else if (isalpha(*p) || *p == '_') 299 { 300 thisval = EvaluateConstant(p, &p); 301 } 302 else 303 { 304 error("..Parse error, expected '(' or constant in line %d\n", 305 iLine); 306 return -1; 307 } 308 309 if (inv) 310 thisval = !thisval; 311 312 /* Check how to combine the current value */ 313 if (pstart[0] == '(') 314 { 315 val = thisval; 316 } 317 else if (pstart[0] == '&' && pstart[1] == '&') 318 { 319 val = val && thisval; 320 } 321 else if (pstart[0] == '&' && pstart[1] != '&') 322 { 323 val = val & thisval; 324 } 325 else if (pstart[0] == '|' && pstart[1] == '|') 326 { 327 trace("found || val = %d, thisval = %d\n", val, thisval); 328 val = val || thisval; 329 } 330 else if (pstart[0] == '|' && pstart[1] != '|') 331 { 332 val = val | thisval; 333 } 334 else if (pstart[0] == '+') 335 { 336 val = val + thisval; 337 } 338 else 339 { 340 error("+Parse error: expected '(' or operator in Line %d, got %c\n", 341 iLine, pstart[0]); 342 return -1; 343 } 344 345 p = GetNextChar(p); 346 347 /* End of current subexpression? */ 348 if (*p == ')') 349 { 350 if (pNext) 351 { 352 *pNext = p + 1; 353 } 354 return val; 355 } 356 357 /* Continue with a new start position */ 358 pstart = p; 359 } 360 361 return val; 362 } 363 364 int 365 ParseInputFile(const char *pszInFile, FILE *fileOut) 366 { 367 char* pInputData, *pCurrentLine, *p1, *p2; 368 size_t cbInFileLenth; 369 int iIfLevel, iCopyLevel; 370 371 trace("parsing input file: %s\n", pszInFile); 372 373 /* Set the global file name */ 374 gpszCurFile = pszInFile; 375 376 /* Load the input file into memory */ 377 pInputData = LoadFile(pszInFile, &cbInFileLenth); 378 if (!pInputData) 379 { 380 error("Could not load input file %s\n", pszInFile); 381 return -1; 382 } 383 384 /* Zero terminate the file */ 385 pInputData[cbInFileLenth] = 0; 386 387 pCurrentLine = pInputData; 388 iLine = 1; 389 iCopyLevel = iIfLevel = 0; 390 391 /* The main processing loop */ 392 do 393 { 394 trace("line %d: ", iLine); 395 396 /* If this is a normal line ... */ 397 if (pCurrentLine[0] != '$') 398 { 399 /* Check if we are to copy this line */ 400 if (iCopyLevel == iIfLevel) 401 { 402 trace("copying\n"); 403 WriteLine(pCurrentLine, fileOut); 404 } 405 else 406 trace("skipping\n"); 407 408 /* Continue with next line */ 409 continue; 410 } 411 412 /* Check for $endif */ 413 if (strncmp(pCurrentLine, "$endif", 6) == 0) 414 { 415 trace("found $endif\n"); 416 if (iIfLevel <= 0) 417 { 418 error("Parse error: $endif without $if in %s:%d\n", pszInFile, iLine); 419 return -1; 420 } 421 if (iCopyLevel == iIfLevel) 422 { 423 iCopyLevel--; 424 } 425 iIfLevel--; 426 427 /* Continue with next line */ 428 continue; 429 } 430 431 /* The rest is only parsed when we are in a true block */ 432 if (iCopyLevel < iIfLevel) 433 { 434 trace("skipping\n"); 435 436 /* Continue with next line */ 437 continue; 438 } 439 440 /* Check for $define */ 441 if (strncmp(pCurrentLine, "$define", 7) == 0) 442 { 443 PDEFINE pDefine; 444 char *pchName, *pchValue; 445 size_t cchName, cchValue; 446 447 trace("found $define\n"); 448 p1 = GetNextChar(pCurrentLine + 7); 449 if (*p1 != '(') 450 { 451 error("Parse error: expected '(' at %s:%d\n", 452 pszInFile, iLine); 453 return -1; 454 } 455 456 pchName = GetNextChar(p1 + 1); 457 cchName = strxlen(pchName); 458 p1 = GetNextChar(pchName + cchName); 459 460 /* Check for assignment */ 461 if (*p1 == '=') 462 { 463 trace("found $define with assignment\n"); 464 pchValue = GetNextChar(p1 + 1); 465 cchValue = strxlen(pchValue); 466 p1 = GetNextChar(pchValue + cchValue); 467 } 468 else 469 { 470 pchValue = 0; 471 cchValue = 0; 472 } 473 474 /* Allocate a DEFINE structure */ 475 pDefine = malloc(sizeof(DEFINE) + cchName + cchValue + 2); 476 if (pDefine == 0) 477 { 478 error("Failed to allocate %u bytes\n", 479 sizeof(DEFINE) + cchName + cchValue + 2); 480 return -1; 481 } 482 483 pDefine->pszName = pDefine->achBuffer; 484 strncpy(pDefine->pszName, pchName, cchName); 485 pDefine->pszName[cchName] = 0; 486 pDefine->cchName = cchName; 487 pDefine->val = 1; 488 489 if (pchValue != 0) 490 { 491 pDefine->pszValue = &pDefine->achBuffer[cchName + 1]; 492 strncpy(pDefine->pszValue, pchValue, cchValue); 493 pDefine->pszValue[cchValue] = 0; 494 pDefine->cchValue = cchValue; 495 } 496 else 497 { 498 pDefine->pszValue = 0; 499 pDefine->cchValue = 0; 500 } 501 502 /* Insert the new define into the global list */ 503 pDefine->pNext = gpDefines; 504 gpDefines = pDefine; 505 506 /* Check for closing ')' */ 507 if (*p1 != ')') 508 { 509 error("Parse error: expected ')' at %s:%d\n", 510 pszInFile, iLine); 511 return -1; 512 } 513 } 514 515 /* Check for $if */ 516 else if (strncmp(pCurrentLine, "$if", 3) == 0) 517 { 518 int val; 519 520 trace("found $if\n"); 521 /* Increase the if-level */ 522 iIfLevel++; 523 524 /* Get beginning of the expression */ 525 p1 = GetNextChar(pCurrentLine + 3); 526 527 /* evaluate the expression */ 528 val = EvaluateExpression(p1, 0); 529 530 if (val) 531 { 532 iCopyLevel = iIfLevel; 533 } 534 else if (val == -1) 535 { 536 /* Parse error */ 537 return -1; 538 } 539 } 540 541 /* Check for $include */ 542 else if (strncmp(pCurrentLine, "$include", 8) == 0) 543 { 544 int ret; 545 546 trace("found $include\n"); 547 p1 = GetNextChar(pCurrentLine + 8); 548 if (*p1 != '(') 549 { 550 error("Parse error: expected '(' at %s:%d, found '%c'\n", 551 pszInFile, iLine, *p1); 552 return -1; 553 } 554 p1++; 555 p2 = strchr(p1, ')'); 556 *p2 = 0; 557 558 /* Parse the included file */ 559 ret = ParseInputFile(p1, fileOut); 560 561 /* Restore the global file name */ 562 gpszCurFile = pszInFile; 563 564 /* Restore the zeroed character */ 565 *p2 = ')'; 566 567 if (ret == -1) 568 { 569 return -1; 570 } 571 } 572 573 /* Check for $$ comment */ 574 else if (strncmp(pCurrentLine, "$$", 2) == 0) 575 { 576 trace("$$ ignored\n"); 577 /* continue with next line */ 578 continue; 579 } 580 581 else 582 { 583 trace("wot:%s\n", pCurrentLine); 584 } 585 586 /* Continue with next line */ 587 } 588 while (pCurrentLine = GetNextLine(pCurrentLine), 589 iLine++, 590 pCurrentLine != 0); 591 592 /* Free the file data */ 593 free(pInputData); 594 595 trace("Done with file.\n\n"); 596 597 return 0; 598 } 599 600 601 int 602 main(int argc, char* argv[]) 603 { 604 char *pszInFile, *pszOutFile; 605 FILE* fileOut; 606 int ret; 607 608 if (argc != 3) 609 { 610 error("Usage: hpp <inputfile> <outputfile>\n"); 611 exit(1); 612 } 613 614 pszInFile = convert_path(argv[1]); 615 pszOutFile = convert_path(argv[2]); 616 617 fileOut = fopen(pszOutFile, "wb"); 618 if (fileOut == NULL) 619 { 620 error("Cannot open output file %s", pszOutFile); 621 exit(1); 622 } 623 624 ret = ParseInputFile(pszInFile, fileOut); 625 626 fclose(fileOut); 627 free(pszInFile); 628 free(pszOutFile); 629 630 return ret; 631 } 632