From 89afd4d063b79ef2eba81d1bfc7857c388679c5e Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Fri, 22 Oct 2021 01:38:29 +0200 Subject: [PATCH] LibC: Implement mbsnrtowcs --- Tests/LibC/TestWchar.cpp | 39 +++++++++++++++++++++++++++++++ Userland/Libraries/LibC/wchar.cpp | 29 +++++++++++++++++++---- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Tests/LibC/TestWchar.cpp b/Tests/LibC/TestWchar.cpp index 4ac7282504..c8b6f71f30 100644 --- a/Tests/LibC/TestWchar.cpp +++ b/Tests/LibC/TestWchar.cpp @@ -441,6 +441,45 @@ TEST_CASE(mbsrtowcs) EXPECT_EQ(src, nullptr); } +TEST_CASE(mbsnrtowcs) +{ + mbstate_t state = {}; + const char good_chars[] = "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e"; + const char* src; + size_t ret = 0; + + // Convert nothing. + src = good_chars; + ret = mbsnrtowcs(nullptr, &src, 0, 0, &state); + EXPECT_EQ(ret, 0ul); + EXPECT_EQ(src, good_chars); + + // Convert one full wide character. + src = good_chars; + ret = mbsnrtowcs(nullptr, &src, 4, 0, &state); + EXPECT_EQ(ret, 1ul); + EXPECT_EQ(src, good_chars + 4); + + // Encounter a null character. + src = good_chars; + ret = mbsnrtowcs(nullptr, &src, 10, 0, &state); + EXPECT_EQ(ret, 2ul); + EXPECT_EQ(src, nullptr); + + // Convert an incomplete character. + // Make sure that we point past the last processed byte. + src = good_chars; + ret = mbsnrtowcs(nullptr, &src, 6, 0, &state); + EXPECT_EQ(ret, 1ul); + EXPECT_EQ(src, good_chars + 6); + EXPECT_EQ(mbsinit(&state), 0); + + // Finish converting the incomplete character. + ret = mbsnrtowcs(nullptr, &src, 2, 0, &state); + EXPECT_EQ(ret, 1ul); + EXPECT_EQ(src, good_chars + 8); +} + TEST_CASE(wcslcpy) { auto buf = static_cast(malloc(8 * sizeof(wchar_t))); diff --git a/Userland/Libraries/LibC/wchar.cpp b/Userland/Libraries/LibC/wchar.cpp index e2cea8ea61..3188b54b5f 100644 --- a/Userland/Libraries/LibC/wchar.cpp +++ b/Userland/Libraries/LibC/wchar.cpp @@ -534,7 +534,7 @@ size_t wcsnrtombs(char* dest, const wchar_t** src, size_t nwc, size_t len, mbsta return written; } -size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) +size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nms, size_t len, mbstate_t* ps) { static mbstate_t _anonymous_state = {}; @@ -543,8 +543,21 @@ size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) size_t written = 0; while (written < len || !dst) { + // End of source buffer, no incomplete character. + // src continues to point to the next byte. + if (nms == 0) { + return written; + } + // Convert next multibyte to wchar. - size_t ret = mbrtowc(dst, *src, MB_LEN_MAX, ps); + size_t ret = mbrtowc(dst, *src, nms, ps); + + // Multibyte sequence is incomplete. + if (ret == -2ul) { + // Point just past the last processed byte. + *src += nms; + return written; + } // Multibyte sequence is invalid. if (ret == -1ul) { @@ -559,6 +572,7 @@ size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) } *src += ret; + nms -= ret; written += 1; if (dst) dst += 1; @@ -588,9 +602,14 @@ size_t wcsrtombs(char* dest, const wchar_t** src, size_t len, mbstate_t* ps) return wcsnrtombs(dest, src, SIZE_MAX, len, ps); } -size_t mbsnrtowcs(wchar_t*, const char**, size_t, size_t, mbstate_t*) +size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) { - dbgln("FIXME: Implement mbsnrtowcs()"); - TODO(); + static mbstate_t anonymous_state = {}; + + if (ps == nullptr) + ps = &anonymous_state; + + // SIZE_MAX is as close as we are going to get to "unlimited". + return mbsnrtowcs(dst, src, SIZE_MAX, len, ps); } }