From 4cb7362e99d2ce0e8568b0e56dad07f17adc1ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Thu, 19 Jan 2017 11:30:48 -0800 Subject: [PATCH] Added more unit tests and fixed bugs with CRT replacement functions. --- include/bx/string.h | 14 +++++------ src/commandline.cpp | 16 ++++++------- src/string.cpp | 56 +++++++++++++++++++++++++------------------ tests/string_test.cpp | 39 ++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/include/bx/string.h b/include/bx/string.h index 4715062..8c01679 100644 --- a/include/bx/string.h +++ b/include/bx/string.h @@ -116,29 +116,29 @@ namespace bx bool toBool(const char* _str); /// String compare. - int32_t strncmp(const char* _lhs, const char* _rhs, size_t _max = -1); + int32_t strncmp(const char* _lhs, const char* _rhs, size_t _max = INT32_MAX); /// Case insensitive string compare. - int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max = -1); + int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max = INT32_MAX); /// size_t strnlen(const char* _str, size_t _max = -1); /// Copy _num characters from string _src to _dst buffer of maximum _dstSize capacity /// including zero terminator. Copy will be terminated with '\0'. - size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num = -1); + size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num = INT32_MAX); /// - const char* strnchr(const char* _str, char _ch, size_t _max = -1); + const char* strnchr(const char* _str, char _ch, size_t _max = INT32_MAX); /// - const char* strnrchr(const char* _str, char _ch, size_t _max = -1); + const char* strnrchr(const char* _str, char _ch, size_t _max = INT32_MAX); /// Find substring in string. Limit search to _size. - const char* strnstr(const char* _str, const char* _find, size_t _max = -1); + const char* strnstr(const char* _str, const char* _find, size_t _max = INT32_MAX); /// Find substring in string. Case insensitive. Limit search to _max. - const char* stristr(const char* _str, const char* _find, size_t _max = -1); + const char* stristr(const char* _str, const char* _find, size_t _max = INT32_MAX); /// Find new line. Returns pointer after new line terminator. const char* strnl(const char* _str); diff --git a/src/commandline.cpp b/src/commandline.cpp index 3cbe098..b303fbc 100644 --- a/src/commandline.cpp +++ b/src/commandline.cpp @@ -5,8 +5,6 @@ #include -#include - namespace bx { // Reference: @@ -37,7 +35,7 @@ namespace bx switch (state) { case SkipWhitespace: - for (; isspace(*curr); ++curr) {}; // skip whitespace + for (; isSpace(*curr); ++curr) {}; // skip whitespace state = SetTerm; break; @@ -68,7 +66,7 @@ namespace bx { sub = !sub; } - else if (isspace(*curr) && !sub) + else if (isSpace(*curr) && !sub) { state = End; } @@ -271,7 +269,7 @@ namespace bx ++arg; if (_short == *arg) { - if (1 == strlen(arg) ) + if (1 == strnlen(arg) ) { if (0 == _skip) { @@ -280,7 +278,7 @@ namespace bx return ""; } else if (ii+_numParams < m_argc - && '-' != *m_argv[ii+1] ) + && '-' != *m_argv[ii+1] ) { return m_argv[ii+1]; } @@ -293,8 +291,8 @@ namespace bx } } else if (NULL != _long - && '-' == *arg - && 0 == strincmp(arg+1, _long) ) + && '-' == *arg + && 0 == strincmp(arg+1, _long) ) { if (0 == _skip) { @@ -303,7 +301,7 @@ namespace bx return ""; } else if (ii+_numParams < m_argc - && '-' != *m_argv[ii+1] ) + && '-' != *m_argv[ii+1] ) { return m_argv[ii+1]; } diff --git a/src/string.cpp b/src/string.cpp index b730633..4fd9bdc 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -52,12 +52,12 @@ namespace bx char toLower(char _ch) { - return _ch - (isUpper(_ch) ? 0x20 : 0); + return _ch + (isUpper(_ch) ? 0x20 : 0); } char toUpper(char _ch) { - return _ch + (isLower(_ch) ? 0x20 : 0); + return _ch - (isLower(_ch) ? 0x20 : 0); } bool toBool(const char* _str) @@ -73,14 +73,14 @@ namespace bx ; ++_lhs, ++_rhs, --_max ) { - if (*_lhs != '\0' - || *_rhs != '\0') + if (*_lhs == '\0' + || *_rhs == '\0') { break; } } - return *_lhs - *_rhs; + return 0 == _max ? 0 : *_lhs - *_rhs; } int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max) @@ -90,14 +90,14 @@ namespace bx ; ++_lhs, ++_rhs, --_max ) { - if (*_lhs != '\0' - || *_rhs != '\0') + if (*_lhs == '\0' + || *_rhs == '\0') { break; } } - return *_lhs - *_rhs; + return 0 == _max ? 0 : *_lhs - *_rhs; } size_t strnlen(const char* _str, size_t _max) @@ -150,32 +150,42 @@ namespace bx const char* strnstr(const char* _str, const char* _find, size_t _max) { - char first = *_find; - if ('\0' == first) - { - return _str; - } + const char* ptr = _str; - const char* cmp = _find + 1; - size_t len = strnlen(cmp); - do + size_t stringLen = strnlen(_str, _max); + const size_t findLen = strnlen(_find); + + for (; stringLen >= findLen; ++ptr, --stringLen) { - for (char match = *_str++; match != first && 0 < _max; match = *_str++, --_max) + // Find start of the string. + while (*ptr != *_find) { - if ('\0' == match) + ++ptr; + --stringLen; + + // Search pattern lenght can't be longer than the string. + if (findLen > stringLen) { return NULL; } } - if (0 == _max) + // Set pointers. + const char* string = ptr; + const char* search = _find; + + // Start comparing. + while (*string++ == *search++) { - return NULL; + // If end of the 'search' string is reached, all characters match. + if ('\0' == *search) + { + return ptr; + } } + } - } while (0 != strncmp(_str, cmp, len) ); - - return --_str; + return NULL; } const char* stristr(const char* _str, const char* _find, size_t _max) diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 771cace..1600830 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -10,6 +10,19 @@ bx::AllocatorI* g_allocator; +TEST_CASE("chars", "") +{ + for (char ch = 'A'; ch <= 'Z'; ++ch) + { + REQUIRE(!bx::isLower(ch) ); + REQUIRE(!bx::isNumeric(ch) ); + REQUIRE(bx::isUpper(ch) ); + REQUIRE(bx::isAlpha(ch) ); + REQUIRE(bx::isAlphaNum(ch) ); + REQUIRE(bx::isLower(bx::toLower(ch) ) ); + } +} + TEST_CASE("strnlen", "") { const char* test = "test"; @@ -45,6 +58,7 @@ TEST_CASE("strincmp", "") REQUIRE(0 == bx::strincmp("test", "test") ); REQUIRE(0 == bx::strincmp("test", "testestes", 4) ); REQUIRE(0 == bx::strincmp("testestes", "test", 4) ); + REQUIRE(0 != bx::strincmp("preprocess", "platform") ); } TEST_CASE("strnchr", "") @@ -63,6 +77,31 @@ TEST_CASE("strnrchr", "") REQUIRE(&test[2] == bx::strnrchr(test, 's') ); } +TEST_CASE("stristr", "") +{ + const char* test = "The Quick Brown Fox Jumps Over The Lazy Dog."; + + REQUIRE(NULL == bx::stristr(test, "quick", 8) ); + REQUIRE(NULL == bx::stristr(test, "quick1") ); + REQUIRE(&test[4] == bx::stristr(test, "quick", 9) ); + REQUIRE(&test[4] == bx::stristr(test, "quick") ); +} + +TEST_CASE("strnstr", "") +{ + const char* test = "The Quick Brown Fox Jumps Over The Lazy Dog."; + + REQUIRE(NULL == bx::strnstr(test, "quick", 8) ); + REQUIRE(NULL == bx::strnstr(test, "quick1") ); + REQUIRE(NULL == bx::strnstr(test, "quick", 9) ); + REQUIRE(NULL == bx::strnstr(test, "quick") ); + + REQUIRE(NULL == bx::strnstr(test, "Quick", 8) ); + REQUIRE(NULL == bx::strnstr(test, "Quick1") ); + REQUIRE(&test[4] == bx::strnstr(test, "Quick", 9) ); + REQUIRE(&test[4] == bx::strnstr(test, "Quick") ); +} + TEST_CASE("StringView", "") { bx::StringView sv("test");