diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 48276b8bcf9..46163150c17 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1381,7 +1381,7 @@ @ stdcall SHRegSetUSValueW( wstr wstr long ptr long long) shlwapi.SHRegSetUSValueW @ stdcall SHRegWriteUSValueA(long str long ptr long long) shlwapi.SHRegWriteUSValueA @ stdcall SHRegWriteUSValueW(long wstr long ptr long long) shlwapi.SHRegWriteUSValueW -@ stdcall SHTruncateString(str long) shlwapi.SHTruncateString +@ stdcall SHTruncateString(str long) # @ stub SaveAlternatePackageRootPath # @ stub SaveStateRootFolderPath @ stdcall ScrollConsoleScreenBufferA(long ptr ptr ptr ptr) kernel32.ScrollConsoleScreenBufferA @@ -1525,13 +1525,13 @@ # @ stub StmReduceSize # @ stub StmReserve # @ stub StmWrite -@ stdcall StrCSpnA(str str) shlwapi.StrCSpnA -@ stdcall StrCSpnIA(str str) shlwapi.StrCSpnIA -@ stdcall StrCSpnIW(wstr wstr) shlwapi.StrCSpnIW -@ stdcall StrCSpnW(wstr wstr) shlwapi.StrCSpnW -@ stdcall StrCatBuffA(str str long) shlwapi.StrCatBuffA -@ stdcall StrCatBuffW(wstr wstr long) shlwapi.StrCatBuffW -@ stdcall StrCatChainW(ptr long long wstr) shlwapi.StrCatChainW +@ stdcall StrCSpnA(str str) +@ stdcall StrCSpnIA(str str) +@ stdcall StrCSpnIW(wstr wstr) +@ stdcall StrCSpnW(wstr wstr) +@ stdcall StrCatBuffA(str str long) +@ stdcall StrCatBuffW(wstr wstr long) +@ stdcall StrCatChainW(ptr long long wstr) @ stdcall StrChrA(str long) # @ stub StrChrA_MB @ stdcall StrChrIA(str long) @@ -1546,8 +1546,8 @@ @ stdcall StrCmpIW(wstr wstr) @ stdcall StrCmpLogicalW(wstr wstr) @ stdcall StrCmpNA(str str long) -@ stdcall StrCmpNCA(str ptr long) shlwapi.StrCmpNCA -@ stdcall StrCmpNCW(wstr wstr long) shlwapi.StrCmpNCW +@ stdcall StrCmpNCA(str str long) +@ stdcall StrCmpNCW(wstr wstr long) @ stdcall StrCmpNIA(str str long) @ stdcall StrCmpNICA(long long long) @ stdcall StrCmpNICW(wstr wstr long) @@ -1563,16 +1563,16 @@ @ stdcall StrIsIntlEqualW(long wstr wstr long) @ stdcall StrPBrkA(str str) @ stdcall StrPBrkW(wstr wstr) -@ stdcall StrRChrA(str str long) shlwapi.StrRChrA -@ stdcall StrRChrIA(str str long) shlwapi.StrRChrIA +@ stdcall StrRChrA(str str long) +@ stdcall StrRChrIA(str str long) @ stdcall StrRChrIW(wstr wstr long) @ stdcall StrRChrW(wstr wstr long) -@ stdcall StrRStrIA(str str str) shlwapi.StrRStrIA -@ stdcall StrRStrIW(wstr wstr wstr) shlwapi.StrRStrIW -@ stdcall StrSpnA(str str) shlwapi.StrSpnA +@ stdcall StrRStrIA(str str str) +@ stdcall StrRStrIW(wstr wstr wstr) +@ stdcall StrSpnA(str str) @ stdcall StrSpnW(wstr wstr) -@ stdcall StrStrA(str str) shlwapi.StrStrA -@ stdcall StrStrIA(str str) shlwapi.StrStrIA +@ stdcall StrStrA(str str) +@ stdcall StrStrIA(str str) @ stdcall StrStrIW(wstr wstr) @ stdcall StrStrNIW(wstr wstr long) @ stdcall StrStrNW(wstr wstr long) diff --git a/dlls/kernelbase/string.c b/dlls/kernelbase/string.c index a858f3a51a6..4c18acffe50 100644 --- a/dlls/kernelbase/string.c +++ b/dlls/kernelbase/string.c @@ -305,11 +305,45 @@ BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) return char_compare(ch1, ch2, NORM_IGNORECASE); } +static BOOL WINAPI ChrCmpA(WORD ch1, WORD ch2) +{ + return char_compare(ch1, ch2, 0); +} + BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) { return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL; } +static char * strstr_helper(const char *str, const char *search, + INT (WINAPI *cmp_func)(const char *, const char *, int)) +{ + const char *end; + size_t len; + + if (!str || !search || !*search) + return NULL; + + len = strlen(search); + end = str + strlen(str); + + while (str + len <= end) + { + if (!cmp_func(str, search, len)) + return (char *)str; + str = CharNextA(str); + } + + return NULL; +} + +char * WINAPI StrStrA(const char *str, const char *search) +{ + TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search)); + + return strstr_helper(str, search, StrCmpNA); +} + WCHAR * WINAPI StrStrW(const WCHAR *str, const WCHAR *search) { TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); @@ -378,6 +412,16 @@ int WINAPI StrCmpNW(const WCHAR *str, const WCHAR *comp, int len) return CompareStringW(GetThreadLocale(), 0, str, len, comp, len) - CSTR_EQUAL; } +DWORD WINAPI StrCmpNCA(const char *str, const char *comp, int len) +{ + return StrCmpNA(str, comp, len); +} + +DWORD WINAPI StrCmpNCW(const WCHAR *str, const WCHAR *comp, int len) +{ + return StrCmpNW(str, comp, len); +} + int WINAPI StrCmpNIW(const WCHAR *str, const WCHAR *comp, int len) { TRACE("%s, %s, %i\n", wine_dbgstr_w(str), wine_dbgstr_w(comp), len); @@ -416,6 +460,13 @@ WCHAR * WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count) return dst; } +char * WINAPI StrStrIA(const char *str, const char *search) +{ + TRACE("%s, %s\n", wine_dbgstr_a(str), debugstr_a(search)); + + return strstr_helper(str, search, StrCmpNIA); +} + WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search) { unsigned int len; @@ -439,12 +490,111 @@ WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search) return NULL; } +static int strspn_helper(const char *str, const char *match, char * (WINAPI *func)(const char *, WORD), BOOL invert) +{ + const char *ptr = str; + + if (!str || !*str || !match) + return 0; + + while (*ptr) + { + const char *test = func(match, *ptr); + + if (!invert && !test) + break; + if (invert && test) + break; + + ptr = CharNextA(ptr); + }; + + return ptr - str; +} + +int WINAPI StrSpnA(const char *str, const char *match) +{ + TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); + + return strspn_helper(str, match, StrChrA, FALSE); +} + int WINAPI StrSpnW(const WCHAR *str, const WCHAR *match) { if (!str || !match) return 0; return strspnW(str, match); } +int WINAPI StrCSpnA(const char *str, const char *match) +{ + TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); + + return strspn_helper(str, match, StrChrA, TRUE); +} + +int WINAPI StrCSpnW(const WCHAR *str, const WCHAR *match) +{ + if (!str || !match) + return 0; + + return strcspnW(str, match); +} + +int WINAPI StrCSpnIA(const char *str, const char *match) +{ + TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); + + return strspn_helper(str, match, StrChrIA, TRUE); +} + +int WINAPI StrCSpnIW(const WCHAR *str, const WCHAR *match) +{ + const WCHAR *ptr = str; + + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(match)); + + if (!str || !*str || !match) + return 0; + + while (*ptr) + { + if (StrChrIW(match, *ptr)) break; + ptr++; + } + + return ptr - str; +} + +static LPSTR strrchra_helper(const char *str, const char *end, WORD ch, BOOL (WINAPI *cmp_func)(WORD, WORD)) +{ + const char *ret = NULL; + WORD ch2; + + if (!str) + return NULL; + + if (!end) + end = str + lstrlenA(str); + + while (*str && str <= end) + { + ch2 = IsDBCSLeadByte(*str) ? *str << 8 | str[1] : *str; + + if (!cmp_func(ch, ch2)) + ret = str; + str = CharNextA(str); + } + + return (char *)ret; +} + +char * WINAPI StrRChrA(const char *str, const char *end, WORD ch) +{ + TRACE("%s, %s, %#x\n", wine_dbgstr_a(str), wine_dbgstr_a(end), ch); + + return strrchra_helper(str, end, ch, ChrCmpA); +} + WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch) { WCHAR *ret = NULL; @@ -459,6 +609,13 @@ WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch) return ret; } +char * WINAPI StrRChrIA(const char *str, const char *end, WORD ch) +{ + TRACE("%s, %s, %#x\n", wine_dbgstr_a(str), wine_dbgstr_a(end), ch); + + return strrchra_helper(str, end, ch, ChrCmpIA); +} + WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch) { WCHAR *ret = NULL; @@ -473,6 +630,73 @@ WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch) return ret; } +char * WINAPI StrRStrIA(const char *str, const char *end, const char *search) +{ + char *ret = NULL; + WORD ch1, ch2; + int len; + + TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search)); + + if (!str || !search || !*search) + return NULL; + + if (IsDBCSLeadByte(*search)) + ch1 = *search << 8 | (UCHAR)search[1]; + else + ch1 = *search; + len = lstrlenA(search); + + if (!end) + end = str + lstrlenA(str); + else /* reproduce the broken behaviour on Windows */ + end += min(len - 1, lstrlenA(end)); + + while (str + len <= end && *str) + { + ch2 = IsDBCSLeadByte(*str) ? *str << 8 | (UCHAR)str[1] : *str; + if (!ChrCmpIA(ch1, ch2)) + { + if (!StrCmpNIA(str, search, len)) + ret = (char *)str; + } + + str = CharNextA(str); + } + + return ret; +} + +WCHAR * WINAPI StrRStrIW(const WCHAR *str, const WCHAR *end, const WCHAR *search) +{ + WCHAR *ret = NULL; + int len; + + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); + + if (!str || !search || !*search) + return NULL; + + len = strlenW(search); + + if (!end) + end = str + strlenW(str); + else + end += min(len - 1, lstrlenW(end)); + + while (str + len <= end && *str) + { + if (!ChrCmpIW(*search, *str)) + { + if (!StrCmpNIW(str, search, len)) + ret = (WCHAR *)str; + } + str++; + } + + return ret; +} + char * WINAPI StrPBrkA(const char *str, const char *match) { TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); @@ -1120,3 +1344,85 @@ BOOL WINAPI StrIsIntlEqualW(BOOL case_sensitive, const WCHAR *str, const WCHAR * return (CompareStringW(GetThreadLocale(), flags, str, len, cmp, len) == CSTR_EQUAL); } + +char * WINAPI StrCatBuffA(char *str, const char *cat, INT max_len) +{ + INT len; + + TRACE("%p, %s, %d\n", str, wine_dbgstr_a(cat), max_len); + + if (!str) + return NULL; + + len = strlen(str); + max_len -= len; + if (max_len > 0) + StrCpyNA(str + len, cat, max_len); + + return str; +} + +WCHAR * WINAPI StrCatBuffW(WCHAR *str, const WCHAR *cat, INT max_len) +{ + INT len; + + TRACE("%p, %s, %d\n", str, wine_dbgstr_w(cat), max_len); + + if (!str) + return NULL; + + len = strlenW(str); + max_len -= len; + if (max_len > 0) + StrCpyNW(str + len, cat, max_len); + + return str; +} + +DWORD WINAPI StrCatChainW(WCHAR *str, DWORD max_len, DWORD at, const WCHAR *cat) +{ + TRACE("%s, %u, %d, %s\n", wine_dbgstr_w(str), max_len, at, wine_dbgstr_w(cat)); + + if (at == -1) + at = strlenW(str); + + if (!max_len) + return at; + + if (at == max_len) + at--; + + if (cat && at < max_len) + { + str += at; + while (at < max_len - 1 && *cat) + { + *str++ = *cat++; + at++; + } + *str = 0; + } + + return at; +} + +DWORD WINAPI SHTruncateString(char *str, DWORD size) +{ + char *last_byte; + + if (!str || !size) + return 0; + + last_byte = str + size - 1; + + while (str < last_byte) + str += IsDBCSLeadByte(*str) ? 2 : 1; + + if (str == last_byte && IsDBCSLeadByte(*str)) + { + *str = '\0'; + size--; + } + + return size; +}