diff --git a/src/core/common/string.cpp b/src/core/common/string.cpp index c759110bc..6117f67eb 100644 --- a/src/core/common/string.cpp +++ b/src/core/common/string.cpp @@ -202,13 +202,15 @@ Error StringParseUint8(const char *&aString, uint8_t &aUint8, uint8_t aMaxValue) Error error = kErrorParse; const char *cur = aString; uint16_t value = 0; + uint8_t digit; - for (; (*cur >= '0') && (*cur <= '9'); cur++) + while (ParseDigit(*cur, digit) == kErrorNone) { value *= 10; - value += static_cast(*cur - '0'); + value += digit; VerifyOrExit(value <= aMaxValue, error = kErrorParse); error = kErrorNone; + cur++; } aString = cur; @@ -236,7 +238,7 @@ void StringConvertToUppercase(char *aString) char ToLowercase(char aChar) { - if ((aChar >= 'A') && (aChar <= 'Z')) + if (IsUppercase(aChar)) { aChar += 'a' - 'A'; } @@ -246,7 +248,7 @@ char ToLowercase(char aChar) char ToUppercase(char aChar) { - if ((aChar >= 'a') && (aChar <= 'z')) + if (IsLowercase(aChar)) { aChar -= 'a' - 'A'; } @@ -254,6 +256,43 @@ char ToUppercase(char aChar) return aChar; } +bool IsDigit(char aChar) { return ('0' <= aChar && aChar <= '9'); } + +bool IsUppercase(char aChar) { return ('A' <= aChar && aChar <= 'Z'); } + +bool IsLowercase(char aChar) { return ('a' <= aChar && aChar <= 'z'); } + +Error ParseDigit(char aDigitChar, uint8_t &aValue) +{ + Error error = kErrorNone; + + VerifyOrExit(IsDigit(aDigitChar), error = kErrorInvalidArgs); + aValue = static_cast(aDigitChar - '0'); + +exit: + return error; +} + +Error ParseHexDigit(char aHexChar, uint8_t &aValue) +{ + Error error = kErrorNone; + + if (('A' <= aHexChar) && (aHexChar <= 'F')) + { + ExitNow(aValue = static_cast(aHexChar - 'A' + 10)); + } + + if (('a' <= aHexChar) && (aHexChar <= 'f')) + { + ExitNow(aValue = static_cast(aHexChar - 'a' + 10)); + } + + error = ParseDigit(aHexChar, aValue); + +exit: + return error; +} + const char *ToYesNo(bool aBool) { static const char *const kYesNoStrings[] = {"no", "yes"}; diff --git a/src/core/common/string.hpp b/src/core/common/string.hpp index 358d7f842..00f903c3d 100644 --- a/src/core/common/string.hpp +++ b/src/core/common/string.hpp @@ -282,6 +282,63 @@ char ToLowercase(char aChar); */ char ToUppercase(char aChar); +/** + * Checks whether a given character is an uppercase letter ('A'-'Z'). + * + * @param[in] aChar The character to check. + * + * @retval TRUE @p aChar is an uppercase letter. + * @retval FALSE @p aChar is not an uppercase letter. + * + */ +bool IsUppercase(char aChar); + +/** + * Checks whether a given character is a lowercase letter ('a'-'z'). + * + * @param[in] aChar The character to check. + * + * @retval TRUE @p aChar is a lowercase letter. + * @retval FALSE @p aChar is not a lowercase letter. + * + */ +bool IsLowercase(char aChar); + +/** + * Checks whether a given character is a digit character ('0'-'9'). + * + * @param[in] aChar The character to check. + * + * @retval TRUE @p aChar is a digit character. + * @retval FALSE @p aChar is not a digit character. + * + */ +bool IsDigit(char aChar); + +/** + * Parse a given digit character to its numeric value. + * + * @param[in] aDigitChar The digit character to parse. + * @param[out] aValue A reference to return the parsed value on success. + * + * @retval kErrorNone Successfully parsed the digit, @p aValue is updated. + * @retval kErrorInvalidArgs @p aDigitChar is not a valid digit character. + * + */ +Error ParseDigit(char aDigitChar, uint8_t &aValue); + +/** + * Parse a given hex digit character ('0'-'9', 'A'-'F', or 'a'-'f') to its numeric value. + * + * @param[in] aHexChar The hex digit character to parse. + * @param[out] aValue A reference to return the parsed value on success. + * + * @retval kErrorNone Successfully parsed the digit, @p aValue is updated. + * @retval kErrorInvalidArgs @p aHexChar is not a valid hex digit character. + * + */ +Error ParseHexDigit(char aHexChar, uint8_t &aValue); + /** * Coverts a boolean to "yes" or "no" string. * diff --git a/src/core/meshcop/meshcop.cpp b/src/core/meshcop/meshcop.cpp index 8bce74582..5eeb391ea 100644 --- a/src/core/meshcop/meshcop.cpp +++ b/src/core/meshcop/meshcop.cpp @@ -95,7 +95,7 @@ bool JoinerPskd::IsPskdValid(const char *aPskdString) { char c = aPskdString[i]; - VerifyOrExit(isdigit(c) || isupper(c)); + VerifyOrExit(IsDigit(c) || IsUppercase(c)); VerifyOrExit(c != 'I' && c != 'O' && c != 'Q' && c != 'Z'); } diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index 8e5cdc869..d82dfb4f1 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -586,22 +586,9 @@ Error Address::ParseFrom(const char *aString, char aTerminatorChar) while (true) { - char c = *aString; uint8_t digit; - if (('A' <= c) && (c <= 'F')) - { - digit = static_cast(c - 'A' + 10); - } - else if (('a' <= c) && (c <= 'f')) - { - digit = static_cast(c - 'a' + 10); - } - else if (('0' <= c) && (c <= '9')) - { - digit = static_cast(c - '0'); - } - else + if (ParseHexDigit(*aString, digit) != kErrorNone) { break; } diff --git a/src/core/utils/parse_cmdline.cpp b/src/core/utils/parse_cmdline.cpp index 3f30c8337..00b96047b 100644 --- a/src/core/utils/parse_cmdline.cpp +++ b/src/core/utils/parse_cmdline.cpp @@ -48,37 +48,6 @@ static bool IsSeparator(char aChar) { return (aChar == ' ') || (aChar == '\t') | static bool IsEscapable(char aChar) { return IsSeparator(aChar) || (aChar == '\\'); } -static Error ParseDigit(char aDigitChar, uint8_t &aValue) -{ - Error error = kErrorNone; - - VerifyOrExit(('0' <= aDigitChar) && (aDigitChar <= '9'), error = kErrorInvalidArgs); - aValue = static_cast(aDigitChar - '0'); - -exit: - return error; -} - -static Error ParseHexDigit(char aHexChar, uint8_t &aValue) -{ - Error error = kErrorNone; - - if (('A' <= aHexChar) && (aHexChar <= 'F')) - { - ExitNow(aValue = static_cast(aHexChar - 'A' + 10)); - } - - if (('a' <= aHexChar) && (aHexChar <= 'f')) - { - ExitNow(aValue = static_cast(aHexChar - 'a' + 10)); - } - - error = ParseDigit(aHexChar, aValue); - -exit: - return error; -} - Error ParseCmd(char *aCommandString, Arg aArgs[], uint8_t aArgsMaxLength) { Error error = kErrorNone; diff --git a/tests/unit/test_string.cpp b/tests/unit/test_string.cpp index 7158ca28c..251fc31fb 100644 --- a/tests/unit/test_string.cpp +++ b/tests/unit/test_string.cpp @@ -337,6 +337,8 @@ void TestStringParseUint8(void) {"0256", kErrorParse}, // Larger than max `uint8_t` }; + uint8_t digit; + printf("\nTest 11: TestStringParseUint8() function\n"); for (const TestCase &testCase : kTestCases) @@ -363,6 +365,64 @@ void TestStringParseUint8(void) } } + for (char c = '0'; c <= '9'; c++) + { + VerifyOrQuit(IsDigit(c)); + VerifyOrQuit(!IsUppercase(c)); + VerifyOrQuit(!IsLowercase(c)); + + SuccessOrQuit(ParseDigit(c, digit)); + VerifyOrQuit(digit == (c - '0')); + + SuccessOrQuit(ParseHexDigit(c, digit)); + VerifyOrQuit(digit == (c - '0')); + } + + for (char c = 'A'; c <= 'Z'; c++) + { + VerifyOrQuit(!IsDigit(c)); + VerifyOrQuit(IsUppercase(c)); + VerifyOrQuit(!IsLowercase(c)); + VerifyOrQuit(ParseDigit(c, digit) != kErrorNone); + + if (c <= 'F') + { + SuccessOrQuit(ParseHexDigit(c, digit)); + VerifyOrQuit(digit == (c - 'A' + 10)); + } + else + { + VerifyOrQuit(ParseHexDigit(c, digit) != kErrorNone); + } + } + + for (char c = 'a'; c <= 'z'; c++) + { + VerifyOrQuit(!IsDigit(c)); + VerifyOrQuit(!IsUppercase(c)); + VerifyOrQuit(IsLowercase(c)); + VerifyOrQuit(ParseDigit(c, digit) != kErrorNone); + + if (c <= 'f') + { + SuccessOrQuit(ParseHexDigit(c, digit)); + VerifyOrQuit(digit == (c - 'a' + 10)); + } + else + { + VerifyOrQuit(ParseHexDigit(c, digit) != kErrorNone); + } + } + + VerifyOrQuit(!IsDigit(static_cast('0' - 1))); + VerifyOrQuit(!IsDigit(static_cast('9' + 1))); + + VerifyOrQuit(!IsUppercase(static_cast('A' - 1))); + VerifyOrQuit(!IsUppercase(static_cast('Z' + 1))); + + VerifyOrQuit(!IsLowercase(static_cast('a' - 1))); + VerifyOrQuit(!IsLowercase(static_cast('z' + 1))); + printf("\n\n -- PASS\n"); }