xref: /aosp_15_r20/bionic/libc/bionic/wctype.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
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