cmdlib: fix broken Q_strcasecmp and Q_strncasecmp

string_view isn't null terminated, can't use C string functions
This commit is contained in:
Eric Wasylishen 2024-11-29 00:01:59 -07:00
parent 638076ffb2
commit d7eca5f317
3 changed files with 65 additions and 21 deletions

View File

@ -41,34 +41,47 @@
#include <algorithm>
#include <string>
#if defined(__has_include) && __has_include(<strings.h>)
#include <strings.h>
#endif
char Q_tolower(char x)
{
if (x >= 'A' && x <= 'Z') {
x += 'a' - 'A';
}
return x;
}
int32_t Q_strncasecmp(std::string_view a, std::string_view b, size_t maxcount)
{
return
#ifdef _WIN32
_strnicmp
#elif defined(__has_include) && __has_include(<strings.h>)
strncasecmp
#else
strnicmp
#endif
(a.data(), b.data(), maxcount);
return Q_strcasecmp(
a.substr(0, maxcount),
b.substr(0, maxcount));
}
int32_t Q_strcasecmp(std::string_view a, std::string_view b)
{
return
#ifdef _WIN32
_stricmp
#elif defined(__has_include) && __has_include(<strings.h>)
strcasecmp
#else
stricmp
#endif
(a.data(), b.data());
const char *a_ptr = a.data();
const char *b_ptr = b.data();
const size_t common_size = std::min(a.size(), b.size());
for (size_t i = 0; i < common_size; ++i) {
char achar = Q_tolower(a_ptr[i]);
char bchar = Q_tolower(b_ptr[i]);
if (achar < bchar) {
return -1;
}
if (achar > bchar) {
return 1;
}
}
// the first common_size chars are the same
if (a.size() < b.size()) {
return -1;
}
if (a.size() > b.size()) {
return 1;
}
return 0;
}
void // mxd

View File

@ -30,6 +30,7 @@
#include <ostream>
#include <tuple> // for std::apply()
char Q_tolower(char x);
int32_t Q_strncasecmp(std::string_view a, std::string_view b, size_t maxcount);
int32_t Q_strcasecmp(std::string_view a, std::string_view b);
bool string_iequals(std::string_view a, std::string_view b); // mxd

View File

@ -382,3 +382,33 @@ TEST(qmat, transpose)
EXPECT_EQ(in.transpose(), exp);
}
TEST(string, strcasecmp)
{
EXPECT_EQ('x', Q_tolower('X'));
EXPECT_EQ('"', Q_tolower('"'));
const char *test = "abcA**";
// lhs < rhs
EXPECT_LT(Q_strcasecmp("a", "aa"), 0);
EXPECT_LT(Q_strcasecmp("aaa", "BBB"), 0);
EXPECT_LT(Q_strcasecmp("AAA", "bbb"), 0);
// lhs == rhs
EXPECT_EQ(Q_strcasecmp(std::string_view(&test[0], 1), std::string_view(&test[3], 1)), 0);
EXPECT_EQ(Q_strcasecmp("test", "TEST"), 0);
EXPECT_EQ(Q_strcasecmp("test", "test"), 0);
// lhs > rhs
EXPECT_GT(Q_strcasecmp("test", "aaaa"), 0);
EXPECT_GT(Q_strcasecmp("test", "AAAA"), 0);
EXPECT_GT(Q_strcasecmp("test", "tes"), 0);
EXPECT_GT(Q_strcasecmp("TEST", "T"), 0);
}
TEST(string, strncasecmp)
{
EXPECT_EQ(Q_strncasecmp("*lava123", "*LAVA", 5), 0);
EXPECT_EQ(Q_strncasecmp("*lava123", "*LAVA", 8), 1);
}