mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 06:57:46 +00:00
LibC: Implement wcsrtombs
This commit is contained in:
parent
fccb06b2cd
commit
b0babd062e
3 changed files with 91 additions and 0 deletions
|
@ -316,3 +316,50 @@ TEST_CASE(wcrtomb)
|
|||
ret = wcrtomb(buf, L'\uFFFD', nullptr);
|
||||
EXPECT_NE(ret, (size_t)-1);
|
||||
}
|
||||
|
||||
TEST_CASE(wcsrtombs)
|
||||
{
|
||||
mbstate_t state = {};
|
||||
char buf[MB_LEN_MAX * 4];
|
||||
const wchar_t good_chars[] = { L'\U0001F41E', L'\U0001F41E', L'\0' };
|
||||
const wchar_t bad_chars[] = { L'\U0001F41E', static_cast<wchar_t>(0x1111F41E), L'\0' };
|
||||
const wchar_t* src;
|
||||
size_t ret = 0;
|
||||
|
||||
// Convert normal and valid wchar_t values.
|
||||
src = good_chars;
|
||||
ret = wcsrtombs(buf, &src, 9, &state);
|
||||
EXPECT_EQ(ret, 8ul);
|
||||
EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e", 9), 0);
|
||||
EXPECT_EQ(src, nullptr);
|
||||
EXPECT_NE(mbsinit(&state), 0);
|
||||
|
||||
// Stop on invalid wchar values.
|
||||
src = bad_chars;
|
||||
ret = wcsrtombs(buf, &src, 9, &state);
|
||||
EXPECT_EQ(ret, -1ul);
|
||||
EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e", 4), 0);
|
||||
EXPECT_EQ(errno, EILSEQ);
|
||||
EXPECT_EQ(src, bad_chars + 1);
|
||||
|
||||
// Valid characters but not enough space.
|
||||
src = good_chars;
|
||||
ret = wcsrtombs(buf, &src, 7, &state);
|
||||
EXPECT_EQ(ret, 4ul);
|
||||
EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e", 4), 0);
|
||||
EXPECT_EQ(src, good_chars + 1);
|
||||
|
||||
// Try a conversion with no destination and too short length.
|
||||
src = good_chars;
|
||||
ret = wcsrtombs(nullptr, &src, 2, &state);
|
||||
EXPECT_EQ(ret, 8ul);
|
||||
EXPECT_EQ(src, nullptr);
|
||||
EXPECT_NE(mbsinit(&state), 0);
|
||||
|
||||
// Try a conversion using the internal anonymous state.
|
||||
src = good_chars;
|
||||
ret = wcsrtombs(buf, &src, 9, nullptr);
|
||||
EXPECT_EQ(ret, 8ul);
|
||||
EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e", 9), 0);
|
||||
EXPECT_EQ(src, nullptr);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <AK/Format.h>
|
||||
#include <AK/UnicodeUtils.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
static unsigned int mbstate_expected_bytes(mbstate_t* state)
|
||||
|
@ -462,4 +463,46 @@ int wcwidth(wchar_t wc)
|
|||
// TODO: Implement wcwidth for non-ASCII characters.
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t wcsrtombs(char* dest, const wchar_t** src, size_t len, mbstate_t* ps)
|
||||
{
|
||||
static mbstate_t _anonymous_state = {};
|
||||
|
||||
if (ps == nullptr)
|
||||
ps = &_anonymous_state;
|
||||
|
||||
size_t written = 0;
|
||||
while (true) {
|
||||
size_t ret = 0;
|
||||
char buf[MB_LEN_MAX];
|
||||
|
||||
// Convert next wchar to multibyte.
|
||||
ret = wcrtomb(buf, **src, ps);
|
||||
|
||||
// wchar can't be represented as multibyte.
|
||||
if (ret == (size_t)-1) {
|
||||
errno = EILSEQ;
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
// New bytes don't fit the buffer.
|
||||
if (dest && len < written + ret) {
|
||||
return written;
|
||||
}
|
||||
|
||||
if (dest) {
|
||||
memcpy(dest, buf, ret);
|
||||
dest += ret;
|
||||
}
|
||||
|
||||
// Null character has been reached
|
||||
if (**src == L'\0') {
|
||||
*src = nullptr;
|
||||
return written;
|
||||
}
|
||||
|
||||
*src += 1;
|
||||
written += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,5 +56,6 @@ double wcstod(const wchar_t*, wchar_t**);
|
|||
long double wcstold(const wchar_t*, wchar_t**);
|
||||
int swprintf(wchar_t*, size_t, const wchar_t*, ...);
|
||||
int wcwidth(wchar_t);
|
||||
size_t wcsrtombs(char*, const wchar_t**, size_t, mbstate_t*);
|
||||
|
||||
__END_DECLS
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue