diff --git a/include/EAStdC/EAString.h b/include/EAStdC/EAString.h index 36e751d..abeb458 100644 --- a/include/EAStdC/EAString.h +++ b/include/EAStdC/EAString.h @@ -32,7 +32,9 @@ // char_t* Strrchr(const char_t* pString, char_t c); // size_t Strspn(const char_t* pString, const char_t* pSubString); // char_t* Strstr(const char_t* pString, const char_t* pSubString); +// char_t* Strnstr(const char_t* pString, const char_t* pSubString, size_t n); // char_t* Stristr(const char_t* pString, const char_t* pSubString); +// char_t* Strnistr(const char_t* pString, const char_t* pSubString, size_t n); // bool Strstart(const char_t* pString, const char_t* pPrefix); // bool Stristart(const char_t* pString, const char_t* pPrefix); // bool Strend(const char_t* pString, const char_t* pSuffix, size_t stringLength = kSizeTypeUnset); @@ -1041,6 +1043,20 @@ EASTDC_API char32_t* Strstr(const char32_t* pString, const char32_t* pSubString) #endif +/// Strnstr +/// +/// Finds the first occurrence of pSubString within pString, exclusive of the +/// terminating null character, where not more than n characters are searched. +/// This is similar to the strnstr C function. +/// Note: Has the same const char return decision that Strstr. +EASTDC_API char* Strnstr(const char* pString, const char* pSubString, size_t n); +EASTDC_API char16_t* Strnstr(const char16_t* pString, const char16_t* pSubString, size_t n); +EASTDC_API char32_t* Strnstr(const char32_t* pString, const char32_t* pSubString, size_t n); +#if EA_WCHAR_UNIQUE +EASTDC_API wchar_t* Strnstr(const wchar_t* pString, const wchar_t* pSubString, size_t n); +#endif + + /// Stristr /// /// This is a case-insensitive version of Strstr. @@ -1059,6 +1075,18 @@ EASTDC_API char32_t* Stristr(const char32_t* pString, const char32_t* pSubString #endif +/// Strnistr +/// +/// This is a case-insensitive version of Strnstr. +/// +EASTDC_API char* Strnistr(const char* pString, const char* pSubString, size_t n); +EASTDC_API char16_t* Strnistr(const char16_t* pString, const char16_t* pSubString, size_t n); +EASTDC_API char32_t* Strnistr(const char32_t* pString, const char32_t* pSubString, size_t n); +#if EA_WCHAR_UNIQUE + EASTDC_API wchar_t* Strnistr(const wchar_t* pString, const wchar_t* pSubString, size_t n); +#endif + + /// Strrstr /// /// Finds the last occurrence of pSubString within pString, exclusive of the @@ -2570,11 +2598,21 @@ namespace StdC return reinterpret_cast(Strstr(EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pString), EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pSubString))); } + inline wchar_t* Strnstr(const wchar_t* pString, const wchar_t* pSubString, size_t n) + { + return reinterpret_cast(Strnstr(EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pString), EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pSubString), n)); + } + inline wchar_t* Stristr(const wchar_t* pString, const wchar_t* pSubString) { return reinterpret_cast(Stristr(EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pString), EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pSubString))); } + inline wchar_t* Strnistr(const wchar_t* pString, const wchar_t* pSubString, size_t n) + { + return reinterpret_cast(Strnistr(EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pString), EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pSubString), n)); + } + inline wchar_t* Strrstr(const wchar_t* pString, const wchar_t* pSubString) { return reinterpret_cast(Strrstr(EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pString), EASTDC_UNICODE_CONST_CHAR_PTR_CAST(pSubString))); diff --git a/source/EAString.cpp b/source/EAString.cpp index 5c2594d..45fb01d 100644 --- a/source/EAString.cpp +++ b/source/EAString.cpp @@ -2295,6 +2295,92 @@ EASTDC_API char32_t* Strstr(const char32_t* pString, const char32_t* pSubString) +EASTDC_API char* Strnstr(const char* pString, const char* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char* s1 = (char*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + if (*s1 == *pSubString) + { + const char* s2 = (s1 - 1); + const char* p2 = (pSubString - 1); + char cs, cp; + + while((cs = *++s2) == (cp = *++p2) && cs){} // Do nothing + + if(!cp) + return s1; + } + } + return 0; +} + +EASTDC_API char16_t* Strnstr(const char16_t* pString, const char16_t* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char16_t*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char16_t* s1 = (char16_t*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + if (*s1 == *pSubString) + { + const char16_t* s2 = (s1 - 1); + const char16_t* p2 = (pSubString - 1); + char16_t cs, cp; + + while((cs = *++s2) == (cp = *++p2) && cs){} // Do nothing + + if(!cp) + return s1; + } + } + return 0; +} + +EASTDC_API char32_t* Strnstr(const char32_t* pString, const char32_t* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char32_t*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char32_t* s1 = (char32_t*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + if (*s1 == *pSubString) + { + const char32_t* s2 = (s1 - 1); + const char32_t* p2 = (pSubString - 1); + char32_t cs, cp; + + while((cs = *++s2) == (cp = *++p2) && cs){} // Do nothing + + if(!cp) + return s1; + } + } + return 0; +} + + + EASTDC_API char* Stristr(const char* s1, const char* s2) { const char* cp = s1; @@ -2366,6 +2452,88 @@ EASTDC_API char32_t* Stristr(const char32_t* s1, const char32_t* s2) +EASTDC_API char* Strnistr(const char* pString, const char* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char* s1 = (char*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + const char* s2 = s1; + const char* p2 = pSubString; + + while(*s2 && *p2 && (Tolower(*s2) == Tolower(*p2))) + { + ++s2; ++p2; + } + + if(*p2 == 0) + return s1; + } + return 0; +} + +EASTDC_API char16_t* Strnistr(const char16_t* pString, const char16_t* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char16_t*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char16_t* s1 = (char16_t*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + const char16_t* s2 = s1; + const char16_t* p2 = pSubString; + + while(*s2 && *p2 && (Tolower(*s2) == Tolower(*p2))) + { + ++s2; ++p2; + } + + if(*p2 == 0) + return s1; + } + return 0; +} + +EASTDC_API char32_t* Strnistr(const char32_t* pString, const char32_t* pSubString, size_t n) +{ + if (*pSubString == 0) + return (char32_t*)pString; + + size_t len = Strlen(pSubString); + + if (n < len) + return 0; + + char32_t* s1 = (char32_t*)pString; + for(size_t i = 0; (*s1 != 0) && (i <= n - len) ; ++i, ++s1) + { + const char32_t* s2 = s1; + const char32_t* p2 = pSubString; + + while(*s2 && *p2 && (Tolower(*s2) == Tolower(*p2))) + { + ++s2; ++p2; + } + + if(*p2 == 0) + return s1; + } + return 0; +} + + EASTDC_API char* Strrstr(const char* s1, const char* s2) { diff --git a/test/source/TestString.cpp b/test/source/TestString.cpp index 7e49300..98ef483 100644 --- a/test/source/TestString.cpp +++ b/test/source/TestString.cpp @@ -1236,6 +1236,45 @@ static int TestStringCore() EATEST_VERIFY(Strstr(s32, EA_CHAR32("abcd")) == &s32[3]); } + // char* Strnstr(const char* pString, const char* pSubString, size_t n); + // char16_t* Strnstr(const char16_t* pString, const char16_t* pSubString, size_t n); + // char32_t* Strnstr(const char32_t* pString, const char32_t* pSubString, size_t n); + { + char s8[] = "012abcdf89abcdef"; + + EATEST_VERIFY(Strnstr(s8, "", 0) == &s8[0]); + EATEST_VERIFY(Strnstr(s8, "012", 3) == &s8[0]); + EATEST_VERIFY(Strnstr(s8, "012", 2) == 0); + EATEST_VERIFY(Strnstr(s8, "abcde", 20) == &s8[10]); + EATEST_VERIFY(Strnstr(s8, "abcde", 10) == 0); + EATEST_VERIFY(Strnstr(s8, ":/1", 20) == 0); + EATEST_VERIFY(Strnstr(s8, "abcd", 10) == &s8[3]); + EATEST_VERIFY(Strnstr(s8, "abcd", 5) == 0); + } + { + char16_t s16[24]; Strlcpy(s16, EA_CHAR16("012abcdf89abcdef"), EAArrayCount(s16)); // Can't do char16_t variable[64] = EA_CHAR16(...) because some compilers don't support 16 bit string literals. + + EATEST_VERIFY(Strnstr(s16, EA_CHAR16(""), 0) == &s16[0]); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("012"), 3) == &s16[0]); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("012"), 2) == 0); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("abcde"), 20) == &s16[10]); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("abcde"), 10) == 0); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16(":/1"), 20) == 0); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("abcd"), 10) == &s16[3]); + EATEST_VERIFY(Strnstr(s16, EA_CHAR16("abcd"), 5) == 0); + } + { + char32_t s32[24]; Strlcpy(s32, EA_CHAR32("012abcdf89abcdef"), EAArrayCount(s32)); // Can't do char32_t variable[64] = EA_CHAR32(...) because some compilers don't support 32 bit string literals. + + EATEST_VERIFY(Strnstr(s32, EA_CHAR32(""), 0) == &s32[0]); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("012"), 3) == &s32[0]); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("012"), 2) == 0); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("abcde"), 20) == &s32[10]); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("abcde"), 10) == 0); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32(":/1"), 20) == 0); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("abcd"), 10) == &s32[3]); + EATEST_VERIFY(Strnstr(s32, EA_CHAR32("abcd"), 5) == 0); + } // char* Stristr(const char* pString, const char* pSubString); // char16_t* Stristr(const char16_t* pString, const char16_t* pSubString); @@ -1269,6 +1308,46 @@ static int TestStringCore() } + // char* Strnistr(const char* pString, const char* pSubString, size_t n); + // char16_t* Strnistr(const char16_t* pString, const char16_t* pSubString, size_t n); + // char32_t* Strnistr(const char32_t* pString, const char32_t* pSubString, size_t n); + { + char s8[] = "012aBcdf89aBcDEf"; + + EATEST_VERIFY(Strnistr(s8, "", 0) == &s8[0]); + EATEST_VERIFY(Strnistr(s8, "012", 3) == &s8[0]); + EATEST_VERIFY(Strnistr(s8, "012", 2) == 0); + EATEST_VERIFY(Strnistr(s8, "abcde", 20) == &s8[10]); + EATEST_VERIFY(Strnistr(s8, "abcde", 10) == 0); + EATEST_VERIFY(Strnistr(s8, ":/1", 20) == 0); + EATEST_VERIFY(Strnistr(s8, "abcd", 10) == &s8[3]); + EATEST_VERIFY(Strnistr(s8, "abcd", 5) == 0); + } + { + char16_t s16[24]; Strlcpy(s16, EA_CHAR16("012aBcdf89aBcDEf"), EAArrayCount(s16)); // Can't do char16_t variable[64] = EA_CHAR16(...) because some compilers don't support 16 bit string literals. + + EATEST_VERIFY(Strnistr(s16, EA_CHAR16(""), 0) == &s16[0]); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("012"), 3) == &s16[0]); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("012"), 2) == 0); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("abcde"), 20) == &s16[10]); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("abcde"), 10) == 0); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16(":/1"), 20) == 0); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("abcd"), 10) == &s16[3]); + EATEST_VERIFY(Strnistr(s16, EA_CHAR16("abcd"), 5) == 0); + } + { + char32_t s32[24]; Strlcpy(s32, EA_CHAR32("012aBcdf89aBcDEf"), EAArrayCount(s32)); // Can't do char32_t variable[64] = EA_CHAR32(...) because some compilers don't support 32 bit string literals. + + EATEST_VERIFY(Strnistr(s32, EA_CHAR32(""), 0) == &s32[0]); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("012"), 3) == &s32[0]); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("012"), 2) == 0); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("abcde"), 20) == &s32[10]); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("abcde"), 10) == 0); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32(":/1"), 20) == 0); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("abcd"), 10) == &s32[3]); + EATEST_VERIFY(Strnistr(s32, EA_CHAR32("abcd"), 5) == 0); + } + // char* Strrstr(const char* pString, const char* pSubString); // char16_t* Strrstr(const char16_t* pString, const char16_t* pSubString); // char32_t* Strrstr(const char32_t* pString, const char32_t* pSubString);