1use core::{char, slice, str};
5
6use crate::{
7 header::errno,
8 platform::{
9 self,
10 types::{c_char, wchar_t},
11 },
12};
13
14use super::mbstate_t;
15
16static UTF8_CHAR_WIDTH: [u8; 256] = [
22 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
23 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
25 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
27 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
29 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
35 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
39
40#[inline]
42fn utf8_char_width(b: u8) -> usize {
43 UTF8_CHAR_WIDTH[usize::from(b)].into()
44}
45
46pub unsafe fn mbrtowc(pwc: *mut wchar_t, s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize {
48 let size = utf8_char_width(unsafe { *s } as u8);
49 if size > n {
50 platform::ERRNO.set(errno::EILSEQ);
51 return -2isize as usize;
52 }
53 if size == 0 {
54 platform::ERRNO.set(errno::EILSEQ);
55 return -1isize as usize;
56 }
57
58 let slice = unsafe { slice::from_raw_parts(s.cast::<u8>(), size) };
59 let decoded = str::from_utf8(slice);
60 if decoded.is_err() {
61 platform::ERRNO.set(errno::EILSEQ);
62 return -1isize as usize;
63 }
64
65 let wc = decoded.unwrap();
66
67 let result: wchar_t = wc.chars().next().unwrap() as wchar_t;
68
69 if !pwc.is_null() {
70 unsafe { *pwc = result };
71 }
72
73 if result != 0 { size } else { 0 }
74}
75
76pub unsafe fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize {
78 let dc = char::from_u32(wc as u32);
79
80 if dc.is_none() {
81 platform::ERRNO.set(errno::EILSEQ);
82 return -1isize as usize;
83 }
84
85 let c = dc.unwrap();
86 let size = c.len_utf8();
87 let slice = unsafe { slice::from_raw_parts_mut(s.cast::<u8>(), size) };
88
89 c.encode_utf8(slice);
90
91 size
92}
93
94pub fn get_char_encoded_length(first_byte: u8) -> Option<usize> {
96 if first_byte >> 7 == 0 {
97 Some(1)
98 } else if first_byte >> 5 == 6 {
99 Some(2)
100 } else if first_byte >> 4 == 0xe {
101 Some(3)
102 } else if first_byte >> 3 == 0x1e {
103 Some(4)
104 } else {
105 None
106 }
107}