VirtualBox

Ignore:
Timestamp:
Apr 18, 2008 1:49:01 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
29853
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.

File:
1 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
Note: See TracChangeset for help on using the changeset viewer.

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