VirtualBox

Changeset 17141 in vbox for trunk


Ignore:
Timestamp:
Feb 25, 2009 5:09:22 PM (16 years ago)
Author:
vboxsync
Message:

IPRT: Added support for short option lists (ls -latrT4). This fixes a bug in the short option without values, where we didn't check that the following char was the string terminator.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/getopt.h

    r17096 r17141  
    166166    /** Number of items in paOptions. */
    167167    size_t          cOptions;
     168    /** The next short option.
     169     * (For parsing ls -latrT4 kind of option lists.) */
     170    const char     *pszNextShort;
    168171    /* More members will be added later for dealing with initial
    169172       call, optional sorting, '--' and so on. */
  • trunk/src/VBox/Runtime/common/misc/getopt.cpp

    r17101 r17141  
    4646    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
    4747
    48     pState->argv        = argv;
    49     pState->argc        = argc;
    50     pState->paOptions   = paOptions;
    51     pState->cOptions    = cOptions;
    52     pState->iNext       = iFirst;
     48    pState->argv         = argv;
     49    pState->argc         = argc;
     50    pState->paOptions    = paOptions;
     51    pState->cOptions     = cOptions;
     52    pState->iNext        = iFirst;
     53    pState->pszNextShort = NULL;
    5354
    5455    /* validate the options. */
     
    127128RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion)
    128129{
     130    /*
     131     * Make sure the union is completely cleared out, whatever happens below.
     132     */
    129133    pValueUnion->u64 = 0;
    130134    pValueUnion->pDef = NULL;
    131135
    132     if (pState->iNext >= pState->argc)
    133         return 0;
     136    /*
     137     * The next option.
     138     */
     139    bool            fShort;
     140    int             iThis;
     141    const char     *pszArgThis;
     142    PCRTGETOPTDEF   pOpt;
     143
     144    if (pState->pszNextShort)
     145    {
     146        /*
     147         * We've got short options left over from the previous call.
     148         */
     149        pOpt = rtGetOptSearchShort(*pState->pszNextShort, pState->paOptions, pState->cOptions);
     150        if (!pOpt)
     151        {
     152            pValueUnion->psz = pState->pszNextShort;
     153            return VERR_GETOPT_UNKNOWN_OPTION;
     154        }
     155        pState->pszNextShort++;
     156        pszArgThis = pState->pszNextShort - 2;
     157        iThis = pState->iNext;
     158        fShort = true;
     159    }
     160    else
     161    {
     162        /*
     163         * Pop off the next argument.
     164         */
     165        if (pState->iNext >= pState->argc)
     166            return 0;
     167        iThis = pState->iNext++;
     168        pszArgThis = pState->argv[iThis];
     169
     170        /*
     171         * Do a long option search first and the a short option one.
     172         * This way we can make sure single dash long options doesn't
     173         * get mixed up with short ones.
     174         */
     175        pOpt = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions);
     176        if (    !pOpt
     177            &&  pszArgThis[0] == '-'
     178            &&  pszArgThis[1] != '-'
     179            &&  pszArgThis[1] != '\0')
     180        {
     181            pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions);
     182            fShort = pOpt != NULL;
     183        }
     184        else
     185            fShort = false;
     186    }
     187
    134188
    135189    /** @todo Handle '--' and possibly implement an RTGetOptInit that lets us
     
    140194     */
    141195
    142     /*
    143      * Pop off the next argument.
    144      */
    145     int             iThis = pState->iNext++;
    146     const char     *pszArgThis = pState->argv[iThis];
    147 
    148     /*
    149      * Do a long option search first and the a short option one.
    150      * This way we can make sure single dash long options doesn't
    151      * get mixed up with short ones.
    152      */
    153     bool            fShort = false;
    154     PCRTGETOPTDEF   pOpt   = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions);
    155     if (    !pOpt
    156         &&  pszArgThis[0] == '-'
    157         &&  pszArgThis[1] != '-'
    158         &&  pszArgThis[1] != '\0')
    159     {
    160         pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions);
    161         fShort = pOpt != NULL;
    162     }
    163196    if (pOpt)
    164197    {
     
    191224                else /* same argument. */
    192225                    pszValue = &pszArgThis[2  + (pszArgThis[2] == ':' || pszArgThis[2] == '=')];
     226                if (pState->pszNextShort)
     227                {
     228                    pState->pszNextShort = NULL;
     229                    pState->iNext++;
     230                }
    193231            }
    194232            else
     
    285323            }
    286324        }
     325        else if (fShort)
     326        {
     327            /*
     328             * Deal with "compressed" short option lists, correcting the next
     329             * state variables for the start and end cases.
     330             */
     331            if (pszArgThis[2])
     332            {
     333                if (!pState->pszNextShort)
     334                {
     335                    /* start */
     336                    pState->pszNextShort = &pszArgThis[2];
     337                    pState->iNext--;
     338                }
     339            }
     340            else if (pState->pszNextShort)
     341            {
     342                /* end */
     343                pState->pszNextShort = NULL;
     344                pState->iNext++;
     345            }
     346        }
     347
    287348        return pOpt->iShort;
    288349    }
     
    294355
    295356    if (*pszArgThis == '-')
     357    {
     358        pValueUnion->psz = pszArgThis;
    296359        return VERR_GETOPT_UNKNOWN_OPTION;
     360    }
    297361
    298362    pValueUnion->psz = pszArgThis;
  • trunk/src/VBox/Runtime/testcase/tstGetOpt.cpp

    r17100 r17141  
    4141    int cErrors = 0;
    4242    RTR3Init();
     43    RTPrintf("tstGetOpt: TESTING...\n");
    4344
    4445    RTGETOPTSTATE GetState;
    4546    RTGETOPTUNION Val;
    4647#define CHECK(expr)  do { if (!(expr)) { RTPrintf("tstGetOpt: error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); cErrors++; } } while (0)
     48#define CHECK2(expr, fmt) \
     49    do { \
     50        if (!(expr)) { \
     51            RTPrintf("tstGetOpt: error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); \
     52            RTPrintf fmt; \
     53            cErrors++; \
     54         } \
     55    } while (0)
     56
     57#define CHECK_pDef(paOpts, i) \
     58    CHECK2(Val.pDef == &(paOpts)[(i)], ("Got #%d (%p) expected #%d\n", (int)(Val.pDef - &(paOpts)[0]), Val.pDef, i));
    4759
    4860#define CHECK_GETOPT(expr, chRet, iInc) \
    4961    do { \
    5062        const int iPrev = GetState.iNext; \
    51         CHECK((expr) == (chRet)); \
    52         CHECK(GetState.iNext == (iInc) + iPrev); \
     63        const int rc = (expr); \
     64        CHECK2(rc == (chRet), ("got %d, expected %d\n", rc, (chRet))); \
     65        CHECK2(GetState.iNext == (iInc) + iPrev, ("iNext=%d expected %d\n", GetState.iNext, (iInc) + iPrev)); \
    5366        GetState.iNext = (iInc) + iPrev; \
    5467    } while (0)
    5568
     69
     70
    5671    /*
    57      * Simple.
     72     * The basics.
    5873     */
    5974    static const RTGETOPTDEF s_aOpts2[] =
     
    6479        { NULL,                 'q', RTGETOPT_REQ_NOTHING },
    6580        { "--quiet",            384, RTGETOPT_REQ_NOTHING },
    66         { "-startvm",           385, RTGETOPT_REQ_NOTHING },
     81        { "-novalue",           385, RTGETOPT_REQ_NOTHING },
     82        { "-startvm",           386, RTGETOPT_REQ_STRING },
     83        { "nodash",             387, RTGETOPT_REQ_NOTHING },
     84        { "nodashval",          388, RTGETOPT_REQ_STRING },
    6785    };
    6886
     
    7189        "-s",               "string1",
    7290        "--optwithstring",  "string2",
     91
    7392        "-i",               "-42",
    7493        "-i:-42",
     
    7695        "-i:",              "-42",
    7796        "-i=",              "-42",
     97
    7898        "--optwithint",     "42",
    7999        "--optwithint:42",
     
    81101        "--optwithint:",    "42",
    82102        "--optwithint=",    "42",
     103
    83104        "-v",
    84105        "--verbose",
    85106        "-q",
    86107        "--quiet",
    87         "-startvm",
     108
     109        "-novalue",
     110        "-startvm",         "myvm",
     111
     112        "nodash",
     113        "nodashval",        "string3",
     114
    88115        "filename1",
    89116        "-q",
    90117        "filename2",
     118
     119        "-vqi999",
    91120        NULL
    92121    };
     
    125154
    126155    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1);
    127     CHECK(Val.pDef == &s_aOpts2[2]);
     156    CHECK_pDef(s_aOpts2, 2);
    128157    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1);
    129     CHECK(Val.pDef == &s_aOpts2[2]);
     158    CHECK_pDef(s_aOpts2, 2);
     159
    130160    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1);
    131     CHECK(Val.pDef == &s_aOpts2[3]);
     161    CHECK_pDef(s_aOpts2, 3);
    132162    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 384, 1);
    133     CHECK(Val.pDef == &s_aOpts2[4]);
     163    CHECK_pDef(s_aOpts2, 4);
     164
     165    /* -novalue / -startvm (single dash long options) */
    134166    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 385, 1);
    135     CHECK(Val.pDef == &s_aOpts2[5]);
    136 
     167    CHECK_pDef(s_aOpts2, 5);
     168    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 386, 2);
     169    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "myvm"));
     170
     171    /* no-dash options */
     172    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 387, 1);
     173    CHECK_pDef(s_aOpts2, 7);
     174    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 388, 2);
     175    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string3"));
     176
     177    /* non-option, option, non-option  */
    137178    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1);
    138179    CHECK(Val.psz && !strcmp(Val.psz, "filename1"));
    139180    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1);
    140     CHECK(Val.pDef == &s_aOpts2[3]);
     181    CHECK_pDef(s_aOpts2, 3);
    141182    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1);
    142183    CHECK(Val.psz && !strcmp(Val.psz, "filename2"));
    143184
     185    /* compress short options */
     186    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 0);
     187    CHECK_pDef(s_aOpts2, 2);
     188    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 0);
     189    CHECK_pDef(s_aOpts2, 3);
     190    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
     191    CHECK(Val.i32 == 999);
     192
     193    /* the end */
    144194    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0);
    145195    CHECK(Val.pDef == NULL);
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