LibC: Implement mbsrtowcs

This commit is contained in:
Tim Schumacher 2021-10-10 21:34:00 +02:00 committed by Brian Gianforcaro
parent b0babd062e
commit 420bdccf0b
3 changed files with 86 additions and 0 deletions

View file

@ -363,3 +363,54 @@ TEST_CASE(wcsrtombs)
EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e", 9), 0);
EXPECT_EQ(src, nullptr);
}
TEST_CASE(mbsrtowcs)
{
mbstate_t state = {};
wchar_t buf[4];
const char good_chars[] = "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e";
const char bad_chars[] = "\xf0\x9f\x90\x9e\xf0\xff\x90\x9e";
const char* src;
size_t ret = 0;
// Convert normal and valid multibyte sequences.
src = good_chars;
ret = mbsrtowcs(buf, &src, 3, &state);
EXPECT_EQ(ret, 2ul);
EXPECT_EQ(buf[0], L'\U0001F41E');
EXPECT_EQ(buf[1], L'\U0001F41E');
EXPECT_EQ(buf[2], L'\0');
EXPECT_EQ(src, nullptr);
EXPECT_NE(mbsinit(&state), 0);
// Stop on invalid multibyte sequences.
src = bad_chars;
ret = mbsrtowcs(buf, &src, 3, &state);
EXPECT_EQ(ret, -1ul);
EXPECT_EQ(buf[0], L'\U0001F41E');
EXPECT_EQ(errno, EILSEQ);
EXPECT_EQ(src, bad_chars + 4);
// Valid sequence but not enough space.
src = good_chars;
ret = mbsrtowcs(buf, &src, 1, &state);
EXPECT_EQ(ret, 1ul);
EXPECT_EQ(buf[0], L'\U0001F41E');
EXPECT_EQ(src, good_chars + 4);
// Try a conversion with no destination and too short length.
src = good_chars;
ret = mbsrtowcs(nullptr, &src, 1, &state);
EXPECT_EQ(ret, 2ul);
EXPECT_EQ(src, nullptr);
EXPECT_NE(mbsinit(&state), 0);
// Try a conversion using the internal anonymous state.
src = good_chars;
ret = mbsrtowcs(buf, &src, 3, nullptr);
EXPECT_EQ(ret, 2ul);
EXPECT_EQ(buf[0], L'\U0001F41E');
EXPECT_EQ(buf[1], L'\U0001F41E');
EXPECT_EQ(buf[2], L'\0');
EXPECT_EQ(src, nullptr);
}

View file

@ -505,4 +505,38 @@ size_t wcsrtombs(char* dest, const wchar_t** src, size_t len, mbstate_t* ps)
written += ret;
}
}
size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps)
{
static mbstate_t _anonymous_state = {};
if (ps == nullptr)
ps = &_anonymous_state;
size_t written = 0;
while (written < len || !dst) {
// Convert next multibyte to wchar.
size_t ret = mbrtowc(dst, *src, MB_LEN_MAX, ps);
// Multibyte sequence is invalid.
if (ret == -1ul) {
errno = EILSEQ;
return (size_t)-1;
}
// Null byte has been reached.
if (**src == '\0') {
*src = nullptr;
return written;
}
*src += ret;
written += 1;
if (dst)
dst += 1;
}
// If we are here, we have written `len` wchars, but not reached the null byte.
return written;
}
}

View file

@ -57,5 +57,6 @@ 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*);
size_t mbsrtowcs(wchar_t*, const char**, size_t, mbstate_t*);
__END_DECLS