VirtualBox

Changeset 8147 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Apr 18, 2008 1:49:01 PM (17 years ago)
Author:
vboxsync
Message:

Extended RTGetOpt:

o Support 8-, 16- and 64-bit types too.
o Added flags to force hexadecimal, decimal or octal value baseing.
o When no hex/dec/oct flag is present, default to decimal but recognize the hex prefix (0x).
o Support the usual option value separators ([:= ]) and not just space.

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/getopt.cpp

    r6000 r8147  
    3232#include <iprt/string.h>
    3333#include <iprt/assert.h>
     34#include <iprt/ctype.h>
    3435
    3536
    3637
    37 RTDECL(int) RTGetOpt(int argc, char *argv[], PCRTOPTIONDEF paOptions, size_t cOptions, int *piThis, PRTOPTIONUNION pValueUnion)
     38RTDECL(int) RTGetOpt(int argc, char **argv, PCRTOPTIONDEF paOptions, size_t cOptions, int *piThis, PRTOPTIONUNION pValueUnion)
    3839{
     40    pValueUnion->u64 = 0;
    3941    pValueUnion->pDef = NULL;
    4042
     
    5153        for (size_t i = 0; i < cOptions; i++)
    5254        {
    53             bool fShort = false;
    54             if (    (   paOptions[i].pszLong
    55                      && !strcmp(pszArgThis, paOptions[i].pszLong))
    56                 ||  (   (fShort = (pszArgThis[1] == paOptions[i].iShort))
    57                      && pszArgThis[2] == '\0'
    58                     )
    59                )
     55            Assert(!(paOptions[i].fFlags & ~RTGETOPT_VALID_MASK));
     56
     57            if ((paOptions[i].fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
    6058            {
    61                 Assert(!(paOptions[i].fFlags & ~RTGETOPT_REQ_MASK));
    62                 pValueUnion->pDef = &paOptions[i];
     59                /*
     60                 * A value is required with the argument. We're trying to very
     61                 * understanding here and will permit any of the following:
     62                 *      -svalue, -s:value, -s=value,
     63                 *      -s value, -s: value, -s= value
     64                 * (Ditto for long options.)
     65                 */
     66                bool fShort = false;
     67                size_t cchLong = 2;
     68                if (    (   paOptions[i].pszLong
     69                         && !strncmp(pszArgThis, paOptions[i].pszLong, (cchLong = strlen(paOptions[i].pszLong)))
     70                         && (   pszArgThis[cchLong] == '\0'
     71                             || pszArgThis[cchLong] == ':'
     72                             || pszArgThis[cchLong] == '=')
     73                        )
     74                    ||  (fShort = (pszArgThis[1] == paOptions[i].iShort))
     75                   )
     76                {
     77                    pValueUnion->pDef = &paOptions[i]; /* in case of error. */
    6378
    64                 if ((paOptions[i].fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
    65                 {
    66                     if (iThis >= argc - 1)
    67                         return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
     79                    /*
     80                     * Find the argument value
     81                     */
     82                    const char *pszValue;
     83                    if (    fShort
     84                        ?       pszArgThis[2] == '\0'
     85                            || ((pszArgThis[2] == ':' || pszArgThis[2] == '=') && pszArgThis[3] == '\0')
     86                        :   pszArgThis[cchLong] == '\0' || pszArgThis[cchLong + 1] == '\0')
     87                    {
     88                        if (iThis + 1 >= argc)
     89                            return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
     90                        pszValue = argv[iThis + 1];
     91                        (*piThis)++;
     92                    }
     93                    else /* same argument. */
     94                        pszValue = fShort
     95                                 ? &pszArgThis[2  + (pszArgThis[2] == ':' || pszArgThis[2] == '=')]
     96                                 : &pszArgThis[cchLong + 1];
    6897
    69                     int iNext = (*piThis)++;
    70                     switch (paOptions[i].fFlags & RTGETOPT_REQ_MASK)
     98                    /*
     99                     * Transform into a option value as requested.
     100                     * If decimal conversion fails, we'll check for "0x<xdigit>" and
     101                     * try a 16 based conversion. We will not interpret any of the
     102                     * generic ints as octals.
     103                     */
     104                    switch (paOptions[i].fFlags & (RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_OCT | RTGETOPT_FLAG_DEC))
    71105                    {
    72106                        case RTGETOPT_REQ_STRING:
    73                             pValueUnion->psz = argv[iNext];
     107                            pValueUnion->psz = pszValue;
    74108                            break;
    75109
    76                         case RTGETOPT_REQ_INT32:
    77                         {
    78                             int32_t i32;
    79                             if (RTStrToInt32Full(argv[iNext], 10, &i32))
    80                                 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
    81 
    82                             pValueUnion->i32 = i32;
    83                             break;
     110#define MY_INT_CASE(req,type,memb,convfn) \
     111                        case req: \
     112                        { \
     113                            type Value; \
     114                            if (    convfn(pszValue, 10, &Value) != VINF_SUCCESS \
     115                                &&  (   pszValue[0] != '0' \
     116                                     || (pszValue[1] != 'x' && pszValue[1] != 'X') \
     117                                     || !RT_C_IS_XDIGIT(pszValue[2]) \
     118                                     || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
     119                                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
     120                            pValueUnion->memb = Value; \
     121                            break; \
     122                        }
     123#define MY_BASE_INT_CASE(req,type,memb,convfn,base) \
     124                        case req: \
     125                        { \
     126                            type Value; \
     127                            if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
     128                                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
     129                            pValueUnion->memb = Value; \
     130                            break; \
    84131                        }
    85132
    86                         case RTGETOPT_REQ_UINT32:
    87                         {
    88                             uint32_t u32;
    89                             if (RTStrToUInt32Full(argv[iNext], 10, &u32))
    90                                 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
    91    
    92                             pValueUnion->u32 = u32;
    93                             break;
    94                         }
     133                        MY_INT_CASE(RTGETOPT_REQ_INT8,   int8_t,   i,   RTStrToInt8Full)
     134                        MY_INT_CASE(RTGETOPT_REQ_INT16,  int16_t,  i,   RTStrToInt16Full)
     135                        MY_INT_CASE(RTGETOPT_REQ_INT32,  int32_t,  i,   RTStrToInt32Full)
     136                        MY_INT_CASE(RTGETOPT_REQ_INT64,  int64_t,  i,   RTStrToInt64Full)
     137                        MY_INT_CASE(RTGETOPT_REQ_UINT8,  uint8_t,  u,   RTStrToUInt8Full)
     138                        MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u,   RTStrToUInt16Full)
     139                        MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u,   RTStrToUInt32Full)
     140                        MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u,   RTStrToUInt64Full)
     141
     142                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_HEX, int8_t,   i,   RTStrToInt8Full,   16)
     143                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_HEX, int16_t,  i,   RTStrToInt16Full,  16)
     144                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_HEX, int32_t,  i,   RTStrToInt32Full,  16)
     145                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_HEX, int64_t,  i,   RTStrToInt64Full,  16)
     146                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_HEX, uint8_t,  u,   RTStrToUInt8Full,  16)
     147                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u,   RTStrToUInt16Full, 16)
     148                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u,   RTStrToUInt32Full, 16)
     149                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u,   RTStrToUInt64Full, 16)
     150
     151                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_DEC, int8_t,   i,   RTStrToInt8Full,   10)
     152                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_DEC, int16_t,  i,   RTStrToInt16Full,  10)
     153                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_DEC, int32_t,  i,   RTStrToInt32Full,  10)
     154                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_DEC, int64_t,  i,   RTStrToInt64Full,  10)
     155                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_DEC, uint8_t,  u,   RTStrToUInt8Full,  10)
     156                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u,   RTStrToUInt16Full, 10)
     157                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u,   RTStrToUInt32Full, 10)
     158                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u,   RTStrToUInt64Full, 10)
     159
     160                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_OCT, int8_t,   i,   RTStrToInt8Full,   8)
     161                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_OCT, int16_t,  i,   RTStrToInt16Full,  8)
     162                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_OCT, int32_t,  i,   RTStrToInt32Full,  8)
     163                        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_OCT, int64_t,  i,   RTStrToInt64Full,  8)
     164                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_OCT, uint8_t,  u,   RTStrToUInt8Full,  8)
     165                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u,   RTStrToUInt16Full, 8)
     166                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u,   RTStrToUInt32Full, 8)
     167                        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u,   RTStrToUInt64Full, 8)
     168#undef MY_INT_CASE
     169#undef MY_BASE_INT_CASE
    95170
    96171                        default:
     
    98173                            return VERR_INTERNAL_ERROR;
    99174                    }
     175                    return paOptions[i].iShort;
    100176                }
    101 
     177            }
     178            else if (   (   paOptions[i].pszLong
     179                         && !strcmp(pszArgThis, paOptions[i].pszLong))
     180                     || (   pszArgThis[1] == paOptions[i].iShort
     181                         && pszArgThis[2] == '\0') /** @todo implement support for ls -lsR like stuff?  */
     182                    )
     183            {
     184                pValueUnion->pDef = &paOptions[i];
    102185                return paOptions[i].iShort;
    103186            }
     
    105188    }
    106189
    107     /** @todo Sort options and arguments (i.e. stuff that doesn't start with '-'), stop when 
     190    /** @todo Sort options and arguments (i.e. stuff that doesn't start with '-'), stop when
    108191     * encountering the first argument. */
    109192
  • trunk/src/VBox/Runtime/testcase/tstGetOpt.cpp

    r6000 r8147  
    4242#define CHECK(expr)  do { if (!(expr)) { RTPrintf("tstGetOpt: error line %d (i=%d): %s\n", __LINE__, i, #expr); cErrors++; } } while (0)
    4343
    44 #define CHECK_GETOPT(expr, chRet, iNext) \
     44#define CHECK_GETOPT(expr, chRet, iInc) \
    4545    do { \
     46        const int iPrev = i; \
    4647        CHECK((expr) == (chRet)); \
    47         CHECK(i == (iNext)); \
    48         i = (iNext); \
     48        CHECK(i == (iInc) + iPrev); \
     49        i = (iInc) + iPrev; \
    4950    } while (0)
    5051
     
    5253     * Simple.
    5354     */
    54     static const RTOPTIONDEF s_aOpts2[] = 
     55    static const RTOPTIONDEF s_aOpts2[] =
    5556    {
    5657        { "--optwithstring",    's', RTGETOPT_REQ_STRING },
     
    6162    };
    6263
    63     char *argv2[] = 
     64    char *argv2[] =
    6465    {
    6566        "-s",               "string1",
    6667        "--optwithstring",  "string2",
    6768        "-i",               "-42",
     69        "-i:-42",
     70        "-i=-42",
     71        "-i:",              "-42",
     72        "-i=",              "-42",
    6873        "--optwithint",     "42",
     74        "--optwithint:42",
     75        "--optwithint=42",
     76        "--optwithint:",    "42",
     77        "--optwithint=",    "42",
    6978        "-v",
    7079        "--verbose",
     
    8089    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 's', 2);
    8190    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string1"));
    82     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 's', 4);
     91    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 's', 2);
    8392    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string2"));
    84     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 6);
     93
     94    /* -i */
     95    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
    8596    CHECK(Val.i32 == -42);
    86     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 8);
     97    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 1);
     98    CHECK(Val.i32 == -42);
     99    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 1);
     100    CHECK(Val.i32 == -42);
     101    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
     102    CHECK(Val.i32 == -42);
     103    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
     104    CHECK(Val.i32 == -42);
     105
     106    /* --optwithint */
     107    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
    87108    CHECK(Val.i32 == 42);
    88     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 9);
     109    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 1);
     110    CHECK(Val.i32 == 42);
     111    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 1);
     112    CHECK(Val.i32 == 42);
     113    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
     114    CHECK(Val.i32 == 42);
     115    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'i', 2);
     116    CHECK(Val.i32 == 42);
     117
     118    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 1);
    89119    CHECK(Val.pDef == &s_aOpts2[2]);
    90     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 10);
     120    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 1);
    91121    CHECK(Val.pDef == &s_aOpts2[2]);
    92     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'q', 11);
     122    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'q', 1);
    93123    CHECK(Val.pDef == &s_aOpts2[3]);
    94     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 384, 12);
     124    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 384, 1);
    95125    CHECK(Val.pDef == &s_aOpts2[4]);
    96     CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 0, 12);
     126    CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 0, 0);
    97127    CHECK(Val.pDef == NULL);
    98128    CHECK(argc2 == i);
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