diff --git a/src/header/wchar/mod.rs b/src/header/wchar/mod.rs index 514666110e..8786b4ca24 100644 --- a/src/header/wchar/mod.rs +++ b/src/header/wchar/mod.rs @@ -4,8 +4,8 @@ use core::{char, ffi::VaList as va_list, mem, ptr, slice, usize}; use crate::{ header::{ - ctype::isspace, errno::{ERANGE, EILSEQ}, stdio::*, - stdlib::MB_CUR_MAX, string, time::*, wctype::*, + ctype::isspace, errno::{ERANGE, EILSEQ, ENOMEM}, stdio::*, + stdlib::{MB_CUR_MAX, MB_LEN_MAX, malloc}, string, time::*, wctype::*, }, platform::{self, errno, types::*}, }; @@ -319,6 +319,23 @@ pub unsafe extern "C" fn vswprintf( -1 } +#[no_mangle] +pub unsafe extern "C" fn wcpcpy( + d: *mut wchar_t, + s: *const wchar_t, +) -> *mut wchar_t { + return (wcscpy(d, s)).offset(wcslen(s) as isize); +} + +#[no_mangle] +pub unsafe extern "C" fn wcpncpy( + d: *mut wchar_t, + s: *const wchar_t, + n: size_t, +) -> *mut wchar_t { + return (wcsncpy(d, s, n)).offset(wcsnlen(s, n) as isize); +} + //widechar to multibyte #[no_mangle] pub unsafe extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> size_t { @@ -332,6 +349,20 @@ 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 wcsdup(s: *const wchar_t) -> *mut wchar_t { + let l = wcslen(s); + + let mut d = malloc((l + 1)*mem::size_of::()) as *mut wchar_t; + + if d.is_null() { + errno = ENOMEM; + return ptr::null_mut(); + } + + wmemcpy(d, s, l + 1) +} + #[no_mangle] pub unsafe extern "C" fn wcsrtombs( mut s: *mut c_char, @@ -550,6 +581,66 @@ pub unsafe extern "C" fn wcsncpy( ws1 } +#[no_mangle] +pub unsafe extern "C" fn wcsnlen(mut s: *const wchar_t, maxlen: size_t) -> size_t { + let mut len = 0; + + while len < maxlen { + if *s == 0 { + break; + } + + len = len + 1; + s = s.offset(1); + } + + return len; +} + +#[no_mangle] +pub unsafe extern "C" fn wcsnrtombs( + mut dest: *mut c_char, + src: *mut *const wchar_t, + nwc: size_t, + len: size_t, + ps: *mut mbstate_t, +) -> size_t { + let mut written = 0; + let mut read = 0; + let mut buf: [c_char; MB_LEN_MAX as usize] = [0; MB_LEN_MAX as usize]; + + while read < nwc { + buf.fill(0); + + let ret = wcrtomb(buf.as_mut_ptr(), **src, ps); + + if ret == size_t::MAX { + errno = EILSEQ; + return size_t::MAX; + } + + if !dest.is_null() && len < written + ret { + return written; + } + + if !dest.is_null() { + ptr::copy_nonoverlapping(buf.as_ptr(), dest, ret); + dest = dest.add(ret); + } + + if **src == '\0' as wchar_t { + *src = ptr::null(); + return written; + } + + *src = (*src).add(1); + read += 1; + written += ret; + } + written +} + + #[no_mangle] pub unsafe extern "C" fn wcspbrk(mut wcs: *const wchar_t, set: *const wchar_t) -> *mut wchar_t { wcs = wcs.add(wcscspn(wcs, set)); diff --git a/tests/Makefile b/tests/Makefile index 47a54ada8f..0fc45f0805 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -111,7 +111,10 @@ EXPECT_NAMES=\ wchar/ungetwc \ wchar/wprintf \ wchar/wcrtomb \ + wchar/wcpcpy \ + wchar/wcpncpy \ wchar/wcscspn \ + wchar/wcsdup \ wchar/wcsrchr \ wchar/wcsrtombs \ wchar/wcsstr \ @@ -122,6 +125,8 @@ EXPECT_NAMES=\ wchar/wcstoumax \ wchar/wcscasecmp \ wchar/wcsncasecmp \ + wchar/wcsnlen \ + wchar/wcsnrtombs \ wchar/wcswidth \ wctype/towlower \ wctype/towupper diff --git a/tests/expected/bins_static/wchar/wcpcpy.stderr b/tests/expected/bins_static/wchar/wcpcpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcpcpy.stdout b/tests/expected/bins_static/wchar/wcpcpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcpncpy.stderr b/tests/expected/bins_static/wchar/wcpncpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcpncpy.stdout b/tests/expected/bins_static/wchar/wcpncpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsdup.stderr b/tests/expected/bins_static/wchar/wcsdup.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsdup.stdout b/tests/expected/bins_static/wchar/wcsdup.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsnlen.stderr b/tests/expected/bins_static/wchar/wcsnlen.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsnlen.stdout b/tests/expected/bins_static/wchar/wcsnlen.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsnrtombs.stderr b/tests/expected/bins_static/wchar/wcsnrtombs.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/wchar/wcsnrtombs.stdout b/tests/expected/bins_static/wchar/wcsnrtombs.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/wchar/wcpcpy.c b/tests/wchar/wcpcpy.c new file mode 100644 index 0000000000..c65421220d --- /dev/null +++ b/tests/wchar/wcpcpy.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + wchar_t src[] = L"こんにちは世界!"; + wchar_t dest[9]; + + wchar_t* result = wcpcpy(dest, src); + + assert(wcscmp(dest, src) == 0); + assert(*result == L'\0'); + assert(result == dest + wcslen(src)); + + return 0; +} \ No newline at end of file diff --git a/tests/wchar/wcpncpy.c b/tests/wchar/wcpncpy.c new file mode 100644 index 0000000000..9621ad2458 --- /dev/null +++ b/tests/wchar/wcpncpy.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int main() { + wchar_t src[] = L"Привет мир"; + wchar_t dest[10]; + wchar_t* result = wcpncpy(dest, src, 5); + + assert(wcsncmp(dest, src, 5) == 0); + assert(*result == L'\0'); + assert(result == dest + 5); + + return 0; +} diff --git a/tests/wchar/wcsdup.c b/tests/wchar/wcsdup.c new file mode 100644 index 0000000000..27d4a2c580 --- /dev/null +++ b/tests/wchar/wcsdup.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +int main() { + wchar_t src[] = L"こんにちは世界Привет мир"; + + wchar_t* dup = wcsdup(src); + + assert(wcscmp(dup, src) == 0); + assert(dup != src); + free(dup); + + return 0; +} diff --git a/tests/wchar/wcsnlen.c b/tests/wchar/wcsnlen.c new file mode 100644 index 0000000000..ff1c705fbf --- /dev/null +++ b/tests/wchar/wcsnlen.c @@ -0,0 +1,9 @@ +#include +#include + +int main() { + // size is 17 + wchar_t* str1 = L"こんにちは世界Привет мир"; + assert(wcsnlen(str1, 10) == 10); + assert(wcsnlen(str1, 100) == 17); +} \ No newline at end of file diff --git a/tests/wchar/wcsnrtombs.c b/tests/wchar/wcsnrtombs.c new file mode 100644 index 0000000000..483301d629 --- /dev/null +++ b/tests/wchar/wcsnrtombs.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int main() { + setlocale(LC_ALL, ""); + + const wchar_t *src = L"こんにちは世界Привет мир"; + char dst[20]; + mbstate_t ps; + + size_t result = wcsnrtombs(dst, &src, 4, sizeof(dst), &ps); + assert(result == 12); + assert(strcmp(dst, "こんにち") == 0); + + return 0; +}