Changeset 49326 in vbox
- Timestamp:
- Oct 30, 2013 4:33:40 AM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 90311
- Location:
- trunk
- Files:
-
- 4 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/mangling.h
r49182 r49326 961 961 # define RTNetTCPChecksum RT_MANGLER(RTNetTCPChecksum) 962 962 # define RTNetUDPChecksum RT_MANGLER(RTNetUDPChecksum) 963 # define RTNetStrToMacAddr RT_MANGLER(RTNetStrToMacAddr) 963 964 # define RTNetIsIPv4AddrStr RT_MANGLER(RTNetIsIPv4AddrStr) 964 965 # define RTNetStrToIPv4Addr RT_MANGLER(RTNetStrToIPv4Addr) -
trunk/include/iprt/net.h
r45716 r49326 38 38 * @{ 39 39 */ 40 41 /** 42 * Converts an stringified Ethernet MAC address into the RTMAC representation. 43 * 44 * @todo This should be move to some generic part of the runtime. 45 * 46 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on 47 * failure. 48 * 49 * @param pszValue The value to convert. 50 * @param pAddr Where to store the result. 51 */ 52 RTDECL(int) RTNetStrToMacAddr(const char *pszAddr, PRTMAC pMacAddr); 40 53 41 54 /** -
trunk/src/VBox/Runtime/Makefile.kmk
r49182 r49326 364 364 common/net/netaddrstr.cpp \ 365 365 common/net/netaddrstr2.cpp \ 366 common/net/macstr.cpp \ 366 367 common/path/rtPathRootSpecLen.cpp \ 367 368 common/path/rtPathVolumeSpecLen.cpp \ … … 1665 1666 common/math/gcc/umoddi3.c \ 1666 1667 common/math/gcc/xordi3.c 1668 # 1669 # actually it's for clang 1670 if $(VBOX_XCODE_VERSION) >= 5 1671 RuntimeR0_SOURCES.darwin += r0drv/darwin/bzero-r0drv-darwin.cpp 1672 endif 1673 1674 1667 1675 endif 1668 1676 -
trunk/src/VBox/Runtime/common/misc/getopt.cpp
r46489 r49326 111 111 * Converts an stringified Ethernet MAC address into the RTMAC representation. 112 112 * 113 * @todo This should be move to some generic part of the runtime.114 *115 113 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on 116 114 * failure. … … 121 119 static int rtgetoptConvertMacAddr(const char *pszValue, PRTMAC pAddr) 122 120 { 123 /* 124 * Not quite sure if I should accept stuff like "08::27:::1" here... 125 * The code is accepting "::" patterns now, except for for the first 126 * and last parts. 127 */ 128 129 /* first */ 130 char *pszNext; 131 int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]); 132 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) 133 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 134 if (*pszNext++ != ':') 135 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 136 137 /* middle */ 138 for (unsigned i = 1; i < 5; i++) 139 { 140 if (*pszNext == ':') 141 pAddr->au8[i] = 0; 142 else 143 { 144 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]); 145 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) 146 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 147 if (*pszNext != ':') 148 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 149 } 150 pszNext++; 151 } 152 153 /* last */ 154 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]); 155 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) 156 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 157 pszNext = RTStrStripL(pszNext); 158 if (*pszNext) 121 122 int rc = RTNetStrToMacAddr(pszValue, pAddr); 123 if (RT_FAILURE(rc)) 159 124 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 160 125 -
trunk/src/VBox/Runtime/common/net/macstr.cpp
r49247 r49326 5 5 6 6 /* 7 * Copyright (C) 20 07-2013 Oracle Corporation7 * Copyright (C) 2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 30 30 #include <iprt/cidr.h> 31 31 #include <iprt/net.h> /* must come before getopt.h */ 32 #include <iprt/getopt.h>33 32 #include "internal/iprt.h" 34 33 … … 38 37 #include <iprt/message.h> 39 38 #include <iprt/string.h> 40 #include <iprt/uuid.h>41 42 43 /*******************************************************************************44 * Global Variables *45 *******************************************************************************/46 /**47 * Standard options that gets included unless RTGETOPTINIT_FLAGS_NO_STD_OPTS is48 * set.49 */50 static RTGETOPTDEF const g_aStdOptions[] =51 {52 { "--help", 'h', RTGETOPT_REQ_NOTHING },53 { "-help", 'h', RTGETOPT_REQ_NOTHING },54 { "--version", 'V', RTGETOPT_REQ_NOTHING },55 { "-version", 'V', RTGETOPT_REQ_NOTHING },56 };57 /** The index of --help in g_aStdOptions. Used for some trickery. */58 #define RTGETOPT_STD_OPTIONS_HELP_IDX 059 60 61 62 RTDECL(int) RTGetOptInit(PRTGETOPTSTATE pState, int argc, char **argv,63 PCRTGETOPTDEF paOptions, size_t cOptions,64 int iFirst, uint32_t fFlags)65 {66 AssertReturn(!(fFlags & ~(RTGETOPTINIT_FLAGS_OPTS_FIRST | RTGETOPTINIT_FLAGS_NO_STD_OPTS)), VERR_INVALID_PARAMETER);67 68 pState->argv = argv;69 pState->argc = argc;70 pState->paOptions = paOptions;71 pState->cOptions = cOptions;72 pState->iNext = iFirst;73 pState->pszNextShort = NULL;74 pState->pDef = NULL;75 pState->uIndex = UINT32_MAX;76 pState->fFlags = fFlags;77 pState->cNonOptions = 0;78 79 /* validate the options. */80 for (size_t i = 0; i < cOptions; i++)81 {82 Assert(!(paOptions[i].fFlags & ~RTGETOPT_VALID_MASK));83 Assert(paOptions[i].iShort > 0);84 Assert(paOptions[i].iShort != VINF_GETOPT_NOT_OPTION);85 Assert(paOptions[i].iShort != '-');86 }87 88 return VINF_SUCCESS;89 }90 RT_EXPORT_SYMBOL(RTGetOptInit);91 92 93 /**94 * Converts an stringified IPv4 address into the RTNETADDRIPV4 representation.95 *96 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on97 * failure.98 *99 * @param pszValue The value to convert.100 * @param pAddr Where to store the result.101 */102 static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr)103 {104 if (RT_FAILURE(RTNetStrToIPv4Addr(pszValue, pAddr)))105 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;106 return VINF_SUCCESS;107 }108 39 109 40 … … 111 42 * Converts an stringified Ethernet MAC address into the RTMAC representation. 112 43 * 113 * @todo This should be move to some generic part of the runtime. 114 * 115 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on 116 * failure. 44 * @returns VINF_SUCCESS on success. 117 45 * 118 46 * @param pszValue The value to convert. 119 47 * @param pAddr Where to store the result. 120 48 */ 121 static int rtgetoptConvertMacAddr(const char *pszValue, PRTMAC pAddr)49 RTDECL(int) RTNetStrToMacAddr(const char *pszValue, PRTMAC pAddr) 122 50 { 123 51 /* … … 144 72 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]); 145 73 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) 146 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;74 return rc; 147 75 if (*pszNext != ':') 148 return VERR_ GETOPT_INVALID_ARGUMENT_FORMAT;76 return VERR_INVALID_PARAMETER; 149 77 } 150 78 pszNext++; … … 154 82 rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]); 155 83 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) 156 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;84 return rc; 157 85 pszNext = RTStrStripL(pszNext); 158 86 if (*pszNext) 159 return VERR_ GETOPT_INVALID_ARGUMENT_FORMAT;87 return VERR_INVALID_PARAMETER; 160 88 161 89 return VINF_SUCCESS; 162 90 } 163 164 165 /** 166 * Searches for a long option. 167 * 168 * @returns Pointer to a matching option. 169 * @param pszOption The alleged long option. 170 * @param paOptions Option array. 171 * @param cOptions Number of items in the array. 172 * @param fFlags Init flags. 173 */ 174 static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions, uint32_t fFlags) 175 { 176 PCRTGETOPTDEF pOpt = paOptions; 177 while (cOptions-- > 0) 178 { 179 if (pOpt->pszLong) 180 { 181 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING) 182 { 183 /* 184 * A value is required with the argument. We're trying to be 185 * understanding here and will permit any of the following: 186 * --long12:value, --long12=value, --long12 value, 187 * --long:value, --long=value, --long value, 188 * 189 * If the option is index, then all trailing chars must be 190 * digits. For error reporting reasons we also match where 191 * there is no index. 192 */ 193 size_t cchLong = strlen(pOpt->pszLong); 194 if ( !strncmp(pszOption, pOpt->pszLong, cchLong) 195 || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE 196 && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong))) 197 { 198 if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) 199 while (RT_C_IS_DIGIT(pszOption[cchLong])) 200 cchLong++; 201 if ( pszOption[cchLong] == '\0' 202 || pszOption[cchLong] == ':' 203 || pszOption[cchLong] == '=') 204 return pOpt; 205 } 206 } 207 else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) 208 { 209 /* 210 * The option takes an index but no value. 211 * As above, we also match where there is no index. 212 */ 213 size_t cchLong = strlen(pOpt->pszLong); 214 if ( !strncmp(pszOption, pOpt->pszLong, cchLong) 215 || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE 216 && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong))) 217 { 218 while (RT_C_IS_DIGIT(pszOption[cchLong])) 219 cchLong++; 220 if (pszOption[cchLong] == '\0') 221 return pOpt; 222 } 223 } 224 else if ( !strcmp(pszOption, pOpt->pszLong) 225 || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE 226 && !RTStrICmp(pszOption, pOpt->pszLong))) 227 return pOpt; 228 } 229 pOpt++; 230 } 231 232 if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS)) 233 for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++) 234 if ( !strcmp(pszOption, g_aStdOptions[i].pszLong) 235 || ( g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE 236 && !RTStrICmp(pszOption, g_aStdOptions[i].pszLong))) 237 return &g_aStdOptions[i]; 238 239 return NULL; 240 } 241 242 243 /** 244 * Searches for a matching short option. 245 * 246 * @returns Pointer to a matching option. 247 * @param chOption The option char. 248 * @param paOptions Option array. 249 * @param cOptions Number of items in the array. 250 * @param fFlags Init flags. 251 */ 252 static PCRTGETOPTDEF rtGetOptSearchShort(int chOption, PCRTGETOPTDEF paOptions, size_t cOptions, uint32_t fFlags) 253 { 254 PCRTGETOPTDEF pOpt = paOptions; 255 while (cOptions-- > 0) 256 { 257 if (pOpt->iShort == chOption) 258 return pOpt; 259 pOpt++; 260 } 261 262 if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS)) 263 { 264 for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++) 265 if (g_aStdOptions[i].iShort == chOption) 266 return &g_aStdOptions[i]; 267 if (chOption == '?') 268 return &g_aStdOptions[RTGETOPT_STD_OPTIONS_HELP_IDX]; 269 } 270 return NULL; 271 } 272 273 274 /** 275 * Value string -> Value union. 276 * 277 * @returns IPRT status code. 278 * @param fFlags The value flags. 279 * @param pszValue The value string. 280 * @param pValueUnion Where to return the processed value. 281 */ 282 static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion) 283 { 284 /* 285 * Transform into a option value as requested. 286 * If decimal conversion fails, we'll check for "0x<xdigit>" and 287 * try a 16 based conversion. We will not interpret any of the 288 * generic ints as octals. 289 */ 290 switch (fFlags & ( RTGETOPT_REQ_MASK 291 | RTGETOPT_FLAG_HEX 292 | RTGETOPT_FLAG_DEC 293 | RTGETOPT_FLAG_OCT)) 294 { 295 case RTGETOPT_REQ_STRING: 296 pValueUnion->psz = pszValue; 297 break; 298 299 case RTGETOPT_REQ_BOOL: 300 if ( !RTStrICmp(pszValue, "true") 301 || !RTStrICmp(pszValue, "t") 302 || !RTStrICmp(pszValue, "yes") 303 || !RTStrICmp(pszValue, "y") 304 || !RTStrICmp(pszValue, "enabled") 305 || !RTStrICmp(pszValue, "enable") 306 || !RTStrICmp(pszValue, "en") 307 || !RTStrICmp(pszValue, "e") 308 || !RTStrICmp(pszValue, "on") 309 || !RTStrCmp(pszValue, "1") 310 ) 311 pValueUnion->f = true; 312 else if ( !RTStrICmp(pszValue, "false") 313 || !RTStrICmp(pszValue, "f") 314 || !RTStrICmp(pszValue, "no") 315 || !RTStrICmp(pszValue, "n") 316 || !RTStrICmp(pszValue, "disabled") 317 || !RTStrICmp(pszValue, "disable") 318 || !RTStrICmp(pszValue, "dis") 319 || !RTStrICmp(pszValue, "d") 320 || !RTStrICmp(pszValue, "off") 321 || !RTStrCmp(pszValue, "0") 322 ) 323 pValueUnion->f = false; 324 else 325 { 326 pValueUnion->psz = pszValue; 327 return VERR_GETOPT_UNKNOWN_OPTION; 328 } 329 break; 330 331 case RTGETOPT_REQ_BOOL_ONOFF: 332 if (!RTStrICmp(pszValue, "on")) 333 pValueUnion->f = true; 334 else if (!RTStrICmp(pszValue, "off")) 335 pValueUnion->f = false; 336 else 337 { 338 pValueUnion->psz = pszValue; 339 return VERR_GETOPT_UNKNOWN_OPTION; 340 } 341 break; 342 343 #define MY_INT_CASE(req, type, memb, convfn) \ 344 case req: \ 345 { \ 346 type Value; \ 347 if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \ 348 && ( pszValue[0] != '0' \ 349 || (pszValue[1] != 'x' && pszValue[1] != 'X') \ 350 || !RT_C_IS_XDIGIT(pszValue[2]) \ 351 || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \ 352 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ 353 pValueUnion->memb = Value; \ 354 break; \ 355 } 356 #define MY_BASE_INT_CASE(req, type, memb, convfn, base) \ 357 case req: \ 358 { \ 359 type Value; \ 360 if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \ 361 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ 362 pValueUnion->memb = Value; \ 363 break; \ 364 } 365 366 MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i8, RTStrToInt8Full) 367 MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i16, RTStrToInt16Full) 368 MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i32, RTStrToInt32Full) 369 MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i64, RTStrToInt64Full) 370 MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u8, RTStrToUInt8Full) 371 MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full) 372 MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full) 373 MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full) 374 375 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i8, RTStrToInt8Full, 16) 376 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i16, RTStrToInt16Full, 16) 377 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i32, RTStrToInt32Full, 16) 378 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i64, RTStrToInt64Full, 16) 379 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u8, RTStrToUInt8Full, 16) 380 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16) 381 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16) 382 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16) 383 384 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i8, RTStrToInt8Full, 10) 385 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i16, RTStrToInt16Full, 10) 386 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i32, RTStrToInt32Full, 10) 387 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i64, RTStrToInt64Full, 10) 388 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u8, RTStrToUInt8Full, 10) 389 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10) 390 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10) 391 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10) 392 393 MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i8, RTStrToInt8Full, 8) 394 MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i16, RTStrToInt16Full, 8) 395 MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i32, RTStrToInt32Full, 8) 396 MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i64, RTStrToInt64Full, 8) 397 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u8, RTStrToUInt8Full, 8) 398 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8) 399 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8) 400 MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8) 401 402 #undef MY_INT_CASE 403 #undef MY_BASE_INT_CASE 404 405 case RTGETOPT_REQ_IPV4ADDR: 406 { 407 RTNETADDRIPV4 Addr; 408 if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS) 409 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 410 pValueUnion->IPv4Addr = Addr; 411 break; 412 } 413 414 case RTGETOPT_REQ_IPV4CIDR: 415 { 416 RTNETADDRIPV4 network; 417 RTNETADDRIPV4 netmask; 418 if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) 419 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 420 pValueUnion->CidrIPv4.IPv4Network.u = network.u; 421 pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; 422 break; 423 } 424 425 case RTGETOPT_REQ_MACADDR: 426 { 427 RTMAC Addr; 428 if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS) 429 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 430 pValueUnion->MacAddr = Addr; 431 break; 432 } 433 434 case RTGETOPT_REQ_UUID: 435 { 436 RTUUID Uuid; 437 if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS) 438 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 439 pValueUnion->Uuid = Uuid; 440 break; 441 } 442 443 default: 444 AssertMsgFailed(("f=%#x\n", fFlags)); 445 return VERR_INTERNAL_ERROR; 446 } 447 448 return VINF_SUCCESS; 449 } 450 451 452 /** 453 * Moves one argv option entries. 454 * 455 * @param papszTo Destination. 456 * @param papszFrom Source. 457 */ 458 static void rtGetOptMoveArgvEntries(char **papszTo, char **papszFrom) 459 { 460 if (papszTo != papszFrom) 461 { 462 Assert((uintptr_t)papszTo < (uintptr_t)papszFrom); 463 char * const pszMoved = papszFrom[0]; 464 memmove(&papszTo[1], &papszTo[0], (uintptr_t)papszFrom - (uintptr_t)papszTo); 465 papszTo[0] = pszMoved; 466 } 467 } 468 469 470 RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion) 471 { 472 /* 473 * Reset the variables kept in state. 474 */ 475 pState->pDef = NULL; 476 pState->uIndex = UINT32_MAX; 477 478 /* 479 * Make sure the union is completely cleared out, whatever happens below. 480 */ 481 pValueUnion->u64 = 0; 482 pValueUnion->pDef = NULL; 483 484 /* 485 * The next option. 486 */ 487 bool fShort; 488 int iThis; 489 const char *pszArgThis; 490 PCRTGETOPTDEF pOpt; 491 492 if (pState->pszNextShort) 493 { 494 /* 495 * We've got short options left over from the previous call. 496 */ 497 pOpt = rtGetOptSearchShort(*pState->pszNextShort, pState->paOptions, pState->cOptions, pState->fFlags); 498 if (!pOpt) 499 { 500 pValueUnion->psz = pState->pszNextShort; 501 return VERR_GETOPT_UNKNOWN_OPTION; 502 } 503 pState->pszNextShort++; 504 pszArgThis = pState->pszNextShort - 2; 505 iThis = pState->iNext; 506 fShort = true; 507 } 508 else 509 { 510 /* 511 * Pop off the next argument. Sorting options and dealing with the 512 * dash-dash makes this a little extra complicated. 513 */ 514 for (;;) 515 { 516 if (pState->iNext >= pState->argc) 517 return 0; 518 519 if (pState->cNonOptions) 520 { 521 if (pState->cNonOptions == INT32_MAX) 522 { 523 pValueUnion->psz = pState->argv[pState->iNext++]; 524 return VINF_GETOPT_NOT_OPTION; 525 } 526 527 if (pState->iNext + pState->cNonOptions >= pState->argc) 528 { 529 pState->cNonOptions = INT32_MAX; 530 continue; 531 } 532 } 533 534 iThis = pState->iNext++; 535 pszArgThis = pState->argv[iThis + pState->cNonOptions]; 536 537 /* 538 * Do a long option search first and then a short option one. 539 * This way we can make sure single dash long options doesn't 540 * get mixed up with short ones. 541 */ 542 pOpt = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions, pState->fFlags); 543 if ( !pOpt 544 && pszArgThis[0] == '-' 545 && pszArgThis[1] != '-' 546 && pszArgThis[1] != '\0') 547 { 548 pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions, pState->fFlags); 549 fShort = pOpt != NULL; 550 } 551 else 552 fShort = false; 553 554 /* Look for dash-dash. */ 555 if (!pOpt && !strcmp(pszArgThis, "--")) 556 { 557 rtGetOptMoveArgvEntries(&pState->argv[iThis], &pState->argv[iThis + pState->cNonOptions]); 558 pState->cNonOptions = INT32_MAX; 559 continue; 560 } 561 562 /* Options first hacks. */ 563 if (pState->fFlags & RTGETOPTINIT_FLAGS_OPTS_FIRST) 564 { 565 if (pOpt) 566 rtGetOptMoveArgvEntries(&pState->argv[iThis], &pState->argv[iThis + pState->cNonOptions]); 567 else if (*pszArgThis == '-') 568 { 569 pValueUnion->psz = pszArgThis; 570 return VERR_GETOPT_UNKNOWN_OPTION; 571 } 572 else 573 { 574 /* not an option, add it to the non-options and try again. */ 575 pState->iNext--; 576 pState->cNonOptions++; 577 578 /* Switch to returning non-options if we've reached the end. */ 579 if (pState->iNext + pState->cNonOptions >= pState->argc) 580 pState->cNonOptions = INT32_MAX; 581 continue; 582 } 583 } 584 585 /* done */ 586 break; 587 } 588 } 589 590 if (pOpt) 591 { 592 pValueUnion->pDef = pOpt; /* in case of no value or error. */ 593 594 if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING) 595 { 596 /* 597 * Find the argument value. 598 * 599 * A value is required with the argument. We're trying to be 600 * understanding here and will permit any of the following: 601 * -svalue, -s value, -s:value and -s=value 602 * (Ditto for long options.) 603 */ 604 const char *pszValue; 605 if (fShort) 606 { 607 if (pszArgThis[2] == '\0') 608 { 609 if (iThis + 1 >= pState->argc) 610 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; 611 pszValue = pState->argv[iThis + pState->cNonOptions + 1]; 612 rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); 613 pState->iNext++; 614 } 615 else /* same argument. */ 616 pszValue = &pszArgThis[2 + (pszArgThis[2] == ':' || pszArgThis[2] == '=')]; 617 if (pState->pszNextShort) 618 { 619 pState->pszNextShort = NULL; 620 pState->iNext++; 621 } 622 } 623 else 624 { 625 size_t cchLong = strlen(pOpt->pszLong); 626 if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) 627 { 628 629 if (pszArgThis[cchLong] == '\0') 630 return VERR_GETOPT_INDEX_MISSING; 631 632 uint32_t uIndex; 633 char *pszRet = NULL; 634 int rc = RTStrToUInt32Ex(&pszArgThis[cchLong], &pszRet, 10, &uIndex); 635 if (rc == VWRN_TRAILING_CHARS) 636 { 637 if ( pszRet[0] != ':' 638 && pszRet[0] != '=') 639 return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; 640 pState->uIndex = uIndex; 641 pszValue = pszRet + 1; 642 } 643 else if (rc == VINF_SUCCESS) 644 { 645 if (iThis + 1 >= pState->argc) 646 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; 647 pState->uIndex = uIndex; 648 pszValue = pState->argv[iThis + pState->cNonOptions + 1]; 649 rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); 650 pState->iNext++; 651 } 652 else 653 AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */ 654 } 655 else 656 { 657 if (pszArgThis[cchLong] == '\0') 658 { 659 if (iThis + 1 >= pState->argc) 660 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; 661 pszValue = pState->argv[iThis + pState->cNonOptions + 1]; 662 rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); 663 pState->iNext++; 664 } 665 else /* same argument. */ 666 pszValue = &pszArgThis[cchLong + 1]; 667 } 668 } 669 670 /* 671 * Set up the ValueUnion. 672 */ 673 int rc = rtGetOptProcessValue(pOpt->fFlags, pszValue, pValueUnion); 674 if (RT_FAILURE(rc)) 675 return rc; 676 } 677 else if (fShort) 678 { 679 /* 680 * Deal with "compressed" short option lists, correcting the next 681 * state variables for the start and end cases. 682 */ 683 if (pszArgThis[2]) 684 { 685 if (!pState->pszNextShort) 686 { 687 /* start */ 688 pState->pszNextShort = &pszArgThis[2]; 689 pState->iNext--; 690 } 691 } 692 else if (pState->pszNextShort) 693 { 694 /* end */ 695 pState->pszNextShort = NULL; 696 pState->iNext++; 697 } 698 } 699 else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) 700 { 701 size_t cchLong = strlen(pOpt->pszLong); 702 if (pszArgThis[cchLong] == '\0') 703 return VERR_GETOPT_INDEX_MISSING; 704 705 uint32_t uIndex; 706 if (RTStrToUInt32Full(&pszArgThis[cchLong], 10, &uIndex) == VINF_SUCCESS) 707 pState->uIndex = uIndex; 708 else 709 AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */ 710 } 711 712 pState->pDef = pOpt; 713 return pOpt->iShort; 714 } 715 716 /* 717 * Not a known option argument. If it starts with a switch char (-) we'll 718 * fail with unknown option, and if it doesn't we'll return it as a non-option. 719 */ 720 if (*pszArgThis == '-') 721 { 722 pValueUnion->psz = pszArgThis; 723 return VERR_GETOPT_UNKNOWN_OPTION; 724 } 725 726 pValueUnion->psz = pszArgThis; 727 return VINF_GETOPT_NOT_OPTION; 728 } 729 RT_EXPORT_SYMBOL(RTGetOpt); 730 731 732 RTDECL(int) RTGetOptFetchValue(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion, uint32_t fFlags) 733 { 734 /* 735 * Validate input. 736 */ 737 PCRTGETOPTDEF pOpt = pState->pDef; 738 AssertReturn(!(fFlags & ~RTGETOPT_VALID_MASK), VERR_INVALID_PARAMETER); 739 AssertReturn((fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING, VERR_INVALID_PARAMETER); 740 741 /* 742 * Make sure the union is completely cleared out, whatever happens below. 743 */ 744 pValueUnion->u64 = 0; 745 pValueUnion->pDef = NULL; 746 747 /* 748 * Pop off the next argument and convert it into a value union. 749 */ 750 if (pState->iNext >= pState->argc) 751 return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; 752 int iThis = pState->iNext++; 753 const char *pszValue = pState->argv[iThis + (pState->cNonOptions != INT32_MAX ? pState->cNonOptions : 0)]; 754 pValueUnion->pDef = pOpt; /* in case of no value or error. */ 755 756 if (pState->cNonOptions && pState->cNonOptions != INT32_MAX) 757 rtGetOptMoveArgvEntries(&pState->argv[iThis], &pState->argv[iThis + pState->cNonOptions]); 758 759 return rtGetOptProcessValue(fFlags, pszValue, pValueUnion); 760 } 761 RT_EXPORT_SYMBOL(RTGetOptFetchValue); 762 763 764 RTDECL(RTEXITCODE) RTGetOptPrintError(int ch, PCRTGETOPTUNION pValueUnion) 765 { 766 if (ch == VINF_GETOPT_NOT_OPTION) 767 RTMsgError("Invalid parameter: %s", pValueUnion->psz); 768 else if (ch > 0) 769 { 770 if (RT_C_IS_GRAPH(ch)) 771 RTMsgError("Unhandled option: -%c", ch); 772 else 773 RTMsgError("Unhandled option: %i (%#x)", ch, ch); 774 } 775 else if (ch == VERR_GETOPT_UNKNOWN_OPTION) 776 RTMsgError("Unknown option: '%s'", pValueUnion->psz); 777 else if (ch == VERR_GETOPT_INVALID_ARGUMENT_FORMAT) 778 /** @todo r=klaus not really ideal, as the value isn't available */ 779 RTMsgError("The value given '%s' has an invalid format.", pValueUnion->pDef->pszLong); 780 else if (pValueUnion->pDef) 781 RTMsgError("%s: %Rrs\n", pValueUnion->pDef->pszLong, ch); 782 else 783 RTMsgError("%Rrs\n", ch); 784 785 return RTEXITCODE_SYNTAX; 786 } 787 RT_EXPORT_SYMBOL(RTGetOptPrintError); 788 91 RT_EXPORT_SYMBOL(RTNetStrToMacAddr);
Note:
See TracChangeset
for help on using the changeset viewer.