- Timestamp:
- Apr 18, 2008 1:49:01 PM (17 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/getopt.cpp
r6000 r8147 32 32 #include <iprt/string.h> 33 33 #include <iprt/assert.h> 34 #include <iprt/ctype.h> 34 35 35 36 36 37 37 RTDECL(int) RTGetOpt(int argc, char * argv[], PCRTOPTIONDEF paOptions, size_t cOptions, int *piThis, PRTOPTIONUNION pValueUnion)38 RTDECL(int) RTGetOpt(int argc, char **argv, PCRTOPTIONDEF paOptions, size_t cOptions, int *piThis, PRTOPTIONUNION pValueUnion) 38 39 { 40 pValueUnion->u64 = 0; 39 41 pValueUnion->pDef = NULL; 40 42 … … 51 53 for (size_t i = 0; i < cOptions; i++) 52 54 { 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) 60 58 { 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. */ 63 78 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]; 68 97 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)) 71 105 { 72 106 case RTGETOPT_REQ_STRING: 73 pValueUnion->psz = argv[iNext];107 pValueUnion->psz = pszValue; 74 108 break; 75 109 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; \ 84 131 } 85 132 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 95 170 96 171 default: … … 98 173 return VERR_INTERNAL_ERROR; 99 174 } 175 return paOptions[i].iShort; 100 176 } 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]; 102 185 return paOptions[i].iShort; 103 186 } … … 105 188 } 106 189 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 108 191 * encountering the first argument. */ 109 192 -
trunk/src/VBox/Runtime/testcase/tstGetOpt.cpp
r6000 r8147 42 42 #define CHECK(expr) do { if (!(expr)) { RTPrintf("tstGetOpt: error line %d (i=%d): %s\n", __LINE__, i, #expr); cErrors++; } } while (0) 43 43 44 #define CHECK_GETOPT(expr, chRet, i Next) \44 #define CHECK_GETOPT(expr, chRet, iInc) \ 45 45 do { \ 46 const int iPrev = i; \ 46 47 CHECK((expr) == (chRet)); \ 47 CHECK(i == (i Next)); \48 i = (i Next); \48 CHECK(i == (iInc) + iPrev); \ 49 i = (iInc) + iPrev; \ 49 50 } while (0) 50 51 … … 52 53 * Simple. 53 54 */ 54 static const RTOPTIONDEF s_aOpts2[] = 55 static const RTOPTIONDEF s_aOpts2[] = 55 56 { 56 57 { "--optwithstring", 's', RTGETOPT_REQ_STRING }, … … 61 62 }; 62 63 63 char *argv2[] = 64 char *argv2[] = 64 65 { 65 66 "-s", "string1", 66 67 "--optwithstring", "string2", 67 68 "-i", "-42", 69 "-i:-42", 70 "-i=-42", 71 "-i:", "-42", 72 "-i=", "-42", 68 73 "--optwithint", "42", 74 "--optwithint:42", 75 "--optwithint=42", 76 "--optwithint:", "42", 77 "--optwithint=", "42", 69 78 "-v", 70 79 "--verbose", … … 80 89 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 's', 2); 81 90 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); 83 92 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); 85 96 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); 87 108 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); 89 119 CHECK(Val.pDef == &s_aOpts2[2]); 90 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 1 0);120 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'v', 1); 91 121 CHECK(Val.pDef == &s_aOpts2[2]); 92 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'q', 1 1);122 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 'q', 1); 93 123 CHECK(Val.pDef == &s_aOpts2[3]); 94 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 384, 1 2);124 CHECK_GETOPT(RTGetOpt(argc2, argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), &i, &Val), 384, 1); 95 125 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); 97 127 CHECK(Val.pDef == NULL); 98 128 CHECK(argc2 == i);
Note:
See TracChangeset
for help on using the changeset viewer.