[PATCH v3 3/4] msvcrt: Call LCMapString to handle casing.

Daniel Lehman dlehman25 at gmail.com
Wed Feb 13 20:39:50 CST 2019


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/msvcrt/tests/string.c | 215 +++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/wcs.c          |  10 +-
 2 files changed, 223 insertions(+), 2 deletions(-)

diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index d0cc51bc4a..c8642ec53f 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -3678,6 +3678,220 @@ static void test_C_locale(void)
     }
 }
 
+static void test_SpecialCasing(void)
+{
+    int i;
+    wint_t ret, exp;
+    _locale_t locale;
+    struct test {
+        const char *lang;
+        wint_t ch;
+        wint_t exp; /* 0 if self */
+    };
+
+    static const struct test ucases[] = {
+        {"English", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+        {"English", 0x0130},   /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+
+        {"Turkish", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+        {"Turkish", 0x0130},   /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+
+        {"Greek", 0x1F88, 0x1F80}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
+        {"Greek", 0x1F89, 0x1F81}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8A, 0x1F82}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8B, 0x1F83}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8C, 0x1F84}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8D, 0x1F85}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8E, 0x1F86}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+        {"Greek", 0x1F8F, 0x1F87}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+
+        {"Greek", 0x1F98, 0x1F90}, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI */
+        {"Greek", 0x1F99, 0x1F91}, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9A, 0x1F92}, /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9B, 0x1F93}, /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9C, 0x1F94}, /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9D, 0x1F95}, /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9E, 0x1F96}, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+        {"Greek", 0x1F9F, 0x1F97}, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+
+        {"Greek", 0x1FA8, 0x1FA0}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
+        {"Greek", 0x1FA9, 0x1FA1}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAA, 0x1FA2}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAB, 0x1FA3}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAC, 0x1FA4}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAD, 0x1FA5}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAE, 0x1FA6}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+        {"Greek", 0x1FAF, 0x1FA7}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+
+        {"Greek", 0x1FBC, 0x1FB3}, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
+        {"Greek", 0x1FCC, 0x1FC3}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
+        {"Greek", 0x1FFC, 0x1FF3}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
+    };
+    static const struct test lcases[] = {
+        {"English", 'i', 'I'}, /* LATIN SMALL LETTER I */
+        {"English", 0x0131},   /* LATIN SMALL LETTER DOTLESS I */
+
+        {"Turkish", 'i', 'I'}, /* LATIN SMALL LETTER I */
+        {"Turkish", 0x0131},   /* LATIN SMALL LETTER DOTLESS I */
+
+        {"German", 0x00DF},  /* LATIN SMALL LETTER SHARP S */
+
+        {"English", 0xFB00}, /* LATIN SMALL LIGATURE FF */
+        {"English", 0xFB01}, /* LATIN SMALL LIGATURE FI */
+        {"English", 0xFB02}, /* LATIN SMALL LIGATURE FL */
+        {"English", 0xFB03}, /* LATIN SMALL LIGATURE FFI */
+        {"English", 0xFB04}, /* LATIN SMALL LIGATURE FFL */
+        {"English", 0xFB05}, /* LATIN SMALL LIGATURE LONG ST */
+        {"English", 0xFB06}, /* LATIN SMALL LIGATURE ST */
+
+        {"Armenian", 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */
+        {"Armenian", 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */
+        {"Armenian", 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */
+        {"Armenian", 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */
+        {"Armenian", 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */
+        {"Armenian", 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */
+
+        {"Armenian", 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */
+        {"Armenian", 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */
+        {"Armenian", 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */
+        {"Armenian", 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */
+        {"Armenian", 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */
+        {"Armenian", 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */
+
+        {"English", 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
+        {"Greek",   0x0390}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+        {"Greek",   0x03B0}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+        {"English", 0x01F0}, /* LATIN SMALL LETTER J WITH CARON */
+        {"English", 0x1E96}, /* LATIN SMALL LETTER H WITH LINE BELOW */
+        {"English", 0x1E97}, /* LATIN SMALL LETTER T WITH DIAERESIS */
+        {"English", 0x1E98}, /* LATIN SMALL LETTER W WITH RING ABOVE */
+        {"English", 0x1E99}, /* LATIN SMALL LETTER Y WITH RING ABOVE */
+        {"English", 0x1E9A}, /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
+        {"Greek",   0x1F50}, /* GREEK SMALL LETTER UPSILON WITH PSILI */
+        {"Greek",   0x1F52}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
+        {"Greek",   0x1F54}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
+        {"Greek",   0x1F56}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
+        {"Greek",   0x1FB6}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
+        {"Greek",   0x1FC6}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
+        {"Greek",   0x1FD2}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
+        {"Greek",   0x1FD3}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */
+        {"Greek",   0x1FD6}, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
+        {"Greek",   0x1FD7}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
+        {"Greek",   0x1FE2}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
+        {"Greek",   0x1FE3}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */
+        {"Greek",   0x1FE4}, /* GREEK SMALL LETTER RHO WITH PSILI */
+        {"Greek",   0x1FE6}, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
+        {"Greek",   0x1FE7}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
+        {"Greek",   0x1FF6}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
+
+        {"Greek", 0x1F80, 0x1F88}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
+        {"Greek", 0x1F81, 0x1F89}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F82, 0x1F8A}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F83, 0x1F8B}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F84, 0x1F8C}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F85, 0x1F8D}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F86, 0x1F8E}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+        {"Greek", 0x1F87, 0x1F8F}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+
+        {"Greek", 0x1F90, 0x1F98}, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
+        {"Greek", 0x1F91, 0x1F99}, /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F92, 0x1F9A}, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F93, 0x1F9B}, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F94, 0x1F9C}, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F95, 0x1F9D}, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1F96, 0x1F9E}, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+        {"Greek", 0x1F97, 0x1F9F}, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+
+        {"Greek", 0x1FA0, 0x1FA8}, /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA1, 0x1FA9}, /* GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA2, 0x1FAA}, /* GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA3, 0x1FAB}, /* GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA4, 0x1FAC}, /* GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA5, 0x1FAD}, /* GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA6, 0x1FAE}, /* GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+        {"Greek", 0x1FA7, 0x1FAF}, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+
+        {"Greek", 0x1FB3, 0x1FBC}, /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
+        {"Greek", 0x1FC3, 0x1FCC}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
+        {"Greek", 0x1FF3, 0x1FFC}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
+
+        {"Greek", 0x1FB2}, /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FB4}, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FC2}, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FC4}, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FF2}, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
+        {"Greek", 0x1FF4}, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
+
+        {"Greek", 0x1FB7}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
+        {"Greek", 0x1FC7}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
+        {"Greek", 0x1FF7}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
+    };
+
+    for (i = 0; i < ARRAY_SIZE(ucases); i++) {
+        if (!setlocale(LC_ALL, ucases[i].lang)) {
+            win_skip("skipping special case tests for %s\n", ucases[i].lang);
+            continue;
+        }
+
+        ret = p_towlower(ucases[i].ch);
+        exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
+        ok(ret == exp || broken(ret != exp), /* WinXP/2k3/Vista/2k8 */
+            "expected lowercase %x, got %x for locale %s\n",
+            exp, ret, ucases[i].lang);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(lcases); i++) {
+        if (!setlocale(LC_ALL, lcases[i].lang)) {
+            win_skip("skipping special case tests for %s\n", lcases[i].lang);
+            continue;
+        }
+
+        ret = p_towupper(lcases[i].ch);
+        exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
+        ok(ret == exp || broken(ret != exp), /* WinXP/2k3/Vista/2k8 */
+            "expected uppercase %x, got %x for locale %s\n",
+            exp, ret, lcases[i].lang);
+    }
+
+    setlocale(LC_ALL, "C");
+
+    if (!p__towlower_l || !p__towupper_l || !p__create_locale)
+    {
+        win_skip("_towlower_l/_towupper_l/_create_locale not available\n");
+        return;
+    }
+
+    /* test _towlower_l creating locale */
+    for (i = 0; i < ARRAY_SIZE(ucases); i++) {
+        if (!(locale = p__create_locale(LC_ALL, ucases[i].lang))) {
+            win_skip("locale %s not available.  skipping\n", ucases[i].lang);
+            continue;
+        }
+
+        ret = p__towlower_l(ucases[i].ch, locale);
+        exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
+        ok(ret == exp, "expected lowercase %x, got %x for locale %s\n",
+            exp, ret, ucases[i].lang);
+
+        p__free_locale(locale);
+    }
+
+    /* test _towupper_l creating locale */
+    for (i = 0; i < ARRAY_SIZE(lcases); i++) {
+        if (!(locale = p__create_locale(LC_ALL, lcases[i].lang))) {
+            win_skip("locale %s not available.  skipping\n", lcases[i].lang);
+            continue;
+        }
+
+        ret = p__towupper_l(lcases[i].ch, locale);
+        exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
+        ok(ret == exp, "expected uppercase %x, got %x for locale %s\n",
+            exp, ret, lcases[i].lang);
+
+        p__free_locale(locale);
+    }
+}
+
 START_TEST(string)
 {
     char mem[100];
@@ -3812,4 +4026,5 @@ START_TEST(string)
     test__tcsnicoll();
     test___strncnt();
     test_C_locale();
+    test_SpecialCasing();
 }
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 28e82ec303..08a21c516a 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -2479,6 +2479,7 @@ MSVCRT_size_t CDECL MSVCRT_wcsnlen(const MSVCRT_wchar_t *s, MSVCRT_size_t maxlen
 int CDECL MSVCRT__towupper_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
 {
     MSVCRT_pthreadlocinfo locinfo;
+    WCHAR wc;
 
     if(!locale)
         locinfo = get_locinfo();
@@ -2491,7 +2492,9 @@ int CDECL MSVCRT__towupper_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
         return c;
     }
 
-    return toupperW(c);
+    if(LCMapStringW(locinfo->lc_handle[MSVCRT_LC_CTYPE], LCMAP_UPPERCASE, &c, 1, &wc, 1))
+        return wc;
+    return c;
 }
 
 /*********************************************************************
@@ -2508,6 +2511,7 @@ int CDECL MSVCRT_towupper(MSVCRT_wint_t c)
 int CDECL MSVCRT__towlower_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
 {
     MSVCRT_pthreadlocinfo locinfo;
+    WCHAR wc;
 
     if(!locale)
         locinfo = get_locinfo();
@@ -2520,7 +2524,9 @@ int CDECL MSVCRT__towlower_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
         return c;
     }
 
-    return tolowerW(c);
+    if(LCMapStringW(locinfo->lc_handle[MSVCRT_LC_CTYPE], LCMAP_LOWERCASE, &c, 1, &wc, 1))
+        return wc;
+    return c;
 }
 
 /*********************************************************************
-- 
2.17.1




More information about the wine-devel mailing list