- Timestamp:
- May 8, 2012 12:14:06 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bldprogs/VBoxCPP.cpp
r41202 r41204 309 309 310 310 311 /******************************************************************************* 312 * Global Variables * 313 *******************************************************************************/ 314 315 316 /** 317 * Changes the preprocessing mode. 318 * 319 * @param pThis The C preprocessor instance. 320 * @param enmMode The new mode. 321 */ 322 static void vbcppSetMode(PVBCPP pThis, VBCPPMODE enmMode) 323 { 324 switch (enmMode) 325 { 326 case kVBCppMode_Standard: 327 pThis->fKeepComments = false; 328 pThis->fRespectSourceDefines = true; 329 pThis->fAllowRedefiningCmdLineDefines = true; 330 pThis->fPassThruDefines = false; 331 pThis->fUndecidedConditionals = false; 332 pThis->fLineSplicing = true; 333 pThis->enmIncludeAction = kVBCppIncludeAction_Include; 334 break; 335 336 case kVBCppMode_Selective: 337 pThis->fKeepComments = true; 338 pThis->fRespectSourceDefines = false; 339 pThis->fAllowRedefiningCmdLineDefines = false; 340 pThis->fPassThruDefines = true; 341 pThis->fUndecidedConditionals = true; 342 pThis->fLineSplicing = false; 343 pThis->enmIncludeAction = kVBCppIncludeAction_PassThru; 344 break; 345 346 case kVBCppMode_SelectiveD: 347 pThis->fKeepComments = true; 348 pThis->fRespectSourceDefines = true; 349 pThis->fAllowRedefiningCmdLineDefines = false; 350 pThis->fPassThruDefines = false; 351 pThis->fUndecidedConditionals = false; 352 pThis->fLineSplicing = false; 353 pThis->enmIncludeAction = kVBCppIncludeAction_Drop; 354 break; 355 356 default: 357 AssertFailedReturnVoid(); 358 } 359 pThis->enmMode = enmMode; 360 } 361 362 363 /** 364 * Initializes the C preprocessor instance data. 365 * 366 * @param pThis The C preprocessor instance data. 367 */ 368 static void vbcppInit(PVBCPP pThis) 369 { 370 vbcppSetMode(pThis, kVBCppMode_Selective); 371 pThis->cIncludes = 0; 372 pThis->papszIncludes = NULL; 373 pThis->pszInput = NULL; 374 pThis->pszOutput = NULL; 375 pThis->StrSpace = NULL; 376 pThis->UndefStrSpace = NULL; 377 pThis->pExpStack = NULL; 378 pThis->cExpStackDepth = 0; 379 pThis->cCondStackDepth = 0; 380 pThis->pCondStack = NULL; 381 pThis->fIf0Mode = false; 382 pThis->fMaybePreprocessorLine = true; 383 VBCPP_BITMAP_EMPTY(pThis->bmDefined); 384 VBCPP_BITMAP_EMPTY(pThis->bmArgs); 385 pThis->cCondStackDepth = 0; 386 pThis->pInputStack = NULL; 387 RT_ZERO(pThis->StrmOutput); 388 pThis->rcExit = RTEXITCODE_SUCCESS; 389 pThis->fStrmOutputValid = false; 390 } 311 312 313 314 /* 315 * 316 * 317 * Message Handling. 318 * Message Handling. 319 * Message Handling. 320 * Message Handling. 321 * Message Handling. 322 * 323 * 324 */ 391 325 392 326 … … 457 391 458 392 393 394 395 396 /* 397 * 398 * 399 * C Identifier/Word Parsing. 400 * C Identifier/Word Parsing. 401 * C Identifier/Word Parsing. 402 * C Identifier/Word Parsing. 403 * C Identifier/Word Parsing. 404 * 405 * 406 */ 407 408 459 409 /** 460 410 * Checks if the given character is a valid C identifier lead character. … … 523 473 524 474 525 /** 526 * Frees a define. 527 * 528 * @returns VINF_SUCCESS (used when called by RTStrSpaceDestroy) 529 * @param pStr Pointer to the VBCPPDEF::Core member. 530 * @param pvUser Unused. 531 */ 532 static DECLCALLBACK(int) vbcppFreeDefine(PRTSTRSPACECORE pStr, void *pvUser) 533 { 534 RTMemFree(pStr); 535 NOREF(pvUser); 536 return VINF_SUCCESS; 537 } 538 539 540 /** 541 * Removes a define. 542 * 543 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 544 * @param pThis The C preprocessor instance. 545 * @param pszDefine The define name, no argument list or anything. 546 * @param cchDefine The length of the name. RTSTR_MAX is ok. 547 * @param fExplicitUndef Explicit undefinition, that is, in a selective 548 * preprocessing run it will evaluate to undefined. 549 */ 550 static RTEXITCODE vbcppDefineUndef(PVBCPP pThis, const char *pszDefine, size_t cchDefine, bool fExplicitUndef) 551 { 552 PRTSTRSPACECORE pHit = RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine); 553 if (pHit) 554 { 555 RTStrSpaceRemove(&pThis->StrSpace, pHit->pszString); 556 vbcppFreeDefine(pHit, NULL); 557 } 558 559 if (fExplicitUndef) 560 { 561 if (cchDefine == RTSTR_MAX) 562 cchDefine = strlen(pszDefine); 563 564 PRTSTRSPACECORE pStr = (PRTSTRSPACECORE)RTMemAlloc(sizeof(*pStr) + cchDefine + 1); 565 if (!pStr) 566 return vbcppError(pThis, "out of memory"); 567 char *pszDst = (char *)(pStr + 1); 568 pStr->pszString = pszDst; 569 memcpy(pszDst, pszDefine, cchDefine); 570 pszDst[cchDefine] = '\0'; 571 if (!RTStrSpaceInsert(&pThis->UndefStrSpace, pStr)) 572 RTMemFree(pStr); 573 } 574 575 return RTEXITCODE_SUCCESS; 576 } 577 578 579 /** 580 * Inserts a define (rejecting and freeing it in some case). 581 * 582 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 583 * @param pThis The C preprocessor instance. 584 * @param pDef The define to insert. 585 */ 586 static RTEXITCODE vbcppDefineInsert(PVBCPP pThis, PVBCPPDEF pDef) 587 { 588 /* 589 * Ignore in source-file defines when doing selective preprocessing. 590 */ 591 if ( !pThis->fRespectSourceDefines 592 && !pDef->fCmdLine) 593 { 594 /* Ignore*/ 595 vbcppFreeDefine(&pDef->Core, NULL); 596 return RTEXITCODE_SUCCESS; 597 } 598 599 /* 600 * Insert it and update the lead character hint bitmap. 601 */ 602 if (RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core)) 603 VBCPP_BITMAP_SET(pThis->bmDefined, *pDef->Core.pszString); 604 else 605 { 606 /* 607 * Duplicate. When doing selective D preprocessing, let the command 608 * line take precendece. 609 */ 610 PVBCPPDEF pOld = (PVBCPPDEF)RTStrSpaceGet(&pThis->StrSpace, pDef->Core.pszString); Assert(pOld); 611 if ( pThis->fAllowRedefiningCmdLineDefines 612 || pDef->fCmdLine == pOld->fCmdLine) 613 { 614 if (pDef->fCmdLine) 615 RTMsgWarning("Redefining '%s'\n", pDef->Core.pszString); 616 617 RTStrSpaceRemove(&pThis->StrSpace, pOld->Core.pszString); 618 vbcppFreeDefine(&pOld->Core, NULL); 619 620 bool fRc = RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core); 621 Assert(fRc); 622 } 623 else 624 { 625 RTMsgWarning("Ignoring redefinition of '%s'\n", pDef->Core.pszString); 626 vbcppFreeDefine(&pDef->Core, NULL); 627 } 628 } 629 630 return RTEXITCODE_SUCCESS; 631 } 632 633 634 /** 635 * Adds a define. 636 * 637 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 638 * @param pThis The C preprocessor instance. 639 * @param pszDefine The define name, no parameter list. 640 * @param cchDefine The length of the name. 641 * @param pszParams The parameter list. 642 * @param cchParams The length of the parameter list. 643 * @param pszValue The value. 644 * @param cchDefine The length of the value. 645 * @param fCmdLine Set if originating on the command line. 646 */ 647 static RTEXITCODE vbcppDefineAddFn(PVBCPP pThis, const char *pszDefine, size_t cchDefine, 648 const char *pszParams, size_t cchParams, 649 const char *pszValue, size_t cchValue, 650 bool fCmdLine) 651 652 { 653 Assert(RTStrNLen(pszDefine, cchDefine) == cchDefine); 654 Assert(RTStrNLen(pszParams, cchParams) == cchParams); 655 Assert(RTStrNLen(pszValue, cchValue) == cchValue); 656 657 /* 658 * Determin the number of arguments and how much space their names 659 * requires. Performing syntax validation while parsing. 660 */ 661 uint32_t cchArgNames = 0; 662 uint32_t cArgs = 0; 663 for (size_t off = 0; off < cchParams; off++) 664 { 665 /* Skip blanks and maybe one comma. */ 666 bool fIgnoreComma = cArgs != 0; 667 while (off < cchParams) 668 { 669 if (!RT_C_IS_SPACE(pszParams[off])) 670 { 671 if (pszParams[off] != ',' || !fIgnoreComma) 672 { 673 if (vbcppIsCIdentifierLeadChar(pszParams[off])) 674 break; 675 /** @todo variadic macros. */ 676 return vbcppErrorPos(pThis, &pszParams[off], "Unexpected character"); 677 } 678 fIgnoreComma = false; 679 } 680 off++; 681 } 682 if (off >= cchParams) 683 break; 684 685 /* Found and argument. First character is already validated. */ 686 cArgs++; 687 cchArgNames += 2; 688 off++; 689 while ( off < cchParams 690 && vbcppIsCIdentifierChar(pszParams[off])) 691 off++, cchArgNames++; 692 } 693 694 /* 695 * Allocate a structure. 696 */ 697 size_t cbDef = RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1 + cchArgNames]) 698 + sizeof(const char *) * cArgs; 699 cbDef = RT_ALIGN_Z(cbDef, sizeof(const char *)); 700 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(cbDef); 701 if (!pDef) 702 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 703 704 char *pszDst = &pDef->szValue[cchValue + 1]; 705 pDef->Core.pszString = pszDst; 706 memcpy(pszDst, pszDefine, cchDefine); 707 pszDst += cchDefine; 708 *pszDst++ = '\0'; 709 pDef->fFunction = true; 710 pDef->fVarArg = false; 711 pDef->fCmdLine = fCmdLine; 712 pDef->cArgs = cArgs; 713 pDef->papszArgs = (const char **)((uintptr_t)pDef + cbDef - sizeof(const char *) * cArgs); 714 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 715 memcpy(pDef->szValue, pszValue, cchValue); 716 pDef->szValue[cchValue] = '\0'; 717 718 /* 719 * Set up the arguments. 720 */ 721 uint32_t iArg = 0; 722 for (size_t off = 0; off < cchParams; off++) 723 { 724 /* Skip blanks and maybe one comma. */ 725 bool fIgnoreComma = cArgs != 0; 726 while (off < cchParams) 727 { 728 if (!RT_C_IS_SPACE(pszParams[off])) 729 { 730 if (pszParams[off] != ',' || !fIgnoreComma) 731 break; 732 fIgnoreComma = false; 733 } 734 off++; 735 } 736 if (off >= cchParams) 737 break; 738 739 /* Found and argument. First character is already validated. */ 740 pDef->papszArgs[iArg] = pszDst; 741 do 742 { 743 *pszDst++ = pszParams[off++]; 744 } while ( off < cchParams 745 && vbcppIsCIdentifierChar(pszParams[off])); 746 *pszDst++ = '\0'; 747 iArg++; 748 } 749 Assert((uintptr_t)pszDst <= (uintptr_t)pDef->papszArgs); 750 751 return vbcppDefineInsert(pThis, pDef); 752 } 753 754 755 /** 756 * Adds a define. 757 * 758 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 759 * @param pThis The C preprocessor instance. 760 * @param pszDefine The define name and optionally the argument 761 * list. 762 * @param cchDefine The length of the name. RTSTR_MAX is ok. 763 * @param pszValue The value. 764 * @param cchDefine The length of the value. RTSTR_MAX is ok. 765 * @param fCmdLine Set if originating on the command line. 766 */ 767 static RTEXITCODE vbcppDefineAdd(PVBCPP pThis, const char *pszDefine, size_t cchDefine, 768 const char *pszValue, size_t cchValue, bool fCmdLine) 769 { 770 /* 771 * We need the lengths. Trim the input. 772 */ 773 if (cchDefine == RTSTR_MAX) 774 cchDefine = strlen(pszDefine); 775 while (cchDefine > 0 && RT_C_IS_SPACE(*pszDefine)) 776 pszDefine++, cchDefine--; 777 while (cchDefine > 0 && RT_C_IS_SPACE(pszDefine[cchDefine - 1])) 778 cchDefine--; 779 if (!cchDefine) 780 return vbcppErrorPos(pThis, pszDefine, "The define has no name"); 781 782 if (cchValue == RTSTR_MAX) 783 cchValue = strlen(pszValue); 784 while (cchValue > 0 && RT_C_IS_SPACE(*pszValue)) 785 pszValue++, cchValue--; 786 while (cchValue > 0 && RT_C_IS_SPACE(pszValue[cchValue - 1])) 787 cchValue--; 788 789 /* 790 * Arguments make the job a bit more annoying. Handle that elsewhere 791 */ 792 const char *pszParams = (const char *)memchr(pszDefine, '(', cchDefine); 793 if (pszParams) 794 { 795 size_t cchParams = pszDefine + cchDefine - pszParams; 796 cchDefine -= cchParams; 797 if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 798 return RTEXITCODE_FAILURE; 799 if (pszParams[cchParams - 1] != ')') 800 return vbcppErrorPos(pThis, pszParams + cchParams - 1, "Missing closing parenthesis"); 801 pszParams++; 802 cchParams -= 2; 803 return vbcppDefineAddFn(pThis, pszDefine, cchDefine, pszParams, cchParams, pszValue, cchValue, fCmdLine); 804 } 805 806 /* 807 * Simple define, no arguments. 808 */ 809 if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 810 return RTEXITCODE_FAILURE; 811 812 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1])); 813 if (!pDef) 814 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 815 816 pDef->Core.pszString = &pDef->szValue[cchValue + 1]; 817 memcpy((char *)pDef->Core.pszString, pszDefine, cchDefine); 818 ((char *)pDef->Core.pszString)[cchDefine] = '\0'; 819 pDef->fFunction = false; 820 pDef->fVarArg = false; 821 pDef->fCmdLine = fCmdLine; 822 pDef->cArgs = 0; 823 pDef->papszArgs = NULL; 824 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 825 memcpy(pDef->szValue, pszValue, cchValue); 826 pDef->szValue[cchValue] = '\0'; 827 828 return vbcppDefineInsert(pThis, pDef); 829 } 830 831 832 /** 833 * Checks if a define exists. 834 * 835 * @returns true or false. 836 * @param pThis The C preprocessor instance. 837 * @param pszDefine The define name and optionally the argument 838 * list. 839 * @param cchDefine The length of the name. RTSTR_MAX is ok. 840 */ 841 static bool vbcppDefineExists(PVBCPP pThis, const char *pszDefine, size_t cchDefine) 842 { 843 return cchDefine > 0 844 && VBCPP_BITMAP_IS_SET(pThis->bmDefined, *pszDefine) 845 && RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine) != NULL; 846 } 847 848 849 /** 850 * Adds an include directory. 851 * 852 * @returns Program exit code, with error message on failure. 853 * @param pThis The C preprocessor instance. 854 * @param pszDir The directory to add. 855 */ 856 static RTEXITCODE vbcppAddInclude(PVBCPP pThis, const char *pszDir) 857 { 858 uint32_t cIncludes = pThis->cIncludes; 859 if (cIncludes >= _64K) 860 return vbcppError(pThis, "Too many include directories"); 861 862 void *pv = RTMemRealloc(pThis->papszIncludes, (cIncludes + 1) * sizeof(char **)); 863 if (!pv) 864 return vbcppError(pThis, "No memory for include directories"); 865 pThis->papszIncludes = (char **)pv; 866 867 int rc = RTStrDupEx(&pThis->papszIncludes[cIncludes], pszDir); 868 if (RT_FAILURE(rc)) 869 return vbcppError(pThis, "No string memory for include directories"); 870 871 pThis->cIncludes = cIncludes + 1; 872 return RTEXITCODE_SUCCESS; 873 } 874 875 876 /** 877 * Parses the command line options. 878 * 879 * @returns Program exit code. Exit on non-success or if *pfExit is set. 880 * @param pThis The C preprocessor instance. 881 * @param argc The argument count. 882 * @param argv The argument vector. 883 * @param pfExit Pointer to the exit indicator. 884 */ 885 static RTEXITCODE vbcppParseOptions(PVBCPP pThis, int argc, char **argv, bool *pfExit) 886 { 887 RTEXITCODE rcExit; 888 889 *pfExit = false; 890 891 /* 892 * Option config. 893 */ 894 static RTGETOPTDEF const s_aOpts[] = 895 { 896 { "--define", 'D', RTGETOPT_REQ_STRING }, 897 { "--include-dir", 'I', RTGETOPT_REQ_STRING }, 898 { "--undefine", 'U', RTGETOPT_REQ_STRING }, 899 { "--keep-comments", 'C', RTGETOPT_REQ_NOTHING }, 900 { "--strip-comments", 'c', RTGETOPT_REQ_NOTHING }, 901 { "--D-strip", 'd', RTGETOPT_REQ_NOTHING }, 902 }; 903 904 RTGETOPTUNION ValueUnion; 905 RTGETOPTSTATE GetOptState; 906 int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 907 AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE); 908 909 /* 910 * Process the options. 911 */ 912 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0) 913 { 914 switch (rc) 915 { 916 case 'c': 917 pThis->fKeepComments = false; 918 break; 919 920 case 'C': 921 pThis->fKeepComments = false; 922 break; 923 924 case 'd': 925 vbcppSetMode(pThis, kVBCppMode_SelectiveD); 926 break; 927 928 case 'D': 929 { 930 const char *pszEqual = strchr(ValueUnion.psz, '='); 931 if (pszEqual) 932 rcExit = vbcppDefineAdd(pThis, ValueUnion.psz, pszEqual - ValueUnion.psz, pszEqual + 1, RTSTR_MAX, true); 933 else 934 rcExit = vbcppDefineAdd(pThis, ValueUnion.psz, RTSTR_MAX, "1", 1, true); 935 if (rcExit != RTEXITCODE_SUCCESS) 936 return rcExit; 937 break; 938 } 939 940 case 'I': 941 rcExit = vbcppAddInclude(pThis, ValueUnion.psz); 942 if (rcExit != RTEXITCODE_SUCCESS) 943 return rcExit; 944 break; 945 946 case 'U': 947 rcExit = vbcppDefineUndef(pThis, ValueUnion.psz, RTSTR_MAX, true); 948 break; 949 950 case 'h': 951 RTPrintf("No help yet, sorry\n"); 952 *pfExit = true; 953 return RTEXITCODE_SUCCESS; 954 955 case 'V': 956 { 957 /* The following is assuming that svn does it's job here. */ 958 static const char s_szRev[] = "$Revision$"; 959 const char *psz = RTStrStripL(strchr(s_szRev, ' ')); 960 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz); 961 *pfExit = true; 962 return RTEXITCODE_SUCCESS; 963 } 964 965 case VINF_GETOPT_NOT_OPTION: 966 if (!pThis->pszInput) 967 pThis->pszInput = ValueUnion.psz; 968 else if (!pThis->pszOutput) 969 pThis->pszOutput = ValueUnion.psz; 970 else 971 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "too many file arguments"); 972 break; 973 974 975 /* 976 * Errors and bugs. 977 */ 978 default: 979 return RTGetOptPrintError(rc, &ValueUnion); 980 } 981 } 982 983 return RTEXITCODE_SUCCESS; 984 } 985 986 987 /** 988 * Opens the input and output streams. 989 * 990 * @returns Exit code. 991 * @param pThis The C preprocessor instance. 992 */ 993 static RTEXITCODE vbcppOpenStreams(PVBCPP pThis) 994 { 995 if (!pThis->pszInput) 996 return vbcppError(pThis, "Preprocessing the standard input stream is currently not supported"); 997 998 size_t cchName = strlen(pThis->pszInput); 999 PVBCPPINPUT pInput = (PVBCPPINPUT)RTMemAlloc(RT_OFFSETOF(VBCPPINPUT, szName[cchName + 1])); 1000 if (!pInput) 1001 return vbcppError(pThis, "out of memory"); 1002 pInput->pUp = pThis->pInputStack; 1003 pInput->pszSpecified = pInput->szName; 1004 memcpy(pInput->szName, pThis->pszInput, cchName + 1); 1005 pThis->pInputStack = pInput; 1006 int rc = ScmStreamInitForReading(&pInput->StrmInput, pThis->pszInput); 1007 if (RT_FAILURE(rc)) 1008 return vbcppError(pThis, "ScmStreamInitForReading returned %Rrc when opening input file (%s)", 1009 rc, pThis->pszInput); 1010 1011 rc = ScmStreamInitForWriting(&pThis->StrmOutput, &pInput->StrmInput); 1012 if (RT_FAILURE(rc)) 1013 return vbcppError(pThis, "ScmStreamInitForWriting returned %Rrc", rc); 1014 1015 pThis->fStrmOutputValid = true; 1016 return RTEXITCODE_SUCCESS; 1017 } 475 476 477 478 479 /* 480 * 481 * 482 * Output 483 * Output 484 * Output 485 * Output 486 * Output 487 * 488 * 489 */ 1018 490 1019 491 … … 1089 561 1090 562 1091 /** 1092 * Processes a multi-line comment. 1093 * 1094 * Must either string the comment or keep it. If the latter, we must refrain 1095 * from replacing C-words in it. 1096 * 1097 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1098 * @param pThis The C preprocessor instance. 1099 * @param pStrmInput The input stream. 1100 */ 1101 static RTEXITCODE vbcppProcessMultiLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 1102 { 1103 /* The open comment sequence. */ 1104 ScmStreamGetCh(pStrmInput); /* '*' */ 1105 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1106 if ( pThis->fKeepComments 1107 && !pThis->fIf0Mode) 1108 rcExit = vbcppOutputWrite(pThis, "/*", 2); 1109 1110 /* The comment.*/ 1111 unsigned ch; 1112 while ( rcExit == RTEXITCODE_SUCCESS 1113 && (ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0 ) 1114 { 1115 if (ch == '*') 1116 { 1117 /* Closing sequence? */ 1118 unsigned ch2 = ScmStreamPeekCh(pStrmInput); 1119 if (ch2 == '/') 1120 { 1121 ScmStreamGetCh(pStrmInput); 1122 if ( pThis->fKeepComments 1123 && !pThis->fIf0Mode) 1124 rcExit = vbcppOutputWrite(pThis, "*/", 2); 1125 break; 1126 } 1127 } 1128 1129 if ( ( pThis->fKeepComments 1130 && !pThis->fIf0Mode) 1131 || ch == '\r' 1132 || ch == '\n') 1133 { 1134 rcExit = vbcppOutputCh(pThis, ch); 1135 if (rcExit != RTEXITCODE_SUCCESS) 1136 break; 1137 1138 /* Reset the maybe-preprocessor-line indicator when necessary. */ 1139 if (ch == '\r' || ch == '\n') 1140 pThis->fMaybePreprocessorLine = true; 1141 } 1142 } 1143 return rcExit; 1144 } 1145 1146 1147 /** 1148 * Processes a single line comment. 1149 * 1150 * Must either string the comment or keep it. If the latter, we must refrain 1151 * from replacing C-words in it. 1152 * 1153 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1154 * @param pThis The C preprocessor instance. 1155 * @param pStrmInput The input stream. 1156 */ 1157 static RTEXITCODE vbcppProcessOneLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 1158 { 1159 RTEXITCODE rcExit; 1160 SCMEOL enmEol; 1161 size_t cchLine; 1162 const char *pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); Assert(pszLine); 1163 pszLine--; cchLine++; /* unfetching the first slash. */ 1164 for (;;) 1165 { 1166 if ( pThis->fKeepComments 1167 && !pThis->fIf0Mode) 1168 rcExit = vbcppOutputWrite(pThis, pszLine, cchLine + enmEol); 1169 else 1170 rcExit = vbcppOutputWrite(pThis, pszLine + cchLine, enmEol); 1171 if (rcExit != RTEXITCODE_SUCCESS) 1172 break; 1173 if ( cchLine == 0 1174 || pszLine[cchLine - 1] != '\\') 1175 break; 1176 1177 pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); 1178 if (!pszLine) 1179 break; 1180 } 1181 pThis->fMaybePreprocessorLine = true; 1182 return rcExit; 1183 } 1184 1185 1186 /** 1187 * Processes a double quoted string. 1188 * 1189 * Must not replace any C-words in strings. 1190 * 1191 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1192 * @param pThis The C preprocessor instance. 1193 * @param pStrmInput The input stream. 1194 */ 1195 static RTEXITCODE vbcppProcessDoubleQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 1196 { 1197 RTEXITCODE rcExit = vbcppOutputCh(pThis, '"'); 1198 if (rcExit == RTEXITCODE_SUCCESS) 1199 { 1200 bool fEscaped = false; 1201 for (;;) 1202 { 1203 unsigned ch = ScmStreamGetCh(pStrmInput); 1204 if (ch == ~(unsigned)0) 1205 { 1206 rcExit = vbcppError(pThis, "Unterminated double quoted string"); 1207 break; 1208 } 1209 1210 rcExit = vbcppOutputCh(pThis, ch); 1211 if (rcExit != RTEXITCODE_SUCCESS) 1212 break; 1213 1214 if (ch == '"' && !fEscaped) 1215 break; 1216 fEscaped = !fEscaped && ch == '\\'; 1217 } 1218 } 1219 return rcExit; 1220 } 1221 1222 1223 /** 1224 * Processes a single quoted litteral. 1225 * 1226 * Must not replace any C-words in strings. 1227 * 1228 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1229 * @param pThis The C preprocessor instance. 1230 * @param pStrmInput The input stream. 1231 */ 1232 static RTEXITCODE vbcppProcessSingledQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 1233 { 1234 RTEXITCODE rcExit = vbcppOutputCh(pThis, '\''); 1235 if (rcExit == RTEXITCODE_SUCCESS) 1236 { 1237 bool fEscaped = false; 1238 for (;;) 1239 { 1240 unsigned ch = ScmStreamGetCh(pStrmInput); 1241 if (ch == ~(unsigned)0) 1242 { 1243 rcExit = vbcppError(pThis, "Unterminated singled quoted string"); 1244 break; 1245 } 1246 1247 rcExit = vbcppOutputCh(pThis, ch); 1248 if (rcExit != RTEXITCODE_SUCCESS) 1249 break; 1250 1251 if (ch == '\'' && !fEscaped) 1252 break; 1253 fEscaped = !fEscaped && ch == '\\'; 1254 } 1255 } 1256 return rcExit; 1257 } 563 564 565 566 /* 567 * 568 * 569 * Input 570 * Input 571 * Input 572 * Input 573 * Input 574 * 575 * 576 */ 1258 577 1259 578 … … 1392 711 } 1393 712 713 714 /** 715 * Processes a multi-line comment. 716 * 717 * Must either string the comment or keep it. If the latter, we must refrain 718 * from replacing C-words in it. 719 * 720 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 721 * @param pThis The C preprocessor instance. 722 * @param pStrmInput The input stream. 723 */ 724 static RTEXITCODE vbcppProcessMultiLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 725 { 726 /* The open comment sequence. */ 727 ScmStreamGetCh(pStrmInput); /* '*' */ 728 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 729 if ( pThis->fKeepComments 730 && !pThis->fIf0Mode) 731 rcExit = vbcppOutputWrite(pThis, "/*", 2); 732 733 /* The comment.*/ 734 unsigned ch; 735 while ( rcExit == RTEXITCODE_SUCCESS 736 && (ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0 ) 737 { 738 if (ch == '*') 739 { 740 /* Closing sequence? */ 741 unsigned ch2 = ScmStreamPeekCh(pStrmInput); 742 if (ch2 == '/') 743 { 744 ScmStreamGetCh(pStrmInput); 745 if ( pThis->fKeepComments 746 && !pThis->fIf0Mode) 747 rcExit = vbcppOutputWrite(pThis, "*/", 2); 748 break; 749 } 750 } 751 752 if ( ( pThis->fKeepComments 753 && !pThis->fIf0Mode) 754 || ch == '\r' 755 || ch == '\n') 756 { 757 rcExit = vbcppOutputCh(pThis, ch); 758 if (rcExit != RTEXITCODE_SUCCESS) 759 break; 760 761 /* Reset the maybe-preprocessor-line indicator when necessary. */ 762 if (ch == '\r' || ch == '\n') 763 pThis->fMaybePreprocessorLine = true; 764 } 765 } 766 return rcExit; 767 } 768 769 770 /** 771 * Processes a single line comment. 772 * 773 * Must either string the comment or keep it. If the latter, we must refrain 774 * from replacing C-words in it. 775 * 776 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 777 * @param pThis The C preprocessor instance. 778 * @param pStrmInput The input stream. 779 */ 780 static RTEXITCODE vbcppProcessOneLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput) 781 { 782 RTEXITCODE rcExit; 783 SCMEOL enmEol; 784 size_t cchLine; 785 const char *pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); Assert(pszLine); 786 pszLine--; cchLine++; /* unfetching the first slash. */ 787 for (;;) 788 { 789 if ( pThis->fKeepComments 790 && !pThis->fIf0Mode) 791 rcExit = vbcppOutputWrite(pThis, pszLine, cchLine + enmEol); 792 else 793 rcExit = vbcppOutputWrite(pThis, pszLine + cchLine, enmEol); 794 if (rcExit != RTEXITCODE_SUCCESS) 795 break; 796 if ( cchLine == 0 797 || pszLine[cchLine - 1] != '\\') 798 break; 799 800 pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); 801 if (!pszLine) 802 break; 803 } 804 pThis->fMaybePreprocessorLine = true; 805 return rcExit; 806 } 807 808 809 /** 810 * Processes a double quoted string. 811 * 812 * Must not replace any C-words in strings. 813 * 814 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 815 * @param pThis The C preprocessor instance. 816 * @param pStrmInput The input stream. 817 */ 818 static RTEXITCODE vbcppProcessDoubleQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 819 { 820 RTEXITCODE rcExit = vbcppOutputCh(pThis, '"'); 821 if (rcExit == RTEXITCODE_SUCCESS) 822 { 823 bool fEscaped = false; 824 for (;;) 825 { 826 unsigned ch = ScmStreamGetCh(pStrmInput); 827 if (ch == ~(unsigned)0) 828 { 829 rcExit = vbcppError(pThis, "Unterminated double quoted string"); 830 break; 831 } 832 833 rcExit = vbcppOutputCh(pThis, ch); 834 if (rcExit != RTEXITCODE_SUCCESS) 835 break; 836 837 if (ch == '"' && !fEscaped) 838 break; 839 fEscaped = !fEscaped && ch == '\\'; 840 } 841 } 842 return rcExit; 843 } 844 845 846 /** 847 * Processes a single quoted litteral. 848 * 849 * Must not replace any C-words in strings. 850 * 851 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 852 * @param pThis The C preprocessor instance. 853 * @param pStrmInput The input stream. 854 */ 855 static RTEXITCODE vbcppProcessSingledQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput) 856 { 857 RTEXITCODE rcExit = vbcppOutputCh(pThis, '\''); 858 if (rcExit == RTEXITCODE_SUCCESS) 859 { 860 bool fEscaped = false; 861 for (;;) 862 { 863 unsigned ch = ScmStreamGetCh(pStrmInput); 864 if (ch == ~(unsigned)0) 865 { 866 rcExit = vbcppError(pThis, "Unterminated singled quoted string"); 867 break; 868 } 869 870 rcExit = vbcppOutputCh(pThis, ch); 871 if (rcExit != RTEXITCODE_SUCCESS) 872 break; 873 874 if (ch == '\'' && !fEscaped) 875 break; 876 fEscaped = !fEscaped && ch == '\\'; 877 } 878 } 879 return rcExit; 880 } 881 882 883 /** 884 * Processes a C word, possibly replacing it with a definition. 885 * 886 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 887 * @param pThis The C preprocessor instance. 888 * @param pStrmInput The input stream. 889 * @param ch The first character. 890 */ 891 static RTEXITCODE vbcppProcessCWord(PVBCPP pThis, PSCMSTREAM pStrmInput, char ch) 892 { 893 /** @todo Implement this... */ 894 return vbcppOutputCh(pThis, ch); 895 } 896 897 898 899 900 901 902 903 /* 904 * 905 * 906 * D E F I N E S 907 * D E F I N E S 908 * D E F I N E S 909 * D E F I N E S 910 * D E F I N E S 911 * 912 * 913 */ 914 915 916 /** 917 * Checks if a define exists. 918 * 919 * @returns true or false. 920 * @param pThis The C preprocessor instance. 921 * @param pszDefine The define name and optionally the argument 922 * list. 923 * @param cchDefine The length of the name. RTSTR_MAX is ok. 924 */ 925 static bool vbcppDefineExists(PVBCPP pThis, const char *pszDefine, size_t cchDefine) 926 { 927 return cchDefine > 0 928 && VBCPP_BITMAP_IS_SET(pThis->bmDefined, *pszDefine) 929 && RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine) != NULL; 930 } 931 932 933 /** 934 * Frees a define. 935 * 936 * @returns VINF_SUCCESS (used when called by RTStrSpaceDestroy) 937 * @param pStr Pointer to the VBCPPDEF::Core member. 938 * @param pvUser Unused. 939 */ 940 static DECLCALLBACK(int) vbcppFreeDefine(PRTSTRSPACECORE pStr, void *pvUser) 941 { 942 RTMemFree(pStr); 943 NOREF(pvUser); 944 return VINF_SUCCESS; 945 } 946 947 948 /** 949 * Removes a define. 950 * 951 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 952 * @param pThis The C preprocessor instance. 953 * @param pszDefine The define name, no argument list or anything. 954 * @param cchDefine The length of the name. RTSTR_MAX is ok. 955 * @param fExplicitUndef Explicit undefinition, that is, in a selective 956 * preprocessing run it will evaluate to undefined. 957 */ 958 static RTEXITCODE vbcppDefineUndef(PVBCPP pThis, const char *pszDefine, size_t cchDefine, bool fExplicitUndef) 959 { 960 PRTSTRSPACECORE pHit = RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine); 961 if (pHit) 962 { 963 RTStrSpaceRemove(&pThis->StrSpace, pHit->pszString); 964 vbcppFreeDefine(pHit, NULL); 965 } 966 967 if (fExplicitUndef) 968 { 969 if (cchDefine == RTSTR_MAX) 970 cchDefine = strlen(pszDefine); 971 972 PRTSTRSPACECORE pStr = (PRTSTRSPACECORE)RTMemAlloc(sizeof(*pStr) + cchDefine + 1); 973 if (!pStr) 974 return vbcppError(pThis, "out of memory"); 975 char *pszDst = (char *)(pStr + 1); 976 pStr->pszString = pszDst; 977 memcpy(pszDst, pszDefine, cchDefine); 978 pszDst[cchDefine] = '\0'; 979 if (!RTStrSpaceInsert(&pThis->UndefStrSpace, pStr)) 980 RTMemFree(pStr); 981 } 982 983 return RTEXITCODE_SUCCESS; 984 } 985 986 987 /** 988 * Inserts a define (rejecting and freeing it in some case). 989 * 990 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 991 * @param pThis The C preprocessor instance. 992 * @param pDef The define to insert. 993 */ 994 static RTEXITCODE vbcppDefineInsert(PVBCPP pThis, PVBCPPDEF pDef) 995 { 996 /* 997 * Ignore in source-file defines when doing selective preprocessing. 998 */ 999 if ( !pThis->fRespectSourceDefines 1000 && !pDef->fCmdLine) 1001 { 1002 /* Ignore*/ 1003 vbcppFreeDefine(&pDef->Core, NULL); 1004 return RTEXITCODE_SUCCESS; 1005 } 1006 1007 /* 1008 * Insert it and update the lead character hint bitmap. 1009 */ 1010 if (RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core)) 1011 VBCPP_BITMAP_SET(pThis->bmDefined, *pDef->Core.pszString); 1012 else 1013 { 1014 /* 1015 * Duplicate. When doing selective D preprocessing, let the command 1016 * line take precendece. 1017 */ 1018 PVBCPPDEF pOld = (PVBCPPDEF)RTStrSpaceGet(&pThis->StrSpace, pDef->Core.pszString); Assert(pOld); 1019 if ( pThis->fAllowRedefiningCmdLineDefines 1020 || pDef->fCmdLine == pOld->fCmdLine) 1021 { 1022 if (pDef->fCmdLine) 1023 RTMsgWarning("Redefining '%s'\n", pDef->Core.pszString); 1024 1025 RTStrSpaceRemove(&pThis->StrSpace, pOld->Core.pszString); 1026 vbcppFreeDefine(&pOld->Core, NULL); 1027 1028 bool fRc = RTStrSpaceInsert(&pThis->StrSpace, &pDef->Core); 1029 Assert(fRc); 1030 } 1031 else 1032 { 1033 RTMsgWarning("Ignoring redefinition of '%s'\n", pDef->Core.pszString); 1034 vbcppFreeDefine(&pDef->Core, NULL); 1035 } 1036 } 1037 1038 return RTEXITCODE_SUCCESS; 1039 } 1040 1041 1042 /** 1043 * Adds a define. 1044 * 1045 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 1046 * @param pThis The C preprocessor instance. 1047 * @param pszDefine The define name, no parameter list. 1048 * @param cchDefine The length of the name. 1049 * @param pszParams The parameter list. 1050 * @param cchParams The length of the parameter list. 1051 * @param pszValue The value. 1052 * @param cchDefine The length of the value. 1053 * @param fCmdLine Set if originating on the command line. 1054 */ 1055 static RTEXITCODE vbcppDefineAddFn(PVBCPP pThis, const char *pszDefine, size_t cchDefine, 1056 const char *pszParams, size_t cchParams, 1057 const char *pszValue, size_t cchValue, 1058 bool fCmdLine) 1059 1060 { 1061 Assert(RTStrNLen(pszDefine, cchDefine) == cchDefine); 1062 Assert(RTStrNLen(pszParams, cchParams) == cchParams); 1063 Assert(RTStrNLen(pszValue, cchValue) == cchValue); 1064 1065 /* 1066 * Determin the number of arguments and how much space their names 1067 * requires. Performing syntax validation while parsing. 1068 */ 1069 uint32_t cchArgNames = 0; 1070 uint32_t cArgs = 0; 1071 for (size_t off = 0; off < cchParams; off++) 1072 { 1073 /* Skip blanks and maybe one comma. */ 1074 bool fIgnoreComma = cArgs != 0; 1075 while (off < cchParams) 1076 { 1077 if (!RT_C_IS_SPACE(pszParams[off])) 1078 { 1079 if (pszParams[off] != ',' || !fIgnoreComma) 1080 { 1081 if (vbcppIsCIdentifierLeadChar(pszParams[off])) 1082 break; 1083 /** @todo variadic macros. */ 1084 return vbcppErrorPos(pThis, &pszParams[off], "Unexpected character"); 1085 } 1086 fIgnoreComma = false; 1087 } 1088 off++; 1089 } 1090 if (off >= cchParams) 1091 break; 1092 1093 /* Found and argument. First character is already validated. */ 1094 cArgs++; 1095 cchArgNames += 2; 1096 off++; 1097 while ( off < cchParams 1098 && vbcppIsCIdentifierChar(pszParams[off])) 1099 off++, cchArgNames++; 1100 } 1101 1102 /* 1103 * Allocate a structure. 1104 */ 1105 size_t cbDef = RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1 + cchArgNames]) 1106 + sizeof(const char *) * cArgs; 1107 cbDef = RT_ALIGN_Z(cbDef, sizeof(const char *)); 1108 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(cbDef); 1109 if (!pDef) 1110 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 1111 1112 char *pszDst = &pDef->szValue[cchValue + 1]; 1113 pDef->Core.pszString = pszDst; 1114 memcpy(pszDst, pszDefine, cchDefine); 1115 pszDst += cchDefine; 1116 *pszDst++ = '\0'; 1117 pDef->fFunction = true; 1118 pDef->fVarArg = false; 1119 pDef->fCmdLine = fCmdLine; 1120 pDef->cArgs = cArgs; 1121 pDef->papszArgs = (const char **)((uintptr_t)pDef + cbDef - sizeof(const char *) * cArgs); 1122 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 1123 memcpy(pDef->szValue, pszValue, cchValue); 1124 pDef->szValue[cchValue] = '\0'; 1125 1126 /* 1127 * Set up the arguments. 1128 */ 1129 uint32_t iArg = 0; 1130 for (size_t off = 0; off < cchParams; off++) 1131 { 1132 /* Skip blanks and maybe one comma. */ 1133 bool fIgnoreComma = cArgs != 0; 1134 while (off < cchParams) 1135 { 1136 if (!RT_C_IS_SPACE(pszParams[off])) 1137 { 1138 if (pszParams[off] != ',' || !fIgnoreComma) 1139 break; 1140 fIgnoreComma = false; 1141 } 1142 off++; 1143 } 1144 if (off >= cchParams) 1145 break; 1146 1147 /* Found and argument. First character is already validated. */ 1148 pDef->papszArgs[iArg] = pszDst; 1149 do 1150 { 1151 *pszDst++ = pszParams[off++]; 1152 } while ( off < cchParams 1153 && vbcppIsCIdentifierChar(pszParams[off])); 1154 *pszDst++ = '\0'; 1155 iArg++; 1156 } 1157 Assert((uintptr_t)pszDst <= (uintptr_t)pDef->papszArgs); 1158 1159 return vbcppDefineInsert(pThis, pDef); 1160 } 1161 1162 1163 /** 1164 * Adds a define. 1165 * 1166 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg. 1167 * @param pThis The C preprocessor instance. 1168 * @param pszDefine The define name and optionally the argument 1169 * list. 1170 * @param cchDefine The length of the name. RTSTR_MAX is ok. 1171 * @param pszValue The value. 1172 * @param cchDefine The length of the value. RTSTR_MAX is ok. 1173 * @param fCmdLine Set if originating on the command line. 1174 */ 1175 static RTEXITCODE vbcppDefineAdd(PVBCPP pThis, const char *pszDefine, size_t cchDefine, 1176 const char *pszValue, size_t cchValue, bool fCmdLine) 1177 { 1178 /* 1179 * We need the lengths. Trim the input. 1180 */ 1181 if (cchDefine == RTSTR_MAX) 1182 cchDefine = strlen(pszDefine); 1183 while (cchDefine > 0 && RT_C_IS_SPACE(*pszDefine)) 1184 pszDefine++, cchDefine--; 1185 while (cchDefine > 0 && RT_C_IS_SPACE(pszDefine[cchDefine - 1])) 1186 cchDefine--; 1187 if (!cchDefine) 1188 return vbcppErrorPos(pThis, pszDefine, "The define has no name"); 1189 1190 if (cchValue == RTSTR_MAX) 1191 cchValue = strlen(pszValue); 1192 while (cchValue > 0 && RT_C_IS_SPACE(*pszValue)) 1193 pszValue++, cchValue--; 1194 while (cchValue > 0 && RT_C_IS_SPACE(pszValue[cchValue - 1])) 1195 cchValue--; 1196 1197 /* 1198 * Arguments make the job a bit more annoying. Handle that elsewhere 1199 */ 1200 const char *pszParams = (const char *)memchr(pszDefine, '(', cchDefine); 1201 if (pszParams) 1202 { 1203 size_t cchParams = pszDefine + cchDefine - pszParams; 1204 cchDefine -= cchParams; 1205 if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 1206 return RTEXITCODE_FAILURE; 1207 if (pszParams[cchParams - 1] != ')') 1208 return vbcppErrorPos(pThis, pszParams + cchParams - 1, "Missing closing parenthesis"); 1209 pszParams++; 1210 cchParams -= 2; 1211 return vbcppDefineAddFn(pThis, pszDefine, cchDefine, pszParams, cchParams, pszValue, cchValue, fCmdLine); 1212 } 1213 1214 /* 1215 * Simple define, no arguments. 1216 */ 1217 if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine)) 1218 return RTEXITCODE_FAILURE; 1219 1220 PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1])); 1221 if (!pDef) 1222 return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory"); 1223 1224 pDef->Core.pszString = &pDef->szValue[cchValue + 1]; 1225 memcpy((char *)pDef->Core.pszString, pszDefine, cchDefine); 1226 ((char *)pDef->Core.pszString)[cchDefine] = '\0'; 1227 pDef->fFunction = false; 1228 pDef->fVarArg = false; 1229 pDef->fCmdLine = fCmdLine; 1230 pDef->cArgs = 0; 1231 pDef->papszArgs = NULL; 1232 VBCPP_BITMAP_EMPTY(pDef->bmArgs); 1233 memcpy(pDef->szValue, pszValue, cchValue); 1234 pDef->szValue[cchValue] = '\0'; 1235 1236 return vbcppDefineInsert(pThis, pDef); 1237 } 1238 1239 1240 /** 1241 * Processes a abbreviated line number directive. 1242 * 1243 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1244 * @param pThis The C preprocessor instance. 1245 * @param pStrmInput The input stream. 1246 * @param offStart The stream position where the directive 1247 * started (for pass thru). 1248 */ 1249 static RTEXITCODE vbcppProcessDefine(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1250 { 1251 /* 1252 * Parse it. 1253 */ 1254 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput); 1255 if (rcExit == RTEXITCODE_SUCCESS) 1256 { 1257 size_t cchDefine; 1258 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine); 1259 if (pchDefine) 1260 { 1261 /* If it's a function style define, parse out the parameter list. */ 1262 size_t cchParams = 0; 1263 const char *pchParams = NULL; 1264 unsigned ch = ScmStreamPeekCh(pStrmInput); 1265 if (ch == '(') 1266 { 1267 ScmStreamGetCh(pStrmInput); 1268 pchParams = ScmStreamGetCur(pStrmInput); 1269 1270 unsigned chPrev = ch; 1271 while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0) 1272 { 1273 if (ch == '\r' || ch == '\n') 1274 { 1275 if (chPrev != '\\') 1276 { 1277 rcExit = vbcppError(pThis, "Missing ')'"); 1278 break; 1279 } 1280 ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1); 1281 } 1282 if (ch == ')') 1283 { 1284 cchParams = ScmStreamGetCur(pStrmInput) - pchParams; 1285 ScmStreamGetCh(pStrmInput); 1286 break; 1287 } 1288 ScmStreamGetCh(pStrmInput); 1289 } 1290 } 1291 /* The simple kind. */ 1292 else if (!RT_C_IS_SPACE(ch) && ch != ~(unsigned)0) 1293 rcExit = vbcppError(pThis, "Expected whitespace after macro name"); 1294 1295 /* Parse out the value. */ 1296 if (rcExit == RTEXITCODE_SUCCESS) 1297 rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput); 1298 if (rcExit == RTEXITCODE_SUCCESS) 1299 { 1300 size_t offValue = ScmStreamTell(pStrmInput); 1301 const char *pchValue = ScmStreamGetCur(pStrmInput); 1302 unsigned chPrev = ch; 1303 while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0) 1304 { 1305 if (ch == '\r' || ch == '\n') 1306 { 1307 if (chPrev != '\\') 1308 break; 1309 ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1); 1310 } 1311 ScmStreamGetCh(pStrmInput); 1312 } 1313 size_t cchValue = ScmStreamGetCur(pStrmInput) - pchValue; 1314 1315 /* 1316 * Execute. 1317 */ 1318 if (pchParams) 1319 rcExit = vbcppDefineAddFn(pThis, pchDefine, cchDefine, pchParams, cchParams, pchValue, cchValue, false); 1320 else 1321 rcExit = vbcppDefineAdd(pThis, pchDefine, cchDefine, pchValue, cchValue, false); 1322 1323 /* 1324 * Pass thru? 1325 */ 1326 if ( rcExit == RTEXITCODE_SUCCESS 1327 && pThis->fPassThruDefines) 1328 { 1329 unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0; 1330 size_t cch; 1331 if (pchParams) 1332 cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s(%.*s)", 1333 cchIndent, "", cchDefine, pchDefine, cchParams, pchParams); 1334 else 1335 cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s", 1336 cchIndent, "", cchDefine, pchDefine); 1337 if (cch > 0) 1338 vbcppOutputComment(pThis, pStrmInput, offValue, cch, 1); 1339 else 1340 rcExit = vbcppError(pThis, "output error"); 1341 } 1342 } 1343 1344 } 1345 } 1346 return rcExit; 1347 } 1348 1349 1350 /** 1351 * Processes a abbreviated line number directive. 1352 * 1353 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1354 * @param pThis The C preprocessor instance. 1355 * @param pStrmInput The input stream. 1356 * @param offStart The stream position where the directive 1357 * started (for pass thru). 1358 */ 1359 static RTEXITCODE vbcppProcessUndef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1360 { 1361 return vbcppError(pThis, "Not implemented %s", __FUNCTION__); 1362 } 1363 1364 1365 1366 1367 1368 /* 1369 * 1370 * 1371 * C O N D I T I O N A L S 1372 * C O N D I T I O N A L S 1373 * C O N D I T I O N A L S 1374 * C O N D I T I O N A L S 1375 * C O N D I T I O N A L S 1376 * 1377 * 1378 */ 1379 1380 1381 /** 1382 * Combines current stack result with the one being pushed. 1383 * 1384 * @returns Combined result. 1385 * @param enmEvalPush The result of the condition being pushed. 1386 * @param enmEvalStack The current stack result. 1387 */ 1388 static VBCPPEVAL vbcppCondCombine(VBCPPEVAL enmEvalPush, VBCPPEVAL enmEvalStack) 1389 { 1390 if (enmEvalStack == kVBCppEval_False) 1391 return kVBCppEval_False; 1392 return enmEvalPush; 1393 } 1394 1395 1396 /** 1397 * Pushes an conditional onto the stack. 1398 * 1399 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1400 * @param pThis The C preprocessor instance. 1401 * @param pStrmInput The current input stream. 1402 * @param offStart Not currently used, using @a pchCondition and 1403 * @a cchCondition instead. 1404 * @param enmKind The kind of conditional. 1405 * @param enmResult The result of the evaluation. 1406 * @param pchCondition The raw condition. 1407 * @param cchCondition The length of @a pchCondition. 1408 */ 1409 static RTEXITCODE vbcppCondPush(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart, 1410 VBCPPCONDKIND enmKind, VBCPPEVAL enmResult, 1411 const char *pchCondition, size_t cchCondition) 1412 { 1413 if (pThis->cCondStackDepth >= _64K) 1414 return vbcppError(pThis, "Too many nested #if/#ifdef/#ifndef statements"); 1415 1416 /* 1417 * Allocate a new entry and push it. 1418 */ 1419 PVBCPPCOND pCond = (PVBCPPCOND)RTMemAlloc(sizeof(*pCond)); 1420 if (!pCond) 1421 return vbcppError(pThis, "out of memory"); 1422 1423 PVBCPPCOND pUp = pThis->pCondStack; 1424 pCond->enmKind = enmKind; 1425 pCond->enmResult = enmResult; 1426 pCond->enmStackResult = pUp ? vbcppCondCombine(enmResult, pUp->enmStackResult) : enmResult; 1427 pCond->fSeenElse = false; 1428 pCond->iLevel = pThis->cCondStackDepth; 1429 pCond->iKeepLevel = (pUp ? pUp->iKeepLevel : 0) + enmResult == kVBCppEval_Undecided; 1430 pCond->pchCond = pchCondition; 1431 pCond->cchCond = cchCondition; 1432 1433 pCond->pUp = pThis->pCondStack; 1434 pThis->pCondStack = pCond; 1435 pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False; 1436 1437 /* 1438 * Do pass thru. 1439 */ 1440 if ( !pThis->fIf0Mode 1441 && enmResult == kVBCppEval_Undecided) 1442 { 1443 /** @todo this is stripping comments of \#ifdef and \#ifndef atm. */ 1444 const char *pszDirective; 1445 switch (enmKind) 1446 { 1447 case kVBCppCondKind_If: pszDirective = "if"; break; 1448 case kVBCppCondKind_IfDef: pszDirective = "ifdef"; break; 1449 case kVBCppCondKind_IfNDef: pszDirective = "ifndef"; break; 1450 case kVBCppCondKind_ElIf: pszDirective = "elif"; break; 1451 default: AssertFailedReturn(RTEXITCODE_FAILURE); 1452 } 1453 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*s%s %.*s", 1454 pCond->iKeepLevel - 1, "", pszDirective, cchCondition, pchCondition); 1455 if (cch < 0) 1456 return vbcppError(pThis, "Output error %Rrc", (int)cch); 1457 } 1458 1459 return RTEXITCODE_SUCCESS; 1460 } 1461 1462 1463 /** 1464 * Processes a abbreviated line number directive. 1465 * 1466 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1467 * @param pThis The C preprocessor instance. 1468 * @param pStrmInput The input stream. 1469 * @param offStart The stream position where the directive 1470 * started (for pass thru). 1471 */ 1472 static RTEXITCODE vbcppProcessIf(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1473 { 1474 return vbcppError(pThis, "Not implemented %s", __FUNCTION__); 1475 } 1476 1477 1478 /** 1479 * Processes a abbreviated line number directive. 1480 * 1481 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1482 * @param pThis The C preprocessor instance. 1483 * @param pStrmInput The input stream. 1484 * @param offStart The stream position where the directive 1485 * started (for pass thru). 1486 */ 1487 static RTEXITCODE vbcppProcessIfDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1488 { 1489 /* 1490 * Parse it. 1491 */ 1492 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput); 1493 if (rcExit == RTEXITCODE_SUCCESS) 1494 { 1495 size_t cchDefine; 1496 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine); 1497 if (pchDefine) 1498 { 1499 rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput); 1500 if (rcExit == RTEXITCODE_SUCCESS) 1501 { 1502 /* 1503 * Evaluate it. 1504 */ 1505 VBCPPEVAL enmEval; 1506 if (vbcppDefineExists(pThis, pchDefine, cchDefine)) 1507 enmEval = kVBCppEval_True; 1508 else if ( pThis->fUndecidedConditionals 1509 || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL) 1510 enmEval = kVBCppEval_False; 1511 else 1512 enmEval = kVBCppEval_Undecided; 1513 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfDef, enmEval, 1514 pchDefine, cchDefine); 1515 } 1516 } 1517 else 1518 rcExit = vbcppError(pThis, "Malformed #ifdef"); 1519 } 1520 return rcExit; 1521 } 1522 1523 1524 /** 1525 * Processes a abbreviated line number directive. 1526 * 1527 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1528 * @param pThis The C preprocessor instance. 1529 * @param pStrmInput The input stream. 1530 * @param offStart The stream position where the directive 1531 * started (for pass thru). 1532 */ 1533 static RTEXITCODE vbcppProcessIfNDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1534 { 1535 /* 1536 * Parse it. 1537 */ 1538 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput); 1539 if (rcExit == RTEXITCODE_SUCCESS) 1540 { 1541 size_t cchDefine; 1542 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine); 1543 if (pchDefine) 1544 { 1545 rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput); 1546 if (rcExit == RTEXITCODE_SUCCESS) 1547 { 1548 /* 1549 * Evaluate it. 1550 */ 1551 VBCPPEVAL enmEval; 1552 if (vbcppDefineExists(pThis, pchDefine, cchDefine)) 1553 enmEval = kVBCppEval_False; 1554 else if ( pThis->fUndecidedConditionals 1555 || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL) 1556 enmEval = kVBCppEval_True; 1557 else 1558 enmEval = kVBCppEval_Undecided; 1559 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfNDef, enmEval, 1560 pchDefine, cchDefine); 1561 } 1562 } 1563 else 1564 rcExit = vbcppError(pThis, "Malformed #ifndef"); 1565 } 1566 return rcExit; 1567 } 1568 1569 1570 /** 1571 * Processes a abbreviated line number directive. 1572 * 1573 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1574 * @param pThis The C preprocessor instance. 1575 * @param pStrmInput The input stream. 1576 * @param offStart The stream position where the directive 1577 * started (for pass thru). 1578 */ 1579 static RTEXITCODE vbcppProcessElse(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1580 { 1581 /* 1582 * Nothing to parse, just comment positions to find and note down. 1583 */ 1584 offStart = vbcppProcessSkipWhite(pStrmInput); 1585 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput); 1586 if (rcExit == RTEXITCODE_SUCCESS) 1587 { 1588 /* 1589 * Execute. 1590 */ 1591 PVBCPPCOND pCond = pThis->pCondStack; 1592 if (pCond) 1593 { 1594 if (!pCond->fSeenElse) 1595 { 1596 pCond->fSeenElse = true; 1597 if ( pCond->enmResult != kVBCppEval_Undecided 1598 && ( !pCond->pUp 1599 || pCond->pUp->enmStackResult == kVBCppEval_True)) 1600 { 1601 if (pCond->enmResult == kVBCppEval_True) 1602 pCond->enmStackResult = kVBCppEval_False; 1603 else 1604 pCond->enmStackResult = kVBCppEval_True; 1605 pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False; 1606 } 1607 1608 /* 1609 * Do pass thru. 1610 */ 1611 if ( !pThis->fIf0Mode 1612 && pCond->enmResult == kVBCppEval_Undecided) 1613 { 1614 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*selse", pCond->iKeepLevel - 1, ""); 1615 if (cch > 0) 1616 rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 2); 1617 else 1618 rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch); 1619 } 1620 } 1621 else 1622 rcExit = vbcppError(pThis, "Double #else or/and missing #endif"); 1623 } 1624 else 1625 rcExit = vbcppError(pThis, "#else without #if"); 1626 } 1627 return rcExit; 1628 } 1629 1630 1631 /** 1632 * Processes a abbreviated line number directive. 1633 * 1634 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 1635 * @param pThis The C preprocessor instance. 1636 * @param pStrmInput The input stream. 1637 * @param offStart The stream position where the directive 1638 * started (for pass thru). 1639 */ 1640 static RTEXITCODE vbcppProcessEndif(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1641 { 1642 /* 1643 * Nothing to parse, just comment positions to find and note down. 1644 */ 1645 offStart = vbcppProcessSkipWhite(pStrmInput); 1646 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput); 1647 if (rcExit == RTEXITCODE_SUCCESS) 1648 { 1649 /* 1650 * Execute. 1651 */ 1652 PVBCPPCOND pCond = pThis->pCondStack; 1653 if (pCond) 1654 { 1655 pThis->pCondStack = pCond->pUp; 1656 pThis->fIf0Mode = pCond->pUp && pCond->pUp->enmStackResult == kVBCppEval_False; 1657 1658 /* 1659 * Do pass thru. 1660 */ 1661 if ( !pThis->fIf0Mode 1662 && pCond->enmResult == kVBCppEval_Undecided) 1663 { 1664 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sendif", pCond->iKeepLevel - 1, ""); 1665 if (cch > 0) 1666 rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 1); 1667 else 1668 rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch); 1669 } 1670 } 1671 else 1672 rcExit = vbcppError(pThis, "#endif without #if"); 1673 } 1674 return rcExit; 1675 } 1676 1677 1678 1679 1680 1681 /* 1682 * 1683 * 1684 * Misc Directives 1685 * Misc Directives 1686 * Misc Directives 1687 * Misc Directives 1688 * 1689 * 1690 */ 1691 1692 1693 /** 1694 * Adds an include directory. 1695 * 1696 * @returns Program exit code, with error message on failure. 1697 * @param pThis The C preprocessor instance. 1698 * @param pszDir The directory to add. 1699 */ 1700 static RTEXITCODE vbcppAddInclude(PVBCPP pThis, const char *pszDir) 1701 { 1702 uint32_t cIncludes = pThis->cIncludes; 1703 if (cIncludes >= _64K) 1704 return vbcppError(pThis, "Too many include directories"); 1705 1706 void *pv = RTMemRealloc(pThis->papszIncludes, (cIncludes + 1) * sizeof(char **)); 1707 if (!pv) 1708 return vbcppError(pThis, "No memory for include directories"); 1709 pThis->papszIncludes = (char **)pv; 1710 1711 int rc = RTStrDupEx(&pThis->papszIncludes[cIncludes], pszDir); 1712 if (RT_FAILURE(rc)) 1713 return vbcppError(pThis, "No string memory for include directories"); 1714 1715 pThis->cIncludes = cIncludes + 1; 1716 return RTEXITCODE_SUCCESS; 1717 } 1394 1718 1395 1719 … … 1507 1831 * started (for pass thru). 1508 1832 */ 1509 static RTEXITCODE vbcppProcessDefine(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1510 {1511 /*1512 * Parse it.1513 */1514 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);1515 if (rcExit == RTEXITCODE_SUCCESS)1516 {1517 size_t cchDefine;1518 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);1519 if (pchDefine)1520 {1521 /* If it's a function style define, parse out the parameter list. */1522 size_t cchParams = 0;1523 const char *pchParams = NULL;1524 unsigned ch = ScmStreamPeekCh(pStrmInput);1525 if (ch == '(')1526 {1527 ScmStreamGetCh(pStrmInput);1528 pchParams = ScmStreamGetCur(pStrmInput);1529 1530 unsigned chPrev = ch;1531 while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)1532 {1533 if (ch == '\r' || ch == '\n')1534 {1535 if (chPrev != '\\')1536 {1537 rcExit = vbcppError(pThis, "Missing ')'");1538 break;1539 }1540 ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);1541 }1542 if (ch == ')')1543 {1544 cchParams = ScmStreamGetCur(pStrmInput) - pchParams;1545 ScmStreamGetCh(pStrmInput);1546 break;1547 }1548 ScmStreamGetCh(pStrmInput);1549 }1550 }1551 /* The simple kind. */1552 else if (!RT_C_IS_SPACE(ch) && ch != ~(unsigned)0)1553 rcExit = vbcppError(pThis, "Expected whitespace after macro name");1554 1555 /* Parse out the value. */1556 if (rcExit == RTEXITCODE_SUCCESS)1557 rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);1558 if (rcExit == RTEXITCODE_SUCCESS)1559 {1560 size_t offValue = ScmStreamTell(pStrmInput);1561 const char *pchValue = ScmStreamGetCur(pStrmInput);1562 unsigned chPrev = ch;1563 while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)1564 {1565 if (ch == '\r' || ch == '\n')1566 {1567 if (chPrev != '\\')1568 break;1569 ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);1570 }1571 ScmStreamGetCh(pStrmInput);1572 }1573 size_t cchValue = ScmStreamGetCur(pStrmInput) - pchValue;1574 1575 /*1576 * Execute.1577 */1578 if (pchParams)1579 rcExit = vbcppDefineAddFn(pThis, pchDefine, cchDefine, pchParams, cchParams, pchValue, cchValue, false);1580 else1581 rcExit = vbcppDefineAdd(pThis, pchDefine, cchDefine, pchValue, cchValue, false);1582 1583 /*1584 * Pass thru?1585 */1586 if ( rcExit == RTEXITCODE_SUCCESS1587 && pThis->fPassThruDefines)1588 {1589 unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;1590 size_t cch;1591 if (pchParams)1592 cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s(%.*s)",1593 cchIndent, "", cchDefine, pchDefine, cchParams, pchParams);1594 else1595 cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s",1596 cchIndent, "", cchDefine, pchDefine);1597 if (cch > 0)1598 vbcppOutputComment(pThis, pStrmInput, offValue, cch, 1);1599 else1600 rcExit = vbcppError(pThis, "output error");1601 }1602 }1603 1604 }1605 }1606 return rcExit;1607 }1608 1609 1610 /**1611 * Processes a abbreviated line number directive.1612 *1613 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1614 * @param pThis The C preprocessor instance.1615 * @param pStrmInput The input stream.1616 * @param offStart The stream position where the directive1617 * started (for pass thru).1618 */1619 static RTEXITCODE vbcppProcessUndef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1620 {1621 return vbcppError(pThis, "Not implemented %s", __FUNCTION__);1622 }1623 1624 1625 /**1626 * Combines current stack result with the one being pushed.1627 *1628 * @returns Combined result.1629 * @param enmEvalPush The result of the condition being pushed.1630 * @param enmEvalStack The current stack result.1631 */1632 static VBCPPEVAL vbcppCondCombine(VBCPPEVAL enmEvalPush, VBCPPEVAL enmEvalStack)1633 {1634 if (enmEvalStack == kVBCppEval_False)1635 return kVBCppEval_False;1636 return enmEvalPush;1637 }1638 1639 1640 /**1641 * Pushes an conditional onto the stack.1642 *1643 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1644 * @param pThis The C preprocessor instance.1645 * @param pStrmInput The current input stream.1646 * @param offStart Not currently used, using @a pchCondition and1647 * @a cchCondition instead.1648 * @param enmKind The kind of conditional.1649 * @param enmResult The result of the evaluation.1650 * @param pchCondition The raw condition.1651 * @param cchCondition The length of @a pchCondition.1652 */1653 static RTEXITCODE vbcppCondPush(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart,1654 VBCPPCONDKIND enmKind, VBCPPEVAL enmResult,1655 const char *pchCondition, size_t cchCondition)1656 {1657 if (pThis->cCondStackDepth >= _64K)1658 return vbcppError(pThis, "Too many nested #if/#ifdef/#ifndef statements");1659 1660 /*1661 * Allocate a new entry and push it.1662 */1663 PVBCPPCOND pCond = (PVBCPPCOND)RTMemAlloc(sizeof(*pCond));1664 if (!pCond)1665 return vbcppError(pThis, "out of memory");1666 1667 PVBCPPCOND pUp = pThis->pCondStack;1668 pCond->enmKind = enmKind;1669 pCond->enmResult = enmResult;1670 pCond->enmStackResult = pUp ? vbcppCondCombine(enmResult, pUp->enmStackResult) : enmResult;1671 pCond->fSeenElse = false;1672 pCond->iLevel = pThis->cCondStackDepth;1673 pCond->iKeepLevel = (pUp ? pUp->iKeepLevel : 0) + enmResult == kVBCppEval_Undecided;1674 pCond->pchCond = pchCondition;1675 pCond->cchCond = cchCondition;1676 1677 pCond->pUp = pThis->pCondStack;1678 pThis->pCondStack = pCond;1679 pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;1680 1681 /*1682 * Do pass thru.1683 */1684 if ( !pThis->fIf0Mode1685 && enmResult == kVBCppEval_Undecided)1686 {1687 /** @todo this is stripping comments of \#ifdef and \#ifndef atm. */1688 const char *pszDirective;1689 switch (enmKind)1690 {1691 case kVBCppCondKind_If: pszDirective = "if"; break;1692 case kVBCppCondKind_IfDef: pszDirective = "ifdef"; break;1693 case kVBCppCondKind_IfNDef: pszDirective = "ifndef"; break;1694 case kVBCppCondKind_ElIf: pszDirective = "elif"; break;1695 default: AssertFailedReturn(RTEXITCODE_FAILURE);1696 }1697 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*s%s %.*s",1698 pCond->iKeepLevel - 1, "", pszDirective, cchCondition, pchCondition);1699 if (cch < 0)1700 return vbcppError(pThis, "Output error %Rrc", (int)cch);1701 }1702 1703 return RTEXITCODE_SUCCESS;1704 }1705 1706 1707 /**1708 * Processes a abbreviated line number directive.1709 *1710 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1711 * @param pThis The C preprocessor instance.1712 * @param pStrmInput The input stream.1713 * @param offStart The stream position where the directive1714 * started (for pass thru).1715 */1716 static RTEXITCODE vbcppProcessIf(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1717 {1718 return vbcppError(pThis, "Not implemented %s", __FUNCTION__);1719 }1720 1721 1722 /**1723 * Processes a abbreviated line number directive.1724 *1725 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1726 * @param pThis The C preprocessor instance.1727 * @param pStrmInput The input stream.1728 * @param offStart The stream position where the directive1729 * started (for pass thru).1730 */1731 static RTEXITCODE vbcppProcessIfDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1732 {1733 /*1734 * Parse it.1735 */1736 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);1737 if (rcExit == RTEXITCODE_SUCCESS)1738 {1739 size_t cchDefine;1740 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);1741 if (pchDefine)1742 {1743 rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);1744 if (rcExit == RTEXITCODE_SUCCESS)1745 {1746 /*1747 * Evaluate it.1748 */1749 VBCPPEVAL enmEval;1750 if (vbcppDefineExists(pThis, pchDefine, cchDefine))1751 enmEval = kVBCppEval_True;1752 else if ( pThis->fUndecidedConditionals1753 || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)1754 enmEval = kVBCppEval_False;1755 else1756 enmEval = kVBCppEval_Undecided;1757 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfDef, enmEval,1758 pchDefine, cchDefine);1759 }1760 }1761 else1762 rcExit = vbcppError(pThis, "Malformed #ifdef");1763 }1764 return rcExit;1765 }1766 1767 1768 /**1769 * Processes a abbreviated line number directive.1770 *1771 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1772 * @param pThis The C preprocessor instance.1773 * @param pStrmInput The input stream.1774 * @param offStart The stream position where the directive1775 * started (for pass thru).1776 */1777 static RTEXITCODE vbcppProcessIfNDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1778 {1779 /*1780 * Parse it.1781 */1782 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);1783 if (rcExit == RTEXITCODE_SUCCESS)1784 {1785 size_t cchDefine;1786 const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);1787 if (pchDefine)1788 {1789 rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);1790 if (rcExit == RTEXITCODE_SUCCESS)1791 {1792 /*1793 * Evaluate it.1794 */1795 VBCPPEVAL enmEval;1796 if (vbcppDefineExists(pThis, pchDefine, cchDefine))1797 enmEval = kVBCppEval_False;1798 else if ( pThis->fUndecidedConditionals1799 || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)1800 enmEval = kVBCppEval_True;1801 else1802 enmEval = kVBCppEval_Undecided;1803 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfNDef, enmEval,1804 pchDefine, cchDefine);1805 }1806 }1807 else1808 rcExit = vbcppError(pThis, "Malformed #ifndef");1809 }1810 return rcExit;1811 }1812 1813 1814 /**1815 * Processes a abbreviated line number directive.1816 *1817 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1818 * @param pThis The C preprocessor instance.1819 * @param pStrmInput The input stream.1820 * @param offStart The stream position where the directive1821 * started (for pass thru).1822 */1823 static RTEXITCODE vbcppProcessElse(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1824 {1825 /*1826 * Nothing to parse, just comment positions to find and note down.1827 */1828 offStart = vbcppProcessSkipWhite(pStrmInput);1829 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);1830 if (rcExit == RTEXITCODE_SUCCESS)1831 {1832 /*1833 * Execute.1834 */1835 PVBCPPCOND pCond = pThis->pCondStack;1836 if (pCond)1837 {1838 if (!pCond->fSeenElse)1839 {1840 pCond->fSeenElse = true;1841 if ( pCond->enmResult != kVBCppEval_Undecided1842 && ( !pCond->pUp1843 || pCond->pUp->enmStackResult == kVBCppEval_True))1844 {1845 if (pCond->enmResult == kVBCppEval_True)1846 pCond->enmStackResult = kVBCppEval_False;1847 else1848 pCond->enmStackResult = kVBCppEval_True;1849 pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;1850 }1851 1852 /*1853 * Do pass thru.1854 */1855 if ( !pThis->fIf0Mode1856 && pCond->enmResult == kVBCppEval_Undecided)1857 {1858 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*selse", pCond->iKeepLevel - 1, "");1859 if (cch > 0)1860 rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 2);1861 else1862 rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);1863 }1864 }1865 else1866 rcExit = vbcppError(pThis, "Double #else or/and missing #endif");1867 }1868 else1869 rcExit = vbcppError(pThis, "#else without #if");1870 }1871 return rcExit;1872 }1873 1874 1875 /**1876 * Processes a abbreviated line number directive.1877 *1878 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1879 * @param pThis The C preprocessor instance.1880 * @param pStrmInput The input stream.1881 * @param offStart The stream position where the directive1882 * started (for pass thru).1883 */1884 static RTEXITCODE vbcppProcessEndif(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)1885 {1886 /*1887 * Nothing to parse, just comment positions to find and note down.1888 */1889 offStart = vbcppProcessSkipWhite(pStrmInput);1890 RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);1891 if (rcExit == RTEXITCODE_SUCCESS)1892 {1893 /*1894 * Execute.1895 */1896 PVBCPPCOND pCond = pThis->pCondStack;1897 if (pCond)1898 {1899 pThis->pCondStack = pCond->pUp;1900 pThis->fIf0Mode = pCond->pUp && pCond->pUp->enmStackResult == kVBCppEval_False;1901 1902 /*1903 * Do pass thru.1904 */1905 if ( !pThis->fIf0Mode1906 && pCond->enmResult == kVBCppEval_Undecided)1907 {1908 ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sendif", pCond->iKeepLevel - 1, "");1909 if (cch > 0)1910 rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 1);1911 else1912 rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);1913 }1914 }1915 else1916 rcExit = vbcppError(pThis, "#endif without #if");1917 }1918 return rcExit;1919 }1920 1921 1922 /**1923 * Processes a abbreviated line number directive.1924 *1925 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.1926 * @param pThis The C preprocessor instance.1927 * @param pStrmInput The input stream.1928 * @param offStart The stream position where the directive1929 * started (for pass thru).1930 */1931 1833 static RTEXITCODE vbcppProcessPragma(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart) 1932 1834 { … … 2024 1926 2025 1927 2026 /** 2027 * Processes a C word, possibly replacing it with a definition. 2028 * 2029 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg. 2030 * @param pThis The C preprocessor instance. 2031 * @param pStrmInput The input stream. 2032 * @param ch The first character. 2033 */ 2034 static RTEXITCODE vbcppProcessCWord(PVBCPP pThis, PSCMSTREAM pStrmInput, char ch) 2035 { 2036 /** @todo Implement this... */ 2037 return vbcppOutputCh(pThis, ch); 2038 } 1928 /* 1929 * 1930 * 1931 * M a i n b o d y. 1932 * M a i n b o d y. 1933 * M a i n b o d y. 1934 * M a i n b o d y. 1935 * M a i n b o d y. 1936 * 1937 * 1938 */ 2039 1939 2040 1940 … … 2127 2027 2128 2028 /** 2029 * Opens the input and output streams. 2030 * 2031 * @returns Exit code. 2032 * @param pThis The C preprocessor instance. 2033 */ 2034 static RTEXITCODE vbcppOpenStreams(PVBCPP pThis) 2035 { 2036 if (!pThis->pszInput) 2037 return vbcppError(pThis, "Preprocessing the standard input stream is currently not supported"); 2038 2039 size_t cchName = strlen(pThis->pszInput); 2040 PVBCPPINPUT pInput = (PVBCPPINPUT)RTMemAlloc(RT_OFFSETOF(VBCPPINPUT, szName[cchName + 1])); 2041 if (!pInput) 2042 return vbcppError(pThis, "out of memory"); 2043 pInput->pUp = pThis->pInputStack; 2044 pInput->pszSpecified = pInput->szName; 2045 memcpy(pInput->szName, pThis->pszInput, cchName + 1); 2046 pThis->pInputStack = pInput; 2047 int rc = ScmStreamInitForReading(&pInput->StrmInput, pThis->pszInput); 2048 if (RT_FAILURE(rc)) 2049 return vbcppError(pThis, "ScmStreamInitForReading returned %Rrc when opening input file (%s)", 2050 rc, pThis->pszInput); 2051 2052 rc = ScmStreamInitForWriting(&pThis->StrmOutput, &pInput->StrmInput); 2053 if (RT_FAILURE(rc)) 2054 return vbcppError(pThis, "ScmStreamInitForWriting returned %Rrc", rc); 2055 2056 pThis->fStrmOutputValid = true; 2057 return RTEXITCODE_SUCCESS; 2058 } 2059 2060 2061 /** 2062 * Changes the preprocessing mode. 2063 * 2064 * @param pThis The C preprocessor instance. 2065 * @param enmMode The new mode. 2066 */ 2067 static void vbcppSetMode(PVBCPP pThis, VBCPPMODE enmMode) 2068 { 2069 switch (enmMode) 2070 { 2071 case kVBCppMode_Standard: 2072 pThis->fKeepComments = false; 2073 pThis->fRespectSourceDefines = true; 2074 pThis->fAllowRedefiningCmdLineDefines = true; 2075 pThis->fPassThruDefines = false; 2076 pThis->fUndecidedConditionals = false; 2077 pThis->fLineSplicing = true; 2078 pThis->enmIncludeAction = kVBCppIncludeAction_Include; 2079 break; 2080 2081 case kVBCppMode_Selective: 2082 pThis->fKeepComments = true; 2083 pThis->fRespectSourceDefines = false; 2084 pThis->fAllowRedefiningCmdLineDefines = false; 2085 pThis->fPassThruDefines = true; 2086 pThis->fUndecidedConditionals = true; 2087 pThis->fLineSplicing = false; 2088 pThis->enmIncludeAction = kVBCppIncludeAction_PassThru; 2089 break; 2090 2091 case kVBCppMode_SelectiveD: 2092 pThis->fKeepComments = true; 2093 pThis->fRespectSourceDefines = true; 2094 pThis->fAllowRedefiningCmdLineDefines = false; 2095 pThis->fPassThruDefines = false; 2096 pThis->fUndecidedConditionals = false; 2097 pThis->fLineSplicing = false; 2098 pThis->enmIncludeAction = kVBCppIncludeAction_Drop; 2099 break; 2100 2101 default: 2102 AssertFailedReturnVoid(); 2103 } 2104 pThis->enmMode = enmMode; 2105 } 2106 2107 2108 /** 2109 * Parses the command line options. 2110 * 2111 * @returns Program exit code. Exit on non-success or if *pfExit is set. 2112 * @param pThis The C preprocessor instance. 2113 * @param argc The argument count. 2114 * @param argv The argument vector. 2115 * @param pfExit Pointer to the exit indicator. 2116 */ 2117 static RTEXITCODE vbcppParseOptions(PVBCPP pThis, int argc, char **argv, bool *pfExit) 2118 { 2119 RTEXITCODE rcExit; 2120 2121 *pfExit = false; 2122 2123 /* 2124 * Option config. 2125 */ 2126 static RTGETOPTDEF const s_aOpts[] = 2127 { 2128 { "--define", 'D', RTGETOPT_REQ_STRING }, 2129 { "--include-dir", 'I', RTGETOPT_REQ_STRING }, 2130 { "--undefine", 'U', RTGETOPT_REQ_STRING }, 2131 { "--keep-comments", 'C', RTGETOPT_REQ_NOTHING }, 2132 { "--strip-comments", 'c', RTGETOPT_REQ_NOTHING }, 2133 { "--D-strip", 'd', RTGETOPT_REQ_NOTHING }, 2134 }; 2135 2136 RTGETOPTUNION ValueUnion; 2137 RTGETOPTSTATE GetOptState; 2138 int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2139 AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE); 2140 2141 /* 2142 * Process the options. 2143 */ 2144 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0) 2145 { 2146 switch (rc) 2147 { 2148 case 'c': 2149 pThis->fKeepComments = false; 2150 break; 2151 2152 case 'C': 2153 pThis->fKeepComments = false; 2154 break; 2155 2156 case 'd': 2157 vbcppSetMode(pThis, kVBCppMode_SelectiveD); 2158 break; 2159 2160 case 'D': 2161 { 2162 const char *pszEqual = strchr(ValueUnion.psz, '='); 2163 if (pszEqual) 2164 rcExit = vbcppDefineAdd(pThis, ValueUnion.psz, pszEqual - ValueUnion.psz, pszEqual + 1, RTSTR_MAX, true); 2165 else 2166 rcExit = vbcppDefineAdd(pThis, ValueUnion.psz, RTSTR_MAX, "1", 1, true); 2167 if (rcExit != RTEXITCODE_SUCCESS) 2168 return rcExit; 2169 break; 2170 } 2171 2172 case 'I': 2173 rcExit = vbcppAddInclude(pThis, ValueUnion.psz); 2174 if (rcExit != RTEXITCODE_SUCCESS) 2175 return rcExit; 2176 break; 2177 2178 case 'U': 2179 rcExit = vbcppDefineUndef(pThis, ValueUnion.psz, RTSTR_MAX, true); 2180 break; 2181 2182 case 'h': 2183 RTPrintf("No help yet, sorry\n"); 2184 *pfExit = true; 2185 return RTEXITCODE_SUCCESS; 2186 2187 case 'V': 2188 { 2189 /* The following is assuming that svn does it's job here. */ 2190 static const char s_szRev[] = "$Revision$"; 2191 const char *psz = RTStrStripL(strchr(s_szRev, ' ')); 2192 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz); 2193 *pfExit = true; 2194 return RTEXITCODE_SUCCESS; 2195 } 2196 2197 case VINF_GETOPT_NOT_OPTION: 2198 if (!pThis->pszInput) 2199 pThis->pszInput = ValueUnion.psz; 2200 else if (!pThis->pszOutput) 2201 pThis->pszOutput = ValueUnion.psz; 2202 else 2203 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "too many file arguments"); 2204 break; 2205 2206 2207 /* 2208 * Errors and bugs. 2209 */ 2210 default: 2211 return RTGetOptPrintError(rc, &ValueUnion); 2212 } 2213 } 2214 2215 return RTEXITCODE_SUCCESS; 2216 } 2217 2218 2219 /** 2129 2220 * Terminates the preprocessor. 2130 2221 * … … 2178 2269 2179 2270 return pThis->rcExit; 2271 } 2272 2273 2274 /** 2275 * Initializes the C preprocessor instance data. 2276 * 2277 * @param pThis The C preprocessor instance data. 2278 */ 2279 static void vbcppInit(PVBCPP pThis) 2280 { 2281 vbcppSetMode(pThis, kVBCppMode_Selective); 2282 pThis->cIncludes = 0; 2283 pThis->papszIncludes = NULL; 2284 pThis->pszInput = NULL; 2285 pThis->pszOutput = NULL; 2286 pThis->StrSpace = NULL; 2287 pThis->UndefStrSpace = NULL; 2288 pThis->pExpStack = NULL; 2289 pThis->cExpStackDepth = 0; 2290 pThis->cCondStackDepth = 0; 2291 pThis->pCondStack = NULL; 2292 pThis->fIf0Mode = false; 2293 pThis->fMaybePreprocessorLine = true; 2294 VBCPP_BITMAP_EMPTY(pThis->bmDefined); 2295 VBCPP_BITMAP_EMPTY(pThis->bmArgs); 2296 pThis->cCondStackDepth = 0; 2297 pThis->pInputStack = NULL; 2298 RT_ZERO(pThis->StrmOutput); 2299 pThis->rcExit = RTEXITCODE_SUCCESS; 2300 pThis->fStrmOutputValid = false; 2180 2301 } 2181 2302
Note:
See TracChangeset
for help on using the changeset viewer.