* Copyright 1998 Eric Kohl
* 1998 Juergen Schmied <j.schmied@metronet.de>
* 2000 Eric Kohl for CodeWeavers
+ * Copyright 2002 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
+/*************************************************************************
+ * COMCTL32_ChrCmpHelperA
+ *
+ * Internal helper for ChrCmpA/COMCTL32_ChrCmpIA.
+ *
+ * NOTES
+ * Both this function and its Unicode counterpart are very inneficient. To
+ * fix this, CompareString must be completely implemented and optimised
+ * first. Then the core character test can be taken out of that function and
+ * placed here, so that it need never be called at all. Until then, do not
+ * attempt to optimise this code unless you are willing to test that it
+ * still performs correctly.
+ */
+static BOOL COMCTL32_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
+{
+ char str1[3], str2[3];
+
+ str1[0] = LOBYTE(ch1);
+ if (IsDBCSLeadByte(str1[0]))
+ {
+ str1[1] = HIBYTE(ch1);
+ str1[2] = '\0';
+ }
+ else
+ str1[1] = '\0';
+
+ str2[0] = LOBYTE(ch2);
+ if (IsDBCSLeadByte(str2[0]))
+ {
+ str2[1] = HIBYTE(ch2);
+ str2[2] = '\0';
+ }
+ else
+ str2[1] = '\0';
+
+ return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
+}
+
+/*************************************************************************
+ * COMCTL32_ChrCmpHelperW
+ *
+ * Internal helper for COMCTL32_ChrCmpW/ChrCmpIW.
+ */
+static BOOL COMCTL32_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
+{
+ WCHAR str1[2], str2[2];
+
+ str1[0] = ch1;
+ str1[1] = '\0';
+ str2[0] = ch2;
+ str2[1] = '\0';
+ return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
+}
+
+/*************************************************************************
+ * COMCTL32_ChrCmpA (internal)
+ *
+ * Internal helper function.
+ */
+static BOOL COMCTL32_ChrCmpA(WORD ch1, WORD ch2)
+{
+ return COMCTL32_ChrCmpHelperA(ch1, ch2, 0);
+}
+
+/*************************************************************************
+ * COMCTL32_ChrCmpIA (internal)
+ *
+ * Compare two characters, ignoring case.
+ *
+ * PARAMS
+ * ch1 [I] First character to compare
+ * ch2 [I] Second character to compare
+ *
+ * RETURNS
+ * FALSE, if the characters are equal.
+ * Non-zero otherwise.
+ */
+static BOOL COMCTL32_ChrCmpIA(WORD ch1, WORD ch2)
+{
+ TRACE("(%d,%d)\n", ch1, ch2);
+
+ return COMCTL32_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
+}
+
+/*************************************************************************
+ * COMCTL32_ChrCmpW
+ *
+ * Internal helper function.
+ */
+static BOOL COMCTL32_ChrCmpW(WCHAR ch1, WCHAR ch2)
+{
+ return COMCTL32_ChrCmpHelperW(ch1, ch2, 0);
+}
+
/**************************************************************************
* StrChrA [COMCTL32.350]
*
* not found.
* Failure: NULL, if any arguments are invalid.
*/
-LPSTR WINAPI StrChrA (LPCSTR lpszStr, CHAR ch)
+LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
{
- return strchr (lpszStr, ch);
+ TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
+
+ if (lpszStr)
+ {
+ while (*lpszStr)
+ {
+ if (!COMCTL32_ChrCmpA(*lpszStr, ch))
+ return (LPSTR)lpszStr;
+ lpszStr = CharNextA(lpszStr);
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ * COMCTL32_StrStrHelperA
+ *
+ * Internal implementation of StrStrA/StrStrIA
+ */
+static LPSTR COMCTL32_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
+ int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
+{
+ size_t iLen;
+
+ if (!lpszStr || !lpszSearch || !*lpszSearch)
+ return NULL;
+
+ iLen = strlen(lpszSearch);
+
+ while (*lpszStr)
+ {
+ if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
+ return (LPSTR)lpszStr;
+ lpszStr = CharNextA(lpszStr);
+ }
+ return NULL;
}
+/*************************************************************************
+ * COMCTL32_StrStrHelperW
+ *
+ * Internal implementation of StrStrW/StrStrIW
+ */
+static LPWSTR COMCTL32_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
+ int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
+{
+ int iLen;
+
+ if (!lpszStr || !lpszSearch || !*lpszSearch)
+ return NULL;
+
+ iLen = strlenW(lpszSearch);
+
+ while (*lpszStr)
+ {
+ if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
+ return (LPWSTR)lpszStr;
+ lpszStr = CharNextW(lpszStr);
+ }
+ return NULL;
+}
/**************************************************************************
* StrStrIA [COMCTL32.355]
* Find a substring within a string, ignoring case.
*
* PARAMS
- * lpStr1 [I] String to search in
- * lpStr2 [I] String to look for
+ * lpszStr [I] String to search in
+ * lpszSearch [I] String to look for
*
* RETURNS
* The start of lpszSearch within lpszStr, or NULL if not found.
*/
-LPSTR WINAPI StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
-{
- INT len1, len2, i;
- CHAR first;
-
- if (*lpStr2 == 0)
- return ((LPSTR)lpStr1);
- len1 = 0;
- while (lpStr1[len1] != 0) ++len1;
- len2 = 0;
- while (lpStr2[len2] != 0) ++len2;
- if (len2 == 0)
- return ((LPSTR)(lpStr1 + len1));
- first = tolower (*lpStr2);
- while (len1 >= len2) {
- if (tolower(*lpStr1) == first) {
- for (i = 1; i < len2; ++i)
- if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
- break;
- if (i >= len2)
- return ((LPSTR)lpStr1);
- }
- ++lpStr1; --len1;
- }
- return (NULL);
+LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
+{
+ TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
+
+ return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
}
/**************************************************************************
*
* See StrStrIA.
*/
-LPWSTR WINAPI StrStrIW (LPCWSTR lpStr1, LPCWSTR lpStr2)
-{
- INT len1, len2, i;
- WCHAR first;
-
- if (*lpStr2 == 0)
- return ((LPWSTR)lpStr1);
- len1 = 0;
- while (lpStr1[len1] != 0) ++len1;
- len2 = 0;
- while (lpStr2[len2] != 0) ++len2;
- if (len2 == 0)
- return ((LPWSTR)(lpStr1 + len1));
- first = tolowerW (*lpStr2);
- while (len1 >= len2) {
- if (tolowerW (*lpStr1) == first) {
- for (i = 1; i < len2; ++i)
- if (tolowerW (lpStr1[i]) != tolowerW(lpStr2[i]))
- break;
- if (i >= len2)
- return ((LPWSTR)lpStr1);
- }
- ++lpStr1; --len1;
- }
- return (NULL);
+LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
+{
+ TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
+
+ return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
}
/**************************************************************************
return atoiW(lpString);
}
+/*************************************************************************
+ * COMCTL32_StrSpnHelperA (internal)
+ *
+ * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
+ */
+static int COMCTL32_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
+ LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
+ BOOL bInvert)
+{
+ LPCSTR lpszRead = lpszStr;
+ if (lpszStr && *lpszStr && lpszMatch)
+ {
+ while (*lpszRead)
+ {
+ LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
+
+ if (!bInvert && !lpszTest)
+ break;
+ if (bInvert && lpszTest)
+ break;
+ lpszRead = CharNextA(lpszRead);
+ };
+ }
+ return lpszRead - lpszStr;
+}
+
/**************************************************************************
* StrCSpnA [COMCTL32.356]
*
* The length of the part of lpszStr containing only chars not in lpszMatch,
* or 0 if any parameter is invalid.
*/
-INT WINAPI StrCSpnA( LPCSTR lpStr, LPCSTR lpSet)
+int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
{
- return strcspn(lpStr, lpSet);
+ TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
+
+ return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
}
/**************************************************************************
*
* See StrChrA.
*/
-LPWSTR WINAPI StrChrW( LPCWSTR lpStart, WORD wMatch)
+LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
{
- return strchrW(lpStart, wMatch);
+ LPWSTR lpszRet = NULL;
+
+ TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
+
+ if (lpszStr)
+ lpszRet = strchrW(lpszStr, ch);
+ return lpszRet;
}
/**************************************************************************
* An integer less than, equal to or greater than 0, indicating that
* lpszStr is less than, the same, or greater than lpszComp.
*/
-INT WINAPI StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
+INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
{
- return strncmp(lpStr1, lpStr2, nChar);
+ INT iRet;
+
+ TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
+
+ iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
+ return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/**************************************************************************
* StrCmpNIA [COMCTL32.353]
*
+ * Compare two strings, up to a maximum length, ignoring case.
+ *
+ * PARAMS
+ * lpszStr [I] First string to compare
+ * lpszComp [I] Second string to compare
+ * iLen [I] Maximum number of chars to compare.
+ *
+ * RETURNS
+ * An integer less than, equal to or greater than 0, indicating that
+ * lpszStr is less than, the same, or greater than lpszComp.
*/
-INT WINAPI StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
+int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
{
- return strncasecmp(lpStr1, lpStr2, nChar);
+ INT iRet;
+
+ TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
+
+ iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
+ return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
-/**************************************************************************
- * StrCmpNW [COMCTL32.360]
+/*************************************************************************
+ * StrCmpNIW [COMCTL32.361]
*
+ * See StrCmpNIA.
*/
-INT WINAPI StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
+INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
{
- return strncmpW(lpStr1, lpStr2, nChar);
+ INT iRet;
+
+ TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
+
+ iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
+ return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/**************************************************************************
- * StrCmpNIW [COMCTL32.361]
+ * StrCmpNW [COMCTL32.360]
*
+ * See StrCmpNA.
*/
-INT WINAPI StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
+INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
{
- FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
- return 0;
+ INT iRet;
+
+ TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
+
+ iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
+ return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
-/**************************************************************************
- * StrRChrA [COMCTL32.351]
+/*************************************************************************
+ * COMCTL32_StrRChrHelperA
*
+ * Internal implementation of StrRChrA/StrRChrIA.
*/
-LPSTR WINAPI StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
+static LPSTR COMCTL32_StrRChrHelperA(LPCSTR lpszStr,
+ LPCSTR lpszEnd, WORD ch,
+ BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
{
- LPCSTR lpGotIt = NULL;
- BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
+ LPCSTR lpszRet = NULL;
- TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
+ if (lpszStr)
+ {
+ WORD ch2;
- if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
+ if (!lpszEnd)
+ lpszEnd = lpszStr + lstrlenA(lpszStr);
- for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
+ while (*lpszStr && lpszStr <= lpszEnd)
{
- if (*lpStart != LOBYTE(wMatch)) continue;
- if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
- lpGotIt = lpStart;
+ ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
+
+ if (!pChrCmpFn(ch, ch2))
+ lpszRet = lpszStr;
+ lpszStr = CharNextA(lpszStr);
}
- return (LPSTR)lpGotIt;
+ }
+ return (LPSTR)lpszRet;
}
+/*************************************************************************
+ * COMCTL32_StrRChrHelperW
+ *
+ * Internal implementation of StrRChrW/StrRChrIW.
+ */
+static LPWSTR COMCTL32_StrRChrHelperW(LPCWSTR lpszStr,
+ LPCWSTR lpszEnd, WCHAR ch,
+ BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
+{
+ LPCWSTR lpszRet = NULL;
+
+ if (lpszStr)
+ {
+ if (!lpszEnd)
+ lpszEnd = lpszStr + strlenW(lpszStr);
+
+ while (*lpszStr && lpszStr <= lpszEnd)
+ {
+ if (!pChrCmpFn(ch, *lpszStr))
+ lpszRet = lpszStr;
+ lpszStr = CharNextW(lpszStr);
+ }
+ }
+ return (LPWSTR)lpszRet;
+}
/**************************************************************************
- * StrRChrW [COMCTL32.359]
+ * StrRChrA [COMCTL32.351]
+ *
+ * Find the last occurence of a character in string.
+ *
+ * PARAMS
+ * lpszStr [I] String to search in
+ * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
+ * ch [I] Character to search for.
*
+ * RETURNS
+ * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
+ * or NULL if not found.
+ * Failure: NULL, if any arguments are invalid.
*/
-LPWSTR WINAPI StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
+LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
{
- LPCWSTR lpGotIt = NULL;
+ TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
- TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
- if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
+ return COMCTL32_StrRChrHelperA(lpszStr, lpszEnd, ch, COMCTL32_ChrCmpA);
+}
- for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
- if (*lpStart == wMatch) lpGotIt = lpStart;
- return (LPWSTR)lpGotIt;
-}
+/**************************************************************************
+ * StrRChrW [COMCTL32.359]
+ *
+ * See StrRChrA.
+ */
+LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
+{
+ TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
+ return COMCTL32_StrRChrHelperW(lpszStr, lpszEnd, ch, COMCTL32_ChrCmpW);
+}
/**************************************************************************
* StrStrA [COMCTL32.354]
*
+ * Find a substring within a string.
+ *
+ * PARAMS
+ * lpszStr [I] String to search in
+ * lpszSearch [I] String to look for
+ *
+ * RETURNS
+ * The start of lpszSearch within lpszStr, or NULL if not found.
*/
-LPSTR WINAPI StrStrA( LPCSTR lpFirst, LPCSTR lpSrch)
+LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
{
- return strstr(lpFirst, lpSrch);
+ TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
+
+ return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncmp);
}
/**************************************************************************
* StrStrW [COMCTL32.362]
*
+ * See StrStrA.
*/
-LPWSTR WINAPI StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch)
+LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
{
- return strstrW(lpFirst, lpSrch);
+ TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
+
+ return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
+}
+
+/*************************************************************************
+ * StrChrIA [COMCTL32.366]
+ *
+ * Find a given character in a string, ignoring case.
+ *
+ * PARAMS
+ * lpszStr [I] String to search in.
+ * ch [I] Character to search for.
+ *
+ * RETURNS
+ * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
+ * not found.
+ * Failure: NULL, if any arguments are invalid.
+ */
+LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
+{
+ TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
+
+ if (lpszStr)
+ {
+ while (*lpszStr)
+ {
+ if (!COMCTL32_ChrCmpIA(*lpszStr, ch))
+ return (LPSTR)lpszStr;
+ lpszStr = CharNextA(lpszStr);
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ * StrChrIW [COMCTL32.367]
+ *
+ * See StrChrA.
+ */
+LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
+{
+ TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
+
+ if (lpszStr)
+ {
+ ch = toupperW(ch);
+ while (*lpszStr)
+ {
+ if (toupperW(*lpszStr) == ch)
+ return (LPWSTR)lpszStr;
+ lpszStr = CharNextW(lpszStr);
+ }
+ lpszStr = NULL;
+ }
+ return (LPWSTR)lpszStr;
+}
+
+/*************************************************************************
+ * StrRStrIA [COMCTL32.372]
+ *
+ * Find the last occurence of a substring within a string.
+ *
+ * PARAMS
+ * lpszStr [I] String to search in
+ * lpszEnd [I] End of lpszStr
+ * lpszSearch [I] String to look for
+ *
+ * RETURNS
+ * The last occurence lpszSearch within lpszStr, or NULL if not found.
+ */
+LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
+{
+ LPSTR lpszRet = NULL;
+ WORD ch1, ch2;
+ INT iLen;
+
+ TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
+
+ if (!lpszStr || !lpszSearch || !*lpszSearch)
+ return NULL;
+
+ if (!lpszEnd)
+ lpszEnd = lpszStr + lstrlenA(lpszStr);
+
+ if (IsDBCSLeadByte(*lpszSearch))
+ ch1 = *lpszSearch << 8 | lpszSearch[1];
+ else
+ ch1 = *lpszSearch;
+ iLen = lstrlenA(lpszSearch);
+
+ while (lpszStr <= lpszEnd && *lpszStr)
+ {
+ ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
+ if (!COMCTL32_ChrCmpIA(ch1, ch2))
+ {
+ if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
+ lpszRet = (LPSTR)lpszStr;
+ }
+ lpszStr = CharNextA(lpszStr);
+ }
+ return lpszRet;
+}
+
+/*************************************************************************
+ * StrRStrIW [COMCTL32.373]
+ *
+ * See StrRStrIA.
+ */
+LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
+{
+ LPWSTR lpszRet = NULL;
+ INT iLen;
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
+
+ if (!lpszStr || !lpszSearch || !*lpszSearch)
+ return NULL;
+
+ if (!lpszEnd)
+ lpszEnd = lpszStr + strlenW(lpszStr);
+
+ iLen = strlenW(lpszSearch);
+
+ while (lpszStr <= lpszEnd && *lpszStr)
+ {
+ if (!COMCTL32_ChrCmpIA(*lpszSearch, *lpszStr))
+ {
+ if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
+ lpszRet = (LPWSTR)lpszStr;
+ }
+ lpszStr = CharNextW(lpszStr);
+ }
+ return lpszRet;
+}
+
+/*************************************************************************
+ * COMCTL32_StrSpnHelperW
+ *
+ * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
+ */
+static int COMCTL32_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
+ LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
+ BOOL bInvert)
+{
+ LPCWSTR lpszRead = lpszStr;
+ if (lpszStr && *lpszStr && lpszMatch)
+ {
+ while (*lpszRead)
+ {
+ LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
+
+ if (!bInvert && !lpszTest)
+ break;
+ if (bInvert && lpszTest)
+ break;
+ lpszRead = CharNextW(lpszRead);
+ };
+ }
+ return lpszRead - lpszStr;
+}
+
+/*************************************************************************
+ * StrCSpnIA [COMCTL32.374]
+ *
+ * Find the length of the start of a string that does not contain certain
+ * characters, ignoring case.
+ *
+ * PARAMS
+ * lpszStr [I] String to search
+ * lpszMatch [I] Characters that cannot be in the substring
+ *
+ * RETURNS
+ * The length of the part of lpszStr containing only chars not in lpszMatch,
+ * or 0 if any parameter is invalid.
+ */
+int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
+{
+ TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
+
+ return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
+}
+
+/*************************************************************************
+ * StrCSpnIW [COMCTL32.375]
+ *
+ * See StrCSpnIA.
+ */
+int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
+{
+ TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
+
+ return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
+}
+
+/**************************************************************************
+ * StrRChrIA [COMCTL32.368]
+ *
+ * Find the last occurence of a character in string, ignoring case.
+ *
+ * PARAMS
+ * lpszStr [I] String to search in
+ * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
+ * ch [I] Character to search for.
+ *
+ * RETURNS
+ * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
+ * or NULL if not found.
+ * Failure: NULL, if any arguments are invalid.
+ */
+LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
+{
+ LPCSTR lpszRet = NULL;
+
+ TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
+
+ if (lpszStr)
+ {
+ WORD ch2;
+
+ if (!lpszEnd)
+ lpszEnd = lpszStr + lstrlenA(lpszStr);
+
+ while (*lpszStr && lpszStr <= lpszEnd)
+ {
+ ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
+
+ if (ch == ch2)
+ lpszRet = lpszStr;
+ lpszStr = CharNextA(lpszStr);
+ }
+ }
+ return (LPSTR)lpszRet;
}
/**************************************************************************
- * StrSpnW [COMCTL32.364]
+ * StrRChrIW [COMCTL32.369]
*
+ * See StrRChrIA.
*/
-INT WINAPI StrSpnW( LPWSTR lpStr, LPWSTR lpSet)
+LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
{
- LPWSTR lpLoop = lpStr;
+ LPCWSTR lpszRet = NULL;
+
+ TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
+
+ if (lpszStr)
+ {
+ if (!lpszEnd)
+ lpszEnd = lpszStr + strlenW(lpszStr);
+
+ while (*lpszStr && lpszStr <= lpszEnd)
+ {
+ if (ch == *lpszStr)
+ lpszRet = lpszStr;
+ lpszStr = CharNextW(lpszStr);
+ }
+ }
+ return (LPWSTR)lpszRet;
+}
+
+/*************************************************************************
+ * StrSpnW [COMCTL32.364]
+ *
+ * See StrSpnA.
+ */
+int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
+{
+ TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
+
+ return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
+}
+
+/*************************************************************************
+ * StrCSpnW [COMCTL32.@]
+ *
+ * See StrCSpnA.
+ */
+int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
+{
+ TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
+
+ return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
+}
+
+/*************************************************************************
+ * IntlStrEqWorkerA [COMCTL32.376]
+ *
+ * Compare two strings.
+ *
+ * PARAMS
+ * bCase [I] Whether to compare case sensitively
+ * lpszStr [I] First string to compare
+ * lpszComp [I] Second string to compare
+ * iLen [I] Length to compare
+ *
+ * RETURNS
+ * TRUE If the strings are equal.
+ * FALSE Otherwise.
+ */
+BOOL WINAPI IntlStrEqWorkerA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
+ int iLen)
+{
+ DWORD dwFlags = LOCALE_USE_CP_ACP;
+ int iRet;
+
+ TRACE("(%d,%s,%s,%d)\n", bCase,
+ debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
+
+ /* FIXME: These flags are undocumented and unknown by our CompareString.
+ * We need defines for them.
+ */
+ dwFlags |= bCase ? 0x10000000 : 0x10000001;
+
+ iRet = CompareStringA(GetThreadLocale(),
+ dwFlags, lpszStr, iLen, lpszComp, iLen);
+
+ if (!iRet)
+ iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
+
+ return iRet == 2 ? TRUE : FALSE;
+}
+
+/*************************************************************************
+ * IntlStrEqWorkerW [COMCTL32.377]
+ *
+ * See IntlStrEqWorkerA.
+ */
+BOOL WINAPI IntlStrEqWorkerW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
+ int iLen)
+{
+ DWORD dwFlags;
+ int iRet;
+
+ TRACE("(%d,%s,%s,%d)\n", bCase,
+ debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
- /* validate ptr */
- if ((lpStr == 0) || (lpSet == 0)) return 0;
+ /* FIXME: These flags are undocumented and unknown by our CompareString.
+ * We need defines for them.
+ */
+ dwFlags = bCase ? 0x10000000 : 0x10000001;
-/* while(*lpLoop) { if lpLoop++; } */
+ iRet = CompareStringW(GetThreadLocale(),
+ dwFlags, lpszStr, iLen, lpszComp, iLen);
- for(; (*lpLoop != 0); lpLoop++)
- if( strchrW(lpSet, *(WORD*)lpLoop))
- return (INT)(lpLoop-lpStr);
+ if (!iRet)
+ iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
- return (INT)(lpLoop-lpStr);
+ return iRet == 2 ? TRUE : FALSE;
}