- Timestamp:
- May 6, 2012 8:31:02 PM (13 years ago)
- Location:
- trunk/src/bldprogs
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bldprogs/Makefile.kmk
r41177 r41179 50 50 scmstream.cpp 51 51 52 #BLDPROGS += VBoxCPP52 BLDPROGS += VBoxCPP 53 53 VBoxCPP_TEMPLATE = VBoxAdvBldProg 54 54 VBoxCPP_SOURCES = \ -
trunk/src/bldprogs/VBoxCPP.cpp
r41177 r41179 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Build Tool - A mini C Preprocessor. 3 * VBox Build Tool - A mini C Preprocessor. 4 * 5 * This is not attempting to be standard compliant, just get the job done! 4 6 */ 5 7 … … 24 26 #include <iprt/alloca.h> 25 27 #include <iprt/assert.h> 28 #include <iprt/asm.h> 26 29 #include <iprt/ctype.h> 27 #include <iprt/env.h>28 30 #include <iprt/err.h> 29 31 #include <iprt/file.h> … … 34 36 #include <iprt/message.h> 35 37 #include <iprt/path.h> 36 #include <iprt/process.h>37 38 #include <iprt/stream.h> 38 39 #include <iprt/string.h> 39 #include <iprt/uuid.h>40 40 41 41 #include "scmstream.h" 42 42 43 44 /******************************************************************************* 45 * Defined Constants And Macros * 46 *******************************************************************************/ 47 /** The bitmap type. */ 48 #define VBCPP_BITMAP_TYPE uint64_t 49 /** The bitmap size as a multiple of VBCPP_BITMAP_TYPE. */ 50 #define VBCPP_BITMAP_SIZE (128 / 64) 51 /** Checks if a bit is set. */ 52 #define VBCPP_BITMAP_IS_SET(a_bm, a_ch) ASMBitTest(a_bm, (a_ch) & 0x7f) 53 /** Sets a bit. */ 54 #define VBCPP_BITMAP_SET(a_bm, a_ch) ASMBitSet(a_bm, (a_ch) & 0x7f) 55 /** Empties the bitmap. */ 56 #define VBCPP_BITMAP_EMPTY(a_bm) do { (a_bm)[0] = 0; (a_bm)[1] = 0; } while (0) 57 /** Joins to bitmaps by OR'ing their values.. */ 58 #define VBCPP_BITMAP_OR(a_bm1, a_bm2) do { (a_bm1)[0] |= (a_bm2)[0]; (a_bm1)[1] |= (a_bm2)[1]; } while (0) 43 59 44 60 … … 72 88 /** The number of known arguments.*/ 73 89 uint32_t cArgs; 74 75 /** @todo More to come later some day... Currently, only care about selective76 * preprocessing. */77 78 /** The define value. (This is followed by the name ).*/90 /** Pointer to a list of argument names. */ 91 const char **papszArgs; 92 /** Lead character bitmap for the argument names. */ 93 VBCPP_BITMAP_TYPE bmArgs[VBCPP_BITMAP_SIZE]; 94 /** The define value. (This is followed by the name and arguments.) */ 79 95 char szValue[1]; 80 96 } VBCPPDEF; … … 84 100 85 101 /** 102 * Expansion context. 103 */ 104 typedef struct VBCPPCTX 105 { 106 /** The next context on the stack. */ 107 struct VBCPPCTX *pUp; 108 /** The define being expanded. */ 109 PVBCPPDEF pDef; 110 /** Arguments. */ 111 struct VBCPPCTXARG 112 { 113 /** The value. */ 114 const char *pchValue; 115 /** The value length. */ 116 const char *cchValue; 117 } aArgs[1]; 118 } VBCPPCTX; 119 /** Pointer to an define expansion context. */ 120 typedef VBCPPCTX *PVBCPPCTX; 121 122 123 /** 86 124 * C Preprocessor instance data. 87 125 */ … … 91 129 * @{ */ 92 130 /** The preprocessing mode. */ 93 VBCPPMODE enmMode;131 VBCPPMODE enmMode; 94 132 /** Whether to keep comments. */ 95 bool fKeepComments;133 bool fKeepComments; 96 134 97 135 /** The number of include directories. */ 98 uint32_t cIncludes;136 uint32_t cIncludes; 99 137 /** Array of directories to search for include files. */ 100 c onst char**papszIncludes;138 char **papszIncludes; 101 139 102 140 /** The name of the input file. */ 103 const char *pszInput;141 const char *pszInput; 104 142 /** The name of the output file. NULL if stdout. */ 105 const char *pszOutput;143 const char *pszOutput; 106 144 /** @} */ 107 145 108 146 /** The define string space. */ 109 RTSTRSPACE StrSpace;147 RTSTRSPACE StrSpace; 110 148 /** Indicates whether a C-word might need expansion. 111 149 * The bitmap is indexed by C-word lead character. Bits that are set 112 150 * indicates that the lead character is used in a \#define that we know and 113 151 * should expand. */ 114 uint32_t bmDefined[256/32]; 152 VBCPP_BITMAP_TYPE bmDefined[VBCPP_BITMAP_SIZE]; 153 /** Indicates whether a C-word might need argument expansion. 154 * The bitmap is indexed by C-word lead character. Bits that are set 155 * indicates that the lead character is used in an argument of an currently 156 * expanding \#define. */ 157 VBCPP_BITMAP_TYPE bmArgs[VBCPP_BITMAP_SIZE]; 158 159 /** Expansion context stack. */ 160 PVBCPPCTX pStack; 161 /** The current stack depth. */ 162 uint32_t cStackDepth; 163 /** Whether the current line could be a preprocessor line. 164 * This is set when EOL is encountered and cleared again when a 165 * non-comment-or-space character is encountered. See vbcppPreprocess. */ 166 bool fMaybePreprocessorLine; 167 168 /** The current input stream. */ 169 PSCMSTREAM pCurStrmInput; 170 /** The input stream. */ 171 SCMSTREAM StrmInput; 172 /** The output stream. */ 173 SCMSTREAM StrmOutput; 174 175 /** The status of the whole job, as far as we know. */ 176 RTEXITCODE rcExit; 177 /** Whether StrmOutput is valid (for vbcppTerm). */ 178 bool fStrmOutputValid; 115 179 } VBCPP; 116 180 /** Pointer to the C preprocessor instance data. */ … … 134 198 pThis->pszOutput = NULL; 135 199 pThis->StrSpace = NULL; 136 RT_ZERO(pThis->bmDefined); 137 200 pThis->pStack = NULL; 201 pThis->cStackDepth = 0; 202 VBCPP_BITMAP_EMPTY(pThis->bmDefined); 203 VBCPP_BITMAP_EMPTY(pThis->bmArgs); 204 RT_ZERO(pThis->StrmInput); 205 RT_ZERO(pThis->StrmOutput); 206 pThis->rcExit = RTEXITCODE_SUCCESS; 207 pThis->fStrmOutputValid = false; 208 } 209 210 211 /** 212 * Displays an error message. 213 * 214 * @returns RTEXITCODE_FAILURE 215 * @param pThis The C preprocessor instance. 216 * @param pszMsg The message. 217 * @param ... Message arguments. 218 */ 219 static RTEXITCODE vbcppError(PVBCPP pThis, const char *pszMsg, ...) 220 { 221 NOREF(pThis); 222 va_list va; 223 va_start(va, pszMsg); 224 RTMsgErrorV(pszMsg, va); 225 va_end(va); 226 return pThis->rcExit = RTEXITCODE_FAILURE; 227 } 228 229 230 /** 231 * Displays an error message. 232 * 233 * @returns RTEXITCODE_FAILURE 234 * @param pThis The C preprocessor instance. 235 * @param pszPos Pointer to the offending character. 236 * @param pszMsg The message. 237 * @param ... Message arguments. 238 */ 239 static RTEXITCODE vbcppErrorPos(PVBCPP pThis, const char *pszPos, const char *pszMsg, ...) 240 { 241 NOREF(pszPos); NOREF(pThis); 242 va_list va; 243 va_start(va, pszMsg); 244 RTMsgErrorV(pszMsg, va); 245 va_end(va); 246 return pThis->rcExit = RTEXITCODE_FAILURE; 247 } 248 249 250 /** 251 * Checks if the given character is a valid C identifier lead character. 252 * 253 * @returns true / false. 254 * @param ch The character to inspect. 255 */ 256 DECLINLINE(bool) vbcppIsCIdentifierLeadChar(char ch) 257 { 258 return RT_C_IS_ALPHA(ch) 259 || ch == '_'; 260 } 261 262 263 /** 264 * Checks if the given character is a valid C identifier character. 265 * 266 * @returns true / false. 267 * @param ch The character to inspect. 268 */ 269 DECLINLINE(bool) vbcppIsCIdentifierChar(char ch) 270 { 271 return RT_C_IS_ALNUM(ch) 272 || ch == '_'; 273 } 274 275 276 277 /** 278 * 279 * @returns @c true if valid, @c false if not. Error message already displayed 280 * on failure. 281 * @param pThis The C preprocessor instance. 282 * @param pchIdentifier The start of the identifier to validate. 283 * @param cchIdentifier The length of the identifier. RTSTR_MAX if not 284 * known. 285 */ 286 static bool vbcppValidateCIdentifier(PVBCPP pThis, const char *pchIdentifier, size_t cchIdentifier) 287 { 288 if (cchIdentifier == RTSTR_MAX) 289 cchIdentifier = strlen(pchIdentifier); 290 291 if (cchIdentifier == 0) 292 { 293 vbcppErrorPos(pThis, pchIdentifier, "Zero length identifier"); 294 return false; 295 } 296 297 if (!vbcppIsCIdentifierLeadChar(*pchIdentifier)) 298 { 299 vbcppErrorPos(pThis, pchIdentifier, "Bad lead chararacter in identifier: '%.*s'", cchIdentifier, pchIdentifier); 300 return false; 301 } 302 303 for (size_t off = 1; off < cchIdentifier; off++) 304 { 305 if (!vbcppIsCIdentifierChar(pchIdentifier[off])) 306 { 307 vbcppErrorPos(pThis, pchIdentifier + off, "Illegal chararacter in identifier: '%.*s' (#%zu)", cchIdentifier, pchIdentifier, off + 1); 308 return false; 309 } 310 } 311 312 return true; 313 } 314 315 316 /** 317 * Frees a define. 318 * 319 * @returns VINF_SUCCESS (used when called by RTStrSpaceDestroy) 320 * @param pStr Pointer to the VBCPPDEF::Core member. 321 * @param pvUser Unused. 322 */ 323 static DECLCALLBACK(int) vbcppFreeDefine(PRTSTRSPACECORE pStr, void *pvUser) 324 { 325 RTMemFree(pStr); 326 NOREF(pvUser); 327 return VINF_SUCCESS; 138 328 } 139 329 … … 143 333 * 144 334 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 145 * @param pThis The C pr ocessor instance.335 * @param pThis The C preprocessor instance. 146 336 * @param pszDefine The define name, no argument list or anything. 147 337 * @param cchDefine The length of the name. RTSTR_MAX is ok. … … 153 343 { 154 344 RTStrSpaceRemove(&pThis->StrSpace, pHit->pszString); 155 RTMemFree(pHit);345 vbcppFreeDefine(pHit, NULL); 156 346 } 157 347 return RTEXITCODE_SUCCESS; 158 348 } 159 349 350 /** 351 * Inserts a define. 352 * 353 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 354 * @param pThis The C preprocessor instance. 355 * @param pDef The define to insert. 356 */ 357 static RTEXITCODE vbcppInsertDefine(PVBCPP pThis, PVBCPPDEF pDef) 358 { 359 if (RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core)) 360 VBCPP_BITMAP_SET(pThis->bmDefined, *pDef->Core.pszString); 361 else 362 { 363 RTMsgWarning("Redefining '%s'\n", pDef->Core.pszString); 364 PVBCPPDEF pOld = (PVBCPPDEF)vbcppRemoveDefine(pThis, pDef->Core.pszString, pDef->Core.cchString); 365 bool fRc = RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core); 366 Assert(fRc); Assert(pOld); 367 vbcppFreeDefine(&pOld->Core, NULL); 368 } 369 370 return RTEXITCODE_SUCCESS; 371 } 372 160 373 161 374 /** … … 163 376 * 164 377 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 165 * @param pThis The C processor instance. 378 * @param pThis The C preprocessor instance. 379 * @param pszDefine The define name, no parameter list. 380 * @param cchDefine The length of the name. 381 * @param pszParams The parameter list. 382 * @param cchParams The length of the parameter list. 383 * @param pszValue The value. 384 * @param cchDefine The length of the value. 385 */ 386 static RTEXITCODE vbcppAddDefineFn(PVBCPP pThis, const char *pszDefine, size_t cchDefine, 387 const char *pszParams, size_t cchParams, 388 const char *pszValue, size_t cchValue) 389 390 { 391 Assert(RTStrNLen(pszDefine, cchDefine) == cchDefine); 392 Assert(RTStrNLen(pszParams, cchParams) == cchParams); 393 Assert(RTStrNLen(pszValue, cchValue) == cchValue); 394 395 /* 396 * Determin the number of arguments and how much space their names 397 * requires. Performing syntax validation while parsing. 398 */ 399 uint32_t cchArgNames = 0; 400 uint32_t cArgs = 0; 401 for (size_t off = 0; off < cchParams; off++) 402 { 403 /* Skip blanks and maybe one comma. */ 404 bool fIgnoreComma = cArgs != 0; 405 while (off < cchParams) 406 { 407 if (!RT_C_IS_SPACE(pszParams[off])) 408 { 409 if (pszParams[off] != ',' || !fIgnoreComma) 410 { 411 if (vbcppIsCIdentifierLeadChar(pszParams[off])) 412 break; 413 /** @todo variadic macros. */ 414 return vbcppErrorPos(pThis, &pszParams[off], "Unexpected character"); 415 } 416 fIgnoreComma = false; 417 } 418 off++; 419 } 420 if (off >= cchParams) 421 break; 422 423 /* Found and argument. First character is already validated. */ 424 cArgs++; 425 cchArgNames += 2; 426 off++; 427 while ( off < cchParams 428 && vbcppIsCIdentifierChar(pszParams[off])) 429 off++, cchArgNames++; 430 } 431 432 /* 433 * Allocate a structure. 434 */ 435 size_t cbDef = RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1 + cchArgNames]) 436 + sizeof(const char *) * cArgs; 437 cbDef = RT_ALIGN_Z(cbDef, sizeof(const char *)); 438 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(cbDef); 439 if (!pDef) 440 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 441 442 char *pszDst = &pDef->szValue[cchValue + 1]; 443 pDef->Core.pszString = pszDst; 444 memcpy(pszDst, pszDefine, cchDefine); 445 pszDst += cchDefine; 446 *pszDst++ = '\0'; 447 pDef->fFunction = true; 448 pDef->fVarArg = false; 449 pDef->cArgs = cArgs; 450 pDef->papszArgs = (const char **)((uintptr_t)pDef + cbDef - sizeof(const char *) * cArgs); 451 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 452 memcpy(pDef->szValue, pszValue, cchValue); 453 pDef->szValue[cchValue] = '\0'; 454 455 /* 456 * Set up the arguments. 457 */ 458 uint32_t iArg = 0; 459 for (size_t off = 0; off < cchParams; off++) 460 { 461 /* Skip blanks and maybe one comma. */ 462 bool fIgnoreComma = cArgs != 0; 463 while (off < cchParams) 464 { 465 if (!RT_C_IS_SPACE(pszParams[off])) 466 { 467 if (pszParams[off] != ',' || !fIgnoreComma) 468 break; 469 fIgnoreComma = false; 470 } 471 off++; 472 } 473 if (off >= cchParams) 474 break; 475 476 /* Found and argument. First character is already validated. */ 477 pDef->papszArgs[iArg] = pszDst; 478 do 479 { 480 *pszDst++ = pszParams[off++]; 481 } while ( off < cchParams 482 && vbcppIsCIdentifierChar(pszParams[off])); 483 *pszDst++ = '\0'; 484 iArg++; 485 } 486 Assert((uintptr_t)pszDst <= (uintptr_t)pDef->papszArgs); 487 488 return vbcppInsertDefine(pThis, pDef); 489 } 490 491 492 /** 493 * Adds a define. 494 * 495 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 496 * @param pThis The C preprocessor instance. 166 497 * @param pszDefine The define name and optionally the argument 167 498 * list. … … 173 504 const char *pszValue, size_t cchValue) 174 505 { 506 /* 507 * We need the lengths. Trim the input. 508 */ 175 509 if (cchDefine == RTSTR_MAX) 176 510 cchDefine = strlen(pszDefine); 511 while (cchDefine > 0 && RT_C_IS_SPACE(*pszDefine)) 512 pszDefine++, cchDefine--; 513 while (cchDefine > 0 && RT_C_IS_SPACE(pszDefine[cchDefine - 1])) 514 cchDefine--; 515 if (!cchDefine) 516 return vbcppErrorPos(pThis, pszDefine, "The define has no name"); 517 177 518 if (cchValue == RTSTR_MAX) 178 519 cchValue = strlen(pszValue); 179 180 const char *pszParan = (const char *)memchr(pszDefine, '(', cchDefine); 181 if (pszParan) 182 return RTMsgErrorExit(RTEXITCODE_FAILURE, "function defines are not implemented. sorry"); 183 184 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(sizeof(*pDef) + cchValue + cchDefine + 2); 520 while (cchValue > 0 && RT_C_IS_SPACE(*pszValue)) 521 pszValue++, cchValue--; 522 while (cchValue > 0 && RT_C_IS_SPACE(pszValue[cchValue - 1])) 523 cchValue--; 524 525 /* 526 * Arguments make the job a bit more annoying. Handle that elsewhere 527 */ 528 const char *pszParams = (const char *)memchr(pszDefine, '(', cchDefine); 529 if (pszParams) 530 { 531 size_t cchParams = pszDefine + cchDefine - pszParams; 532 cchDefine -= cchParams; 533 if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 534 return RTEXITCODE_FAILURE; 535 if (pszParams[cchParams - 1] != ')') 536 return vbcppErrorPos(pThis, pszParams + cchParams - 1, "Missing closing parenthesis"); 537 pszParams++; 538 cchParams -= 2; 539 return vbcppAddDefineFn(pThis, pszDefine, cchDefine, pszParams, cchParams, pszValue, cchValue); 540 } 541 542 /* 543 * Simple define, no arguments. 544 */ 545 if (vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 546 return RTEXITCODE_FAILURE; 547 548 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1])); 185 549 if (!pDef) 186 550 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 187 551 552 pDef->Core.pszString = &pDef->szValue[cchValue + 1]; 553 memcpy((char *)pDef->Core.pszString, pszDefine, cchDefine); 554 ((char *)pDef->Core.pszString)[cchDefine] = '\0'; 188 555 pDef->fFunction = false; 189 556 pDef->fVarArg = false; 190 557 pDef->cArgs = 0; 558 pDef->papszArgs = NULL; 559 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 191 560 memcpy(pDef->szValue, pszValue, cchValue); 192 561 pDef->szValue[cchValue] = '\0'; 193 pDef->Core.pszString = &pDef->szValue[cchValue + 1]; 194 memcpy(&pDef->szValue[cchValue + 1], pszDefine, cchDefine); 195 pDef->szValue[cchValue + 1 + cchDefine] = '\0'; 196 197 if (!RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core)) 198 { 199 RTMsgWarning("Redefining '%s'\n", pDef->Core.pszString); 200 vbcppRemoveDefine(pThis, pDef->Core.pszString, cchDefine); 201 RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core); 202 } 203 return RTEXITCODE_SUCCESS; 204 } 205 562 563 return vbcppInsertDefine(pThis, pDef); 564 } 565 566 567 /** 568 * Adds an include directory. 569 * 570 * @returns Program exit code, with error message on failure. 571 * @param pThis The C preprocessor instance. 572 * @param pszDir The directory to add. 573 */ 206 574 static RTEXITCODE vbcppAddInclude(PVBCPP pThis, const char *pszDir) 207 575 { 576 uint32_t cIncludes = pThis->cIncludes; 577 if (cIncludes >= _64K) 578 return vbcppError(pThis, "Too many include directories"); 579 580 void *pv = RTMemRealloc(pThis->papszIncludes, (cIncludes + 1) * sizeof(char **)); 581 if (!pv) 582 return vbcppError(pThis, "No memory for include directories"); 583 pThis->papszIncludes = (char **)pv; 584 585 int rc = RTStrDupEx(&pThis->papszIncludes[cIncludes], pszDir); 586 if (RT_FAILURE(rc)) 587 return vbcppError(pThis, "No string memory for include directories"); 588 589 pThis->cIncludes = cIncludes + 1; 208 590 return RTEXITCODE_SUCCESS; 209 591 } … … 233 615 { "--include-dir", 'I', RTGETOPT_REQ_STRING }, 234 616 { "--undefine", 'U', RTGETOPT_REQ_STRING }, 617 { "--keep-comments", 'C', RTGETOPT_REQ_NOTHING }, 618 { "--strip-comments", 'c', RTGETOPT_REQ_NOTHING }, 235 619 { "--D-strip", 'd', RTGETOPT_REQ_NOTHING }, 236 620 }; … … 248 632 switch (rc) 249 633 { 634 case 'c': 635 pThis->fKeepComments = false; 636 break; 637 638 case 'C': 639 pThis->fKeepComments = false; 640 break; 641 250 642 case 'd': 251 643 pThis->enmMode = kVBCppMode_SelectiveD; 644 pThis->fKeepComments = true; 252 645 break; 253 646 … … 311 704 312 705 706 /** 707 * Opens the input and output streams. 708 * 709 * @returns Exit code. 710 * @param pThis The C preprocessor instance. 711 */ 712 static RTEXITCODE vbcppOpenStreams(PVBCPP pThis) 713 { 714 if (!pThis->pszInput) 715 return vbcppError(pThis, "Preprocessing the standard input stream is currently not supported"); 716 717 int rc = ScmStreamInitForReading(&pThis->StrmInput, pThis->pszInput); 718 if (RT_FAILURE(rc)) 719 return vbcppError(pThis, "ScmStreamInitForReading returned %Rrc when opening input file (%s)", 720 rc, pThis->pszInput); 721 722 rc = ScmStreamInitForWriting(&pThis->StrmOutput, &pThis->StrmInput); 723 if (RT_FAILURE(rc)) 724 return vbcppError(pThis, "ScmStreamInitForWriting returned %Rrc", rc); 725 726 pThis->fStrmOutputValid = true; 727 return RTEXITCODE_SUCCESS; 728 } 729 730 731 /** 732 * Outputs a character. 733 * 734 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 735 * @param pThis The C preprocessor instance. 736 * @param ch The character to output. 737 */ 738 static RTEXITCODE vbcppOutputCh(PVBCPP pThis, char ch) 739 { 740 int rc = ScmStreamPutCh(&pThis->StrmOutput, ch); 741 if (RT_SUCCESS(rc)) 742 return RTEXITCODE_SUCCESS; 743 return vbcppError(pThis, "Output error %Rrc"); 744 } 745 746 747 /** 748 * Outputs a string. 749 * 750 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 751 * @param pThis The C preprocessor instance. 752 * @param pch The string. 753 * @param cch The number of characters to write. 754 */ 755 static RTEXITCODE vbcppOutputWrite(PVBCPP pThis, const char *pch, size_t cch) 756 { 757 int rc = ScmStreamWrite(&pThis->StrmOutput, pch, cch); 758 if (RT_SUCCESS(rc)) 759 return RTEXITCODE_SUCCESS; 760 return vbcppError(pThis, "Output error %Rrc"); 761 } 762 763 764 /** 765 * Processes a multi-line comment. 766 * 767 * Must either string the comment or keep it. If the latter, we must refrain 768 * from replacing C-words in it. 769 * 770 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 771 * @param pThis The C preprocessor instance. 772 * @param pStrmInput The input stream. 773 */ 774 static RTEXITCODE vbcppProcessMultiLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 775 { 776 /* The open comment sequence. */ 777 ScmStreamGetCh(pStrmInput); /* '*' */ 778 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 779 if (pThis->fKeepComments) 780 rcExit = vbcppOutputWrite(pThis, "/*", 2); 781 782 /* The comment.*/ 783 unsigned ch; 784 while ( rcExit == RTEXITCODE_SUCCESS 785 && (ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0 ) 786 { 787 if (ch == '*') 788 { 789 /* Closing sequence? */ 790 unsigned ch2 = ScmStreamPeekCh(pStrmInput); 791 if (ch2 == '/') 792 { 793 ScmStreamGetCh(pStrmInput); 794 if (pThis->fKeepComments) 795 rcExit = vbcppOutputWrite(pThis, "*/", 2); 796 break; 797 } 798 } 799 800 if (pThis->fKeepComments || ch == '\r' || ch == '\n') 801 { 802 rcExit = vbcppOutputCh(pThis, ch); 803 if (rcExit != RTEXITCODE_SUCCESS) 804 break; 805 806 /* Reset the maybe-preprocessor-line indicator when necessary. */ 807 if (ch == '\r' || ch == '\n') 808 pThis->fMaybePreprocessorLine = true; 809 } 810 } 811 return rcExit; 812 } 813 814 815 /** 816 * Processes a single line comment. 817 * 818 * Must either string the comment or keep it. If the latter, we must refrain 819 * from replacing C-words in it. 820 * 821 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 822 * @param pThis The C preprocessor instance. 823 * @param pStrmInput The input stream. 824 */ 825 static RTEXITCODE vbcppProcessOneLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 826 { 827 RTEXITCODE rcExit; 828 SCMEOL enmEol; 829 size_t cchLine; 830 const char *pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); Assert(pszLine); 831 pszLine--; cchLine++; /* unfetching the first slash. */ 832 for (;;) 833 { 834 if (pThis->fKeepComments) 835 rcExit = vbcppOutputWrite(pThis, pszLine, cchLine + enmEol); 836 else 837 rcExit = vbcppOutputWrite(pThis, pszLine + cchLine, enmEol); 838 if (rcExit != RTEXITCODE_SUCCESS) 839 break; 840 if ( cchLine == 0 841 || pszLine[cchLine - 1] != '\\') 842 break; 843 844 pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); 845 if (!pszLine) 846 break; 847 } 848 pThis->fMaybePreprocessorLine = true; 849 return rcExit; 850 } 851 852 853 /** 854 * Processes a double quoted string. 855 * 856 * Must not replace any C-words in strings. 857 * 858 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 859 * @param pThis The C preprocessor instance. 860 * @param pStrmInput The input stream. 861 */ 862 static RTEXITCODE vbcppProcessDoubleQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 863 { 864 RTEXITCODE rcExit = vbcppOutputCh(pThis, '"'); 865 if (rcExit == RTEXITCODE_SUCCESS) 866 { 867 bool fEscaped = false; 868 for (;;) 869 { 870 unsigned ch = ScmStreamGetCh(pStrmInput); 871 if (ch == ~(unsigned)0) 872 { 873 rcExit = vbcppError(pThis, "Unterminated double quoted string"); 874 break; 875 } 876 877 rcExit = vbcppOutputCh(pThis, ch); 878 if (rcExit != RTEXITCODE_SUCCESS) 879 break; 880 881 if (ch == '"' && !fEscaped) 882 break; 883 fEscaped = !fEscaped && ch == '\\'; 884 } 885 } 886 return rcExit; 887 } 888 889 890 /** 891 * Processes a single quoted litteral. 892 * 893 * Must not replace any C-words in strings. 894 * 895 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 896 * @param pThis The C preprocessor instance. 897 * @param pStrmInput The input stream. 898 */ 899 static RTEXITCODE vbcppProcessSingledQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 900 { 901 RTEXITCODE rcExit = vbcppOutputCh(pThis, '\''); 902 if (rcExit == RTEXITCODE_SUCCESS) 903 { 904 bool fEscaped = false; 905 for (;;) 906 { 907 unsigned ch = ScmStreamGetCh(pStrmInput); 908 if (ch == ~(unsigned)0) 909 { 910 rcExit = vbcppError(pThis, "Unterminated singled quoted string"); 911 break; 912 } 913 914 rcExit = vbcppOutputCh(pThis, ch); 915 if (rcExit != RTEXITCODE_SUCCESS) 916 break; 917 918 if (ch == '\'' && !fEscaped) 919 break; 920 fEscaped = !fEscaped && ch == '\\'; 921 } 922 } 923 return rcExit; 924 } 925 926 927 /** 928 * Processes a preprocessor directive. 929 * 930 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 931 * @param pThis The C preprocessor instance. 932 * @param pStrmInput The input stream. 933 */ 934 static RTEXITCODE vbcppProcessDirective(PVBCPP pThis, PSCMSTREAM pStrmInput) 935 { 936 #if 0 937 size_t const offStart = ScmStreamTell(pStrmInput); 938 939 /* 940 * Skip spaces. 941 */ 942 unsigned chPrev = ~(unsigned)0; 943 unsigned ch; 944 while ((ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0) 945 { 946 if (!RT_C_IS_SPACE(ch)) 947 { 948 if () 949 { 950 } 951 } 952 ch = chPrev; 953 } 954 #endif 955 return vbcppError(pThis, "Not implemented"); 956 } 957 958 959 /** 960 * Processes a C word, possibly replacing it with a definition. 961 * 962 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 963 * @param pThis The C preprocessor instance. 964 * @param pStrmInput The input stream. 965 * @param ch The first character. 966 */ 967 static RTEXITCODE vbcppProcessCWord(PVBCPP pThis, PSCMSTREAM pStrmInput, char ch) 968 { 969 /** @todo Implement this... */ 970 return vbcppOutputCh(pThis, ch); 971 } 972 973 974 /** 975 * Does the actually preprocessing of the input file. 976 * 977 * @returns Exit code. 978 * @param pThis The C preprocessor instance. 979 * @param pStrmInput The input stream. 980 */ 981 static RTEXITCODE vbcppPreprocess(PVBCPP pThis, PSCMSTREAM pStrmInput) 982 { 983 /* 984 * Push. 985 */ 986 PSCMSTREAM pStrmInputOld = pThis->pCurStrmInput; 987 pThis->pCurStrmInput = pStrmInput; 988 pThis->fMaybePreprocessorLine = true; 989 990 /* 991 * Parse. 992 */ 993 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 994 unsigned ch; 995 while ((ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0) 996 { 997 if (ch == '/') 998 { 999 ch = ScmStreamPeekCh(pStrmInput); 1000 if (ch == '*') 1001 rcExit = vbcppProcessMultiLineComment(pThis, pStrmInput); 1002 else if (ch == '/') 1003 rcExit = vbcppProcessOneLineComment(pThis, pStrmInput); 1004 else 1005 { 1006 pThis->fMaybePreprocessorLine = false; 1007 rcExit = vbcppOutputCh(pThis, '/'); 1008 } 1009 } 1010 else if (ch == '#' && pThis->fMaybePreprocessorLine) 1011 rcExit = vbcppProcessDirective(pThis, pStrmInput); 1012 else if (ch == '\r' || ch == '\n') 1013 { 1014 pThis->fMaybePreprocessorLine = true; 1015 rcExit = vbcppOutputCh(pThis, ch); 1016 } 1017 else if (RT_C_IS_SPACE(ch)) 1018 rcExit = vbcppOutputCh(pThis, ch); 1019 else 1020 { 1021 pThis->fMaybePreprocessorLine = false; 1022 if (ch == '"') 1023 rcExit = vbcppProcessDoubleQuotedString(pThis, pStrmInput); 1024 else if (ch == '\'') 1025 rcExit = vbcppProcessSingledQuotedString(pThis, pStrmInput); 1026 else if (vbcppIsCIdentifierLeadChar(ch)) 1027 rcExit = vbcppProcessCWord(pThis, pStrmInput, ch); 1028 else 1029 rcExit = vbcppOutputCh(pThis, ch); 1030 } 1031 if (rcExit != RTEXITCODE_SUCCESS) 1032 break; 1033 } 1034 1035 /* 1036 * Pop. 1037 */ 1038 pThis->pCurStrmInput = pStrmInputOld; 1039 pThis->fMaybePreprocessorLine = true; 1040 return rcExit; 1041 } 1042 1043 1044 /** 1045 * Terminates the preprocessor. 1046 * 1047 * This may return failure if an error was delayed. 1048 * 1049 * @returns Exit code. 1050 * @param pThis The C preprocessor instance. 1051 */ 1052 static RTEXITCODE vbcppTerm(PVBCPP pThis) 1053 { 1054 /* 1055 * Flush the output first. 1056 */ 1057 if (pThis->fStrmOutputValid) 1058 { 1059 if (pThis->pszOutput) 1060 { 1061 int rc = ScmStreamWriteToFile(&pThis->StrmOutput, "%s", pThis->pszOutput); 1062 if (RT_FAILURE(rc)) 1063 vbcppError(pThis, "ScmStreamWriteToFile failed with %Rrc when writing '%s'", rc, pThis->pszOutput); 1064 } 1065 else 1066 { 1067 int rc = ScmStreamWriteToStdOut(&pThis->StrmOutput); 1068 if (RT_FAILURE(rc)) 1069 vbcppError(pThis, "ScmStreamWriteToStdOut failed with %Rrc", rc); 1070 } 1071 } 1072 1073 /* 1074 * Cleanup. 1075 */ 1076 ScmStreamDelete(&pThis->StrmInput); 1077 ScmStreamDelete(&pThis->StrmOutput); 1078 1079 RTStrSpaceDestroy(&pThis->StrSpace, vbcppFreeDefine, NULL); 1080 pThis->StrSpace = NULL; 1081 1082 uint32_t i = pThis->cIncludes; 1083 while (i-- > 0) 1084 RTStrFree(pThis->papszIncludes[i]); 1085 RTMemFree(pThis->papszIncludes); 1086 pThis->papszIncludes = NULL; 1087 1088 return pThis->rcExit; 1089 } 1090 313 1091 314 1092 … … 319 1097 return RTMsgInitFailure(rc); 320 1098 321 /* 322 * Parse options.1099 /* 1100 * Do the job. The code says it all. 323 1101 */ 324 1102 VBCPP This; … … 328 1106 if (!fExit && rcExit == RTEXITCODE_SUCCESS) 329 1107 { 330 /* 331 * Process the input file. 332 */ 333 334 } 335 1108 rcExit = vbcppOpenStreams(&This); 1109 if (rcExit == RTEXITCODE_SUCCESS) 1110 rcExit = vbcppPreprocess(&This, &This.StrmInput); 1111 } 1112 1113 if (rcExit == RTEXITCODE_SUCCESS) 1114 rcExit = vbcppTerm(&This); 1115 else 1116 vbcppTerm(&This); 336 1117 return rcExit; 337 1118 } -
trunk/src/bldprogs/scmstream.cpp
r40558 r41179 21 21 #include <iprt/assert.h> 22 22 #include <iprt/ctype.h> 23 #include <iprt/err.h> 23 24 #include <iprt/file.h> 24 #include <iprt/ err.h>25 #include <iprt/handle.h> 25 26 #include <iprt/mem.h> 27 #include <iprt/pipe.h> 26 28 #include <iprt/string.h> 27 29 … … 328 330 329 331 /** 332 * Writes the stream to standard output. 333 * 334 * @returns IPRT status code 335 * @param pStream The stream. 336 */ 337 int ScmStreamWriteToStdOut(PSCMSTREAM pStream) 338 { 339 int rc; 340 341 #ifdef RT_STRICT 342 /* 343 * Check that what we're going to write makes sense first. 344 */ 345 rc = ScmStreamCheckItegrity(pStream); 346 if (RT_FAILURE(rc)) 347 return rc; 348 #endif 349 350 /* 351 * Do the actual writing. 352 */ 353 RTHANDLE h; 354 rc = RTHandleGetStandard(RTHANDLESTD_OUTPUT, &h); 355 if (RT_SUCCESS(rc)) 356 { 357 switch (h.enmType) 358 { 359 case RTHANDLETYPE_FILE: 360 rc = RTFileWrite(h.u.hFile, pStream->pch, pStream->cb, NULL); 361 break; 362 case RTHANDLETYPE_PIPE: 363 rc = RTPipeWriteBlocking(h.u.hPipe, pStream->pch, pStream->cb, NULL); 364 break; 365 default: 366 rc = VERR_INVALID_HANDLE; 367 break; 368 } 369 } 370 return rc; 371 } 372 373 /** 330 374 * Worker for ScmStreamGetLine that builds the line number index while parsing 331 375 * the stream. … … 642 686 const char *ScmStreamGetLine(PSCMSTREAM pStream, size_t *pcchLine, PSCMEOL penmEol) 643 687 { 644 /** @todo this doesn't work when pStream->off !=645 * pStream->paLines[pStream->iLine-1].off. */646 688 if (!pStream->fFullyLineated) 647 689 return scmStreamGetLineInternal(pStream, pcchLine, penmEol); 648 return ScmStreamGetLineByNo(pStream, pStream->iLine, pcchLine, penmEol); 690 691 size_t offCur = pStream->off; 692 size_t iCurLine = pStream->iLine; 693 const char *pszLine = ScmStreamGetLineByNo(pStream, iCurLine, pcchLine, penmEol); 694 if ( pszLine 695 && pStream->paLines[iCurLine].off < offCur) 696 { 697 offCur -= pStream->paLines[iCurLine].off; 698 Assert(offCur <= pStream->paLines[iCurLine].off); 699 *pcchLine -= offCur; 700 pszLine += offCur; 701 } 702 return pszLine; 649 703 } 650 704 -
trunk/src/bldprogs/scmstream.h
r40554 r41179 98 98 int ScmStreamCheckItegrity(PSCMSTREAM pStream); 99 99 int ScmStreamWriteToFile(PSCMSTREAM pStream, const char *pszFilenameFmt, ...); 100 int ScmStreamWriteToStdOut(PSCMSTREAM pStream); 100 101 size_t ScmStreamTell(PSCMSTREAM pStream); 101 102 size_t ScmStreamTellLine(PSCMSTREAM pStream);
Note:
See TracChangeset
for help on using the changeset viewer.