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();