1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <wctype.h>
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <wchar.h>
36
37 #include "bionic/macros.h"
38 #include "private/icu.h"
39
40 enum {
41 WC_TYPE_INVALID = 0,
42 WC_TYPE_ALNUM,
43 WC_TYPE_ALPHA,
44 WC_TYPE_BLANK,
45 WC_TYPE_CNTRL,
46 WC_TYPE_DIGIT,
47 WC_TYPE_GRAPH,
48 WC_TYPE_LOWER,
49 WC_TYPE_PRINT,
50 WC_TYPE_PUNCT,
51 WC_TYPE_SPACE,
52 WC_TYPE_UPPER,
53 WC_TYPE_XDIGIT,
54 WC_TYPE_MAX
55 };
56
__find_u_hasBinaryProperty()57 static u_hasBinaryProperty_t __find_u_hasBinaryProperty() {
58 static auto u_hasBinaryProperty =
59 reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
60 return u_hasBinaryProperty;
61 }
62
63 #define DO_ISW(icu_constant, narrow_fn) \
64 u_hasBinaryProperty_t u_hasBinaryProperty; \
65 if (__predict_true(wc < 0x80) || \
66 !(u_hasBinaryProperty = __find_u_hasBinaryProperty())) { \
67 return narrow_fn(wc); \
68 } \
69 return u_hasBinaryProperty(wc, icu_constant); \
70
iswalnum(wint_t wc)71 int iswalnum(wint_t wc) { DO_ISW(UCHAR_POSIX_ALNUM, isalnum); }
72 __strong_alias(iswalnum_l, iswalnum);
iswalpha(wint_t wc)73 int iswalpha(wint_t wc) { DO_ISW(UCHAR_ALPHABETIC, isalpha); }
74 __strong_alias(iswalpha_l, iswalpha);
iswblank(wint_t wc)75 int iswblank(wint_t wc) { DO_ISW(UCHAR_POSIX_BLANK, isblank); }
76 __strong_alias(iswblank_l, iswblank);
iswgraph(wint_t wc)77 int iswgraph(wint_t wc) { DO_ISW(UCHAR_POSIX_GRAPH, isgraph); }
78 __strong_alias(iswgraph_l, iswgraph);
iswlower(wint_t wc)79 int iswlower(wint_t wc) { DO_ISW(UCHAR_LOWERCASE, islower); }
80 __strong_alias(iswlower_l, iswlower);
iswprint(wint_t wc)81 int iswprint(wint_t wc) { DO_ISW(UCHAR_POSIX_PRINT, isprint); }
82 __strong_alias(iswprint_l, iswprint);
iswspace(wint_t wc)83 int iswspace(wint_t wc) { DO_ISW(UCHAR_WHITE_SPACE, isspace); }
84 __strong_alias(iswspace_l, iswspace);
iswupper(wint_t wc)85 int iswupper(wint_t wc) { DO_ISW(UCHAR_UPPERCASE, isupper); }
86 __strong_alias(iswupper_l, iswupper);
iswxdigit(wint_t wc)87 int iswxdigit(wint_t wc) { DO_ISW(UCHAR_POSIX_XDIGIT, isxdigit); }
88 __strong_alias(iswxdigit_l, iswxdigit);
89
iswcntrl(wint_t wc)90 int iswcntrl(wint_t wc) {
91 if (wc < 0x80) return iscntrl(wc);
92 typedef int8_t (*FnT)(UChar32);
93 static auto u_charType = reinterpret_cast<FnT>(__find_icu_symbol("u_charType"));
94 return u_charType ? (u_charType(wc) == U_CONTROL_CHAR) : iscntrl(wc);
95 }
96 __strong_alias(iswcntrl_l, iswcntrl);
97
iswdigit(wint_t wc)98 int iswdigit(wint_t wc) {
99 if (wc < 0x80) return isdigit(wc);
100 typedef UBool (*FnT)(UChar32);
101 static auto u_isdigit = reinterpret_cast<FnT>(__find_icu_symbol("u_isdigit"));
102 return u_isdigit ? u_isdigit(wc) : isdigit(wc);
103 }
104 __strong_alias(iswdigit_l, iswdigit);
105
iswpunct(wint_t wc)106 int iswpunct(wint_t wc) {
107 if (wc < 0x80) return ispunct(wc);
108 typedef UBool (*FnT)(UChar32);
109 static auto u_ispunct = reinterpret_cast<FnT>(__find_icu_symbol("u_ispunct"));
110 return u_ispunct ? u_ispunct(wc) : ispunct(wc);
111 }
112 __strong_alias(iswpunct_l, iswpunct);
113
iswctype(wint_t wc,wctype_t char_class)114 int iswctype(wint_t wc, wctype_t char_class) {
115 if (char_class < WC_TYPE_ALNUM || char_class > WC_TYPE_XDIGIT) return 0;
116 static int (*fns[])(wint_t) = {
117 iswalnum, iswalpha, iswblank, iswcntrl, iswdigit, iswgraph,
118 iswlower, iswprint, iswpunct, iswspace, iswupper, iswxdigit
119 };
120 return fns[char_class - WC_TYPE_ALNUM](wc);
121 }
122 __strong_alias(iswctype_l, iswctype);
123
towlower(wint_t wc)124 wint_t towlower(wint_t wc) {
125 if (wc < 0x80) return tolower(wc);
126
127 typedef UChar32 (*FnT)(UChar32);
128 static auto u_tolower = reinterpret_cast<FnT>(__find_icu_symbol("u_tolower"));
129 return u_tolower ? u_tolower(wc) : tolower(wc);
130 }
131 __strong_alias(towlower_l, towlower);
132
towupper(wint_t wc)133 wint_t towupper(wint_t wc) {
134 if (wc < 0x80) return toupper(wc);
135
136 typedef UChar32 (*FnT)(UChar32);
137 static auto u_toupper = reinterpret_cast<FnT>(__find_icu_symbol("u_toupper"));
138 return u_toupper ? u_toupper(wc) : toupper(wc);
139 }
140 __strong_alias(towupper_l, towupper);
141
wctype(const char * property)142 wctype_t wctype(const char* property) {
143 static const char* const properties[WC_TYPE_MAX - 1] = {
144 "alnum", "alpha", "blank", "cntrl", "digit", "graph",
145 "lower", "print", "punct", "space", "upper", "xdigit"
146 };
147 for (size_t i = 0; i < arraysize(properties); ++i) {
148 if (!strcmp(properties[i], property)) {
149 return static_cast<wctype_t>(WC_TYPE_ALNUM + i);
150 }
151 }
152 return static_cast<wctype_t>(0);
153 }
154 __strong_alias(wctype_l, wctype);
155
156 static wctrans_t wctrans_tolower = wctrans_t(1);
157 static wctrans_t wctrans_toupper = wctrans_t(2);
158
wctrans(const char * name)159 wctrans_t wctrans(const char* name) {
160 if (strcmp(name, "tolower") == 0) return wctrans_tolower;
161 if (strcmp(name, "toupper") == 0) return wctrans_toupper;
162 errno = EINVAL;
163 return nullptr;
164 }
165 __strong_alias(wctrans_l, wctrans);
166
towctrans(wint_t c,wctrans_t t)167 wint_t towctrans(wint_t c, wctrans_t t) {
168 if (t == wctrans_tolower) return towlower(c);
169 if (t == wctrans_toupper) return towupper(c);
170 errno = EINVAL;
171 return c;
172 }
173 __strong_alias(towctrans_l, towctrans);
174