kernel32: Fix lstrcmp(i)A/W to correct return values and document this behaviour
Rolf Kalbermatter
rolf.kalbermatter at citeng.com
Fri Oct 24 15:13:55 CDT 2003
Changelog
- dlls/kernel/locale.c
Change lstrcmpA/W and lstrcmpiA/W to always return a meaningful return value
- dlls/kernel/tests/locale.c
Add some tests for lstrcmpA/W and lstrcmpiA/W to the regression test framework
These tests run all fine on W2K, although I get 16 errors later in test_EnumLanguageGroupLocalesA.
There remain a few todo_wine in those new tests. They are all about treating
upper case characters always as being greater than any lower case character in
CompareStringA/W.
lstrcmpA("Salut", "SAlut") and lstrcmpA("Salut", "SOlut") should return -1 and not 1
(this is with english local)
I guess this all has to do with the fact that we actually do only implement the
SORT_STRINGSORT flag in CompareStringA/W eventhough that flag is usually not present
which means the function should do a WordSort.
Maybe we should add a FIXME in CompareStringA/W for this, but that would clutter any
output tremendously as that is the mode used for lstrcmpA/W.
Licence: X11/LGPL
Rolf Kalbermatter
Index: dlls/kernel/locale.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/locale.c,v
retrieving revision 1.24
diff -u -r1.24 locale.c
--- dlls/kernel/locale.c 24 Oct 2003 00:24:46 -0000 1.24
+++ dlls/kernel/locale.c 24 Oct 2003 19:51:29 -0000
@@ -2273,44 +2273,66 @@
* lstrcmp (KERNEL32.@)
* lstrcmpA (KERNEL32.@)
*
- * Compare two strings using the current thread locale.
+ * Compare two strings using the current thread locale and if that fails the
+ * system default locale.
*
* PARAMS
* str1 [I] First string to compare
* str2 [I] Second string to compare
*
* RETURNS
- * Success: A number less than, equal to or greater than 0 depending on whether
- * str2 is less than, equal to or greater than str1 respectively.
- * Failure: FALSE. Use GetLastError() to determine the cause.
+ * A number less than, equal to or greater than 0 depending on whether
+ * str1 is less than, equal to or greater than str2 respectively.
*/
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
{
- int ret = CompareStringA(GetThreadLocale(), 0, str1, -1, str2, -1);
- if (ret) ret -= 2;
- return ret;
+ int ret = CompareStringA(GetThreadLocale(), 0, str1, -1, str2, -1);
+ if (!ret)
+ {
+ ret = CompareStringA(GetSystemDefaultLCID(), 0, str1, -1, str2, -1);
+ if (!ret)
+ {
+ if (!str1)
+ return (str2 ? -1 : 0);
+ else if (!str2)
+ return 1;
+ return strcasecmp(str1, str2);
+ }
+ }
+ return ret - 2;
}
/*************************************************************************
* lstrcmpi (KERNEL32.@)
* lstrcmpiA (KERNEL32.@)
*
- * Compare two strings using the current thread locale, ignoring case.
+ * Compare two strings using the current thread locale and if that fails the
+ * system default locale, ignoring case.
*
* PARAMS
* str1 [I] First string to compare
* str2 [I] Second string to compare
*
* RETURNS
- * Success: A number less than, equal to or greater than 0 depending on whether
- * str2 is less than, equal to or greater than str1 respectively.
- * Failure: FALSE. Use GetLastError() to determine the cause.
+ * A number less than, equal to or greater than 0 depending on whether
+ * str1 is less than, equal to or greater than str2 respectively.
*/
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
{
int ret = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1);
- if (ret) ret -= 2;
- return ret;
+ if (!ret)
+ {
+ ret = CompareStringA(GetSystemDefaultLCID(), NORM_IGNORECASE, str1, -1, str2, -1);
+ if (!ret)
+ {
+ if (!str1)
+ return (str2 ? -1 : 0);
+ else if (!str2)
+ return 1;
+ return strcmp(str1, str2);
+ }
+ }
+ return ret - 2;
}
/*************************************************************************
@@ -2321,8 +2343,19 @@
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
{
int ret = CompareStringW(GetThreadLocale(), 0, str1, -1, str2, -1);
- if (ret) ret -= 2;
- return ret;
+ if (!ret)
+ {
+ ret = CompareStringW(GetSystemDefaultLCID(), 0, str1, -1, str2, -1);
+ if (!ret)
+ {
+ if (!str1)
+ return (str2 ? -1 : 0);
+ else if (!str2)
+ return 1;
+ return strcmpW(str1, str2);
+ }
+ }
+ return ret - 2;
}
/*************************************************************************
@@ -2333,8 +2366,19 @@
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
{
int ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1);
- if (ret) ret -= 2;
- return ret;
+ if (!ret)
+ {
+ ret = CompareStringW(GetSystemDefaultLCID(), NORM_IGNORECASE, str1, -1, str2, -1);
+ if (!ret)
+ {
+ if (!str1)
+ return (str2 ? -1 : 0);
+ else if (!str2)
+ return 1;
+ return strcmpiW(str1, str2);
+ }
+ }
+ return ret - 2;
}
/******************************************************************************
Index: dlls/kernel/tests/locale.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/tests/locale.c,v
retrieving revision 1.21
diff -u -r1.21 locale.c
--- dlls/kernel/tests/locale.c 24 Oct 2003 00:26:18 -0000 1.21
+++ dlls/kernel/tests/locale.c 24 Oct 2003 19:51:31 -0000
@@ -754,28 +754,109 @@
int ret;
LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
+ ret = CompareStringA(lcid, 0, NULL, -1, NULL, -1);
+ ok (ret == 0, "(NULL/NULL) Expected 0, got %d\n", ret);
+
+ ret = CompareStringA(lcid, 0, NULL, -1, "Z", -1);
+ ok (ret == 0, "(NULL/<string>) Expected 0, got %d\n", ret);
+
+ ret = CompareStringA(lcid, 0, "Z", -1, NULL, -1);
+ ok (ret == 0, "(<string>/NULL) Expected 0, got %d\n", ret);
+
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
- ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
+ ok (ret == 1, "(Salut/Salute) Expected 1, got %d\n", ret);
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
- ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
+ ok (ret == 2, "(Salut/SaLuT) case insensitive, Expected 2, got %d\n", ret);
+ todo_wine
+ {
+ ret = CompareStringA(lcid, 0, "Salut", -1, "SaLuT", -1);
+ ok (ret == 1, "(Salut/SaLuT) case sensitive, Expected 1, got %d\n", ret);
+ }
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
- ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
+ ok (ret == 3, "(Salut/hola) Expected 3, got %d\n", ret);
ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
- ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
+ ok (ret == 1, "(haha/hoho) Expected 1, got %d\n", ret);
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
- ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
+ ok (ret == 1, "(haha/hoho) Expected 1, got %d\n", ret);
ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
- ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
+ ok (ret == 3, "(haha/hoho) Expected 3, got %d\n", ret);
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "SaLuT", -1);
- ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
+ ok (ret == 2, "(Salut/SaLuT) case insensitive, Expected 2, got %d\n", ret);
+
+ todo_wine
+ {
+ ret = CompareStringA(lcid, 0, "Salut", -1, "SaLuT", -1);
+ ok (ret == 1, "(Salut/SaLuT) case sensitive, Expected 1, got %d\n", ret);
+ }
+}
+
+static void test_lstrcmpA()
+{
+ int ret;
+
+ ret = lstrcmpA(NULL, NULL);
+ ok(!ret, "(NULL/NULL) case sensitive, Expected 0, got %d\n", ret);
+
+ ret = lstrcmpA(NULL, "Z");
+ ok(ret < 0, "(NULL/string) case sensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpA("Z", NULL);
+ ok(ret > 0, "(string/NULL) case sensitive, Expected >0, got %d\n", ret);
+
+ ret = lstrcmpA("Salut", "Salute");
+ ok(ret < 0, "(Salut/Salute) case sensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpA("Salut", "Solut");
+ ok(ret < 0, "(Salut/Solut) case sensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpA("SAlut", "Solut");
+ ok(ret < 0, "(SAlut/Solut) case sensitive, Expected <0, got %d\n", ret);
+
+ todo_wine
+ {
+ ret = lstrcmpA("Salut", "SOlut");
+ ok(ret < 0, "(Salut/SOlut) case sensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpA("Salut", "SaLuT");
+ ok(ret < 0, "(Salut/SaLuT) case sensitive, Expected <0, got %d\n", ret);
+ }
+}
+
+static void test_lstrcmpiA()
+{
+ int ret;
+
+ ret = lstrcmpiA(NULL, NULL);
+ ok(!ret, "(NULL/NULL) case insensitive, Expected 0, got %d\n", ret);
+
+ ret = lstrcmpiA(NULL, "Z");
+ ok(ret < 0, "(NULL/string) case insensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpiA("Z", NULL);
+ ok(ret > 0, "(string/NULL) case insensitive, Expected >0, got %d\n", ret);
+
+ ret = lstrcmpiA("Salut", "Salute");
+ ok(ret < 0, "(Salut/Salute) case insensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpiA("Salut", "Solut");
+ ok(ret < 0, "(Salut/Solute) case insensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpiA("SAlut", "Solut");
+ ok(ret < 0, "(SAlut/Solut) case insensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpiA("Salut", "SOlut");
+ ok(ret < 0, "(Salut/SOlut) case insensitive, Expected <0, got %d\n", ret);
+
+ ret = lstrcmpiA("Salut", "SaLuT");
+ ok(!ret, "(Salut/SaLuT) case insensitive, Expected 0, got %d\n", ret);
}
void test_LCMapStringA(void)
@@ -1702,6 +1783,8 @@
test_GetCurrencyFormatA(); /* Also tests the W version */
test_GetNumberFormatA(); /* Also tests the W version */
test_CompareStringA();
+ test_lstrcmpA();
+ test_lstrcmpiA();
test_LCMapStringA();
test_LCMapStringW();
test_FoldStringA();
More information about the wine-patches
mailing list