- Implement string functions in comctl32.
authorRobert Shearman <R.J.Shearman@warwick.ac.uk>
Fri, 20 Feb 2004 05:16:37 +0000 (05:16 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Fri, 20 Feb 2004 05:16:37 +0000 (05:16 +0000)
- Use CompareString in shlwapi wherever possible instead of ugly
  helpers.

dlls/comctl32/comctl32.spec
dlls/comctl32/string.c
dlls/shlwapi/string.c

index 0a6cf409b8586fd5730a3b771e06c1c289d9aeb9..4f5340674597fdba74e21e503c32d33fe7fb0b90 100644 (file)
 363 stdcall -noname StrStrIW(wstr wstr)
 364 stdcall -noname StrSpnW(wstr wstr)
 365 stdcall -noname StrToIntW(wstr)
-366 stub -noname StrChrIA
-367 stub -noname StrChrIW
-368 stub -noname StrRChrIA
-369 stub -noname StrRChrIW
-372 stub -noname StrRStrIA
-373 stub -noname StrRStrIW
-374 stub -noname StrCSpnIA
-375 stub -noname StrCSpnIW
-376 stub -noname IntlStrEqWorkerA
-377 stub -noname IntlStrEqWorkerW
+366 stdcall -noname StrChrIA(str long)
+367 stdcall -noname StrChrIW(wstr long)
+368 stdcall -noname StrRChrIA(str str long)
+369 stdcall -noname StrRChrIW(wstr wstr long)
+372 stdcall -noname StrRStrIA(str str str)
+373 stdcall -noname StrRStrIW(wstr wstr wstr)
+374 stdcall -noname StrCSpnIA(str str)
+375 stdcall -noname StrCSpnIW(wstr wstr)
+376 stdcall -noname IntlStrEqWorkerA(long str str long)
+377 stdcall -noname IntlStrEqWorkerW(long wstr wstr long)
 382 stdcall -noname SmoothScrollWindow(ptr)
 383 stub -noname DoReaderMode
 384 stub -noname SetPathWordBreakProc
index f5409343b5840a12709a37449ca6c5104ada5979..8cdab69c309105e80de55c04f3ae1c5d0df2aeac 100644 (file)
@@ -4,6 +4,7 @@
  * 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]
  *
@@ -50,11 +145,69 @@ WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
  *           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]
@@ -62,37 +215,17 @@ LPSTR WINAPI StrChrA (LPCSTR lpszStr, CHAR ch)
  * 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);
 }
 
 /**************************************************************************
@@ -117,31 +250,11 @@ INT WINAPI StrToIntA (LPSTR lpszStr)
  *
  * 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);
 }
 
 /**************************************************************************
@@ -154,6 +267,32 @@ INT WINAPI StrToIntW (LPWSTR lpString)
     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]
  *
@@ -168,9 +307,11 @@ INT WINAPI StrToIntW (LPWSTR lpString)
  *  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);
 }
 
 /**************************************************************************
@@ -178,9 +319,15 @@ INT WINAPI StrCSpnA( LPCSTR lpStr, LPCSTR lpSet)
  *
  * 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;
 }
 
 /**************************************************************************
@@ -197,114 +344,534 @@ LPWSTR WINAPI StrChrW( LPCWSTR lpStart, WORD wMatch)
  *  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;
 }
index 186406dab14eaa7f5a9f76ab16e4a2141200caff..b74b2b7db2dc29d4e60f4457b69bf4d473b07fdf 100644 (file)
@@ -280,51 +280,12 @@ LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
  */
 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
 {
-  INT iRet;
+  int iRet;
 
   TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
 
-  iRet = strcmpiW(lpszStr, lpszComp);
-  return iRet < 0 ? -1 : iRet ? 1 : 0;
-}
-
-/*************************************************************************
- * SHLWAPI_StrCmpNHelperA
- *
- * Internal helper for StrCmpNA/StrCmpNIA.
- */
-static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
-                                         INT iLen,
-                                         BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
-{
-  if (!lpszStr)
-  {
-    if (!lpszComp)
-      return 0;
-    return 1;
-  }
-  else if (!lpszComp)
-    return -1;
-
-  while (iLen-- > 0)
-  {
-    int iDiff;
-    WORD ch1, ch2;
-
-    ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
-    ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
-
-    if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
-      return -1;
-    else if (iDiff > 0)
-      return 1;
-    else if (!*lpszStr && !*lpszComp)
-      return 0;
-
-    lpszStr = CharNextA(lpszStr);
-    lpszComp = CharNextA(lpszComp);
-  }
-  return 0;
+  iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************
@@ -343,9 +304,12 @@ static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
  */
 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
 {
+  INT iRet;
+
   TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
 
-  return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
+  iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************
@@ -359,8 +323,8 @@ INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
 
   TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
 
-  iRet = strncmpW(lpszStr, lpszComp, iLen);
-  return iRet < 0 ? -1 : iRet ? 1 : 0;
+  iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************
@@ -376,23 +340,15 @@ INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
  * RETURNS
  *  An integer less than, equal to or greater than 0, indicating that
  *  lpszStr is less than, the same, or greater than lpszComp.
- *
- * NOTES
- *  The Win32 version of this function is _completely_ broken for cases
- *  where iLen is greater than the length of lpszComp. Examples:
- *
- *|  StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
- *|  StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
- *|  StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
- *
- *  This implementation behaves correctly, since it is unlikely any
- *  applications actually rely on this function being broken.
  */
 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
 {
+  INT iRet;
+
   TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
 
-  return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
+  iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************
@@ -406,8 +362,8 @@ INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
 
   TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
 
-  iRet = strncmpiW(lpszStr, lpszComp, iLen);
-  return iRet < 0 ? -1 : iRet ? 1 : 0;
+  iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************
@@ -429,8 +385,8 @@ int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
 
   TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
 
-  iRet = strcmpW(lpszStr, lpszComp);
-  return iRet < 0 ? -1 : iRet ? 1 : 0;
+  iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
+  return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
 }
 
 /*************************************************************************