From cc210361d6c64136fd0a4a3dc44ae3fa1753274f Mon Sep 17 00:00:00 2001 From: Stephan Vedder Date: Sun, 1 Jul 2018 20:59:37 +0200 Subject: [PATCH] wchar support --- Cargo.lock | 18 +- Cargo.toml | 1 + include/bits/wchar.h | 7 +- include/stddef.h | 3 +- include/stdint.h | 427 ++++++++++++++++++++------ src/lib.rs | 1 + src/platform/src/types.rs | 4 +- src/stdio/Cargo.toml | 2 +- src/stdio/src/helpers.rs | 4 +- src/stdio/src/lib.rs | 26 +- src/stdlib/Cargo.toml | 2 + src/stdlib/src/lib.rs | 104 ++++--- src/string/Cargo.toml | 2 +- src/string/src/lib.rs | 5 +- src/todo/wchar/lib.rs | 377 ----------------------- src/wchar/Cargo.toml | 18 ++ src/wchar/build.rs | 11 + src/wchar/cbindgen.toml | 7 + src/wchar/src/lib.rs | 313 +++++++++++-------- src/wchar/src/utf8.rs | 59 ++++ tests/.gitignore | 4 + tests/Makefile | 6 +- tests/expected/wchar/mbrtowc.stderr | 0 tests/expected/wchar/mbrtowc.stdout | 2 + tests/expected/wchar/mbsrtowcs.stderr | 0 tests/expected/wchar/mbsrtowcs.stdout | 1 + tests/expected/wchar/putwchar.stderr | 0 tests/expected/wchar/putwchar.stdout | 0 tests/expected/wchar/wcrtomb.stderr | 0 tests/expected/wchar/wcrtomb.stdout | 2 + tests/wchar/mbrtowc.c | 30 ++ tests/wchar/mbsrtowcs.c | 23 ++ tests/wchar/putwchar.c | 21 ++ tests/wchar/wcrtomb.c | 29 ++ 34 files changed, 840 insertions(+), 669 deletions(-) delete mode 100644 src/todo/wchar/lib.rs create mode 100644 src/wchar/Cargo.toml create mode 100644 src/wchar/build.rs create mode 100644 src/wchar/cbindgen.toml create mode 100644 src/wchar/src/utf8.rs create mode 100644 tests/expected/wchar/mbrtowc.stderr create mode 100644 tests/expected/wchar/mbrtowc.stdout create mode 100644 tests/expected/wchar/mbsrtowcs.stderr create mode 100644 tests/expected/wchar/mbsrtowcs.stdout create mode 100644 tests/expected/wchar/putwchar.stderr create mode 100644 tests/expected/wchar/putwchar.stdout create mode 100644 tests/expected/wchar/wcrtomb.stderr create mode 100644 tests/expected/wchar/wcrtomb.stdout create mode 100644 tests/wchar/mbrtowc.c create mode 100644 tests/wchar/mbsrtowcs.c create mode 100644 tests/wchar/putwchar.c create mode 100644 tests/wchar/wcrtomb.c diff --git a/Cargo.lock b/Cargo.lock index fa1be69c66..bd50ab8712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,6 +304,7 @@ dependencies = [ "sys_wait 0.1.0", "time 0.1.0", "unistd 0.1.0", + "wchar 0.1.0", "wctype 0.1.0", ] @@ -403,7 +404,7 @@ dependencies = [ "errno 0.1.0", "fcntl 0.1.0", "platform 0.1.0", - "stdlib 0.1.0", + "ralloc 1.0.0", "string 0.1.0", "va_list 0.1.0", ] @@ -419,6 +420,7 @@ dependencies = [ "ralloc 1.0.0", "rand 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.0", + "wchar 0.1.0", ] [[package]] @@ -428,7 +430,7 @@ dependencies = [ "cbindgen 0.5.2", "errno 0.1.0", "platform 0.1.0", - "stdlib 0.1.0", + "ralloc 1.0.0", ] [[package]] @@ -606,6 +608,18 @@ name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wchar" +version = "0.1.0" +dependencies = [ + "cbindgen 0.5.2", + "errno 0.1.0", + "platform 0.1.0", + "stdio 0.1.0", + "time 0.1.0", + "va_list 0.1.0", +] + [[package]] name = "wctype" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index b64015bdad..9514720270 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ sys_utsname = { path = "src/sys_utsname" } sys_wait = { path = "src/sys_wait" } time = { path = "src/time" } unistd = { path = "src/unistd" } +wchar = { path = "src/wchar" } wctype = { path = "src/wctype" } [dependencies.compiler_builtins] diff --git a/include/bits/wchar.h b/include/bits/wchar.h index 98216dfb0f..eed486f1bc 100644 --- a/include/bits/wchar.h +++ b/include/bits/wchar.h @@ -1,7 +1,10 @@ #ifndef _BITS_WCHAR_H #define _BITS_WCHAR_H +#include -typedef signed short wchar_t; -typedef signed int wint_t; +#define WEOF (0xFFFFFFFFu) + +typedef int32_t wchar_t; +typedef uint32_t wint_t; #endif /* _BITS_WCHAR_H */ diff --git a/include/stddef.h b/include/stddef.h index fa0bc7daf5..1dc7f60fc1 100644 --- a/include/stddef.h +++ b/include/stddef.h @@ -1,11 +1,12 @@ #ifndef _STDDEF_H #define _STDDEF_H +#include #define NULL 0 typedef signed long long ptrdiff_t; -typedef unsigned char wchar_t; +typedef int32_t wchar_t; typedef unsigned long long size_t; diff --git a/include/stdint.h b/include/stdint.h index cbe5e37fe7..3a578783fa 100644 --- a/include/stdint.h +++ b/include/stdint.h @@ -1,130 +1,367 @@ +/* Copyright (C) 2008-2018 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* + * ISO C Standard: 7.18 Integer types + */ + #ifndef _STDINT_H #define _STDINT_H -#define INT8_C(value) ((int8_t) value) -#define INT8_MIN -0x80 -#define INT8_MAX 0x7F -typedef signed char int8_t; +/* 7.8.1.1 Exact-width integer types */ -#define INT_LEAST8_MIN -0x80 -#define INT_LEAST8_MAX 0x7F -typedef signed char int_least8_t; +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ int8_t; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ int16_t; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ int32_t; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ int64_t; +#endif +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ uint8_t; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ uint16_t; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ uint32_t; +#endif +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ uint64_t; +#endif -#define INT_FAST8_MIN -0x80 -#define INT_FAST8_MAX 0x7F -typedef signed char int_fast8_t; +/* 7.8.1.2 Minimum-width integer types */ -#define UINT8_C(value) ((uint8_t) value ## U) -#define UINT8_MIN 0x00 -#define UINT8_MAX 0xFF -typedef unsigned char uint8_t; +typedef __INT_LEAST8_TYPE__ int_least8_t; +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST64_TYPE__ int_least64_t; +typedef __UINT_LEAST8_TYPE__ uint_least8_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST64_TYPE__ uint_least64_t; -#define UINT_LEAST8_MIN 0x00 -#define UINT_LEAST8_MAX 0xFF -typedef unsigned char uint_least8_t; +/* 7.8.1.3 Fastest minimum-width integer types */ -#define UINT_FAST8_MIN 0x00 -#define UINT_FAST8_MAX 0xFF -typedef unsigned char uint_fast8_t; +typedef __INT_FAST8_TYPE__ int_fast8_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST64_TYPE__ int_fast64_t; +typedef __UINT_FAST8_TYPE__ uint_fast8_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST64_TYPE__ uint_fast64_t; -#define INT16_C(value) value -#define INT16_MIN -0x8000 -#define INT16_MAX 0x7FFF -typedef signed short int16_t; +/* 7.8.1.4 Integer types capable of holding object pointers */ -#define INT_LEAST16_MIN -0x8000 -#define INT_LEAST16_MAX 0x7FFF -typedef signed short int_least16_t; +#ifdef __INTPTR_TYPE__ +typedef __INTPTR_TYPE__ intptr_t; +#endif +#ifdef __UINTPTR_TYPE__ +typedef __UINTPTR_TYPE__ uintptr_t; +#endif -#define INT_FAST16_MIN -0x8000 -#define INT_FAST16_MAX 0x7FFF -typedef signed short int_fast16_t; +/* 7.8.1.5 Greatest-width integer types */ -#define UINT16_C(value) value ## U -#define UINT16_MIN 0x0000 -#define UINT16_MAX 0xFFFF -typedef unsigned short uint16_t; +typedef __INTMAX_TYPE__ intmax_t; +typedef __UINTMAX_TYPE__ uintmax_t; -#define UINT_LEAST16_MIN 0x0000 -#define UINT_LEAST16_MAX 0xFFFF -typedef unsigned short uint_least16_t; +#if (!defined __cplusplus || __cplusplus >= 201103L \ + || defined __STDC_LIMIT_MACROS) -#define UINT_FAST16_MIN 0x0000 -#define UINT_FAST16_MAX 0xFFFF -typedef unsigned short uint_fast16_t; +/* 7.18.2 Limits of specified-width integer types */ -#define INT32_C(value) value ## L -#define INT32_MIN -0x80000000 -#define INT32_MAX 0x7FFFFFFF -typedef signed long int32_t; +#ifdef __INT8_MAX__ +# undef INT8_MAX +# define INT8_MAX __INT8_MAX__ +# undef INT8_MIN +# define INT8_MIN (-INT8_MAX - 1) +#endif +#ifdef __UINT8_MAX__ +# undef UINT8_MAX +# define UINT8_MAX __UINT8_MAX__ +#endif +#ifdef __INT16_MAX__ +# undef INT16_MAX +# define INT16_MAX __INT16_MAX__ +# undef INT16_MIN +# define INT16_MIN (-INT16_MAX - 1) +#endif +#ifdef __UINT16_MAX__ +# undef UINT16_MAX +# define UINT16_MAX __UINT16_MAX__ +#endif +#ifdef __INT32_MAX__ +# undef INT32_MAX +# define INT32_MAX __INT32_MAX__ +# undef INT32_MIN +# define INT32_MIN (-INT32_MAX - 1) +#endif +#ifdef __UINT32_MAX__ +# undef UINT32_MAX +# define UINT32_MAX __UINT32_MAX__ +#endif +#ifdef __INT64_MAX__ +# undef INT64_MAX +# define INT64_MAX __INT64_MAX__ +# undef INT64_MIN +# define INT64_MIN (-INT64_MAX - 1) +#endif +#ifdef __UINT64_MAX__ +# undef UINT64_MAX +# define UINT64_MAX __UINT64_MAX__ +#endif -#define INT_LEAST32_MIN -0x80000000 -#define INT_LEAST32_MAX 0x7FFFFFFF -typedef signed long int_least32_t; +#undef INT_LEAST8_MAX +#define INT_LEAST8_MAX __INT_LEAST8_MAX__ +#undef INT_LEAST8_MIN +#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1) +#undef UINT_LEAST8_MAX +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ +#undef INT_LEAST16_MAX +#define INT_LEAST16_MAX __INT_LEAST16_MAX__ +#undef INT_LEAST16_MIN +#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1) +#undef UINT_LEAST16_MAX +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ +#undef INT_LEAST32_MAX +#define INT_LEAST32_MAX __INT_LEAST32_MAX__ +#undef INT_LEAST32_MIN +#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1) +#undef UINT_LEAST32_MAX +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ +#undef INT_LEAST64_MAX +#define INT_LEAST64_MAX __INT_LEAST64_MAX__ +#undef INT_LEAST64_MIN +#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1) +#undef UINT_LEAST64_MAX +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ -#define INT_FAST32_MIN -0x80000000 -#define INT_FAST32_MAX 0x7FFFFFFF -typedef signed long int_fast32_t; +#undef INT_FAST8_MAX +#define INT_FAST8_MAX __INT_FAST8_MAX__ +#undef INT_FAST8_MIN +#define INT_FAST8_MIN (-INT_FAST8_MAX - 1) +#undef UINT_FAST8_MAX +#define UINT_FAST8_MAX __UINT_FAST8_MAX__ +#undef INT_FAST16_MAX +#define INT_FAST16_MAX __INT_FAST16_MAX__ +#undef INT_FAST16_MIN +#define INT_FAST16_MIN (-INT_FAST16_MAX - 1) +#undef UINT_FAST16_MAX +#define UINT_FAST16_MAX __UINT_FAST16_MAX__ +#undef INT_FAST32_MAX +#define INT_FAST32_MAX __INT_FAST32_MAX__ +#undef INT_FAST32_MIN +#define INT_FAST32_MIN (-INT_FAST32_MAX - 1) +#undef UINT_FAST32_MAX +#define UINT_FAST32_MAX __UINT_FAST32_MAX__ +#undef INT_FAST64_MAX +#define INT_FAST64_MAX __INT_FAST64_MAX__ +#undef INT_FAST64_MIN +#define INT_FAST64_MIN (-INT_FAST64_MAX - 1) +#undef UINT_FAST64_MAX +#define UINT_FAST64_MAX __UINT_FAST64_MAX__ -#define UINT32_C(value) value ## UL -#define UINT32_MIN 0x00000000 -#define UINT32_MAX 0xFFFFFFFF -typedef unsigned long uint32_t; +#ifdef __INTPTR_MAX__ +# undef INTPTR_MAX +# define INTPTR_MAX __INTPTR_MAX__ +# undef INTPTR_MIN +# define INTPTR_MIN (-INTPTR_MAX - 1) +#endif +#ifdef __UINTPTR_MAX__ +# undef UINTPTR_MAX +# define UINTPTR_MAX __UINTPTR_MAX__ +#endif -#define UINT_LEAST32_MIN 0x00000000 -#define UINT_LEAST32_MAX 0xFFFFFFFF -typedef unsigned long uint_least32_t; +#undef INTMAX_MAX +#define INTMAX_MAX __INTMAX_MAX__ +#undef INTMAX_MIN +#define INTMAX_MIN (-INTMAX_MAX - 1) +#undef UINTMAX_MAX +#define UINTMAX_MAX __UINTMAX_MAX__ -#define UINT_FAST32_MIN 0x00000000 -#define UINT_FAST32_MAX 0xFFFFFFFF -typedef unsigned long uint_fast32_t; +/* 7.18.3 Limits of other integer types */ -#define INT64_C(value) value ## LL -#define INT64_MIN -0x8000000000000000 -#define INT64_MAX 0x7FFFFFFFFFFFFFFF -typedef signed long long int64_t; +#undef PTRDIFF_MAX +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#undef PTRDIFF_MIN +#define PTRDIFF_MIN (-PTRDIFF_MAX - 1) -#define INT_LEAST64_MIN -0x8000000000000000 -#define INT_LEAST64_MAX 0x7FFFFFFFFFFFFFFF -typedef signed long long int_least64_t; +#undef SIG_ATOMIC_MAX +#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#undef SIG_ATOMIC_MIN +#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ -#define INT_FAST64_MIN -0x8000000000000000 -#define INT_FAST64_MAX 0x7FFFFFFFFFFFFFFF -typedef signed long long int_fast64_t; +#undef SIZE_MAX +#define SIZE_MAX __SIZE_MAX__ -#define UINT64_C(value) value ## ULL -#define UINT64_MIN 0x0000000000000000 -#define UINT64_MAX 0xFFFFFFFFFFFFFFFF -typedef unsigned long long uint64_t; +#undef WCHAR_MAX +#define WCHAR_MAX __WCHAR_MAX__ +#undef WCHAR_MIN +#define WCHAR_MIN __WCHAR_MIN__ -#define UINT_LEAST64_MIN 0x0000000000000000 -#define UINT_LEAST64_MAX 0xFFFFFFFFFFFFFFFF -typedef unsigned long long uint_least64_t; +#undef WINT_MAX +#define WINT_MAX __WINT_MAX__ +#undef WINT_MIN +#define WINT_MIN __WINT_MIN__ -#define UINT_FAST64_MIN 0x0000000000000000 -#define UINT_FAST64_MAX 0xFFFFFFFFFFFFFFFF -typedef unsigned long long uint_fast64_t; +#endif /* (!defined __cplusplus || __cplusplus >= 201103L + || defined __STDC_LIMIT_MACROS) */ -#define INTMAX_C(value) value ## LL -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -typedef int64_t intmax_t; +#if (!defined __cplusplus || __cplusplus >= 201103L \ + || defined __STDC_CONSTANT_MACROS) -#define UINTMAX_C(value) value ## ULL -#define UINTMAX_MIN UINT64_MIN -#define UINTMAX_MAX UINT64_MAX -typedef uint64_t uintmax_t; +#undef INT8_C +#define INT8_C(c) __INT8_C(c) +#undef INT16_C +#define INT16_C(c) __INT16_C(c) +#undef INT32_C +#define INT32_C(c) __INT32_C(c) +#undef INT64_C +#define INT64_C(c) __INT64_C(c) +#undef UINT8_C +#define UINT8_C(c) __UINT8_C(c) +#undef UINT16_C +#define UINT16_C(c) __UINT16_C(c) +#undef UINT32_C +#define UINT32_C(c) __UINT32_C(c) +#undef UINT64_C +#define UINT64_C(c) __UINT64_C(c) +#undef INTMAX_C +#define INTMAX_C(c) __INTMAX_C(c) +#undef UINTMAX_C +#define UINTMAX_C(c) __UINTMAX_C(c) -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -typedef int64_t intptr_t; +#endif /* (!defined __cplusplus || __cplusplus >= 201103L + || defined __STDC_CONSTANT_MACROS) */ -#define UINTPTR_MIN UINT64_MIN -#define UINTPTR_MAX UINT64_MAX -typedef uint64_t uintptr_t; +#ifdef __STDC_WANT_IEC_60559_BFP_EXT__ +/* TS 18661-1 widths of integer types. */ + +#ifdef __INT8_TYPE__ +# undef INT8_WIDTH +# define INT8_WIDTH 8 +#endif +#ifdef __UINT8_TYPE__ +# undef UINT8_WIDTH +# define UINT8_WIDTH 8 +#endif +#ifdef __INT16_TYPE__ +# undef INT16_WIDTH +# define INT16_WIDTH 16 +#endif +#ifdef __UINT16_TYPE__ +# undef UINT16_WIDTH +# define UINT16_WIDTH 16 +#endif +#ifdef __INT32_TYPE__ +# undef INT32_WIDTH +# define INT32_WIDTH 32 +#endif +#ifdef __UINT32_TYPE__ +# undef UINT32_WIDTH +# define UINT32_WIDTH 32 +#endif +#ifdef __INT64_TYPE__ +# undef INT64_WIDTH +# define INT64_WIDTH 64 +#endif +#ifdef __UINT64_TYPE__ +# undef UINT64_WIDTH +# define UINT64_WIDTH 64 +#endif + +#undef INT_LEAST8_WIDTH +#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__ +#undef UINT_LEAST8_WIDTH +#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__ +#undef INT_LEAST16_WIDTH +#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__ +#undef UINT_LEAST16_WIDTH +#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__ +#undef INT_LEAST32_WIDTH +#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__ +#undef UINT_LEAST32_WIDTH +#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__ +#undef INT_LEAST64_WIDTH +#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__ +#undef UINT_LEAST64_WIDTH +#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__ + +#undef INT_FAST8_WIDTH +#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__ +#undef UINT_FAST8_WIDTH +#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__ +#undef INT_FAST16_WIDTH +#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__ +#undef UINT_FAST16_WIDTH +#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__ +#undef INT_FAST32_WIDTH +#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__ +#undef UINT_FAST32_WIDTH +#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__ +#undef INT_FAST64_WIDTH +#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__ +#undef UINT_FAST64_WIDTH +#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__ + +#ifdef __INTPTR_TYPE__ +# undef INTPTR_WIDTH +# define INTPTR_WIDTH __INTPTR_WIDTH__ +#endif +#ifdef __UINTPTR_TYPE__ +# undef UINTPTR_WIDTH +# define UINTPTR_WIDTH __INTPTR_WIDTH__ +#endif + +#undef INTMAX_WIDTH +#define INTMAX_WIDTH __INTMAX_WIDTH__ +#undef UINTMAX_WIDTH +#define UINTMAX_WIDTH __INTMAX_WIDTH__ + +#undef PTRDIFF_WIDTH +#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__ + +#undef SIG_ATOMIC_WIDTH +#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__ + +#undef SIZE_WIDTH +#define SIZE_WIDTH __SIZE_WIDTH__ + +#undef WCHAR_WIDTH +#define WCHAR_WIDTH __WCHAR_WIDTH__ + +#undef WINT_WIDTH +#define WINT_WIDTH __WINT_WIDTH__ #define SIZE_MAX UINT64_MAX +#endif typedef long sig_atomic_t; -#endif /* _STDINT_H */ +#endif /* _GCC_STDINT_H */ diff --git a/src/lib.rs b/src/lib.rs index 66b4d88090..555deba4ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub extern crate sys_utsname; pub extern crate sys_wait; pub extern crate time; pub extern crate unistd; +pub extern crate wchar; pub extern crate wctype; #[cfg(not(any(test, target_os = "redox")))] diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs index 29ed354d1b..61b1fea30d 100644 --- a/src/platform/src/types.rs +++ b/src/platform/src/types.rs @@ -44,8 +44,8 @@ pub type c_char = i8; pub type c_long = i64; pub type c_ulong = u64; -pub type wchar_t = i16; -pub type wint_t = i32; +pub type wchar_t = i32; +pub type wint_t = u32; pub type wctype_t = i64; pub type off_t = i64; diff --git a/src/stdio/Cargo.toml b/src/stdio/Cargo.toml index aa82586feb..50edfbaa3c 100644 --- a/src/stdio/Cargo.toml +++ b/src/stdio/Cargo.toml @@ -12,5 +12,5 @@ platform = { path = "../platform" } va_list = { path = "../../va_list", features = ["no_std"] } fcntl = { path = "../fcntl" } string = { path = "../string" } -stdlib = { path = "../stdlib" } +ralloc = { path = "../../ralloc", default-features = false } errno = { path = "../errno"} diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs index 378d2af3b6..ef63d69079 100644 --- a/src/stdio/src/helpers.rs +++ b/src/stdio/src/helpers.rs @@ -1,5 +1,5 @@ use super::{internal, BUFSIZ, FILE, UNGET}; -use stdlib::calloc; +use ralloc; use core::{mem, ptr}; use core::sync::atomic::AtomicBool; use platform::types::*; @@ -62,7 +62,7 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> *mut FILE { flags |= F_APP; } - let file = calloc(mem::size_of::() + BUFSIZ + UNGET, 1) as *mut FILE; + let file = ralloc::alloc(mem::size_of::() + BUFSIZ + UNGET, 1) as *mut FILE; // Allocate the file (*file) = FILE { flags: flags, diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index ff4bd1a860..3f850310bf 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -8,12 +8,11 @@ extern crate alloc; extern crate errno; extern crate fcntl; extern crate platform; -extern crate stdlib; +extern crate ralloc; extern crate string; extern crate va_list as vl; -use core::str; -use core::ptr; +use core::{str,ptr,mem}; use core::fmt::{self, Error, Result}; use core::fmt::Write as WriteFmt; use core::sync::atomic::{AtomicBool, Ordering}; @@ -23,8 +22,8 @@ use platform::{c_str, errno, Read, Write}; use errno::STR_ERROR; use vl::VaList as va_list; -mod scanf; mod printf; +mod scanf; mod default; pub use default::*; @@ -219,13 +218,16 @@ pub extern "C" fn cuserid(s: *mut c_char) -> *mut c_char { /// prior to using this function. #[no_mangle] pub extern "C" fn fclose(stream: &mut FILE) -> c_int { - use stdlib::free; + use ralloc::free; flockfile(stream); let r = helpers::fflush_unlocked(stream) | platform::close(stream.fd); if stream.flags & constants::F_PERM == 0 { // Not one of stdin, stdout or stderr unsafe { - free(stream as *mut _ as *mut _); + free( + stream as *mut _ as *mut _, + mem::size_of::() + BUFSIZ + UNGET, + ); } } r @@ -720,7 +722,7 @@ pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int { c } } else { - if stream.wend.is_null() && stream.can_write() { + if stream.wend.is_null() && !stream.can_write() { -1 } else if c as i8 != stream.buf_char && stream.wpos < stream.wend { unsafe { @@ -808,10 +810,10 @@ pub unsafe extern "C" fn setvbuf( size: usize, ) -> c_int { // TODO: Check correctness - use stdlib::calloc; + use ralloc::alloc; let mut buf = buf; if buf.is_null() && mode != _IONBF { - buf = calloc(size, 1) as *mut c_char; + buf = alloc(size, 1) as *mut c_char; } (*stream).buf_size = size; (*stream).buf_char = -1; @@ -907,5 +909,9 @@ pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int { #[no_mangle] pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int { - scanf::scanf(&mut platform::UnsafeStringReader(s as *const u8), format, ap) + scanf::scanf( + &mut platform::UnsafeStringReader(s as *const u8), + format, + ap, + ) } diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index 97ed4e9dfe..1122990e1d 100644 --- a/src/stdlib/Cargo.toml +++ b/src/stdlib/Cargo.toml @@ -14,3 +14,5 @@ ctype = { path = "../ctype" } errno = { path = "../errno" } rand = { version = "0.5.2", default-features = false } time = { path = "../time" } +wchar = { path = "../wchar" } +string = { path = "../string" } \ No newline at end of file diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index ff5404d56d..50eadb2eec 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -9,12 +9,16 @@ extern crate platform; extern crate ralloc; extern crate rand; extern crate time; +extern crate wchar; +extern crate string; use core::{ptr, str}; -use rand::{Rng, SeedableRng}; +use rand::{Rng, SeedableRng}; use rand::rngs::JitterRng; use rand::prng::XorShiftRng; use rand::distributions::Alphanumeric; +use wchar::*; +use string::*; use errno::*; use platform::types::*; @@ -28,6 +32,11 @@ pub const EXIT_FAILURE: c_int = 1; pub const EXIT_SUCCESS: c_int = 0; pub const RAND_MAX: c_int = 2147483647; +//Maximum number of bytes in a multibyte character for the current locale +pub const MB_CUR_MAX: c_int = 4; +//Maximum number of bytes in a multibyte characters for any locale +pub const MB_LEN_MAX: c_int = 4; + static mut ATEXIT_FUNCS: [Option; 32] = [None; 32]; static mut RNG: Option = None; @@ -101,7 +110,7 @@ pub unsafe extern "C" fn atof(s: *const c_char) -> c_double { } macro_rules! dec_num_from_ascii { - ($s: expr, $t: ty) => { + ($s:expr, $t:ty) => { unsafe { let mut s = $s; // Iterate past whitespace @@ -351,8 +360,19 @@ pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_voi } #[no_mangle] -pub extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int { + let mut wc : wchar_t = 0; + let mut state : mbstate_t = mbstate_t { }; + let result : usize = mbrtowc(&mut wc, s, n, &mut state); + + if result == -1isize as usize { + return -1; + } + if result == -2isize as usize { + return -1; + } + + result as i32 } #[no_mangle] @@ -370,16 +390,13 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char { use core::slice; use core::iter; use core::mem; - extern "C" { - fn strlen(s: *const c_char) -> size_t; - } let len = unsafe { strlen(name) }; if len < 6 { unsafe { platform::errno = errno::EINVAL }; unsafe { *name = 0 }; return name; } - for i in len-6..len { + for i in len - 6..len { if unsafe { *name.offset(i as isize) } != b'X' as c_char { unsafe { platform::errno = errno::EINVAL }; unsafe { *name = 0 }; @@ -392,11 +409,9 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char { let mut retries = 100; loop { - let mut char_iter = iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .take(6); + let mut char_iter = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(6); unsafe { - for (i,c) in char_iter.enumerate() { + for (i, c) in char_iter.enumerate() { *name.offset(len as isize - i as isize - 1) = c as c_char } } @@ -404,13 +419,17 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char { unsafe { let mut st: stat = mem::uninitialized(); if platform::stat(name, &mut st) != 0 { - if platform::errno != ENOENT { *name = 0; } + if platform::errno != ENOENT { + *name = 0; + } return name; } mem::forget(st); } - retries = retries -1; - if retries == 0 { break; } + retries = retries - 1; + if retries == 0 { + break; + } } unsafe { platform::errno = EEXIST }; unsafe { *name = 0 }; @@ -421,11 +440,10 @@ fn get_nstime() -> u64 { use core::mem; use time::constants::CLOCK_MONOTONIC; let mut ts: timespec = unsafe { mem::uninitialized() }; - platform::clock_gettime(CLOCK_MONOTONIC, &mut ts); + platform::clock_gettime(CLOCK_MONOTONIC, &mut ts); unsafe { ts.tv_nsec as u64 } } - #[no_mangle] pub extern "C" fn mkstemp(name: *mut c_char) -> c_int { unimplemented!(); @@ -639,7 +657,8 @@ pub fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, if val == -1 || val as c_int >= base { break; } else { - if let Some(res) = num.checked_mul(base as c_ulong) + if let Some(res) = num + .checked_mul(base as c_ulong) .and_then(|num| num.checked_add(val as c_ulong)) { num = res; @@ -665,13 +684,7 @@ pub fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, #[macro_export] macro_rules! strto_impl { ( - $rettype:ty, - $signed:expr, - $maxval:expr, - $minval:expr, - $s:ident, - $endptr:ident, - $base:ident + $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident ) => {{ // ensure these are constants const CHECK_SIGN: bool = $signed; @@ -721,9 +734,8 @@ macro_rules! strto_impl { // convert the string to a number let num_str = $s.offset(idx); let res = match $base { - 0 => detect_base(num_str).and_then(|($base, i)| { - convert_integer(num_str.offset(i), $base) - }), + 0 => detect_base(num_str) + .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)), 8 => convert_octal(num_str), 16 => convert_hex(num_str), _ => convert_integer(num_str, $base), @@ -770,15 +782,15 @@ macro_rules! strto_impl { set_endptr(idx); num - }} + }}; } - #[no_mangle] -pub unsafe extern "C" fn strtoul(s: *const c_char, - endptr: *mut *mut c_char, - base: c_int) - -> c_ulong { +pub unsafe extern "C" fn strtoul( + s: *const c_char, + endptr: *mut *mut c_char, + base: c_int, +) -> c_ulong { strto_impl!( c_ulong, false, @@ -791,10 +803,7 @@ pub unsafe extern "C" fn strtoul(s: *const c_char, } #[no_mangle] -pub unsafe extern "C" fn strtol(s: *const c_char, - endptr: *mut *mut c_char, - base: c_int) - -> c_long { +pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long { strto_impl!( c_long, true, @@ -835,11 +844,22 @@ pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void { } #[no_mangle] -pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *const wchar_t, n: size_t) -> size_t { - unimplemented!(); +pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *mut *const wchar_t, n: size_t) -> size_t { + let mut state: mbstate_t = mbstate_t {}; + wcsrtombs(s, pwcs, n, &mut state) } #[no_mangle] -pub extern "C" fn wctomb(s: *mut c_char, wchar: wchar_t) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: wchar_t) -> c_int { + let mut state : mbstate_t = mbstate_t {}; + let result: usize = wcrtomb(s, wc, &mut state); + + if result == -1isize as usize { + return -1; + } + if result == -2isize as usize { + return -1; + } + + result as c_int } diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml index 9bf1d9dc99..f134d7ff7a 100644 --- a/src/string/Cargo.toml +++ b/src/string/Cargo.toml @@ -9,5 +9,5 @@ cbindgen = { path = "../../cbindgen" } [dependencies] platform = { path = "../platform" } -stdlib = { path = "../stdlib" } +ralloc = { path = "../../ralloc", default-features = false } errno = { path = "../errno" } diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 681bbe2b8f..601b3385d8 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -1,10 +1,9 @@ //! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html - #![no_std] extern crate errno; extern crate platform; -extern crate stdlib; +extern crate ralloc; use platform::types::*; use errno::*; @@ -193,7 +192,7 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char let len = strnlen(s1, size); // the "+ 1" is to account for the NUL byte - let buffer = stdlib::malloc(len + 1) as *mut c_char; + let buffer = ralloc::alloc(len + 1, 1) as *mut c_char; if buffer.is_null() { platform::errno = ENOMEM as c_int; } else { diff --git a/src/todo/wchar/lib.rs b/src/todo/wchar/lib.rs deleted file mode 100644 index b760fba7aa..0000000000 --- a/src/todo/wchar/lib.rs +++ /dev/null @@ -1,377 +0,0 @@ -pub type wchar_t = libc::c_int; -pub type wint_t = libc::c_uint; - -#[no_mangle] -pub extern "C" fn btowc(c: libc::c_int) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fwprintf(stream: *mut FILE, format: *const wchar_t, ...) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fwscanf(stream: *mut FILE, format: *const wchar_t, ...) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswalnum(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswalpha(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswcntrl(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswdigit(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswgraph(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswlower(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswprint(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswpunct(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswspace(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswupper(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn iswxdigit(wc: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fgetwc(stream: *mut FILE) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fgetws(ws: *mut wchar_t, n: libc::c_int, - stream: *mut FILE) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fputwc(wc: wchar_t, stream: *mut FILE) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fputws(ws: *const wchar_t, stream: *mut FILE) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn fwide(stream: *mut FILE, mode: libc::c_int) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn getwc(stream: *mut FILE) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn getwchar() -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn mbsinit(ps: *const mbstate_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn mbrlen(s: *const libc::c_char, n: usize, - ps: *mut mbstate_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn mbrtowc(pwc: *mut wchar_t, s: *const libc::c_char, - n: usize, ps: *mut mbstate_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn mbsrtowcs(dst: *mut wchar_t, - src: *mut *const libc::c_char, len: usize, - ps: *mut mbstate_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn putwc(wc: wchar_t, stream: *mut FILE) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn putwchar(wc: wchar_t) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn swprintf(s: *mut wchar_t, n: usize, - format: *const wchar_t, ...) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn swscanf(s: *const wchar_t, format: *const wchar_t, ...) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn towlower(wc: wint_t) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn towupper(wc: wint_t) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn ungetwc(wc: wint_t, stream: *mut FILE) -> wint_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn vfwprintf(stream: *mut FILE, format: *const wchar_t, - arg: va_list) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn vwprintf(format: *const wchar_t, arg: va_list) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn vswprintf(s: *mut wchar_t, n: usize, format: *const wchar_t, - arg: va_list) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcrtomb(s: *mut libc::c_char, wc: wchar_t, - ps: *mut mbstate_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcscat(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcschr(ws1: *const wchar_t, ws2: wchar_t) - -> *mut libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcscmp(ws1: *const wchar_t, ws2: *const wchar_t) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcscoll(ws1: *const wchar_t, ws2: *const wchar_t) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcscpy(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcscspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsftime(wcs: *mut wchar_t, maxsize: usize, format: *const wchar_t, - timptr: *mut tm) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcslen(ws: *const wchar_t) -> libc::c_ulong { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsncat(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsncmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsncpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcspbrk(ws1: *const wchar_t, ws2: *const wchar_t) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsrchr(ws1: *const wchar_t, ws2: wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsrtombs(dst: *mut libc::c_char, - src: *mut *const wchar_t, len: usize, - ps: *mut mbstate_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsstr(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcstod(nptr: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcstok(ws1: *mut wchar_t, ws2: *const wchar_t, - ptr: *mut *mut wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcstol(nptr: *const wchar_t, endptr: *mut *mut wchar_t, - base: libc::c_int) -> libc::c_long { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcstoul(nptr: *const wchar_t, endptr: *mut *mut wchar_t, - base: libc::c_int) -> libc::c_ulong { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcswcs(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcswidth(pwcs: *const wchar_t, n: usize) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcsxfrm(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) - -> usize { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wctob(c: wint_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wcwidth(wc: wchar_t) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wmemchr(ws: *const wchar_t, wc: wchar_t, n: usize) - -> *mut libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wmemcmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize) - -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wmemcpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: usize) - -> *mut wchar_t { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wprintf(format: *const wchar_t, ...) -> libc::c_int { - unimplemented!(); -} - -#[no_mangle] -pub extern "C" fn wscanf(format: *const wchar_t, ...) -> libc::c_int { - unimplemented!(); -} diff --git a/src/wchar/Cargo.toml b/src/wchar/Cargo.toml new file mode 100644 index 0000000000..97e412f20d --- /dev/null +++ b/src/wchar/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wchar" +version = "0.1.0" +authors = ["Stephan Vedder "] +build = "build.rs" + +[build-dependencies] +cbindgen = { path = "../../cbindgen" } + +[features] +str_internals = [] + +[dependencies] +platform = { path = "../platform" } +stdio = { path = "../stdio" } +errno = { path = "../errno" } +time = { path = "../time" } +va_list = { path = "../../va_list", features = ["no_std"] } \ No newline at end of file diff --git a/src/wchar/build.rs b/src/wchar/build.rs new file mode 100644 index 0000000000..5b64a17833 --- /dev/null +++ b/src/wchar/build.rs @@ -0,0 +1,11 @@ +extern crate cbindgen; + +use std::{env, fs}; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); + fs::create_dir_all("../../target/include").expect("failed to create include directory"); + cbindgen::generate(crate_dir) + .expect("failed to generate bindings") + .write_to_file("../../target/include/wchar.h"); +} diff --git a/src/wchar/cbindgen.toml b/src/wchar/cbindgen.toml new file mode 100644 index 0000000000..0e0aa10c84 --- /dev/null +++ b/src/wchar/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = ["stddef.h", "stdint.h", "time.h", "stdio.h" ] +include_guard = "_WCHAR_H" +header = "#include " +language = "C" + +[enum] +prefix_with_name = true diff --git a/src/wchar/src/lib.rs b/src/wchar/src/lib.rs index 96bb95d1fe..d08f4d2353 100644 --- a/src/wchar/src/lib.rs +++ b/src/wchar/src/lib.rs @@ -1,55 +1,84 @@ -//! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html +//! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html #![no_std] +#![feature(str_internals)] extern crate errno; extern crate platform; -extern crate stdlib; -extern crate string; +extern crate stdio; extern crate time; +extern crate va_list as vl; use platform::types::*; -use errno::*; use time::*; -use core::cmp; use core::usize; use core::ptr; -use core::mem; -use string::*; +use stdio::*; +use vl::VaList as va_list; -pub type wint_t = i32; +mod utf8; + +const WEOF: wint_t = 0xFFFFFFFFu32; + +//Maximum number of bytes in a multibyte character for the current locale +const MB_CUR_MAX: c_int = 4; +//Maximum number of bytes in a multibyte characters for any locale +const MB_LEN_MAX: c_int = 4; #[repr(C)] -pub struct mbstate_t { - pub mbs_count: c_int, - pub mbs_length: c_int, - pub mbs_wch: wint_t, -} +#[derive(Clone, Copy)] +pub struct mbstate_t {} #[no_mangle] pub unsafe extern "C" fn btowc(c: c_int) -> wint_t { //Check for EOF - if c == -1 { - return -1; + if c as wint_t == WEOF { + return WEOF; } let uc = c as u8; let c = uc as c_char; - let mut ps: mbstate_t = mbstate_t { - mbs_count: 0, - mbs_length: 0, - mbs_wch: 0, - }; + let mut ps: mbstate_t = mbstate_t {}; let mut wc: wchar_t = 0; let saved_errno = platform::errno; let status = mbrtowc(&mut wc, &c as (*const c_char), 1, &mut ps); if status == usize::max_value() || status == usize::max_value() - 1 { platform::errno = saved_errno; - return platform::errno; + return WEOF; } return wc as wint_t; } +#[no_mangle] +pub unsafe extern "C" fn fputwc(wc: wchar_t, stream: *mut FILE) -> wint_t { + //Convert wchar_t to multibytes first + static mut INTERNAL: mbstate_t = mbstate_t {}; + let mut bytes: [c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize]; + + let amount = wcrtomb(bytes.as_mut_ptr(), wc, &mut INTERNAL); + + for i in 0..amount { + fputc(bytes[i] as c_int, &mut *stream); + } + + wc as wint_t +} + +#[no_mangle] +pub extern "C" fn fputws(ws: *const wchar_t, stream: *mut FILE) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn fwide(stream: *mut FILE, mode: c_int) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn getwc(stream: *mut FILE) -> wint_t { + unimplemented!(); +} + #[no_mangle] pub extern "C" fn getwchar() -> wint_t { unimplemented!(); @@ -57,24 +86,21 @@ pub extern "C" fn getwchar() -> wint_t { #[no_mangle] pub unsafe extern "C" fn mbsinit(ps: *const mbstate_t) -> c_int { - if ps.is_null() || (*ps).mbs_count == 0 { - return 1; + //Add a check for the state maybe + if ps.is_null() { + 1 } else { - return 0; + 0 } } #[no_mangle] pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize { - static mut internal: mbstate_t = mbstate_t { - mbs_count: 0, - mbs_length: 0, - mbs_wch: 0, - }; - return mbrtowc(ptr::null_mut(), s, n, &mut internal); + static mut INTERNAL: mbstate_t = mbstate_t {}; + mbrtowc(ptr::null_mut(), s, n, &mut INTERNAL) } -//Only works for utf8! +//Only works for UTF8 at the moment #[no_mangle] pub unsafe extern "C" fn mbrtowc( pwc: *mut wchar_t, @@ -82,123 +108,85 @@ pub unsafe extern "C" fn mbrtowc( n: usize, ps: *mut mbstate_t, ) -> usize { - static mut internal: mbstate_t = mbstate_t { - mbs_count: 0, - mbs_length: 0, - mbs_wch: 0, - }; + static mut INTERNAL: mbstate_t = mbstate_t {}; if ps.is_null() { - let ps = &mut internal; + let ps = &mut INTERNAL; } if s.is_null() { let xs: [c_char; 1] = [0]; - utf8_mbrtowc(pwc, &xs[0] as *const c_char, 1, ps); + return utf8::mbrtowc(pwc, &xs[0] as *const c_char, 1, ps); + } else { + return utf8::mbrtowc(pwc, s, n, ps); } - - return utf8_mbrtowc(pwc, s, n, ps); } +//Convert a multibyte string to a wide string with a limited amount of bytes +//Required for in POSIX.1-2008 #[no_mangle] -unsafe extern "C" fn utf8_mbrtowc( - pwc: *mut wchar_t, - s: *const c_char, - n: usize, +pub unsafe extern "C" fn mbsnrtowcs( + dst_ptr: *mut wchar_t, + src_ptr: *mut *const c_char, + src_len: usize, + dst_len: usize, ps: *mut mbstate_t, ) -> usize { - let mut i: usize = 0; + static mut INTERNAL: mbstate_t = mbstate_t {}; - while !(i > 0 && (*ps).mbs_count == 0) { - if (n <= i) { - return -2isize as usize; - } - let c = s.offset(i as isize); - let uc = c as u8; + if ps.is_null() { + let ps = &mut INTERNAL; + } - if (*ps).mbs_count == 0 { - //1 byte sequence - 00–7F - if (uc & 0b10000000) == 0b00000000 { - (*ps).mbs_count = 0; - (*ps).mbs_length = 1; - (*ps).mbs_wch = (uc as wchar_t & 0b1111111) as wint_t; - } - //2 byte sequence - C2–DF - else if (uc & 0b11100000) == 0b11000000 { - (*ps).mbs_count = 1; - (*ps).mbs_length = 2; - (*ps).mbs_wch = (uc as wchar_t & 0b11111) as wint_t; - } - //3 byte sequence - E0–EF - else if (uc & 0b11110000) == 0b11100000 { - (*ps).mbs_count = 2; - (*ps).mbs_length = 3; - (*ps).mbs_wch = (uc as wchar_t & 0b1111) as wint_t; - } - //4 byte sequence - F0–F4 - else if (uc & 0b11111000) == 0b11110000 { - (*ps).mbs_count = 3; - (*ps).mbs_length = 4; - (*ps).mbs_wch = (uc as wchar_t & 0b111) as wint_t; - } else { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - } else { - if (uc & 0b11000000) != 0b10000000 { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } + let mut src = *src_ptr; - (*ps).mbs_wch = (*ps).mbs_wch << 6 | (uc & 0b00111111) as wint_t; - (*ps).mbs_count -= 1; + let mut dst_offset: usize = 0; + let mut src_offset: usize = 0; + + while (dst_ptr.is_null() || dst_offset < dst_len) && src_offset < src_len { + let ps_copy = *ps; + let mut wc: wchar_t = 0; + let amount = mbrtowc( + &mut wc, + src.offset(src_offset as isize), + src_len - src_offset, + ps, + ); + + // Stop in the event a decoding error occured. + if amount == -1isize as usize { + *src_ptr = src.offset(src_offset as isize); + return 1isize as usize; } - i += 1; + // Stop decoding early in the event we encountered a partial character. + if amount == -2isize as usize { + *ps = ps_copy; + break; + } + + // Store the decoded wide character in the destination buffer. + if !dst_ptr.is_null() { + *dst_ptr.offset(dst_offset as isize) = wc; + } + + // Stop decoding after decoding a null character and return a NULL + // source pointer to the caller, not including the null character in the + // number of characters stored in the destination buffer. + if wc == 0 { + src = ptr::null(); + src_offset = 0; + break; + } + + dst_offset += 1; + src_offset += amount; } - // Reject the character if it was produced with an overly long sequence. - if (*ps).mbs_length == 1 && 1 << 7 <= (*ps).mbs_wch { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - if (*ps).mbs_length == 2 && 1 << (5 + 1 * 6) <= (*ps).mbs_wch { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - if (*ps).mbs_length == 3 && 1 << (5 + 2 * 6) <= (*ps).mbs_wch { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - if (*ps).mbs_length == 4 && 1 << (5 + 3 * 6) <= (*ps).mbs_wch { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - - // The definition of UTF-8 prohibits encoding character numbers between - // U+D800 and U+DFFF, which are reserved for use with the UTF-16 encoding - // form (as surrogate pairs) and do not directly represent characters. - if 0xD800 <= (*ps).mbs_wch && (*ps).mbs_wch <= 0xDFFF { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - // RFC 3629 limits UTF-8 to 0x0 through 0x10FFFF. - if 0x10FFFF <= (*ps).mbs_wch { - platform::errno = errno::EILSEQ; - return -1isize as usize; - } - - let result: wchar_t = (*ps).mbs_wch as wchar_t; - - if !pwc.is_null() { - *pwc = result; - } - - (*ps).mbs_length = 0; - (*ps).mbs_wch = 0; - - return if result != 0 { i } else { 0 }; + *src_ptr = src.offset(src_offset as isize); + return dst_offset; } +//Convert a multibyte string to a wide string #[no_mangle] pub extern "C" fn mbsrtowcs( dst: *mut wchar_t, @@ -206,11 +194,31 @@ pub extern "C" fn mbsrtowcs( len: usize, ps: *mut mbstate_t, ) -> usize { + unsafe { mbsnrtowcs(dst, src, usize::max_value(), len, ps) } +} + +#[no_mangle] +pub unsafe extern "C" fn putwc(wc: wchar_t, stream: *mut FILE) -> wint_t { + fputwc(wc, &mut *stream) +} + +#[no_mangle] +pub unsafe extern "C" fn putwchar(wc: wchar_t) -> wint_t { + fputwc(wc, &mut *__stdout()) +} + +#[no_mangle] +pub extern "C" fn swprintf( + s: *mut wchar_t, + n: usize, + format: *const wchar_t, + mut ap: va_list, +) -> c_int { unimplemented!(); } #[no_mangle] -pub extern "C" fn putwchar(wc: wchar_t) -> wint_t { +pub extern "C" fn swscanf(s: *const wchar_t, format: *const wchar_t, mut ap: va_list) -> c_int { unimplemented!(); } @@ -225,10 +233,45 @@ pub extern "C" fn towupper(wc: wint_t) -> wint_t { } #[no_mangle] -pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize { +pub extern "C" fn ungetwc(wc: wint_t, stream: *mut FILE) -> wint_t { unimplemented!(); } +#[no_mangle] +pub extern "C" fn vfwprintf(stream: *mut FILE, format: *const wchar_t, arg: va_list) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn vwprintf(format: *const wchar_t, arg: va_list) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn vswprintf( + s: *mut wchar_t, + n: usize, + format: *const wchar_t, + arg: va_list, +) -> c_int { + unimplemented!(); +} + +//widechar to multibyte +#[no_mangle] +pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize { + let mut buffer: [c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize]; + let mut wc_cpy = wc; + let mut s_cpy = s; + + if s.is_null() { + wc_cpy = 0; + s_cpy = buffer.as_mut_ptr(); + } + + unsafe { utf8::wcrtomb(s_cpy, wc_cpy, ps) } +} + #[no_mangle] pub extern "C" fn wcscat(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t { unimplemented!(); @@ -392,3 +435,13 @@ pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: usize) -> *mut wchar_t { unimplemented!(); } + +#[no_mangle] +pub extern "C" fn wprintf(format: *const wchar_t, mut ap: va_list) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn wscanf(format: *const wchar_t, mut ap: va_list) -> c_int { + unimplemented!(); +} diff --git a/src/wchar/src/utf8.rs b/src/wchar/src/utf8.rs new file mode 100644 index 0000000000..5cd639f818 --- /dev/null +++ b/src/wchar/src/utf8.rs @@ -0,0 +1,59 @@ +//UTF implementation parts for wchar.h. +//Partially ported from the Sortix libc + +#![no_std] + +extern crate errno; +extern crate platform; + +use platform::types::*; +use mbstate_t; +use core::{slice,str,usize,char}; + +//It's guaranteed that we don't have any nullpointers here +pub unsafe fn mbrtowc(pwc: *mut wchar_t, s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize { + let mut size = str::utf8_char_width(*s as u8); + if size > n { + platform::errno = errno::EILSEQ; + return -2isize as usize; + } + if size == 0 { + platform::errno = errno::EILSEQ; + return -1isize as usize; + } + + let slice = slice::from_raw_parts(s as *const u8, size); + let decoded = str::from_utf8(slice); + if decoded.is_err() { + platform::errno = errno::EILSEQ; + return -1isize as usize; + } + + let wc = decoded.unwrap(); + + let result: wchar_t = wc.chars().next().unwrap() as wchar_t; + + if !pwc.is_null() { + *pwc = result; + } + + return if result != 0 { size } else { 0 }; +} + +//It's guaranteed that we don't have any nullpointers here +pub unsafe fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize { + let dc = char::from_u32(wc as u32); + + if dc.is_none() { + platform::errno = errno::EILSEQ; + return -1isize as usize; + } + + let c = dc.unwrap(); + let size = c.len_utf8(); + let mut slice = slice::from_raw_parts_mut(s as *mut u8, size); + + c.encode_utf8(slice); + + size +} diff --git a/tests/.gitignore b/tests/.gitignore index c60d7feecf..e2242ca6a6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -54,6 +54,10 @@ /unistd/getopt /unlink /waitpid +/wchar/mbrtowc +/wchar/mbsrtowcs +/wchar/putwchar +/wchar/wcrtomb /write /time /gmtime diff --git a/tests/Makefile b/tests/Makefile index dbe6063de2..3588a66a5b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -44,6 +44,10 @@ EXPECT_BINS=\ string/strtok_r \ unistd/getopt \ waitpid \ + wchar/mbrtowc \ + wchar/mbsrtowcs \ + wchar/putwchar \ + wchar/wcrtomb \ write \ time \ gmtime \ @@ -112,4 +116,4 @@ TAILLIBS=\ ../target/openlibm/libopenlibm.a %: %.c $(HEADLIBS) $(TAILLIBS) - gcc -fno-stack-protector -Wall $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@" + gcc -fno-stack-protector -Wall -g $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@" diff --git a/tests/expected/wchar/mbrtowc.stderr b/tests/expected/wchar/mbrtowc.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/mbrtowc.stdout b/tests/expected/wchar/mbrtowc.stdout new file mode 100644 index 0000000000..a82952475a --- /dev/null +++ b/tests/expected/wchar/mbrtowc.stdout @@ -0,0 +1,2 @@ +Processing 11 UTF-8 code units: [ 7a c3 9f e6 b0 b4 f0 9f 8d 8c 0 ] +into 5 wchar_t units: [ 7a df 6c34 1f34c 0 ] \ No newline at end of file diff --git a/tests/expected/wchar/mbsrtowcs.stderr b/tests/expected/wchar/mbsrtowcs.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/mbsrtowcs.stdout b/tests/expected/wchar/mbsrtowcs.stdout new file mode 100644 index 0000000000..e8f8258f2e --- /dev/null +++ b/tests/expected/wchar/mbsrtowcs.stdout @@ -0,0 +1 @@ +The length, including '\0': 5 diff --git a/tests/expected/wchar/putwchar.stderr b/tests/expected/wchar/putwchar.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/putwchar.stdout b/tests/expected/wchar/putwchar.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/wcrtomb.stderr b/tests/expected/wchar/wcrtomb.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/wcrtomb.stdout b/tests/expected/wchar/wcrtomb.stdout new file mode 100644 index 0000000000..d41045ed2b --- /dev/null +++ b/tests/expected/wchar/wcrtomb.stdout @@ -0,0 +1,2 @@ +Processing 5 wchar_t units: [ 7a df 6c34 1f34c 0 ] +into 11 UTF-8 code units: [ 7a c3 9f e6 b0 b4 f0 9f 8d 8c 0 ] diff --git a/tests/wchar/mbrtowc.c b/tests/wchar/mbrtowc.c new file mode 100644 index 0000000000..4487d22731 --- /dev/null +++ b/tests/wchar/mbrtowc.c @@ -0,0 +1,30 @@ +#include +#include +#include + +int main(void) +{ + mbstate_t state; + memset(&state, 0, sizeof state); + char in[] = u8"z\u00df\u6c34\U0001F34C"; // or u8"zß水🍌" + size_t in_sz = sizeof in / sizeof *in; + + printf("Processing %zu UTF-8 code units: [ ", in_sz); //Should be 11 regular chars + for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned char)in[n]); + puts("]"); + + wchar_t out[in_sz]; + char *p_in = in, *end = in + in_sz; + wchar_t *p_out = out; + int rc; + while((rc = mbrtowc(p_out, p_in, end - p_in, &state)) > 0) + { + p_in += rc; + p_out += 1; + } + + size_t out_sz = p_out - out + 1; + printf("into %zu wchar_t units: [ ", out_sz); //Should be 5 wchars + for(size_t x = 0; x < out_sz; ++x) printf("%#x ", out[x]); + puts("]"); +} \ No newline at end of file diff --git a/tests/wchar/mbsrtowcs.c b/tests/wchar/mbsrtowcs.c new file mode 100644 index 0000000000..1ee1560a9f --- /dev/null +++ b/tests/wchar/mbsrtowcs.c @@ -0,0 +1,23 @@ +#include +#include + +void print_as_wide(const char* mbstr) +{ + mbstate_t state; + memset(&state, 0, sizeof state); + size_t len = 1 + mbsrtowcs(NULL, &mbstr, 0, &state); + wchar_t wstr[len]; + mbsrtowcs(&wstr[0], &mbstr, len, &state); + + //Should be 5 + printf("The length, including '\\0': %i \n",len); + + //missing wprintf to print this wide string + //wprintf(L"The wide string: %ls \n", &wstr[0]); +} + +int main() +{ + const char* mbstr = u8"z\u00df\u6c34\U0001f34c"; // or u8"zß水🍌" + print_as_wide(mbstr); +} \ No newline at end of file diff --git a/tests/wchar/putwchar.c b/tests/wchar/putwchar.c new file mode 100644 index 0000000000..f9f7ea4123 --- /dev/null +++ b/tests/wchar/putwchar.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main(void) +{ + wchar_t *wcs = L"zß水🍌"; + + int i; + for (i = 0; wcs[i] != L'\0'; i++) + { + if (0xFFFFFFFFu == putwchar(wcs[i])) + { + printf("Unable to putwchar() the wide character.\n"); + exit(EXIT_FAILURE); + } + } + + return 0; +} \ No newline at end of file diff --git a/tests/wchar/wcrtomb.c b/tests/wchar/wcrtomb.c new file mode 100644 index 0000000000..27b05cef6b --- /dev/null +++ b/tests/wchar/wcrtomb.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +int main( void ) +{ + mbstate_t state; + memset(&state, 0, sizeof state); + wchar_t in[] = L"zß水🍌"; // or "z\u00df\u6c34\U0001F34C" + size_t in_sz = sizeof in / sizeof *in; + + printf("Processing %zu wchar_t units: [ ", in_sz); + for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned int)in[n]); + puts("]"); + + char out[MB_CUR_MAX * in_sz]; + char *p = out; + for(size_t n = 0; n < in_sz; ++n) { + int rc = wcrtomb(p, in[n], &state); + if(rc == -1) break; + p += rc; + } + + size_t out_sz = p - out; + printf("into %zu UTF-8 code units: [ ", out_sz); + for(size_t x = 0; x < out_sz; ++x) printf("%#x ", +(unsigned char)out[x]); + puts("]"); +} \ No newline at end of file