Skip to main content

relibc/header/wctype/
mod.rs

1//! `wctype.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/wctype.h.html>.
4
5// TODO: *_l functions
6
7use self::casecmp::casemap;
8use crate::{
9    c_str::CStr,
10    header::ctype,
11    platform::types::{c_char, c_int, wint_t},
12};
13
14mod alpha;
15mod casecmp;
16mod punct;
17
18pub type wctype_t = u32;
19pub type wctrans_t = *const i32;
20
21pub const WEOF: wint_t = 0xFFFF_FFFFu32;
22
23pub const WCTYPE_ALNUM: wctype_t = 1;
24pub const WCTYPE_ALPHA: wctype_t = 2;
25pub const WCTYPE_BLANK: wctype_t = 3;
26pub const WCTYPE_CNTRL: wctype_t = 4;
27pub const WCTYPE_DIGIT: wctype_t = 5;
28pub const WCTYPE_GRAPH: wctype_t = 6;
29pub const WCTYPE_LOWER: wctype_t = 7;
30pub const WCTYPE_PRINT: wctype_t = 8;
31pub const WCTYPE_PUNCT: wctype_t = 9;
32pub const WCTYPE_SPACE: wctype_t = 10;
33pub const WCTYPE_UPPER: wctype_t = 11;
34pub const WCTYPE_XDIGIT: wctype_t = 12;
35
36const WCTRANSUP: wctrans_t = 1 as wctrans_t;
37const WCTRANSLW: wctrans_t = 2 as wctrans_t;
38
39/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswalnum.html>.
40#[unsafe(no_mangle)]
41pub extern "C" fn iswalnum(wc: wint_t) -> c_int {
42    c_int::from(iswdigit(wc) != 0 || iswalpha(wc) != 0)
43}
44
45/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswalpha.html>.
46#[unsafe(no_mangle)]
47pub extern "C" fn iswalpha(wc: wint_t) -> c_int {
48    c_int::from(alpha::is(wc as usize))
49}
50
51/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswblank.html>.
52#[unsafe(no_mangle)]
53pub extern "C" fn iswblank(wc: wint_t) -> c_int {
54    ctype::isblank(wc as c_int)
55}
56
57/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswcntrl.html>.
58#[unsafe(no_mangle)]
59pub extern "C" fn iswcntrl(wc: wint_t) -> c_int {
60    c_int::from(
61        wc < 32
62            || wc.wrapping_sub(0x7f) < 33
63            || wc.wrapping_sub(0x2028) < 2
64            || wc.wrapping_sub(0xfff9) < 3,
65    )
66}
67
68/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswctype.html>.
69#[unsafe(no_mangle)]
70pub extern "C" fn iswctype(wc: wint_t, desc: wctype_t) -> c_int {
71    match desc {
72        WCTYPE_ALNUM => iswalnum(wc),
73        WCTYPE_ALPHA => iswalpha(wc),
74        WCTYPE_BLANK => iswblank(wc),
75        WCTYPE_CNTRL => iswcntrl(wc),
76        WCTYPE_DIGIT => iswdigit(wc),
77        WCTYPE_GRAPH => iswgraph(wc),
78        WCTYPE_LOWER => iswlower(wc),
79        WCTYPE_PRINT => iswprint(wc),
80        WCTYPE_PUNCT => iswpunct(wc),
81        WCTYPE_SPACE => iswspace(wc),
82        WCTYPE_UPPER => iswupper(wc),
83        WCTYPE_XDIGIT => iswxdigit(wc),
84        _ => 0,
85    }
86}
87
88/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswdigit.html>.
89#[unsafe(no_mangle)]
90pub extern "C" fn iswdigit(wc: wint_t) -> c_int {
91    c_int::from(wc.wrapping_sub('0' as wint_t) < 10)
92}
93
94/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswgraph.html>.
95#[unsafe(no_mangle)]
96pub extern "C" fn iswgraph(wc: wint_t) -> c_int {
97    c_int::from(iswspace(wc) == 0 && iswprint(wc) != 0)
98}
99
100/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswlower.html>.
101#[unsafe(no_mangle)]
102pub extern "C" fn iswlower(wc: wint_t) -> c_int {
103    c_int::from(towupper(wc) != wc)
104}
105
106/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswprint.html>.
107#[unsafe(no_mangle)]
108pub extern "C" fn iswprint(wc: wint_t) -> c_int {
109    if wc < 0xff {
110        c_int::from(((wc + 1) & 0x7f) >= 0x21)
111    } else if wc < 0x2028
112        || wc.wrapping_sub(0x202a) < 0xd800 - 0x202a
113        || wc.wrapping_sub(0xe000) < 0xfff9 - 0xe000
114    {
115        1
116    } else if wc.wrapping_sub(0xfffc) > 0x10ffff - 0xfffc || (wc & 0xfffe) == 0xfffe {
117        0
118    } else {
119        1
120    }
121}
122
123/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswpunct.html>.
124#[unsafe(no_mangle)]
125pub extern "C" fn iswpunct(wc: wint_t) -> c_int {
126    c_int::from(punct::is(wc as usize))
127}
128
129/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswspace.html>.
130#[unsafe(no_mangle)]
131pub extern "C" fn iswspace(wc: wint_t) -> c_int {
132    c_int::from(
133        [
134            ' ' as wint_t,
135            '\t' as wint_t,
136            '\n' as wint_t,
137            '\r' as wint_t,
138            11,
139            12,
140            0x0085,
141            0x2000,
142            0x2001,
143            0x2002,
144            0x2003,
145            0x2004,
146            0x2005,
147            0x2006,
148            0x2008,
149            0x2009,
150            0x200a,
151            0x2028,
152            0x2029,
153            0x205f,
154            0x3000,
155        ]
156        .contains(&wc),
157    )
158}
159
160/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswupper.html>.
161#[unsafe(no_mangle)]
162pub extern "C" fn iswupper(wc: wint_t) -> c_int {
163    c_int::from(towlower(wc) != wc)
164}
165
166/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/iswxdigit.html>.
167#[unsafe(no_mangle)]
168pub extern "C" fn iswxdigit(wc: wint_t) -> c_int {
169    c_int::from(wc.wrapping_sub('0' as wint_t) < 10 || (wc | 32).wrapping_sub('a' as wint_t) < 6)
170}
171
172/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/towctrans.html>.
173#[unsafe(no_mangle)]
174pub extern "C" fn towctrans(wc: wint_t, trans: wctrans_t) -> wint_t {
175    match trans {
176        WCTRANSUP => towupper(wc),
177        WCTRANSLW => towlower(wc),
178        _ => wc,
179    }
180}
181
182/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/towlower.html>.
183#[unsafe(no_mangle)]
184pub extern "C" fn towlower(wc: wint_t) -> wint_t {
185    casemap(wc, 0)
186}
187
188/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/towupper.html>.
189#[unsafe(no_mangle)]
190pub extern "C" fn towupper(wc: wint_t) -> wint_t {
191    casemap(wc, 1)
192}
193
194/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/wctrans.html>.
195///
196/// # Safety
197/// The caller must ensure that `class` is convertible to a slice reference, up
198/// to and including a terminating nul.
199#[unsafe(no_mangle)]
200pub unsafe extern "C" fn wctrans(class: *const c_char) -> wctrans_t {
201    let class_cstr = unsafe { CStr::from_ptr(class) };
202    match class_cstr.to_bytes() {
203        b"toupper" => WCTRANSUP,
204        b"tolower" => WCTRANSLW,
205        _ => 0 as wctrans_t,
206    }
207}
208
209/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/wctype.html>.
210///
211/// # Safety
212/// The caller must ensure that `name` is convertible to a slice reference, up
213/// to and including a terminating nul.
214#[unsafe(no_mangle)]
215pub unsafe extern "C" fn wctype(name: *const c_char) -> wctype_t {
216    let name_cstr = unsafe { CStr::from_ptr(name) };
217    match name_cstr.to_bytes() {
218        b"alnum" => WCTYPE_ALNUM,
219        b"alpha" => WCTYPE_ALPHA,
220        b"blank" => WCTYPE_BLANK,
221        b"cntrl" => WCTYPE_CNTRL,
222        b"digit" => WCTYPE_DIGIT,
223        b"graph" => WCTYPE_GRAPH,
224        b"lower" => WCTYPE_LOWER,
225        b"print" => WCTYPE_PRINT,
226        b"punct" => WCTYPE_PUNCT,
227        b"space" => WCTYPE_SPACE,
228        b"upper" => WCTYPE_UPPER,
229        b"xdigit" => WCTYPE_XDIGIT,
230        _ => 0,
231    }
232}