From 7155005be22c403e216f10cbd3f1bf84ee76782e Mon Sep 17 00:00:00 2001 From: Darley Barreto Date: Mon, 8 May 2023 12:39:53 +0000 Subject: [PATCH] Adding `wcsrtombs`. --- src/header/stdlib/mod.rs | 2 +- src/header/wchar/mod.rs | 89 +++++++++++++++++++++++++++++++++++----- tests/Makefile | 1 + tests/wchar/wcsrtombs.c | 21 ++++++++++ 4 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 tests/wchar/wcsrtombs.c diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index ad54751c3f..4803852219 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -1266,7 +1266,7 @@ pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void { } #[no_mangle] -pub extern "C" fn wcstombs(s: *mut c_char, mut pwcs: *const wchar_t, n: size_t) -> size_t { +pub unsafe extern "C" fn wcstombs(s: *mut c_char, mut pwcs: *const wchar_t, n: size_t) -> size_t { let mut state: mbstate_t = mbstate_t {}; wcsrtombs(s, &mut pwcs, n, &mut state) } diff --git a/src/header/wchar/mod.rs b/src/header/wchar/mod.rs index fd8e32d7e4..c947a4e4c2 100644 --- a/src/header/wchar/mod.rs +++ b/src/header/wchar/mod.rs @@ -275,6 +275,85 @@ pub unsafe extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t utf8::wcrtomb(s_cpy, wc_cpy, ps) } +#[no_mangle] +pub unsafe extern "C" fn wcsrtombs( + mut s: *mut c_char, + ws: *mut *const wchar_t, + mut n: size_t, + st: *mut mbstate_t, +) -> size_t { + let mut ws2 = 0 as *const wchar_t; + let mut buf = [0i8; 4]; + let N = n; + let mut l = 0usize; + + if s.is_null() { + n = 0; + ws2 = *ws; + while *ws2 != 0 { + if *ws2 >= 0x80 { + l = wcrtomb(buf.as_mut_ptr(), *ws2, ptr::null_mut()); + if l.wrapping_add(1) == 0 { + return usize::MAX; + } + n = n.wrapping_add(l); + } else { + n = n.wrapping_add(1); + } + ws2 = ws2.offset(1); + } + return n; + } + + while n >= 4 { + if **ws.wrapping_sub(1) >= 0x7f { + if **ws == 0 { + *s = 0; + *ws = 0 as *const wchar_t; + return N.wrapping_sub(n); + } + l = wcrtomb(s, **ws, ptr::null_mut()); + if l.wrapping_add(1) == 0 { + return usize::MAX; + } + s = s.offset(l as isize); + n = n.wrapping_sub(l); + } else { + let new_s = s; + s = s.offset(1); + *new_s = **ws as c_char; + n = n.wrapping_sub(1); + } + *ws = (*ws).offset(1); + } + while n != 0 { + if **ws.wrapping_sub(1) >= 0x7f { + if **ws == 0 { + *s = 0; + *ws = 0 as *const wchar_t; + return N.wrapping_sub(n); + } + l = wcrtomb(buf.as_mut_ptr(), **ws, ptr::null_mut()); + if l.wrapping_add(1) == 0 { + return usize::MAX; + } + if l > n { + return N.wrapping_sub(n); + } + wcrtomb(s, **ws, ptr::null_mut()); + s = s.offset(l as isize); + n = n.wrapping_sub(l) as size_t; + } else { + let new_s = s; + s = s.offset(1); + *new_s = **ws as c_char; + n = n.wrapping_sub(1); + } + *ws = (*ws).offset(1); + } + return N; +} + #[no_mangle] pub unsafe extern "C" fn wcscat(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t { wcsncat(ws1, ws2, usize::MAX) @@ -436,16 +515,6 @@ pub unsafe extern "C" fn wcsrchr(ws1: *const wchar_t, wc: wchar_t) -> *mut wchar last_matching_wc as *mut wchar_t } -// #[no_mangle] -pub extern "C" fn wcsrtombs( - dst: *mut c_char, - src: *mut *const wchar_t, - len: size_t, - ps: *mut mbstate_t, -) -> size_t { - unimplemented!(); -} - #[no_mangle] pub unsafe extern "C" fn wcsspn(wcs: *const wchar_t, set: *const wchar_t) -> size_t { inner_wcsspn(wcs, set, false) diff --git a/tests/Makefile b/tests/Makefile index d28dc313b9..84d51f740c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -110,6 +110,7 @@ EXPECT_NAMES=\ wchar/wcrtomb \ wchar/wcscspn \ wchar/wcsrchr \ + wchar/wcsrtombs \ wchar/wcsstr \ wchar/wcstod \ wchar/wcstok \ diff --git a/tests/wchar/wcsrtombs.c b/tests/wchar/wcsrtombs.c new file mode 100644 index 0000000000..0a070ca696 --- /dev/null +++ b/tests/wchar/wcsrtombs.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main() { + const wchar_t *wcs1 = L""; + size_t mb_len1 = wcsrtombs(NULL, &wcs1, 0, NULL); + assert(mb_len1 == 0); + + const wchar_t *wcs2 = L"Hello, world!"; + size_t mb_len2 = wcsrtombs(NULL, &wcs2, 0, NULL); + assert(mb_len2 == strlen("Hello, world!")); + + char *mbs2 = malloc(mb_len2 + 1); + wcsrtombs(mbs2, &wcs2, mb_len2 + 1, NULL); + assert(strcmp(mbs2, "Hello, world!") == 0); + free(mbs2); + + return 0; +} \ No newline at end of file