1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:57:46 +00:00

LibC: Implement wcsrtombs

This commit is contained in:
Tim Schumacher 2021-10-08 01:22:27 +02:00 committed by Brian Gianforcaro
parent fccb06b2cd
commit b0babd062e
3 changed files with 91 additions and 0 deletions

View file

@ -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);
}

View file

@ -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;
}
}
}

View file

@ -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