/** * Value string -> Value union. * * @returns IPRT status code. * @param fFlags The value flags. * @param pszValue The value string. * @param pValueUnion Where to return the processed value. */ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion) { /* * Transform into a option value as requested. * If decimal conversion fails, we'll check for "0x<xdigit>" and * try a 16 based conversion. We will not interpret any of the * generic ints as octals. */ switch (fFlags & ( RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_DEC | RTGETOPT_FLAG_OCT)) { case RTGETOPT_REQ_STRING: pValueUnion->psz = pszValue; break; case RTGETOPT_REQ_BOOL: if ( !RTStrICmp(pszValue, "true") || !RTStrICmp(pszValue, "t") || !RTStrICmp(pszValue, "yes") || !RTStrICmp(pszValue, "y") || !RTStrICmp(pszValue, "enabled") || !RTStrICmp(pszValue, "enable") || !RTStrICmp(pszValue, "en") || !RTStrICmp(pszValue, "e") || !RTStrICmp(pszValue, "on") || !RTStrCmp(pszValue, "1") ) pValueUnion->f = true; else if ( !RTStrICmp(pszValue, "false") || !RTStrICmp(pszValue, "f") || !RTStrICmp(pszValue, "no") || !RTStrICmp(pszValue, "n") || !RTStrICmp(pszValue, "disabled") || !RTStrICmp(pszValue, "disable") || !RTStrICmp(pszValue, "dis") || !RTStrICmp(pszValue, "d") || !RTStrICmp(pszValue, "off") || !RTStrCmp(pszValue, "0") ) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; case RTGETOPT_REQ_BOOL_ONOFF: if (!RTStrICmp(pszValue, "on")) pValueUnion->f = true; else if (!RTStrICmp(pszValue, "off")) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; #define MY_INT_CASE(req, type, memb, convfn) \ case req: \ { \ type Value; \ if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \ && ( pszValue[0] != '0' \ || (pszValue[1] != 'x' && pszValue[1] != 'X') \ || !RT_C_IS_XDIGIT(pszValue[2]) \ || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } #define MY_BASE_INT_CASE(req, type, memb, convfn, base) \ case req: \ { \ type Value; \ if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i8, RTStrToInt8Full) MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i16, RTStrToInt16Full) MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i32, RTStrToInt32Full) MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i64, RTStrToInt64Full) MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u8, RTStrToUInt8Full) MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full) MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full) MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i8, RTStrToInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i16, RTStrToInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i32, RTStrToInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i64, RTStrToInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u8, RTStrToUInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i8, RTStrToInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i16, RTStrToInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i32, RTStrToInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i64, RTStrToInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u8, RTStrToUInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i8, RTStrToInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i16, RTStrToInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i32, RTStrToInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i64, RTStrToInt64Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u8, RTStrToUInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8) #undef MY_INT_CASE #undef MY_BASE_INT_CASE case RTGETOPT_REQ_IPV4ADDR: { RTNETADDRIPV4 Addr; if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->IPv4Addr = Addr; break; } case RTGETOPT_REQ_IPV4CIDR: { RTNETADDRIPV4 network; RTNETADDRIPV4 netmask; if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->CidrIPv4.IPv4Network.u = network.u; pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; break; } case RTGETOPT_REQ_MACADDR: { RTMAC Addr; if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->MacAddr = Addr; break; } case RTGETOPT_REQ_UUID: { RTUUID Uuid; if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->Uuid = Uuid; break; } default: AssertMsgFailed(("f=%#x\n", fFlags)); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
/** * Value string -> Value union. * * @returns IPRT status code. * @param fFlags The value flags. * @param pszValue The value string. * @param pValueUnion Where to return the processed value. */ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion) { /* * Transform into a option value as requested. * If decimal conversion fails, we'll check for "0x<xdigit>" and * try a 16 based conversion. We will not interpret any of the * generic ints as octals. */ uint32_t const fSwitchValue = fFlags & ( RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_DEC | RTGETOPT_FLAG_OCT); switch (fSwitchValue) { case RTGETOPT_REQ_STRING: pValueUnion->psz = pszValue; break; case RTGETOPT_REQ_BOOL: if ( !RTStrICmp(pszValue, "true") || !RTStrICmp(pszValue, "t") || !RTStrICmp(pszValue, "yes") || !RTStrICmp(pszValue, "y") || !RTStrICmp(pszValue, "enabled") || !RTStrICmp(pszValue, "enable") || !RTStrICmp(pszValue, "en") || !RTStrICmp(pszValue, "e") || !RTStrICmp(pszValue, "on") || !RTStrCmp(pszValue, "1") ) pValueUnion->f = true; else if ( !RTStrICmp(pszValue, "false") || !RTStrICmp(pszValue, "f") || !RTStrICmp(pszValue, "no") || !RTStrICmp(pszValue, "n") || !RTStrICmp(pszValue, "disabled") || !RTStrICmp(pszValue, "disable") || !RTStrICmp(pszValue, "dis") || !RTStrICmp(pszValue, "d") || !RTStrICmp(pszValue, "off") || !RTStrCmp(pszValue, "0") ) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; case RTGETOPT_REQ_BOOL_ONOFF: if (!RTStrICmp(pszValue, "on")) pValueUnion->f = true; else if (!RTStrICmp(pszValue, "off")) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; #define MY_INT_CASE(req, type, memb, convfn) \ case req: \ { \ type Value; \ if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \ && ( pszValue[0] != '0' \ || (pszValue[1] != 'x' && pszValue[1] != 'X') \ || !RT_C_IS_XDIGIT(pszValue[2]) \ || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } #define MY_BASE_INT_CASE(req, type, memb, convfn, base) \ case req: \ { \ type Value; \ if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i8, RTStrToInt8Full) MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i16, RTStrToInt16Full) MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i32, RTStrToInt32Full) MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i64, RTStrToInt64Full) MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u8, RTStrToUInt8Full) MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full) MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full) MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i8, RTStrToInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i16, RTStrToInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i32, RTStrToInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i64, RTStrToInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u8, RTStrToUInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i8, RTStrToInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i16, RTStrToInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i32, RTStrToInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i64, RTStrToInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u8, RTStrToUInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i8, RTStrToInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i16, RTStrToInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i32, RTStrToInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i64, RTStrToInt64Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u8, RTStrToUInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8) #undef MY_INT_CASE #undef MY_BASE_INT_CASE case RTGETOPT_REQ_IPV4ADDR: { RTNETADDRIPV4 Addr; if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->IPv4Addr = Addr; break; } case RTGETOPT_REQ_IPV4CIDR: { RTNETADDRIPV4 network; RTNETADDRIPV4 netmask; if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->CidrIPv4.IPv4Network.u = network.u; pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; break; } case RTGETOPT_REQ_MACADDR: { RTMAC Addr; if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->MacAddr = Addr; break; } case RTGETOPT_REQ_UUID: { RTUUID Uuid; if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->Uuid = Uuid; break; } #define MY_INT_PAIR_CASE(a_fReqValue, a_fReqValueOptional, a_Type, a_MemberPrefix, a_fnConv, a_ConvBase, a_DefaultValue) \ case a_fReqValue: \ case a_fReqValueOptional: \ { \ /* First value: */ \ a_Type Value1; \ char *pszNext = NULL; \ unsigned uBase = pszValue[0] == '0' \ && (pszValue[1] == 'x' || pszValue[1] == 'X') \ && RT_C_IS_XDIGIT(pszValue[2]) \ ? 16 : a_ConvBase; \ int rc = a_fnConv(pszValue, &pszNext, uBase, &Value1); \ if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES) \ { \ /* The second value, could be optional: */ \ a_Type Value2 = a_DefaultValue; \ pszValue = pszNext;\ if (pszValue) \ { \ while (RT_C_IS_BLANK(*pszValue)) \ pszValue++; \ if (*pszValue == ':' || *pszValue == '/' || *pszValue == '|') \ do pszValue++; \ while (RT_C_IS_BLANK(*pszValue)); \ if (pszValue != pszNext) \ { \ uBase = pszValue[0] == '0' \ && (pszValue[1] == 'x' || pszValue[1] == 'X') \ && RT_C_IS_XDIGIT(pszValue[2]) \ ? 16 : a_ConvBase; \ rc = a_fnConv(pszValue, &pszNext, uBase, &Value2); \ if (rc == VINF_SUCCESS) \ { /* likely */ } \ else \ { RTAssertMsg2("z rc=%Rrc: '%s' '%s' uBase=%d\n", rc, pszValue, pszNext, uBase); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ } \ else if (fSwitchValue != (a_fReqValueOptional)) \ { RTAssertMsg2("x\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ } \ else if (fSwitchValue != (a_fReqValueOptional)) \ { RTAssertMsg2("y\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ pValueUnion->a_MemberPrefix##Second = Value2; \ pValueUnion->a_MemberPrefix##First = Value1; \ break; \ } \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ } MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR, uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_DEC, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC, uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX, uint32_t, PairU32.u, RTStrToUInt32Ex, 16, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_OCT, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT, uint32_t, PairU32.u, RTStrToUInt32Ex, 8, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR, uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_DEC, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC, uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_HEX, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX, uint64_t, PairU64.u, RTStrToUInt64Ex, 16, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_OCT, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT, uint64_t, PairU64.u, RTStrToUInt64Ex, 8, UINT64_MAX) default: AssertMsgFailed(("f=%#x\n", fFlags)); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }