From d47a3fa9adbebeea91b75295bfefcc5756de1e69 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 17 Jun 2021 10:13:03 -0700 Subject: [PATCH] [string] new `StringFind()/StringEndsWith()` for a sub-string (#6733) This commit adds a new flavor of function `StringFind()` which finds the first occurrence of a given sub-string within a string. It also adds `StringEndsWith()` function that works with a sub-string. The unit test `test_string` is also updated to cover the new behavior of the newly added function. --- src/core/common/string.cpp | 28 +++++++++++++++++++++++ src/core/common/string.hpp | 23 +++++++++++++++++++ tests/unit/test_string.cpp | 46 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/core/common/string.cpp b/src/core/common/string.cpp index 970d92552..f6916e657 100644 --- a/src/core/common/string.cpp +++ b/src/core/common/string.cpp @@ -66,6 +66,26 @@ const char *StringFind(const char *aString, char aChar) return ret; } +const char *StringFind(const char *aString, const char *aSubString) +{ + const char *ret = nullptr; + size_t len = strlen(aString); + size_t subLen = strlen(aSubString); + + VerifyOrExit(subLen <= len); + + for (size_t index = 0; index <= static_cast(len - subLen); index++) + { + if (memcmp(&aString[index], aSubString, subLen) == 0) + { + ExitNow(ret = &aString[index]); + } + } + +exit: + return ret; +} + bool StringEndsWith(const char *aString, char aChar) { size_t len = strlen(aString); @@ -73,6 +93,14 @@ bool StringEndsWith(const char *aString, char aChar) return len > 0 && aString[len - 1] == aChar; } +bool StringEndsWith(const char *aString, const char *aSubString) +{ + size_t len = strlen(aString); + size_t subLen = strlen(aSubString); + + return (subLen > 0) && (len >= subLen) && (memcmp(aSubString, &aString[len - subLen], subLen) == 0); +} + StringWriter::StringWriter(char *aBuffer, uint16_t aSize) : mBuffer(aBuffer) , mLength(0) diff --git a/src/core/common/string.hpp b/src/core/common/string.hpp index 3a9ef7cea..8d84c79bb 100644 --- a/src/core/common/string.hpp +++ b/src/core/common/string.hpp @@ -78,6 +78,17 @@ uint16_t StringLength(const char *aString, uint16_t aMaxLength); */ const char *StringFind(const char *aString, char aChar); +/** + * This function finds the first occurrence of a given sub-string in a null-terminated string. + * + * @param[in] aString A pointer to the string. + * @param[in] aSubString A sub-string to search for. + * + * @returns The pointer to first occurrence of the @p aSubString in @p aString, or nullptr if cannot be found. + * + */ +const char *StringFind(const char *aString, const char *aSubString); + /** * This function checks whether a null-terminated string ends with a given character. * @@ -90,6 +101,18 @@ const char *StringFind(const char *aString, char aChar); */ bool StringEndsWith(const char *aString, char aChar); +/** + * This function checks whether a null-terminated string ends with a given sub-string. + * + * @param[in] aString A pointer to the string. + * @param[in] aSubString A sun-string to check against. + * + * @retval TRUE If @p aString ends with sub-string @p aSubString. + * @retval FALSE If @p aString does not end with sub-string @p aSubString. + * + */ +bool StringEndsWith(const char *aString, const char *aSubString); + /** * This class implements writing to a string buffer. * diff --git a/tests/unit/test_string.cpp b/tests/unit/test_string.cpp index 5394894ad..343b5fa5f 100644 --- a/tests/unit/test_string.cpp +++ b/tests/unit/test_string.cpp @@ -145,7 +145,8 @@ void TestUtf8(void) void TestStringFind(void) { char emptyString[1] = {'\0'}; - char testString[] = "foo.bar\\."; + char testString[] = "foo.bar.bar\\."; + char testString2[] = "abcabcabcdabc"; printf("\nTest 6: StringFind() function\n"); @@ -153,13 +154,53 @@ void TestStringFind(void) VerifyOrQuit(StringFind(testString, 'o') == &testString[1], "StringFind() failed"); VerifyOrQuit(StringFind(testString, '.') == &testString[3], "StringFind() failed"); VerifyOrQuit(StringFind(testString, 'r') == &testString[6], "StringFind() failed"); - VerifyOrQuit(StringFind(testString, '\\') == &testString[7], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, '\\') == &testString[11], "StringFind() failed"); VerifyOrQuit(StringFind(testString, 'x') == nullptr, "StringFind() failed"); VerifyOrQuit(StringFind(testString, ',') == nullptr, "StringFind() failed"); VerifyOrQuit(StringFind(emptyString, 'f') == nullptr, "StringFind() failed"); VerifyOrQuit(StringFind(emptyString, '.') == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "foo") == &testString[0], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "oo") == &testString[1], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "bar") == &testString[4], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "bar\\") == &testString[8], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "\\.") == &testString[11], "StringFind() failed"); + VerifyOrQuit(StringFind(testString, testString) == testString, "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "fooo") == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "far") == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "bar\\..") == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(testString, "") == &testString[0], "StringFind() failed"); + + VerifyOrQuit(StringFind(emptyString, "foo") == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(emptyString, "bar") == nullptr, "StringFind() failed"); + VerifyOrQuit(StringFind(emptyString, "") == &emptyString[0], "StringFind() failed"); + + // Verify when sub-string has repeated patterns + VerifyOrQuit(StringFind(testString2, "abcabc") == &testString2[0], "StringFind() failed"); + VerifyOrQuit(StringFind(testString2, "abcabcd") == &testString2[3], "StringFind() failed"); + + printf(" -- PASS\n"); +} + +void TestStringEndsWith(void) +{ + printf("\nTest 7: StringEndsWith() function\n"); + + VerifyOrQuit(StringEndsWith("foobar", 'r'), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("foobar", 'a'), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("foobar", '\0'), "StringEndsWith() failed"); + VerifyOrQuit(StringEndsWith("a", 'a'), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("a", 'b'), "StringEndsWith() failed"); + + VerifyOrQuit(StringEndsWith("foobar", "bar"), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("foobar", "ba"), "StringEndsWith() failed"); + VerifyOrQuit(StringEndsWith("foobar", "foobar"), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("foobar", "foobarr"), "StringEndsWith() failed"); + + VerifyOrQuit(!StringEndsWith("", 'a'), "StringEndsWith() failed"); + VerifyOrQuit(!StringEndsWith("", "foo"), "StringEndsWith() failed"); + printf(" -- PASS\n"); } @@ -171,6 +212,7 @@ int main(void) ot::TestStringLength(); ot::TestUtf8(); ot::TestStringFind(); + ot::TestStringEndsWith(); printf("\nAll tests passed.\n"); return 0; }