From bf637fa5e227567a9af82a6881ccbfb7e99546eb Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sat, 22 Nov 2025 23:03:23 +0100 Subject: [PATCH 1/5] feat(string): Merge startWith/endsWith implementations --- .../GameEngine/Include/Common/UnicodeString.h | 24 +++++++++ .../Source/Common/System/AsciiString.cpp | 40 ++------------- .../Source/Common/System/UnicodeString.cpp | 24 +++++++++ .../Libraries/Source/WWVegas/WWLib/stringex.h | 49 +++++++++++++++++++ 4 files changed, 101 insertions(+), 36 deletions(-) diff --git a/Core/GameEngine/Include/Common/UnicodeString.h b/Core/GameEngine/Include/Common/UnicodeString.h index d924b2f9af8..78e0b3e180a 100644 --- a/Core/GameEngine/Include/Common/UnicodeString.h +++ b/Core/GameEngine/Include/Common/UnicodeString.h @@ -306,6 +306,30 @@ class UnicodeString */ int compareNoCase(const WideChar* s) const; + /** + return true iff self starts with the given string. + */ + Bool startsWith(const WideChar* p) const; + inline Bool startsWith(const UnicodeString& stringSrc) const { return startsWith(stringSrc.str()); } + + /** + return true iff self starts with the given string. (case insensitive) + */ + Bool startsWithNoCase(const WideChar* p) const; + inline Bool startsWithNoCase(const UnicodeString& stringSrc) const { return startsWithNoCase(stringSrc.str()); } + + /** + return true iff self ends with the given string. + */ + Bool endsWith(const WideChar* p) const; + Bool endsWith(const UnicodeString& stringSrc) const { return endsWith(stringSrc.str()); } + + /** + return true iff self ends with the given string. (case insensitive) + */ + Bool endsWithNoCase(const WideChar* p) const; + Bool endsWithNoCase(const UnicodeString& stringSrc) const { return endsWithNoCase(stringSrc.str()); } + /** conceptually similar to strtok(): diff --git a/Core/GameEngine/Source/Common/System/AsciiString.cpp b/Core/GameEngine/Source/Common/System/AsciiString.cpp index 1bf7ff672c3..1be78989935 100644 --- a/Core/GameEngine/Source/Common/System/AsciiString.cpp +++ b/Core/GameEngine/Source/Common/System/AsciiString.cpp @@ -477,57 +477,25 @@ void AsciiString::format_va(const char* format, va_list args) // ----------------------------------------------------- Bool AsciiString::startsWith(const char* p) const { - if (*p == 0) - return true; // everything starts with the empty string - - int lenThis = getLength(); - int lenThat = strlen(p); - if (lenThis < lenThat) - return false; // that must be smaller than this - - return strncmp(peek(), p, lenThat) == 0; + return ::startsWith(peek(), p); } // ----------------------------------------------------- Bool AsciiString::startsWithNoCase(const char* p) const { - if (*p == 0) - return true; // everything starts with the empty string - - int lenThis = getLength(); - int lenThat = strlen(p); - if (lenThis < lenThat) - return false; // that must be smaller than this - - return strnicmp(peek(), p, lenThat) == 0; + return ::startsWithNoCase(peek(), p); } // ----------------------------------------------------- Bool AsciiString::endsWith(const char* p) const { - if (*p == 0) - return true; // everything ends with the empty string - - int lenThis = getLength(); - int lenThat = strlen(p); - if (lenThis < lenThat) - return false; // that must be smaller than this - - return strncmp(peek() + lenThis - lenThat, p, lenThat) == 0; + return ::endsWith(peek(), p); } // ----------------------------------------------------- Bool AsciiString::endsWithNoCase(const char* p) const { - if (*p == 0) - return true; // everything ends with the empty string - - int lenThis = getLength(); - int lenThat = strlen(p); - if (lenThis < lenThat) - return false; // that must be smaller than this - - return strnicmp(peek() + lenThis - lenThat, p, lenThat) == 0; + return ::endsWithNoCase(peek(), p); } //----------------------------------------------------------------------------- diff --git a/Core/GameEngine/Source/Common/System/UnicodeString.cpp b/Core/GameEngine/Source/Common/System/UnicodeString.cpp index b6c6ba2b81f..3f0fe47b04f 100644 --- a/Core/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/Core/GameEngine/Source/Common/System/UnicodeString.cpp @@ -406,6 +406,30 @@ void UnicodeString::format_va(const WideChar* format, va_list args) } } +// ----------------------------------------------------- +Bool UnicodeString::startsWith(const WideChar* p) const +{ + return ::startsWith(peek(), p); +} + +// ----------------------------------------------------- +Bool UnicodeString::startsWithNoCase(const WideChar* p) const +{ + return ::startsWithNoCase(peek(), p); +} + +// ----------------------------------------------------- +Bool UnicodeString::endsWith(const WideChar* p) const +{ + return ::endsWith(peek(), p); +} + +// ----------------------------------------------------- +Bool UnicodeString::endsWithNoCase(const WideChar* p) const +{ + return ::endsWithNoCase(peek(), p); +} + //----------------------------------------------------------------------------- Bool UnicodeString::nextToken(UnicodeString* tok, UnicodeString delimiters) { diff --git a/Core/Libraries/Source/WWVegas/WWLib/stringex.h b/Core/Libraries/Source/WWVegas/WWLib/stringex.h index fe452ac2182..46b5b94d75f 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/stringex.h +++ b/Core/Libraries/Source/WWVegas/WWLib/stringex.h @@ -55,6 +55,11 @@ template size_t strlmove_t(char (&dst)[Size], const char *src); template size_t strlmcat_t(char (&dst)[Size], const char *src); #endif +template bool startsWith(const T *str, const T *prefix); +template bool startsWithNoCase(const T *str, const T *prefix); +template bool endsWith(const T *str, const T *suffix); +template bool endsWithNoCase(const T *str, const T *suffix); + // Implementation @@ -182,3 +187,47 @@ template size_t strlcat_t(char (&dst)[Size], const char *src) { ret template size_t strlmove_t(char (&dst)[Size], const char *src) { return strlmove_t(dst, src, Size); } template size_t strlmcat_t(char (&dst)[Size], const char *src) { return strlmcat_t(dst, src, Size); } #endif + +inline int compare_string(const char *a, const char *b, const size_t maxCount, const bool caseSensitive = true) +{ + return caseSensitive ? strncmp(a, b, maxCount) : _strnicmp(a, b, maxCount); +} + +inline int compare_string(const wchar_t *a, const wchar_t *b, const size_t maxCount, const bool caseSensitive = true) +{ + return caseSensitive ? wcsncmp(a, b, maxCount) : _wcsnicmp(a, b, maxCount); +} + +template bool string_edge_equals(const T *str, const T *smaller, const bool endEdge, const bool case_sensitive = true) +{ + if (*smaller == T(0)) + return true; // everything starts or ends with the empty string + + const size_t strlen = strlen_t(str); + const size_t smallen = strlen_t(smaller); + if (strlen < smallen) + return false; // smaller must be smaller than str + + const T* strStart = endEdge ? str + strlen - smallen : str; + + return compare_string(strStart, smaller, smallen, case_sensitive) == 0; +} + +template bool startsWith(const T *str, const T *prefix) +{ + return string_edge_equals(str, prefix, false); +}; +template bool startsWithNoCase(const T *str, const T *prefix) +{ + return string_edge_equals(str, prefix, false, false); +}; + +template bool endsWith(const T *str, const T *suffix) +{ + return string_edge_equals(str, suffix, true); +}; + +template bool endsWithNoCase(const T *str, const T *suffix) +{ + return string_edge_equals(str, suffix, true, false); +}; From b021572fc594f0b114eba9951c1822f8b83bcd33 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Mon, 24 Nov 2025 21:41:52 +0100 Subject: [PATCH 2/5] Dropped templates and defined the functions explicitly --- .../Libraries/Source/WWVegas/WWLib/stringex.h | 198 ++++++++++++------ 1 file changed, 129 insertions(+), 69 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/stringex.h b/Core/Libraries/Source/WWVegas/WWLib/stringex.h index 46b5b94d75f..25e78ea910b 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/stringex.h +++ b/Core/Libraries/Source/WWVegas/WWLib/stringex.h @@ -24,48 +24,48 @@ // Declaration -template size_t strlen_t(const T *str); -template size_t strnlen_t(const T *str, size_t maxlen); +template size_t strlen_t(const T* str); +template size_t strnlen_t(const T* str, size_t maxlen); #if defined(_MSC_VER) && _MSC_VER < 1300 -size_t strnlen(const char *str, size_t maxlen); -size_t wcsnlen(const wchar_t *str, size_t maxlen); +size_t strnlen(const char* str, size_t maxlen); +size_t wcsnlen(const wchar_t* str, size_t maxlen); #endif -template size_t strlcpy_t(T *dst, const T *src, size_t dstsize); -template size_t strlcat_t(T *dst, const T *src, size_t dstsize); +template size_t strlcpy_t(T* dst, const T* src, size_t dstsize); +template size_t strlcat_t(T* dst, const T* src, size_t dstsize); -size_t strlcpy(char *dst, const char *src, size_t dstsize); -size_t strlcat(char *dst, const char *src, size_t dstsize); -size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t dstsize); -size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t dstsize); +size_t strlcpy(char* dst, const char* src, size_t dstsize); +size_t strlcat(char* dst, const char* src, size_t dstsize); +size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dstsize); +size_t wcslcat(wchar_t* dst, const wchar_t* src, size_t dstsize); -template size_t strlmove_t(T *dst, const T *src, size_t dstsize); -template size_t strlmcat_t(T *dst, const T *src, size_t dstsize); +template size_t strlmove_t(T* dst, const T* src, size_t dstsize); +template size_t strlmcat_t(T* dst, const T* src, size_t dstsize); -size_t strlmove(char *dst, const char *src, size_t dstsize); -size_t strlmcat(char *dst, const char *src, size_t dstsize); -size_t wcslmove(wchar_t *dst, const wchar_t *src, size_t dstsize); -size_t wcslmcat(wchar_t *dst, const wchar_t *src, size_t dstsize); +size_t strlmove(char* dst, const char* src, size_t dstsize); +size_t strlmcat(char* dst, const char* src, size_t dstsize); +size_t wcslmove(wchar_t* dst, const wchar_t* src, size_t dstsize); +size_t wcslmcat(wchar_t* dst, const wchar_t* src, size_t dstsize); #if !(defined(_MSC_VER) && _MSC_VER < 1300) -template size_t strlcpy_t(char (&dst)[Size], const char *src); -template size_t strlcat_t(char (&dst)[Size], const char *src); -template size_t strlmove_t(char (&dst)[Size], const char *src); -template size_t strlmcat_t(char (&dst)[Size], const char *src); +template size_t strlcpy_t(char(&dst)[Size], const char* src); +template size_t strlcat_t(char(&dst)[Size], const char* src); +template size_t strlmove_t(char(&dst)[Size], const char* src); +template size_t strlmcat_t(char(&dst)[Size], const char* src); #endif -template bool startsWith(const T *str, const T *prefix); -template bool startsWithNoCase(const T *str, const T *prefix); -template bool endsWith(const T *str, const T *suffix); -template bool endsWithNoCase(const T *str, const T *suffix); +template bool startsWith(const T* str, const T* prefix); +template bool startsWithNoCase(const T* str, const T* prefix); +template bool endsWith(const T* str, const T* suffix); +template bool endsWithNoCase(const T* str, const T* suffix); // Implementation // Templated strlen. // Returns the number of characters until the first zero character. -template size_t strlen_t(const T *str) +template size_t strlen_t(const T* str) { const T* begin = str; while (*str) @@ -75,7 +75,7 @@ template size_t strlen_t(const T *str) // Templated strlen. // Returns the number of characters until the first zero character or when maxlen is reached. -template size_t strnlen_t(const T *str, size_t maxlen) +template size_t strnlen_t(const T* str, size_t maxlen) { const T* begin = str; const T* end = str + maxlen; @@ -85,14 +85,14 @@ template size_t strnlen_t(const T *str, size_t maxlen) } #if defined(_MSC_VER) && _MSC_VER < 1300 -inline size_t strnlen(const char *str, size_t maxlen) { return strnlen_t(str, maxlen); } -inline size_t wcsnlen(const wchar_t *str, size_t maxlen) { return strnlen_t(str, maxlen); } +inline size_t strnlen(const char* str, size_t maxlen) { return strnlen_t(str, maxlen); } +inline size_t wcsnlen(const wchar_t* str, size_t maxlen) { return strnlen_t(str, maxlen); } #endif // Templated strlcpy. Prefer using this over strncpy. // Copies src into dst until dstsize minus one. Always null terminates. // Returns the length of src, excluding the null terminator. -template size_t strlcpy_t(T *dst, const T *src, size_t dstsize) +template size_t strlcpy_t(T* dst, const T* src, size_t dstsize) { const size_t srclen = strlen_t(src); if (dstsize != 0) @@ -107,7 +107,7 @@ template size_t strlcpy_t(T *dst, const T *src, size_t dstsize) // Templated strlcat. Prefer using this over strncpy. // Appends src into dst until dstsize minus one. Always null terminates. // Returns the length of dst + src, excluding the null terminator. -template size_t strlcat_t(T *dst, const T *src, size_t dstsize) +template size_t strlcat_t(T* dst, const T* src, size_t dstsize) { const size_t dstlen = strnlen_t(dst, dstsize); const size_t srclen = strlen_t(src); @@ -129,18 +129,18 @@ template size_t strlcat_t(T *dst, const T *src, size_t dstsize) } #ifndef HAVE_STRLCPY -inline size_t strlcpy(char *dst, const char *src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } +inline size_t strlcpy(char* dst, const char* src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } #endif #ifndef HAVE_STRLCAT -inline size_t strlcat(char *dst, const char *src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } +inline size_t strlcat(char* dst, const char* src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } #endif -inline size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } -inline size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } +inline size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } +inline size_t wcslcat(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } // Templated strlmove. Prefer using this over strlcpy if dst and src overlap. // Moves src into dst until dstsize minus one. Always null terminates. // Returns the length of src, excluding the null terminator. -template size_t strlmove_t(T *dst, const T *src, size_t dstsize) +template size_t strlmove_t(T* dst, const T* src, size_t dstsize) { const size_t srclen = strlen_t(src); if (dstsize > 0) @@ -155,7 +155,7 @@ template size_t strlmove_t(T *dst, const T *src, size_t dstsize) // Templated strlmcat. Prefer using this over strlcat if dst and src overlap. // Appends src into dst until dstsize minus one. Always null terminates. // Returns the length of dst + src, excluding the null terminator. -template size_t strlmcat_t(T *dst, const T *src, size_t dstsize) +template size_t strlmcat_t(T* dst, const T* src, size_t dstsize) { const size_t dstlen = strnlen_t(dst, dstsize); const size_t srclen = strlen_t(src); @@ -176,58 +176,118 @@ template size_t strlmcat_t(T *dst, const T *src, size_t dstsize) return dstlen + srclen; // length tried to create } -inline size_t strlmove(char *dst, const char *src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } -inline size_t strlmcat(char *dst, const char *src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } -inline size_t wcslmove(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } -inline size_t wcslmcat(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } +inline size_t strlmove(char* dst, const char* src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } +inline size_t strlmcat(char* dst, const char* src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } +inline size_t wcslmove(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } +inline size_t wcslmcat(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } #if !(defined(_MSC_VER) && _MSC_VER < 1300) -template size_t strlcpy_t(char (&dst)[Size], const char *src) { return strlcpy_t(dst, src, Size); } -template size_t strlcat_t(char (&dst)[Size], const char *src) { return strlcat_t(dst, src, Size); } -template size_t strlmove_t(char (&dst)[Size], const char *src) { return strlmove_t(dst, src, Size); } -template size_t strlmcat_t(char (&dst)[Size], const char *src) { return strlmcat_t(dst, src, Size); } +template size_t strlcpy_t(char(&dst)[Size], const char* src) { return strlcpy_t(dst, src, Size); } +template size_t strlcat_t(char(&dst)[Size], const char* src) { return strlcat_t(dst, src, Size); } +template size_t strlmove_t(char(&dst)[Size], const char* src) { return strlmove_t(dst, src, Size); } +template size_t strlmcat_t(char(&dst)[Size], const char* src) { return strlmcat_t(dst, src, Size); } #endif -inline int compare_string(const char *a, const char *b, const size_t maxCount, const bool caseSensitive = true) +inline bool startsWith(const char* str, const char* prefix) { - return caseSensitive ? strncmp(a, b, maxCount) : _strnicmp(a, b, maxCount); + if (*prefix == char(0)) + return true; // everything starts with the empty string + + const size_t strlen = ::strlen(str); + const size_t prefixlen = ::strlen(prefix); + if (strlen < prefixlen) + return false; // prefix must be as long or shorter than str + + return ::strncmp(str, prefix, prefixlen) == 0; } -inline int compare_string(const wchar_t *a, const wchar_t *b, const size_t maxCount, const bool caseSensitive = true) +inline bool startsWith(const wchar_t* str, const wchar_t* prefix) { - return caseSensitive ? wcsncmp(a, b, maxCount) : _wcsnicmp(a, b, maxCount); + if (*prefix == wchar_t(0)) + return true; // everything starts with the empty string + + const size_t strlen = ::wcslen(str); + const size_t prefixlen = ::wcslen(prefix); + if (strlen < prefixlen) + return false; // prefix must be as long or shorter than str + + return ::wcsncmp(str, prefix, prefixlen) == 0; } -template bool string_edge_equals(const T *str, const T *smaller, const bool endEdge, const bool case_sensitive = true) +inline bool startsWithNoCase(const char* str, const char* prefix) { - if (*smaller == T(0)) - return true; // everything starts or ends with the empty string + if (*prefix == char(0)) + return true; // everything starts with the empty string - const size_t strlen = strlen_t(str); - const size_t smallen = strlen_t(smaller); - if (strlen < smallen) - return false; // smaller must be smaller than str + const size_t strlen = ::strlen(str); + const size_t prefixlen = ::strlen(prefix); + if (strlen < prefixlen) + return false; // prefix must be as long or shorter than str - const T* strStart = endEdge ? str + strlen - smallen : str; + return ::strnicmp(str, prefix, prefixlen) == 0; +} - return compare_string(strStart, smaller, smallen, case_sensitive) == 0; +inline bool startsWithNoCase(const wchar_t* str, const wchar_t* prefix) +{ + if (*prefix == wchar_t(0)) + return true; // everything starts with the empty string + + const size_t strlen = ::wcslen(str); + const size_t prefixlen = ::wcslen(prefix); + if (strlen < prefixlen) + return false; // prefix must be as long or shorter than str + + return ::wcsnicmp(str, prefix, prefixlen) == 0; } -template bool startsWith(const T *str, const T *prefix) +inline bool endsWith(const char* str, const char* suffix) { - return string_edge_equals(str, prefix, false); -}; -template bool startsWithNoCase(const T *str, const T *prefix) + if (*suffix == char(0)) + return true; // everything ends with the empty string + + const size_t strlen = ::strlen(str); + const size_t suffixlen = ::strlen(suffix); + if (strlen < suffixlen) + return false; // suffix must be as long or shorter than str + + return ::strncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; +} + +inline bool endsWith(const wchar_t* str, const wchar_t* suffix) { - return string_edge_equals(str, prefix, false, false); -}; + if (*suffix == wchar_t(0)) + return true; // everything ends with the empty string + + const size_t strlen = ::wcslen(str); + const size_t suffixlen = ::wcslen(suffix); + if (strlen < suffixlen) + return false; // suffix must be as long or shorter than str -template bool endsWith(const T *str, const T *suffix) + return ::wcsncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; +} + +inline bool endsWithNoCase(const char* str, const char* suffix) { - return string_edge_equals(str, suffix, true); -}; + if (*suffix == char(0)) + return true; // everything ends with the empty string + + const size_t strlen = ::strlen(str); + const size_t suffixlen = ::strlen(suffix); + if (strlen < suffixlen) + return false; // suffix must be as long or shorter than str -template bool endsWithNoCase(const T *str, const T *suffix) + return ::strnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; +} + +inline bool endsWithNoCase(const wchar_t* str, const wchar_t* suffix) { - return string_edge_equals(str, suffix, true, false); -}; + if (*suffix == wchar_t(0)) + return true; // everything ends with the empty string + + const size_t strlen = ::wcslen(str); + const size_t suffixlen = ::wcslen(suffix); + if (strlen < suffixlen) + return false; // suffix must be as long or shorter than str + + return ::wcsnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; +} From f4001ff6505883abcba42975604ee5d8d0af6159 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Mon, 24 Nov 2025 21:45:53 +0100 Subject: [PATCH 3/5] Undo IDE auto formatting. --- .../Libraries/Source/WWVegas/WWLib/stringex.h | 103 +++++++++--------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/stringex.h b/Core/Libraries/Source/WWVegas/WWLib/stringex.h index 25e78ea910b..977e18c2dc0 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/stringex.h +++ b/Core/Libraries/Source/WWVegas/WWLib/stringex.h @@ -24,48 +24,43 @@ // Declaration -template size_t strlen_t(const T* str); -template size_t strnlen_t(const T* str, size_t maxlen); +template size_t strlen_t(const T *str); +template size_t strnlen_t(const T *str, size_t maxlen); #if defined(_MSC_VER) && _MSC_VER < 1300 -size_t strnlen(const char* str, size_t maxlen); -size_t wcsnlen(const wchar_t* str, size_t maxlen); +size_t strnlen(const char *str, size_t maxlen); +size_t wcsnlen(const wchar_t *str, size_t maxlen); #endif -template size_t strlcpy_t(T* dst, const T* src, size_t dstsize); -template size_t strlcat_t(T* dst, const T* src, size_t dstsize); +template size_t strlcpy_t(T *dst, const T *src, size_t dstsize); +template size_t strlcat_t(T *dst, const T *src, size_t dstsize); -size_t strlcpy(char* dst, const char* src, size_t dstsize); -size_t strlcat(char* dst, const char* src, size_t dstsize); -size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dstsize); -size_t wcslcat(wchar_t* dst, const wchar_t* src, size_t dstsize); +size_t strlcpy(char *dst, const char *src, size_t dstsize); +size_t strlcat(char *dst, const char *src, size_t dstsize); +size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t dstsize); +size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t dstsize); -template size_t strlmove_t(T* dst, const T* src, size_t dstsize); -template size_t strlmcat_t(T* dst, const T* src, size_t dstsize); +template size_t strlmove_t(T *dst, const T *src, size_t dstsize); +template size_t strlmcat_t(T *dst, const T *src, size_t dstsize); -size_t strlmove(char* dst, const char* src, size_t dstsize); -size_t strlmcat(char* dst, const char* src, size_t dstsize); -size_t wcslmove(wchar_t* dst, const wchar_t* src, size_t dstsize); -size_t wcslmcat(wchar_t* dst, const wchar_t* src, size_t dstsize); +size_t strlmove(char *dst, const char *src, size_t dstsize); +size_t strlmcat(char *dst, const char *src, size_t dstsize); +size_t wcslmove(wchar_t *dst, const wchar_t *src, size_t dstsize); +size_t wcslmcat(wchar_t *dst, const wchar_t *src, size_t dstsize); #if !(defined(_MSC_VER) && _MSC_VER < 1300) -template size_t strlcpy_t(char(&dst)[Size], const char* src); -template size_t strlcat_t(char(&dst)[Size], const char* src); -template size_t strlmove_t(char(&dst)[Size], const char* src); -template size_t strlmcat_t(char(&dst)[Size], const char* src); +template size_t strlcpy_t(char (&dst)[Size], const char *src); +template size_t strlcat_t(char (&dst)[Size], const char *src); +template size_t strlmove_t(char (&dst)[Size], const char *src); +template size_t strlmcat_t(char (&dst)[Size], const char *src); #endif -template bool startsWith(const T* str, const T* prefix); -template bool startsWithNoCase(const T* str, const T* prefix); -template bool endsWith(const T* str, const T* suffix); -template bool endsWithNoCase(const T* str, const T* suffix); - // Implementation // Templated strlen. // Returns the number of characters until the first zero character. -template size_t strlen_t(const T* str) +template size_t strlen_t(const T *str) { const T* begin = str; while (*str) @@ -75,7 +70,7 @@ template size_t strlen_t(const T* str) // Templated strlen. // Returns the number of characters until the first zero character or when maxlen is reached. -template size_t strnlen_t(const T* str, size_t maxlen) +template size_t strnlen_t(const T *str, size_t maxlen) { const T* begin = str; const T* end = str + maxlen; @@ -85,14 +80,14 @@ template size_t strnlen_t(const T* str, size_t maxlen) } #if defined(_MSC_VER) && _MSC_VER < 1300 -inline size_t strnlen(const char* str, size_t maxlen) { return strnlen_t(str, maxlen); } -inline size_t wcsnlen(const wchar_t* str, size_t maxlen) { return strnlen_t(str, maxlen); } +inline size_t strnlen(const char *str, size_t maxlen) { return strnlen_t(str, maxlen); } +inline size_t wcsnlen(const wchar_t *str, size_t maxlen) { return strnlen_t(str, maxlen); } #endif // Templated strlcpy. Prefer using this over strncpy. // Copies src into dst until dstsize minus one. Always null terminates. // Returns the length of src, excluding the null terminator. -template size_t strlcpy_t(T* dst, const T* src, size_t dstsize) +template size_t strlcpy_t(T *dst, const T *src, size_t dstsize) { const size_t srclen = strlen_t(src); if (dstsize != 0) @@ -107,7 +102,7 @@ template size_t strlcpy_t(T* dst, const T* src, size_t dstsize) // Templated strlcat. Prefer using this over strncpy. // Appends src into dst until dstsize minus one. Always null terminates. // Returns the length of dst + src, excluding the null terminator. -template size_t strlcat_t(T* dst, const T* src, size_t dstsize) +template size_t strlcat_t(T *dst, const T *src, size_t dstsize) { const size_t dstlen = strnlen_t(dst, dstsize); const size_t srclen = strlen_t(src); @@ -129,18 +124,18 @@ template size_t strlcat_t(T* dst, const T* src, size_t dstsize) } #ifndef HAVE_STRLCPY -inline size_t strlcpy(char* dst, const char* src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } +inline size_t strlcpy(char *dst, const char *src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } #endif #ifndef HAVE_STRLCAT -inline size_t strlcat(char* dst, const char* src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } +inline size_t strlcat(char *dst, const char *src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } #endif -inline size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } -inline size_t wcslcat(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } +inline size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlcpy_t(dst, src, dstsize); } +inline size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlcat_t(dst, src, dstsize); } // Templated strlmove. Prefer using this over strlcpy if dst and src overlap. // Moves src into dst until dstsize minus one. Always null terminates. // Returns the length of src, excluding the null terminator. -template size_t strlmove_t(T* dst, const T* src, size_t dstsize) +template size_t strlmove_t(T *dst, const T *src, size_t dstsize) { const size_t srclen = strlen_t(src); if (dstsize > 0) @@ -155,7 +150,7 @@ template size_t strlmove_t(T* dst, const T* src, size_t dstsize) // Templated strlmcat. Prefer using this over strlcat if dst and src overlap. // Appends src into dst until dstsize minus one. Always null terminates. // Returns the length of dst + src, excluding the null terminator. -template size_t strlmcat_t(T* dst, const T* src, size_t dstsize) +template size_t strlmcat_t(T *dst, const T *src, size_t dstsize) { const size_t dstlen = strnlen_t(dst, dstsize); const size_t srclen = strlen_t(src); @@ -176,19 +171,19 @@ template size_t strlmcat_t(T* dst, const T* src, size_t dstsize) return dstlen + srclen; // length tried to create } -inline size_t strlmove(char* dst, const char* src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } -inline size_t strlmcat(char* dst, const char* src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } -inline size_t wcslmove(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } -inline size_t wcslmcat(wchar_t* dst, const wchar_t* src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } +inline size_t strlmove(char *dst, const char *src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } +inline size_t strlmcat(char *dst, const char *src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } +inline size_t wcslmove(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlmove_t(dst, src, dstsize); } +inline size_t wcslmcat(wchar_t *dst, const wchar_t *src, size_t dstsize) { return strlmcat_t(dst, src, dstsize); } #if !(defined(_MSC_VER) && _MSC_VER < 1300) -template size_t strlcpy_t(char(&dst)[Size], const char* src) { return strlcpy_t(dst, src, Size); } -template size_t strlcat_t(char(&dst)[Size], const char* src) { return strlcat_t(dst, src, Size); } -template size_t strlmove_t(char(&dst)[Size], const char* src) { return strlmove_t(dst, src, Size); } -template size_t strlmcat_t(char(&dst)[Size], const char* src) { return strlmcat_t(dst, src, Size); } +template size_t strlcpy_t(char (&dst)[Size], const char *src) { return strlcpy_t(dst, src, Size); } +template size_t strlcat_t(char (&dst)[Size], const char *src) { return strlcat_t(dst, src, Size); } +template size_t strlmove_t(char (&dst)[Size], const char *src) { return strlmove_t(dst, src, Size); } +template size_t strlmcat_t(char (&dst)[Size], const char *src) { return strlmcat_t(dst, src, Size); } #endif -inline bool startsWith(const char* str, const char* prefix) +inline bool startsWith(const char *str, const char *prefix) { if (*prefix == char(0)) return true; // everything starts with the empty string @@ -201,7 +196,7 @@ inline bool startsWith(const char* str, const char* prefix) return ::strncmp(str, prefix, prefixlen) == 0; } -inline bool startsWith(const wchar_t* str, const wchar_t* prefix) +inline bool startsWith(const wchar_t *str, const wchar_t *prefix) { if (*prefix == wchar_t(0)) return true; // everything starts with the empty string @@ -214,7 +209,7 @@ inline bool startsWith(const wchar_t* str, const wchar_t* prefix) return ::wcsncmp(str, prefix, prefixlen) == 0; } -inline bool startsWithNoCase(const char* str, const char* prefix) +inline bool startsWithNoCase(const char *str, const char *prefix) { if (*prefix == char(0)) return true; // everything starts with the empty string @@ -227,7 +222,7 @@ inline bool startsWithNoCase(const char* str, const char* prefix) return ::strnicmp(str, prefix, prefixlen) == 0; } -inline bool startsWithNoCase(const wchar_t* str, const wchar_t* prefix) +inline bool startsWithNoCase(const wchar_t *str, const wchar_t *prefix) { if (*prefix == wchar_t(0)) return true; // everything starts with the empty string @@ -240,7 +235,7 @@ inline bool startsWithNoCase(const wchar_t* str, const wchar_t* prefix) return ::wcsnicmp(str, prefix, prefixlen) == 0; } -inline bool endsWith(const char* str, const char* suffix) +inline bool endsWith(const char *str, const char *suffix) { if (*suffix == char(0)) return true; // everything ends with the empty string @@ -253,7 +248,7 @@ inline bool endsWith(const char* str, const char* suffix) return ::strncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; } -inline bool endsWith(const wchar_t* str, const wchar_t* suffix) +inline bool endsWith(const wchar_t *str, const wchar_t *suffix) { if (*suffix == wchar_t(0)) return true; // everything ends with the empty string @@ -266,7 +261,7 @@ inline bool endsWith(const wchar_t* str, const wchar_t* suffix) return ::wcsncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; } -inline bool endsWithNoCase(const char* str, const char* suffix) +inline bool endsWithNoCase(const char *str, const char *suffix) { if (*suffix == char(0)) return true; // everything ends with the empty string @@ -279,7 +274,7 @@ inline bool endsWithNoCase(const char* str, const char* suffix) return ::strnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; } -inline bool endsWithNoCase(const wchar_t* str, const wchar_t* suffix) +inline bool endsWithNoCase(const wchar_t *str, const wchar_t *suffix) { if (*suffix == wchar_t(0)) return true; // everything ends with the empty string @@ -290,4 +285,4 @@ inline bool endsWithNoCase(const wchar_t* str, const wchar_t* suffix) return false; // suffix must be as long or shorter than str return ::wcsnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; -} +} \ No newline at end of file From daa9ca4d6b7fadbb2ba6b53b191d3bb6b9d042eb Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Tue, 25 Nov 2025 22:07:39 +0100 Subject: [PATCH 4/5] Templated the 4 string functions for char types --- .../Libraries/Source/WWVegas/WWLib/stringex.h | 169 +++++++++++------- 1 file changed, 106 insertions(+), 63 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/stringex.h b/Core/Libraries/Source/WWVegas/WWLib/stringex.h index 977e18c2dc0..3ee0864ef49 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/stringex.h +++ b/Core/Libraries/Source/WWVegas/WWLib/stringex.h @@ -20,6 +20,7 @@ #include "bittype.h" #include +#include // Declaration @@ -55,6 +56,14 @@ template size_t strlmove_t(char (&dst)[Size], const char *src); template size_t strlmcat_t(char (&dst)[Size], const char *src); #endif +template int strncmp_t(const CharT *str1, const CharT *str2, size_t maxcount); +template int strnicmp_t(const CharT* str1, const CharT* str2, size_t maxcount); + +template bool startsWith(const CharT *str, const CharT *prefix); +template bool startsWithNoCase(const CharT *str, const CharT *prefix); +template bool endsWithNoCase(const CharT *str, const CharT *suffix); +template bool endsWithNoCase(const CharT *str, const CharT *suffix); + // Implementation @@ -183,106 +192,140 @@ template size_t strlmove_t(char (&dst)[Size], const char *src) { re template size_t strlmcat_t(char (&dst)[Size], const char *src) { return strlmcat_t(dst, src, Size); } #endif -inline bool startsWith(const char *str, const char *prefix) +// Templated strncmp. +// Compares up to maxcount chars or a null byte is encountered, whichever comes first. +// Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. +template int strncmp_t(const CharT *str1, const CharT *str2, const size_t maxcount) { - if (*prefix == char(0)) - return true; // everything starts with the empty string + if (str1 == nullptr || str2 == nullptr) + { + switch (str1) + { + case str2: + return 0; + case nullptr: + return -1; + default: + return 1; + } + } + for (size_t i = 0; i < maxcount; ++i) + { + CharT c1 = str1[i]; + CharT c2 = str2[i]; + int diff = c1 - c2; + if (diff != 0) + { + return diff; + } + if (c1 == CharT(0)) // both c1 and c2 are null terminators + { + return 0; + } + } + return 0; +} - const size_t strlen = ::strlen(str); - const size_t prefixlen = ::strlen(prefix); - if (strlen < prefixlen) - return false; // prefix must be as long or shorter than str +// Lower case conversion helpers +inline char tolower_t(char c) { + // cast to unsigned char for correct behavior of tolower() + return (char)::tolower((unsigned char)c); +} - return ::strncmp(str, prefix, prefixlen) == 0; +inline wchar_t tolower_t(wchar_t c) { + return (wchar_t)::towlower(c); } -inline bool startsWith(const wchar_t *str, const wchar_t *prefix) +// Templated strnicmp. +// Case insensitively compares up to maxcount chars or a null byte is encountered, whichever comes first. +// Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. +template int strnicmp_t(const CharT *str1, const CharT *str2, const size_t maxcount) { - if (*prefix == wchar_t(0)) - return true; // everything starts with the empty string - - const size_t strlen = ::wcslen(str); - const size_t prefixlen = ::wcslen(prefix); - if (strlen < prefixlen) - return false; // prefix must be as long or shorter than str - - return ::wcsncmp(str, prefix, prefixlen) == 0; + if (str1 == nullptr || str2 == nullptr) + { + switch (str1) + { + case str2: + return 0; + case nullptr: + return -1; + default: + return 1; + } + } + for (size_t i = 0; i < maxcount; ++i) + { + CharT c1 = tolower_t(str1[i]); + CharT c2 = tolower_t(str2[i]); + int diff = c1 - c2; + if (diff != 0) + { + return diff; + } + if (c1 == CharT(0)) // both c1 and c2 are null terminators + { + return 0; + } + } + return 0; } -inline bool startsWithNoCase(const char *str, const char *prefix) +inline int strncmp_t(const char *str1, const char *str2, size_t maxcount) { return ::strncmp(str1, str2, maxcount); }; +inline int strncmp_t(const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::wcsncmp(str1, str2, maxcount); }; +#ifdef _WIN32 +inline int strnicmp_t(const char *str1, const char *str2, size_t maxcount) { return ::_strnicmp(str1, str2, maxcount); }; +inline int strnicmp_t(const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::_wcsnicmp(str1, str2, maxcount); }; +#endif + +template inline bool startsWith(const CharT *str, const CharT *prefix) { - if (*prefix == char(0)) + if (*prefix == CharT(0)) return true; // everything starts with the empty string - const size_t strlen = ::strlen(str); - const size_t prefixlen = ::strlen(prefix); + const size_t strlen = ::strlen_t(str); + const size_t prefixlen = ::strlen_t(prefix); if (strlen < prefixlen) return false; // prefix must be as long or shorter than str - return ::strnicmp(str, prefix, prefixlen) == 0; + return strncmp_t(str, prefix, prefixlen) == 0; } -inline bool startsWithNoCase(const wchar_t *str, const wchar_t *prefix) +template inline bool startsWithNoCase(const CharT *str, const CharT *prefix) { - if (*prefix == wchar_t(0)) + if (*prefix == CharT(0)) return true; // everything starts with the empty string - const size_t strlen = ::wcslen(str); - const size_t prefixlen = ::wcslen(prefix); + const size_t strlen = ::strlen_t(str); + const size_t prefixlen = ::strlen_t(prefix); if (strlen < prefixlen) return false; // prefix must be as long or shorter than str - return ::wcsnicmp(str, prefix, prefixlen) == 0; -} - -inline bool endsWith(const char *str, const char *suffix) -{ - if (*suffix == char(0)) - return true; // everything ends with the empty string - - const size_t strlen = ::strlen(str); - const size_t suffixlen = ::strlen(suffix); - if (strlen < suffixlen) - return false; // suffix must be as long or shorter than str - - return ::strncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; + return strnicmp_t(str, prefix, prefixlen) == 0; } -inline bool endsWith(const wchar_t *str, const wchar_t *suffix) +template inline bool endsWith(const CharT *str, const CharT *suffix) { - if (*suffix == wchar_t(0)) + if (*suffix == CharT(0)) return true; // everything ends with the empty string - const size_t strlen = ::wcslen(str); - const size_t suffixlen = ::wcslen(suffix); + const size_t strlen = ::strlen_t(str); + const size_t suffixlen = ::strlen_t(suffix); if (strlen < suffixlen) return false; // suffix must be as long or shorter than str - return ::wcsncmp(str + strlen - suffixlen, suffix, suffixlen) == 0; + return strncmp_t(str + strlen - suffixlen, suffix, suffixlen) == 0; } -inline bool endsWithNoCase(const char *str, const char *suffix) +template inline bool endsWithNoCase(const CharT *str, const CharT *suffix) { - if (*suffix == char(0)) + if (*suffix == CharT(0)) return true; // everything ends with the empty string - const size_t strlen = ::strlen(str); - const size_t suffixlen = ::strlen(suffix); + const size_t strlen = ::strlen_t(str); + const size_t suffixlen = ::strlen_t(suffix); if (strlen < suffixlen) return false; // suffix must be as long or shorter than str - return ::strnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; + return strnicmp_t(str + strlen - suffixlen, suffix, suffixlen) == 0; } -inline bool endsWithNoCase(const wchar_t *str, const wchar_t *suffix) -{ - if (*suffix == wchar_t(0)) - return true; // everything ends with the empty string - - const size_t strlen = ::wcslen(str); - const size_t suffixlen = ::wcslen(suffix); - if (strlen < suffixlen) - return false; // suffix must be as long or shorter than str - - return ::wcsnicmp(str + strlen - suffixlen, suffix, suffixlen) == 0; -} \ No newline at end of file From 6358c86d7dd90eaa86316bb90a6a589056394f5e Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Wed, 26 Nov 2025 00:35:43 +0100 Subject: [PATCH 5/5] Removed specializations, cleaned up names and null checks --- .../Libraries/Source/WWVegas/WWLib/stringex.h | 105 +++++++----------- 1 file changed, 38 insertions(+), 67 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/stringex.h b/Core/Libraries/Source/WWVegas/WWLib/stringex.h index 3ee0864ef49..8e23b0227a5 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/stringex.h +++ b/Core/Libraries/Source/WWVegas/WWLib/stringex.h @@ -56,13 +56,13 @@ template size_t strlmove_t(char (&dst)[Size], const char *src); template size_t strlmcat_t(char (&dst)[Size], const char *src); #endif -template int strncmp_t(const CharT *str1, const CharT *str2, size_t maxcount); -template int strnicmp_t(const CharT* str1, const CharT* str2, size_t maxcount); +template int strncmp_t(const T *str1, const T *str2, size_t maxcount); +template int strnicmp_t(const T* str1, const T* str2, size_t maxcount); -template bool startsWith(const CharT *str, const CharT *prefix); -template bool startsWithNoCase(const CharT *str, const CharT *prefix); -template bool endsWithNoCase(const CharT *str, const CharT *suffix); -template bool endsWithNoCase(const CharT *str, const CharT *suffix); +template bool startsWith(const T *str, const T *prefix); +template bool startsWithNoCase(const T *str, const T *prefix); +template bool endsWithNoCase(const T *str, const T *suffix); +template bool endsWithNoCase(const T *str, const T *suffix); // Implementation @@ -195,30 +195,18 @@ template size_t strlmcat_t(char (&dst)[Size], const char *src) { re // Templated strncmp. // Compares up to maxcount chars or a null byte is encountered, whichever comes first. // Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. -template int strncmp_t(const CharT *str1, const CharT *str2, const size_t maxcount) +template int strncmp_t(const T *str1, const T *str2, const size_t maxcount) { - if (str1 == nullptr || str2 == nullptr) - { - switch (str1) - { - case str2: - return 0; - case nullptr: - return -1; - default: - return 1; - } - } for (size_t i = 0; i < maxcount; ++i) { - CharT c1 = str1[i]; - CharT c2 = str2[i]; - int diff = c1 - c2; + const T c1 = str1[i]; + const T c2 = str2[i]; + const int diff = (int)c1 - (int)c2; if (diff != 0) { return diff; } - if (c1 == CharT(0)) // both c1 and c2 are null terminators + if (c1 == T(0)) // both c1 and c2 are null terminators { return 0; } @@ -227,42 +215,32 @@ template int strncmp_t(const CharT *str1, const CharT *str2, con } // Lower case conversion helpers -inline char tolower_t(char c) { +inline char tolower_t(char c) +{ // cast to unsigned char for correct behavior of tolower() - return (char)::tolower((unsigned char)c); + return (char)tolower((unsigned char)c); } -inline wchar_t tolower_t(wchar_t c) { - return (wchar_t)::towlower(c); +inline wchar_t tolower_t(wchar_t c) +{ + return (wchar_t)towlower(c); } // Templated strnicmp. // Case insensitively compares up to maxcount chars or a null byte is encountered, whichever comes first. // Returns < 0 if str1 is less than str2, 0 is str1 and str2 are equal and > 0 if str2 is greater than str1. -template int strnicmp_t(const CharT *str1, const CharT *str2, const size_t maxcount) +template int strnicmp_t(const T *str1, const T *str2, const size_t maxcount) { - if (str1 == nullptr || str2 == nullptr) - { - switch (str1) - { - case str2: - return 0; - case nullptr: - return -1; - default: - return 1; - } - } for (size_t i = 0; i < maxcount; ++i) { - CharT c1 = tolower_t(str1[i]); - CharT c2 = tolower_t(str2[i]); - int diff = c1 - c2; + const T c1 = tolower_t(str1[i]); + const T c2 = tolower_t(str2[i]); + const int diff = (int)c1 - (int)c2; if (diff != 0) { return diff; } - if (c1 == CharT(0)) // both c1 and c2 are null terminators + if (c1 == T(0)) // both c1 and c2 are null terminators { return 0; } @@ -270,59 +248,52 @@ template int strnicmp_t(const CharT *str1, const CharT *str2, co return 0; } -inline int strncmp_t(const char *str1, const char *str2, size_t maxcount) { return ::strncmp(str1, str2, maxcount); }; -inline int strncmp_t(const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::wcsncmp(str1, str2, maxcount); }; -#ifdef _WIN32 -inline int strnicmp_t(const char *str1, const char *str2, size_t maxcount) { return ::_strnicmp(str1, str2, maxcount); }; -inline int strnicmp_t(const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::_wcsnicmp(str1, str2, maxcount); }; -#endif - -template inline bool startsWith(const CharT *str, const CharT *prefix) +template inline bool startsWith(const T *str, const T *prefix) { - if (*prefix == CharT(0)) + if (*prefix == T(0)) return true; // everything starts with the empty string - const size_t strlen = ::strlen_t(str); - const size_t prefixlen = ::strlen_t(prefix); + const size_t strlen = strlen_t(str); + const size_t prefixlen = strlen_t(prefix); if (strlen < prefixlen) return false; // prefix must be as long or shorter than str return strncmp_t(str, prefix, prefixlen) == 0; } -template inline bool startsWithNoCase(const CharT *str, const CharT *prefix) +template inline bool startsWithNoCase(const T *str, const T *prefix) { - if (*prefix == CharT(0)) + if (*prefix == T(0)) return true; // everything starts with the empty string - const size_t strlen = ::strlen_t(str); - const size_t prefixlen = ::strlen_t(prefix); + const size_t strlen = strlen_t(str); + const size_t prefixlen = strlen_t(prefix); if (strlen < prefixlen) return false; // prefix must be as long or shorter than str return strnicmp_t(str, prefix, prefixlen) == 0; } -template inline bool endsWith(const CharT *str, const CharT *suffix) +template inline bool endsWith(const T *str, const T *suffix) { - if (*suffix == CharT(0)) + if (*suffix == T(0)) return true; // everything ends with the empty string - const size_t strlen = ::strlen_t(str); - const size_t suffixlen = ::strlen_t(suffix); + const size_t strlen = strlen_t(str); + const size_t suffixlen = strlen_t(suffix); if (strlen < suffixlen) return false; // suffix must be as long or shorter than str return strncmp_t(str + strlen - suffixlen, suffix, suffixlen) == 0; } -template inline bool endsWithNoCase(const CharT *str, const CharT *suffix) +template inline bool endsWithNoCase(const T *str, const T *suffix) { - if (*suffix == CharT(0)) + if (*suffix == T(0)) return true; // everything ends with the empty string - const size_t strlen = ::strlen_t(str); - const size_t suffixlen = ::strlen_t(suffix); + const size_t strlen = strlen_t(str); + const size_t suffixlen = strlen_t(suffix); if (strlen < suffixlen) return false; // suffix must be as long or shorter than str