Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / ctype / towctrans_l.c
blobb829266a49cdf063ceb50dc48d262a45f46e25f8
1 /* Modified (m) 2017 Thomas Wolff: revise Unicode and locale/wchar handling */
2 #include <_ansi.h>
3 #include <wctype.h>
4 #include <stdint.h>
5 //#include <errno.h>
6 #include "local.h"
8 /*
9 struct caseconv_entry describes the case conversion behaviour
10 of a range of Unicode characters.
11 It was designed to be compact for a minimal table size.
12 The range is first...first + diff.
13 Conversion behaviour for a character c in the respective range:
14 mode == TOLO towlower (c) = c + delta
15 mode == TOUP towupper (c) = c + delta
16 mode == TOBOTH (titling case characters)
17 towlower (c) = c + 1
18 towupper (c) = c - 1
19 mode == TO1 capital/small letters are alternating
20 delta == EVENCAP even codes are capital
21 delta == ODDCAP odd codes are capital
22 (this correlates with an even/odd first range value
23 as of Unicode 10.0 but we do not rely on this)
24 As of Unicode 10.0, the following field lengths are sufficient
25 first: 17 bits
26 diff: 8 bits
27 delta: 17 bits
28 mode: 2 bits
29 The reserve of 4 bits (to limit the struct to 6 bytes)
30 is currently added to the 'first' field;
31 should a future Unicode version make it necessary to expand the others,
32 the 'first' field could be reduced as needed, or larger ranges could
33 be split up (reduce limit max=255 e.g. to max=127 or max=63 in
34 script mkcaseconv, check increasing table size).
36 enum {TO1, TOLO, TOUP, TOBOTH};
37 enum {EVENCAP, ODDCAP};
38 static struct caseconv_entry {
39 uint_least32_t first: 21;
40 uint_least32_t diff: 8;
41 uint_least32_t mode: 2;
42 int_least32_t delta: 17;
43 } __attribute__ ((packed))
44 caseconv_table [] = {
45 #include "caseconv.t"
47 #define first(ce) ce.first
48 #define last(ce) (ce.first + ce.diff)
50 /* auxiliary function for binary search in interval properties table */
51 static const struct caseconv_entry *
52 bisearch (wint_t ucs, const struct caseconv_entry *table, int max)
54 int min = 0;
55 int mid;
57 if (ucs < first(table[0]) || ucs > last(table[max]))
58 return 0;
59 while (max >= min)
61 mid = (min + max) / 2;
62 if (ucs > last(table[mid]))
63 min = mid + 1;
64 else if (ucs < first(table[mid]))
65 max = mid - 1;
66 else
67 return &table[mid];
69 return 0;
72 static wint_t
73 toulower (wint_t c)
75 const struct caseconv_entry * cce =
76 bisearch(c, caseconv_table,
77 sizeof(caseconv_table) / sizeof(*caseconv_table) - 1);
79 if (cce)
80 switch (cce->mode)
82 case TOLO:
83 return c + cce->delta;
84 case TOBOTH:
85 return c + 1;
86 case TO1:
87 switch (cce->delta)
89 case EVENCAP:
90 if (!(c & 1))
91 return c + 1;
92 break;
93 case ODDCAP:
94 if (c & 1)
95 return c + 1;
96 break;
97 default:
98 break;
100 default:
101 break;
104 return c;
107 static wint_t
108 touupper (wint_t c)
110 const struct caseconv_entry * cce =
111 bisearch(c, caseconv_table,
112 sizeof(caseconv_table) / sizeof(*caseconv_table) - 1);
114 if (cce)
115 switch (cce->mode)
117 case TOUP:
118 return c + cce->delta;
119 case TOBOTH:
120 return c - 1;
121 case TO1:
122 switch (cce->delta)
124 case EVENCAP:
125 if (c & 1)
126 return c - 1;
127 break;
128 case ODDCAP:
129 if (!(c & 1))
130 return c - 1;
131 break;
132 default:
133 break;
135 default:
136 break;
139 return c;
142 wint_t
143 towctrans_l (wint_t c, wctrans_t w, struct __locale_t *locale)
145 wint_t u = _jp2uc_l (c, locale);
146 wint_t res;
147 if (w == WCT_TOLOWER)
148 res = toulower (u);
149 else if (w == WCT_TOUPPER)
150 res = touupper (u);
151 else
153 // skipping the errno setting that was previously involved
154 // by delegating to towctrans; it was causing trouble (cygwin crash)
155 // and there is no errno specified for towctrans
156 return c;
158 if (res != u)
159 return _uc2jp_l (res, locale);
160 else
161 return c;