mirror of
https://github.com/bkaradzic/bx.git
synced 2026-02-17 20:52:37 +01:00
Removing dependecy on CRT.
This commit is contained in:
@@ -89,26 +89,56 @@ namespace bx
|
||||
};
|
||||
|
||||
///
|
||||
bool toBool(const char* _str);
|
||||
|
||||
/// Case insensitive string compare.
|
||||
int32_t stricmp(const char* _a, const char* _b);
|
||||
bool isSpace(char _ch);
|
||||
|
||||
///
|
||||
size_t strnlen(const char* _str, size_t _max);
|
||||
bool isUpper(char _ch);
|
||||
|
||||
///
|
||||
bool isLower(char _ch);
|
||||
|
||||
///
|
||||
bool isAlpha(char _ch);
|
||||
|
||||
///
|
||||
bool isNumeric(char _ch);
|
||||
|
||||
///
|
||||
bool isAlphaNum(char _ch);
|
||||
|
||||
///
|
||||
char toLower(char _ch);
|
||||
|
||||
///
|
||||
char toUpper(char _ch);
|
||||
|
||||
///
|
||||
bool toBool(const char* _str);
|
||||
|
||||
/// String compare.
|
||||
int32_t strncmp(const char* _lhs, const char* _rhs, size_t _max = -1);
|
||||
|
||||
/// Case insensitive string compare.
|
||||
int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max = -1);
|
||||
|
||||
///
|
||||
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);
|
||||
|
||||
/// Find substring in string. Limit search to _size.
|
||||
const char* strnstr(const char* _str, const char* _find, size_t _size);
|
||||
///
|
||||
const char* strnchr(const char* _str, char _ch, size_t _max = -1);
|
||||
|
||||
/// Find substring in string. Case insensitive.
|
||||
const char* stristr(const char* _str, const char* _find);
|
||||
///
|
||||
const char* strnrchr(const char* _str, char _ch, size_t _max = -1);
|
||||
|
||||
/// Find substring in string. Limit search to _size.
|
||||
const char* strnstr(const char* _str, const char* _find, size_t _max = -1);
|
||||
|
||||
/// Find substring in string. Case insensitive. Limit search to _max.
|
||||
const char* stristr(const char* _str, const char* _find, size_t _max);
|
||||
const char* stristr(const char* _str, const char* _find, size_t _max = -1);
|
||||
|
||||
/// Find new line. Returns pointer after new line terminator.
|
||||
const char* strnl(const char* _str);
|
||||
|
||||
@@ -246,11 +246,11 @@ namespace bx
|
||||
const char* arg = findOption(_short, _long, 1);
|
||||
if (NULL != arg)
|
||||
{
|
||||
if ('0' == *arg || (0 == stricmp(arg, "false") ) )
|
||||
if ('0' == *arg || (0 == strincmp(arg, "false") ) )
|
||||
{
|
||||
_value = false;
|
||||
}
|
||||
else if ('0' != *arg || (0 == stricmp(arg, "true") ) )
|
||||
else if ('0' != *arg || (0 == strincmp(arg, "true") ) )
|
||||
{
|
||||
_value = true;
|
||||
}
|
||||
@@ -294,7 +294,7 @@ namespace bx
|
||||
}
|
||||
else if (NULL != _long
|
||||
&& '-' == *arg
|
||||
&& 0 == stricmp(arg+1, _long) )
|
||||
&& 0 == strincmp(arg+1, _long) )
|
||||
{
|
||||
if (0 == _skip)
|
||||
{
|
||||
|
||||
193
src/string.cpp
193
src/string.cpp
@@ -4,11 +4,8 @@
|
||||
*/
|
||||
|
||||
#include <alloca.h>
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdarg.h> // va_list
|
||||
#include <stdio.h> // vsnprintf, vsnwprintf
|
||||
#include <string.h>
|
||||
#include <wchar.h> // wchar_t
|
||||
|
||||
#include <bx/string.h>
|
||||
|
||||
@@ -17,19 +14,90 @@
|
||||
|
||||
namespace bx
|
||||
{
|
||||
bool isSpace(char _ch)
|
||||
{
|
||||
return ' ' == _ch
|
||||
|| '\t' == _ch
|
||||
|| '\n' == _ch
|
||||
|| '\v' == _ch
|
||||
|| '\f' == _ch
|
||||
|| '\r' == _ch
|
||||
;
|
||||
}
|
||||
|
||||
bool isUpper(char _ch)
|
||||
{
|
||||
return _ch >= 'A' && _ch <= 'Z';
|
||||
}
|
||||
|
||||
bool isLower(char _ch)
|
||||
{
|
||||
return _ch >= 'a' && _ch <= 'z';
|
||||
}
|
||||
|
||||
bool isAlpha(char _ch)
|
||||
{
|
||||
return isLower(_ch) || isUpper(_ch);
|
||||
}
|
||||
|
||||
bool isNumeric(char _ch)
|
||||
{
|
||||
return _ch >= '0' && _ch <= '9';
|
||||
}
|
||||
|
||||
bool isAlphaNum(char _ch)
|
||||
{
|
||||
return isAlpha(_ch) || isNumeric(_ch);
|
||||
}
|
||||
|
||||
char toLower(char _ch)
|
||||
{
|
||||
return _ch - (isUpper(_ch) ? 0x20 : 0);
|
||||
}
|
||||
|
||||
char toUpper(char _ch)
|
||||
{
|
||||
return _ch + (isLower(_ch) ? 0x20 : 0);
|
||||
}
|
||||
|
||||
bool toBool(const char* _str)
|
||||
{
|
||||
char ch = (char)::tolower(_str[0]);
|
||||
char ch = (char)toLower(_str[0]);
|
||||
return ch == 't' || ch == '1';
|
||||
}
|
||||
|
||||
int32_t stricmp(const char* _a, const char* _b)
|
||||
int32_t strncmp(const char* _lhs, const char* _rhs, size_t _max)
|
||||
{
|
||||
#if BX_CRT_MSVC
|
||||
return ::_stricmp(_a, _b);
|
||||
#else
|
||||
return ::strcasecmp(_a, _b);
|
||||
#endif // BX_COMPILER_
|
||||
for (
|
||||
; 0 < _max && *_lhs == *_rhs
|
||||
; ++_lhs, ++_rhs, --_max
|
||||
)
|
||||
{
|
||||
if (*_lhs != '\0'
|
||||
|| *_rhs != '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *_lhs - *_rhs;
|
||||
}
|
||||
|
||||
int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max)
|
||||
{
|
||||
for (
|
||||
; 0 < _max && toLower(*_lhs) == toLower(*_rhs)
|
||||
; ++_lhs, ++_rhs, --_max
|
||||
)
|
||||
{
|
||||
if (*_lhs != '\0'
|
||||
|| *_rhs != '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *_lhs - *_rhs;
|
||||
}
|
||||
|
||||
size_t strnlen(const char* _str, size_t _max)
|
||||
@@ -48,13 +116,39 @@ namespace bx
|
||||
const size_t len = strnlen(_src, _num);
|
||||
const size_t max = _dstSize-1;
|
||||
const size_t num = (len < max ? len : max);
|
||||
strncpy(_dst, _src, num);
|
||||
memcpy(_dst, _src, num);
|
||||
_dst[num] = '\0';
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
const char* strnstr(const char* _str, const char* _find, size_t _size)
|
||||
const char* strnchr(const char* _str, char _ch, size_t _max)
|
||||
{
|
||||
for (size_t ii = 0, len = strnlen(_str, _max); ii < len; ++ii)
|
||||
{
|
||||
if (_str[ii] == _ch)
|
||||
{
|
||||
return &_str[ii];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* strnrchr(const char* _str, char _ch, size_t _max)
|
||||
{
|
||||
for (size_t ii = strnlen(_str, _max); 0 < ii; --ii)
|
||||
{
|
||||
if (_str[ii] == _ch)
|
||||
{
|
||||
return &_str[ii];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* strnstr(const char* _str, const char* _find, size_t _max)
|
||||
{
|
||||
char first = *_find;
|
||||
if ('\0' == first)
|
||||
@@ -63,10 +157,10 @@ namespace bx
|
||||
}
|
||||
|
||||
const char* cmp = _find + 1;
|
||||
size_t len = strlen(cmp);
|
||||
size_t len = strnlen(cmp);
|
||||
do
|
||||
{
|
||||
for (char match = *_str++; match != first && 0 < _size; match = *_str++, --_size)
|
||||
for (char match = *_str++; match != first && 0 < _max; match = *_str++, --_max)
|
||||
{
|
||||
if ('\0' == match)
|
||||
{
|
||||
@@ -74,7 +168,7 @@ namespace bx
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == _size)
|
||||
if (0 == _max)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -84,56 +178,17 @@ namespace bx
|
||||
return --_str;
|
||||
}
|
||||
|
||||
const char* stristr(const char* _str, const char* _find)
|
||||
{
|
||||
const char* ptr = _str;
|
||||
|
||||
for (size_t len = strlen(_str), searchLen = strlen(_find)
|
||||
; len >= searchLen
|
||||
; ++ptr, --len)
|
||||
{
|
||||
// Find start of the string.
|
||||
while (tolower(*ptr) != tolower(*_find) )
|
||||
{
|
||||
++ptr;
|
||||
--len;
|
||||
|
||||
// Search pattern lenght can't be longer than the string.
|
||||
if (searchLen > len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Set pointers.
|
||||
const char* string = ptr;
|
||||
const char* search = _find;
|
||||
|
||||
// Start comparing.
|
||||
while (tolower(*string++) == tolower(*search++) )
|
||||
{
|
||||
// If end of the 'search' string is reached, all characters match.
|
||||
if ('\0' == *search)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* stristr(const char* _str, const char* _find, size_t _max)
|
||||
{
|
||||
const char* ptr = _str;
|
||||
|
||||
size_t stringLen = strnlen(_str, _max);
|
||||
const size_t findLen = strlen(_find);
|
||||
const size_t findLen = strnlen(_find);
|
||||
|
||||
for (; stringLen >= findLen; ++ptr, --stringLen)
|
||||
{
|
||||
// Find start of the string.
|
||||
while (tolower(*ptr) != tolower(*_find) )
|
||||
while (toLower(*ptr) != toLower(*_find) )
|
||||
{
|
||||
++ptr;
|
||||
--stringLen;
|
||||
@@ -150,7 +205,7 @@ namespace bx
|
||||
const char* search = _find;
|
||||
|
||||
// Start comparing.
|
||||
while (tolower(*string++) == tolower(*search++) )
|
||||
while (toLower(*string++) == toLower(*search++) )
|
||||
{
|
||||
// If end of the 'search' string is reached, all characters match.
|
||||
if ('\0' == *search)
|
||||
@@ -205,19 +260,19 @@ namespace bx
|
||||
|
||||
const char* strws(const char* _str)
|
||||
{
|
||||
for (; isspace(*_str); ++_str) {};
|
||||
for (; isSpace(*_str); ++_str) {};
|
||||
return _str;
|
||||
}
|
||||
|
||||
const char* strnws(const char* _str)
|
||||
{
|
||||
for (; !isspace(*_str); ++_str) {};
|
||||
for (; !isSpace(*_str); ++_str) {};
|
||||
return _str;
|
||||
}
|
||||
|
||||
const char* strword(const char* _str)
|
||||
{
|
||||
for (char ch = *_str++; isalnum(ch) || '_' == ch; ch = *_str++) {};
|
||||
for (char ch = *_str++; isAlphaNum(ch) || '_' == ch; ch = *_str++) {};
|
||||
return _str-1;
|
||||
}
|
||||
|
||||
@@ -262,21 +317,21 @@ namespace bx
|
||||
|
||||
const char* findIdentifierMatch(const char* _str, const char* _word)
|
||||
{
|
||||
size_t len = strlen(_word);
|
||||
const char* ptr = strstr(_str, _word);
|
||||
for (; NULL != ptr; ptr = strstr(ptr + len, _word) )
|
||||
size_t len = strnlen(_word);
|
||||
const char* ptr = strnstr(_str, _word);
|
||||
for (; NULL != ptr; ptr = strnstr(ptr + len, _word) )
|
||||
{
|
||||
if (ptr != _str)
|
||||
{
|
||||
char ch = *(ptr - 1);
|
||||
if (isalnum(ch) || '_' == ch)
|
||||
if (isAlphaNum(ch) || '_' == ch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
char ch = ptr[len];
|
||||
if (isalnum(ch) || '_' == ch)
|
||||
if (isAlphaNum(ch) || '_' == ch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -357,10 +412,10 @@ namespace bx
|
||||
|
||||
const char* baseName(const char* _filePath)
|
||||
{
|
||||
const char* bs = strrchr(_filePath, '\\');
|
||||
const char* fs = strrchr(_filePath, '/');
|
||||
const char* bs = strnrchr(_filePath, '\\');
|
||||
const char* fs = strnrchr(_filePath, '/');
|
||||
const char* slash = (bs > fs ? bs : fs);
|
||||
const char* colon = strrchr(_filePath, ':');
|
||||
const char* colon = strnrchr(_filePath, ':');
|
||||
const char* basename = slash > colon ? slash : colon;
|
||||
if (NULL != basename)
|
||||
{
|
||||
@@ -452,7 +507,7 @@ namespace bx
|
||||
|
||||
if (nn == 0)
|
||||
{
|
||||
return(dlen + strlen(s));
|
||||
return(dlen + strnlen(s));
|
||||
}
|
||||
|
||||
while (*s != '\0')
|
||||
|
||||
@@ -28,13 +28,13 @@ int main()
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
tinystl::pair<TinyStlUnorderedMap::iterator, bool> ok = map.insert(tinystl::make_pair(uint64_t(jj), uint16_t(jj) ) );
|
||||
assert(ok.second);
|
||||
assert(ok.second); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
bool ok = bx::mapRemove(map, uint64_t(jj) );
|
||||
assert(ok);
|
||||
assert(ok); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
assert(map.size() == 0);
|
||||
@@ -56,13 +56,13 @@ int main()
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
std::pair<StdUnorderedMap::iterator, bool> ok = map.insert(std::make_pair(uint64_t(jj), uint16_t(jj) ) );
|
||||
assert(ok.second);
|
||||
assert(ok.second); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
bool ok = bx::mapRemove(map, uint64_t(jj) );
|
||||
assert(ok);
|
||||
assert(ok); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
assert(map.size() == 0);
|
||||
@@ -83,13 +83,13 @@ int main()
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
bool ok = map.insert(jj, uint16_t(jj) );
|
||||
assert(ok);
|
||||
assert(ok); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
for (uint32_t jj = 0; jj < numElements; ++jj)
|
||||
{
|
||||
bool ok = map.removeByKey(uint64_t(jj) );
|
||||
assert(ok);
|
||||
assert(ok); BX_UNUSED(ok);
|
||||
}
|
||||
|
||||
assert(map.getNumElements() == 0);
|
||||
|
||||
@@ -40,6 +40,29 @@ TEST_CASE("strlncpy", "")
|
||||
REQUIRE(num == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("strincmp", "")
|
||||
{
|
||||
REQUIRE(0 == bx::strincmp("test", "test") );
|
||||
REQUIRE(0 == bx::strincmp("test", "testestes", 4) );
|
||||
REQUIRE(0 == bx::strincmp("testestes", "test", 4) );
|
||||
}
|
||||
|
||||
TEST_CASE("strnchr", "")
|
||||
{
|
||||
const char* test = "test";
|
||||
REQUIRE(NULL == bx::strnchr(test, 's', 0) );
|
||||
REQUIRE(NULL == bx::strnchr(test, 's', 2) );
|
||||
REQUIRE(&test[2] == bx::strnchr(test, 's') );
|
||||
}
|
||||
|
||||
TEST_CASE("strnrchr", "")
|
||||
{
|
||||
const char* test = "test";
|
||||
REQUIRE(NULL == bx::strnrchr(test, 's', 0) );
|
||||
REQUIRE(NULL == bx::strnrchr(test, 's', 1) );
|
||||
REQUIRE(&test[2] == bx::strnrchr(test, 's') );
|
||||
}
|
||||
|
||||
TEST_CASE("StringView", "")
|
||||
{
|
||||
bx::StringView sv("test");
|
||||
|
||||
@@ -20,3 +20,35 @@ TEST_CASE("vsnprintf truncated", "Truncated output buffer.")
|
||||
REQUIRE(10 == bx::snprintf(buffer, BX_COUNTOF(buffer), "Ten chars!") );
|
||||
REQUIRE(0 == strcmp(buffer, "Ten ch") );
|
||||
}
|
||||
|
||||
static bool test(const char* _expected, const char* _format, ...)
|
||||
{
|
||||
int32_t max = (int32_t)strlen(_expected) + 1;
|
||||
char* temp = (char*)alloca(max);
|
||||
|
||||
va_list argList;
|
||||
va_start(argList, _format);
|
||||
int32_t len = bx::vsnprintf(temp, max, _format, argList);
|
||||
va_end(argList);
|
||||
|
||||
bool result = true
|
||||
&& len == max-1
|
||||
&& 0 == strcmp(_expected, temp)
|
||||
;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
printf("result (%d) %s, expected (%d) %s\n", len, temp, max-1, _expected);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("vsnprintf f", "")
|
||||
{
|
||||
REQUIRE(test("1.337", "%0.3f", 1.337) );
|
||||
REQUIRE(test(" 13.370", "%8.3f", 13.37) );
|
||||
REQUIRE(test(" 13.370", "%*.*f", 8, 3, 13.37) );
|
||||
REQUIRE(test("13.370 ", "%-8.3f", 13.37) );
|
||||
REQUIRE(test("13.370 ", "%*.*f", -8, 3, 13.37) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user