VirtualBox

Changeset 41204 in vbox for trunk


Ignore:
Timestamp:
May 8, 2012 12:14:06 PM (13 years ago)
Author:
vboxsync
Message:

Moved the code around in a more logical order.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bldprogs/VBoxCPP.cpp

    r41202 r41204  
    309309
    310310
    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 */
    391325
    392326
     
    457391
    458392
     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
    459409/**
    460410 * Checks if the given character is a valid C identifier lead character.
     
    523473
    524474
    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 */
    1018490
    1019491
     
    1089561
    1090562
    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 */
    1258577
    1259578
     
    1392711}
    1393712
     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 */
     724static 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 */
     780static 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 */
     818static 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 */
     855static 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 */
     891static 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 */
     925static 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 */
     940static 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 */
     958static 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 */
     994static 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 */
     1055static 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 */
     1175static 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 */
     1249static 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 */
     1359static 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 */
     1388static 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 */
     1409static 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 */
     1472static 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 */
     1487static 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 */
     1533static 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 */
     1579static 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 */
     1640static 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 */
     1700static 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}
    13941718
    13951719
     
    15071831 *                              started (for pass thru).
    15081832 */
    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                 else
    1581                     rcExit = vbcppDefineAdd(pThis, pchDefine, cchDefine, pchValue, cchValue, false);
    1582 
    1583                 /*
    1584                  * Pass thru?
    1585                  */
    1586                 if (   rcExit == RTEXITCODE_SUCCESS
    1587                     && 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                     else
    1595                         cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s",
    1596                                               cchIndent, "", cchDefine, pchDefine);
    1597                     if (cch > 0)
    1598                         vbcppOutputComment(pThis, pStrmInput, offValue, cch, 1);
    1599                     else
    1600                         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 directive
    1617  *                              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 and
    1647  *                              @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->fIf0Mode
    1685         && 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 directive
    1714  *                              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 directive
    1729  *                              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->fUndecidedConditionals
    1753                          || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)
    1754                     enmEval = kVBCppEval_False;
    1755                 else
    1756                     enmEval = kVBCppEval_Undecided;
    1757                 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfDef, enmEval,
    1758                                        pchDefine, cchDefine);
    1759             }
    1760         }
    1761         else
    1762             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 directive
    1775  *                              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->fUndecidedConditionals
    1799                          || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)
    1800                     enmEval = kVBCppEval_True;
    1801                 else
    1802                     enmEval = kVBCppEval_Undecided;
    1803                 rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfNDef, enmEval,
    1804                                        pchDefine, cchDefine);
    1805             }
    1806         }
    1807         else
    1808             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 directive
    1821  *                              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_Undecided
    1842                     && (   !pCond->pUp
    1843                         || pCond->pUp->enmStackResult == kVBCppEval_True))
    1844                 {
    1845                     if (pCond->enmResult == kVBCppEval_True)
    1846                         pCond->enmStackResult = kVBCppEval_False;
    1847                     else
    1848                         pCond->enmStackResult = kVBCppEval_True;
    1849                     pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;
    1850                 }
    1851 
    1852                 /*
    1853                  * Do pass thru.
    1854                  */
    1855                 if (   !pThis->fIf0Mode
    1856                     && 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                     else
    1862                         rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
    1863                 }
    1864             }
    1865             else
    1866                 rcExit = vbcppError(pThis, "Double #else or/and missing #endif");
    1867         }
    1868         else
    1869             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 directive
    1882  *                              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->fIf0Mode
    1906                 && 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                 else
    1912                     rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
    1913             }
    1914         }
    1915         else
    1916             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 directive
    1929  *                              started (for pass thru).
    1930  */
    19311833static RTEXITCODE vbcppProcessPragma(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
    19321834{
     
    20241926
    20251927
    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 */
    20391939
    20401940
     
    21272027
    21282028/**
     2029 * Opens the input and output streams.
     2030 *
     2031 * @returns Exit code.
     2032 * @param   pThis               The C preprocessor instance.
     2033 */
     2034static 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 */
     2067static 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 */
     2117static 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/**
    21292220 * Terminates the preprocessor.
    21302221 *
     
    21782269
    21792270    return pThis->rcExit;
     2271}
     2272
     2273
     2274/**
     2275 * Initializes the C preprocessor instance data.
     2276 *
     2277 * @param   pThis               The C preprocessor instance data.
     2278 */
     2279static 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;
    21802301}
    21812302
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette