Skip to content

Commit 9ee8eac

Browse files
minedgithub-cygwin
authored andcommitted
towupper/towlower: handle Turkic language special casing
For case conversion, Unicode has a standard mapping and a separate list of mapping rules for special cases (file SpecialCasing.txt), some of which are also language-dependent (as configured via locale). However, most of these rules are context-dependent, e.g. Greek capital Sigma is lowered to two different small sigmas, depending on the position at the end of a word. The POSIX API function towupper and tolower cannot consider context as they work only on one character at a time. String casing functions are unfortunately not available. The only special case conversions that apply to a single character are i and I in Turkish and Azerbaijani, where i keeps the dot when capitalised (U+0130) and I keeps not having a dot when converted small (U+0131). The patch handles these special cases, based on locale consideration. (cherry picked from commit 4356ccd)
1 parent 832cb70 commit 9ee8eac

3 files changed

Lines changed: 23 additions & 5 deletions

File tree

newlib/libc/ctype/towctrans.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ _towctrans_r (struct _reent *r,
8181
wctrans_t w)
8282
{
8383
if (w == WCT_TOLOWER || w == WCT_TOUPPER)
84-
return towctrans_l (c, w, 0);
84+
return towctrans_l (c, w, LC_GLOBAL_LOCALE);
8585
else
8686
{
8787
// skipping this because it was causing trouble (cygwin crash)

newlib/libc/ctype/towctrans_l.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,21 @@ bisearch (wint_t ucs, const struct caseconv_entry *table, int max)
6969
return 0;
7070
}
7171

72+
static int
73+
isturk (struct __locale_t *locale)
74+
{
75+
const char * loc = getlocalename_l (LC_CTYPE, locale);
76+
if (!loc)
77+
return 0;
78+
return 0 == strncmp (loc, "tr", 2) || 0 == strncmp (loc, "az", 2);
79+
}
80+
7281
static wint_t
73-
toulower (wint_t c)
82+
toulower (wint_t c, struct __locale_t *locale)
7483
{
84+
if (c == 'I' && isturk (locale))
85+
return 0x131; // LATIN SMALL LETTER DOTLESS I
86+
7587
const struct caseconv_entry * cce =
7688
bisearch(c, caseconv_table,
7789
sizeof(caseconv_table) / sizeof(*caseconv_table) - 1);
@@ -105,8 +117,11 @@ toulower (wint_t c)
105117
}
106118

107119
static wint_t
108-
touupper (wint_t c)
120+
touupper (wint_t c, struct __locale_t *locale)
109121
{
122+
if (c == 'i' && isturk (locale))
123+
return 0x130; // LATIN CAPITAL LETTER I WITH DOT ABOVE
124+
110125
const struct caseconv_entry * cce =
111126
bisearch(c, caseconv_table,
112127
sizeof(caseconv_table) / sizeof(*caseconv_table) - 1);
@@ -145,9 +160,9 @@ towctrans_l (wint_t c, wctrans_t w, struct __locale_t *locale)
145160
wint_t u = _jp2uc_l (c, locale);
146161
wint_t res;
147162
if (w == WCT_TOLOWER)
148-
res = toulower (u);
163+
res = toulower (u, locale);
149164
else if (w == WCT_TOUPPER)
150-
res = touupper (u);
165+
res = touupper (u, locale);
151166
else
152167
{
153168
// skipping the errno setting that was previously involved

winsup/cygwin/release/3.6.7

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ Fixes:
77
- Allow changing primary group even when running with cygserver account
88
caching.
99
Addresses: https://cygwin.com/pipermail/cygwin/2026-January/259250.html
10+
11+
- Correctly handle i->İ, I->ı conversion in turk lnd azerbaijani languages
12+
(LC_CTYPE=tr_TR, tr_CY, az_AZ).

0 commit comments

Comments
 (0)