diff --git a/dlls/kernelbase/Makefile.in b/dlls/kernelbase/Makefile.in index 88ba774a7c1..dcb03b4fdcc 100644 --- a/dlls/kernelbase/Makefile.in +++ b/dlls/kernelbase/Makefile.in @@ -3,4 +3,5 @@ IMPORTS = uuid C_SRCS = \ main.c \ - path.c + path.c \ + string.c diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 7108c40a01f..8294c95282a 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -131,7 +131,7 @@ @ stdcall CheckTokenMembership(long ptr ptr) advapi32.CheckTokenMembership # @ stub CheckTokenMembershipEx @ stdcall ChrCmpIA(long long) shlwapi.ChrCmpIA -@ stdcall ChrCmpIW(long long) shlwapi.ChrCmpIW +@ stdcall ChrCmpIW(long long) @ stdcall ClearCommBreak(long) kernel32.ClearCommBreak @ stdcall ClearCommError(long ptr ptr) kernel32.ClearCommError # @ stub CloseGlobalizationUserSettingsKey @@ -843,17 +843,17 @@ @ stdcall IsCharAlphaNumericA(long) user32.IsCharAlphaNumericA @ stdcall IsCharAlphaNumericW(long) user32.IsCharAlphaNumericW @ stdcall IsCharAlphaW(long) user32.IsCharAlphaW -@ stdcall IsCharBlankW(long) shlwapi.IsCharBlankW -@ stdcall IsCharCntrlW(ptr) shlwapi.IsCharCntrlW -@ stdcall IsCharDigitW(long) shlwapi.IsCharDigitW +@ stdcall IsCharBlankW(long) +@ stdcall IsCharCntrlW(long) +@ stdcall IsCharDigitW(long) @ stdcall IsCharLowerA(long) user32.IsCharLowerA @ stdcall IsCharLowerW(long) user32.IsCharLowerW -@ stdcall IsCharPunctW(long) shlwapi.IsCharPunctW -@ stdcall IsCharSpaceA(long) shlwapi.IsCharSpaceA -@ stdcall IsCharSpaceW(long) shlwapi.IsCharSpaceW +@ stdcall IsCharPunctW(long) +@ stdcall IsCharSpaceA(long) +@ stdcall IsCharSpaceW(long) @ stdcall IsCharUpperA(long) user32.IsCharUpperA @ stdcall IsCharUpperW(long) user32.IsCharUpperW -@ stdcall IsCharXDigitW(long) shlwapi.IsCharXDigitW +@ stdcall IsCharXDigitW(long) @ stdcall IsDBCSLeadByte(long) kernel32.IsDBCSLeadByte @ stdcall IsDBCSLeadByteEx(long long) kernel32.IsDBCSLeadByteEx @ stdcall IsDebuggerPresent() kernel32.IsDebuggerPresent @@ -1535,56 +1535,56 @@ @ stdcall StrChrA(str long) shlwapi.StrChrA # @ stub StrChrA_MB @ stdcall StrChrIA(str long) shlwapi.StrChrIA -@ stdcall StrChrIW(wstr long) shlwapi.StrChrIW +@ stdcall StrChrIW(wstr long) # @ stub StrChrNIW -@ stdcall StrChrNW(wstr long long) shlwapi.StrChrNW -@ stdcall StrChrW(wstr long) shlwapi.StrChrW -@ stdcall StrCmpCA(str str) shlwapi.StrCmpCA -@ stdcall StrCmpCW(wstr wstr) shlwapi.StrCmpCW -@ stdcall StrCmpICA(str str) shlwapi.StrCmpICA -@ stdcall StrCmpICW(wstr wstr) shlwapi.StrCmpICW -@ stdcall StrCmpIW(wstr wstr) shlwapi.StrCmpIW +@ stdcall StrChrNW(wstr long long) +@ stdcall StrChrW(wstr long) +@ stdcall StrCmpCA(str str) +@ stdcall StrCmpCW(wstr wstr) +@ stdcall StrCmpICA(str str) +@ stdcall StrCmpICW(wstr wstr) +@ stdcall StrCmpIW(wstr wstr) @ stdcall StrCmpLogicalW(wstr wstr) shlwapi.StrCmpLogicalW @ stdcall StrCmpNA(str str long) shlwapi.StrCmpNA @ stdcall StrCmpNCA(str ptr long) shlwapi.StrCmpNCA @ stdcall StrCmpNCW(wstr wstr long) shlwapi.StrCmpNCW -@ stdcall StrCmpNIA(str str long) shlwapi.StrCmpNIA -@ stdcall StrCmpNICA(long long long) shlwapi.StrCmpNICA -@ stdcall StrCmpNICW(wstr wstr long) shlwapi.StrCmpNICW -@ stdcall StrCmpNIW(wstr wstr long) shlwapi.StrCmpNIW -@ stdcall StrCmpNW(wstr wstr long) shlwapi.StrCmpNW -@ stdcall StrCmpW(wstr wstr) shlwapi.StrCmpW -@ stdcall StrCpyNW(ptr wstr long) shlwapi.StrCpyNW -@ stdcall StrCpyNXA(ptr str long) shlwapi.StrCpyNXA -@ stdcall StrCpyNXW(ptr wstr long) shlwapi.StrCpyNXW -@ stdcall StrDupA(str) shlwapi.StrDupA -@ stdcall StrDupW(wstr) shlwapi.StrDupW +@ stdcall StrCmpNIA(str str long) +@ stdcall StrCmpNICA(long long long) +@ stdcall StrCmpNICW(wstr wstr long) +@ stdcall StrCmpNIW(wstr wstr long) +@ stdcall StrCmpNW(wstr wstr long) +@ stdcall StrCmpW(wstr wstr) +@ stdcall StrCpyNW(ptr wstr long) +@ stdcall StrCpyNXA(ptr str long) +@ stdcall StrCpyNXW(ptr wstr long) +@ stdcall StrDupA(str) +@ stdcall StrDupW(wstr) @ stdcall StrIsIntlEqualA(long str str long) shlwapi.StrIsIntlEqualA @ stdcall StrIsIntlEqualW(long wstr wstr long) shlwapi.StrIsIntlEqualW @ stdcall StrPBrkA(str str) shlwapi.StrPBrkA -@ stdcall StrPBrkW(wstr wstr) shlwapi.StrPBrkW +@ stdcall StrPBrkW(wstr wstr) @ stdcall StrRChrA(str str long) shlwapi.StrRChrA @ stdcall StrRChrIA(str str long) shlwapi.StrRChrIA -@ stdcall StrRChrIW(wstr wstr long) shlwapi.StrRChrIW -@ stdcall StrRChrW(wstr wstr long) shlwapi.StrRChrW +@ 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 StrSpnW(wstr wstr) shlwapi.StrSpnW +@ stdcall StrSpnW(wstr wstr) @ stdcall StrStrA(str str) shlwapi.StrStrA @ stdcall StrStrIA(str str) shlwapi.StrStrIA -@ stdcall StrStrIW(wstr wstr) shlwapi.StrStrIW -@ stdcall StrStrNIW(wstr wstr long) shlwapi.StrStrNIW -@ stdcall StrStrNW(wstr wstr long) shlwapi.StrStrNW -@ stdcall StrStrW(wstr wstr) shlwapi.StrStrW +@ stdcall StrStrIW(wstr wstr) +@ stdcall StrStrNIW(wstr wstr long) +@ stdcall StrStrNW(wstr wstr long) +@ stdcall StrStrW(wstr wstr) @ stdcall StrToInt64ExA(str long ptr) shlwapi.StrToInt64ExA -@ stdcall StrToInt64ExW(wstr long ptr) shlwapi.StrToInt64ExW +@ stdcall StrToInt64ExW(wstr long ptr) @ stdcall StrToIntA(str) shlwapi.StrToIntA @ stdcall StrToIntExA(str long ptr) shlwapi.StrToIntExA -@ stdcall StrToIntExW(wstr long ptr) shlwapi.StrToIntExW -@ stdcall StrToIntW(wstr) shlwapi.StrToIntW +@ stdcall StrToIntExW(wstr long ptr) +@ stdcall StrToIntW(wstr) @ stdcall StrTrimA(str str) shlwapi.StrTrimA -@ stdcall StrTrimW(wstr wstr) shlwapi.StrTrimW +@ stdcall StrTrimW(wstr wstr) @ stdcall SubmitThreadpoolWork(ptr) kernel32.SubmitThreadpoolWork # @ stub SubscribeEdpEnabledStateChange # @ stub SubscribeStateChangeNotification diff --git a/dlls/kernelbase/string.c b/dlls/kernelbase/string.c new file mode 100644 index 00000000000..4991ba3fd1f --- /dev/null +++ b/dlls/kernelbase/string.c @@ -0,0 +1,519 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "shlwapi.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(string); + +DWORD WINAPI StrCmpCA(const char *str, const char *cmp) +{ + return lstrcmpA(str, cmp); +} + +DWORD WINAPI StrCmpCW(const WCHAR *str, const WCHAR *cmp) +{ + return lstrcmpW(str, cmp); +} + +DWORD WINAPI StrCmpICA(const char *str, const char *cmp) +{ + return lstrcmpiA(str, cmp); +} + +DWORD WINAPI StrCmpICW(const WCHAR *str, const WCHAR *cmp) +{ + return lstrcmpiW(str, cmp); +} + +DWORD WINAPI StrCmpNICA(const char *str, const char *cmp, DWORD len) +{ + return StrCmpNIA(str, cmp, len); +} + +DWORD WINAPI StrCmpNICW(const WCHAR *str, const WCHAR *cmp, DWORD len) +{ + return StrCmpNIW(str, cmp, len); +} + +BOOL WINAPI IsCharBlankW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_BLANK); +} + +BOOL WINAPI IsCharCntrlW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_CNTRL); +} + +BOOL WINAPI IsCharDigitW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_DIGIT); +} + +BOOL WINAPI IsCharPunctW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_PUNCT); +} + +BOOL WINAPI IsCharSpaceA(CHAR c) +{ + WORD type; + return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &type) && (type & C1_SPACE); +} + +BOOL WINAPI IsCharSpaceW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_SPACE); +} + +BOOL WINAPI IsCharXDigitW(WCHAR wc) +{ + WORD type; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &type) && (type & C1_XDIGIT); +} + +WCHAR * WINAPI StrChrW(const WCHAR *str, WCHAR ch) +{ + TRACE("%s, %#x\n", wine_dbgstr_w(str), ch); + + if (!str) + return NULL; + + return strchrW(str, ch); +} + +WCHAR * WINAPI StrChrIW(const WCHAR *str, WCHAR ch) +{ + TRACE("%s, %#x\n", wine_dbgstr_w(str), ch); + + if (!str) + return NULL; + + ch = toupperW(ch); + while (*str) + { + if (toupperW(*str) == ch) + return (WCHAR *)str; + str++; + } + str = NULL; + + return (WCHAR *)str; +} + +WCHAR * WINAPI StrChrNW(const WCHAR *str, WCHAR ch, UINT max_len) +{ + TRACE("%s, %#x, %u\n", wine_dbgstr_wn(str, max_len), ch, max_len); + + if (!str) + return NULL; + + while (*str && max_len-- > 0) + { + if (*str == ch) + return (WCHAR *)str; + str++; + } + + return NULL; +} + +char * WINAPI StrDupA(const char *str) +{ + unsigned int len; + char *ret; + + TRACE("%s\n", wine_dbgstr_a(str)); + + len = str ? strlen(str) + 1 : 1; + ret = LocalAlloc(LMEM_FIXED, len); + + if (ret) + { + if (str) + memcpy(ret, str, len); + else + *ret = '\0'; + } + + return ret; +} + +WCHAR * WINAPI StrDupW(const WCHAR *str) +{ + unsigned int len; + WCHAR *ret; + + TRACE("%s\n", wine_dbgstr_w(str)); + + len = (str ? strlenW(str) + 1 : 1) * sizeof(WCHAR); + ret = LocalAlloc(LMEM_FIXED, len); + + if (ret) + { + if (str) + memcpy(ret, str, len); + else + *ret = '\0'; + } + + return ret; +} + +BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) +{ + return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL; +} + +WCHAR * WINAPI StrStrW(const WCHAR *str, const WCHAR *search) +{ + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); + + if (!str || !search || !*search) + return NULL; + + return strstrW(str, search); +} + +WCHAR * WINAPI StrStrNW(const WCHAR *str, const WCHAR *search, UINT max_len) +{ + unsigned int i, len; + + TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len); + + if (!str || !search || !*search || !max_len) + return NULL; + + len = strlenW(search); + + for (i = max_len; *str && (i > 0); i--, str++) + { + if (!strncmpW(str, search, len)) + return (WCHAR *)str; + } + + return NULL; +} + +int WINAPI StrCmpNIA(const char *str, const char *cmp, int len) +{ + TRACE("%s, %s, %i\n", wine_dbgstr_a(str), wine_dbgstr_a(cmp), len); + return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, str, len, cmp, len) - CSTR_EQUAL; +} + +WCHAR * WINAPI StrStrNIW(const WCHAR *str, const WCHAR *search, UINT max_len) +{ + unsigned int i, len; + + TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len); + + if (!str || !search || !*search || !max_len) + return NULL; + + len = strlenW(search); + + for (i = max_len; *str && (i > 0); i--, str++) + { + if (!strncmpiW(str, search, len)) + return (WCHAR *)str; + } + + return NULL; +} + +int WINAPI StrCmpNW(const WCHAR *str, const WCHAR *comp, int len) +{ + TRACE("%s, %s, %i\n", wine_dbgstr_w(str), wine_dbgstr_w(comp), len); + return CompareStringW(GetThreadLocale(), 0, str, len, comp, len) - CSTR_EQUAL; +} + +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); + return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str, len, comp, len) - CSTR_EQUAL; +} + +int WINAPI StrCmpW(const WCHAR *str, const WCHAR *comp) +{ + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp)); + return CompareStringW(GetThreadLocale(), 0, str, -1, comp, -1) - CSTR_EQUAL; +} + +int WINAPI StrCmpIW(const WCHAR *str, const WCHAR *comp) +{ + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp)); + return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str, -1, comp, -1) - CSTR_EQUAL; +} + +WCHAR * WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count) +{ + const WCHAR *s = src; + WCHAR *d = dst; + + TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), count); + + if (s) + { + while ((count > 1) && *s) + { + count--; + *d++ = *s++; + } + } + if (count) *d = 0; + + return dst; +} + +WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search) +{ + unsigned int len; + const WCHAR *end; + + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); + + if (!str || !search || !*search) + return NULL; + + len = strlenW(search); + end = str + strlenW(str); + + while (str + len <= end) + { + if (!StrCmpNIW(str, search, len)) + return (WCHAR *)str; + str++; + } + + return NULL; +} + +int WINAPI StrSpnW(const WCHAR *str, const WCHAR *match) +{ + if (!str || !match) return 0; + return strspnW(str, match); +} + +WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch) +{ + WCHAR *ret = NULL; + + if (!str) return NULL; + if (!end) end = str + strlenW(str); + while (str < end) + { + if (*str == ch) ret = (WCHAR *)str; + str++; + } + return ret; +} + +WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch) +{ + WCHAR *ret = NULL; + + if (!str) return NULL; + if (!end) end = str + strlenW(str); + while (str < end) + { + if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str; + str++; + } + return ret; +} + +WCHAR * WINAPI StrPBrkW(const WCHAR *str, const WCHAR *match) +{ + if (!str || !match) return NULL; + return strpbrkW(str, match); +} + +BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim) +{ + unsigned int len; + WCHAR *ptr = str; + BOOL ret = FALSE; + + TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(trim)); + + if (!str || !*str) + return FALSE; + + while (*ptr && StrChrW(trim, *ptr)) + ptr++; + + len = strlenW(ptr); + + if (ptr != str) + { + memmove(str, ptr, (len + 1) * sizeof(WCHAR)); + ret = TRUE; + } + + if (len > 0) + { + ptr = str + len; + while (StrChrW(trim, ptr[-1])) + ptr--; /* Skip trailing matches */ + + if (ptr != str + len) + { + *ptr = '\0'; + ret = TRUE; + } + } + + return ret; +} + +BOOL WINAPI StrToInt64ExW(const WCHAR *str, DWORD flags, LONGLONG *ret) +{ + BOOL negative = FALSE; + LONGLONG value = 0; + + TRACE("%s, %#x, %p\n", wine_dbgstr_w(str), flags, ret); + + if (!str || !ret) + return FALSE; + + if (flags > STIF_SUPPORT_HEX) + WARN("Unknown flags %#x.\n", flags); + + /* Skip leading space, '+', '-' */ + while (isspaceW(*str)) + str++; + + if (*str == '-') + { + negative = TRUE; + str++; + } + else if (*str == '+') + str++; + + if (flags & STIF_SUPPORT_HEX && *str == '0' && tolowerW(str[1]) == 'x') + { + /* Read hex number */ + str += 2; + + if (!isxdigitW(*str)) + return FALSE; + + while (isxdigitW(*str)) + { + value *= 16; + if (isdigitW(*str)) + value += (*str - '0'); + else + value += 10 + (tolowerW(*str) - 'a'); + str++; + } + + *ret = value; + return TRUE; + } + + /* Read decimal number */ + if (!isdigitW(*str)) + return FALSE; + + while (isdigitW(*str)) + { + value *= 10; + value += (*str - '0'); + str++; + } + + *ret = negative ? -value : value; + return TRUE; +} + +BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret) +{ + LONGLONG value; + BOOL res; + + TRACE("%s, %#x, %p\n", wine_dbgstr_w(str), flags, ret); + + res = StrToInt64ExW(str, flags, &value); + if (res) *ret = value; + return res; +} + +int WINAPI StrToIntW(const WCHAR *str) +{ + int value = 0; + + TRACE("%s\n", wine_dbgstr_w(str)); + + if (!str) + return 0; + + if (*str == '-' || isdigitW(*str)) + StrToIntExW(str, 0, &value); + return value; +} + +char * WINAPI StrCpyNXA(char *dst, const char *src, int len) +{ + TRACE("%p, %s, %i\n", dst, wine_dbgstr_a(src), len); + + if (dst && src && len > 0) + { + while ((len-- > 1) && *src) + *dst++ = *src++; + if (len >= 0) + *dst = '\0'; + } + + return dst; +} + +WCHAR * WINAPI StrCpyNXW(WCHAR *dst, const WCHAR *src, int len) +{ + TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), len); + + if (dst && src && len > 0) + { + while ((len-- > 1) && *src) + *dst++ = *src++; + if (len >= 0) + *dst = '\0'; + } + + return dst; +}