Skip to content

[libc] wchar string conversion functions mb to wc #149423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

sribee8
Copy link
Contributor

@sribee8 sribee8 commented Jul 17, 2025

Implemented an internal multi-byte to wide character string conversion function, public functions, and tests

@llvmbot llvmbot added the libc label Jul 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

@llvm/pr-subscribers-libc

Author: None (sribee8)

Changes

Implemented an internal multi-byte to wide character string conversion function, public functions, and tests


Patch is 35.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/149423.diff

16 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+3)
  • (modified) libc/include/wchar.yaml (+27)
  • (modified) libc/src/__support/wchar/CMakeLists.txt (+18)
  • (added) libc/src/__support/wchar/mbsnrtowcs.cpp (+59)
  • (added) libc/src/__support/wchar/mbsnrtowcs.h (+29)
  • (modified) libc/src/wchar/CMakeLists.txt (+50)
  • (added) libc/src/wchar/mbsnrtowcs.cpp (+39)
  • (added) libc/src/wchar/mbsnrtowcs.h (+24)
  • (added) libc/src/wchar/mbsrtowcs.cpp (+39)
  • (added) libc/src/wchar/mbsrtowcs.h (+24)
  • (added) libc/src/wchar/mbstowcs.cpp (+38)
  • (added) libc/src/wchar/mbstowcs.h (+22)
  • (modified) libc/test/src/wchar/CMakeLists.txt (+45)
  • (added) libc/test/src/wchar/mbsnrtowcs_test.cpp (+203)
  • (added) libc/test/src/wchar/mbsrtowcs_test.cpp (+176)
  • (added) libc/test/src/wchar/mbstowcs_test.cpp (+162)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9223911f04a93..e0a02abef001c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1261,6 +1261,9 @@ if(LLVM_LIBC_FULL_BUILD)
     # wchar.h entrypoints
     libc.src.wchar.mbrtowc
     libc.src.wchar.mbtowc
+    libc.src.wchar.mbstowcs
+    libc.src.wchar.mbsrtowcs
+    libc.src.wchar.mbsnrtowcs
     libc.src.wchar.wcrtomb
     libc.src.wchar.wctomb
   )
diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml
index 123d3440aeec3..d3166d60c19de 100644
--- a/libc/include/wchar.yaml
+++ b/libc/include/wchar.yaml
@@ -53,6 +53,33 @@ functions:
       - type: wchar_t *__restrict
       - type: const char *__restrict
       - type: size_t
+  - name: mbstowcs
+    standards:
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: wchar_t *__restrict
+      - type: const char *__restrict
+      - type: size_t
+  - name: mbsrtowcs
+    standards:
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: wchar_t *__restrict
+      - type: const char **__restrict
+      - type: size_t
+      - type: mbstate_t *__restrict
+  - name: mbsnrtowcs
+    standards:
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: wchar_t *__restrict
+      - type: const char **__restrict
+      - type: size_t
+      - type: size_t
+      - type: mbstate_t *__restrict
   - name: wmemset
     standards:
       - stdc
diff --git a/libc/src/__support/wchar/CMakeLists.txt b/libc/src/__support/wchar/CMakeLists.txt
index 802441d37fe92..fa5139a8b68b4 100644
--- a/libc/src/__support/wchar/CMakeLists.txt
+++ b/libc/src/__support/wchar/CMakeLists.txt
@@ -68,3 +68,21 @@ add_object_library(
   .character_converter
   .mbstate
 )
+
+add_object_library(
+  mbsnrtowcs
+  HDRS
+    mbsnrtowcs.h
+  SRCS
+    mbsnrtowcs.cpp
+  DEPENDS
+  libc.hdr.errno_macros
+  libc.hdr.types.wchar_t
+  libc.hdr.types.size_t
+  libc.src.__support.common
+  libc.src.__support.error_or
+  libc.src.__support.macros.config
+  .character_converter
+  .mbstate
+  .string_converter
+)
diff --git a/libc/src/__support/wchar/mbsnrtowcs.cpp b/libc/src/__support/wchar/mbsnrtowcs.cpp
new file mode 100644
index 0000000000000..9eb2b5423af87
--- /dev/null
+++ b/libc/src/__support/wchar/mbsnrtowcs.cpp
@@ -0,0 +1,59 @@
+//===-- Implementation for mbsnrtowcs function ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/wchar/mbsnrtowcs.h"
+#include "hdr/errno_macros.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/wchar/character_converter.h"
+#include "src/__support/wchar/mbstate.h"
+#include "src/__support/wchar/string_converter.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+ErrorOr<size_t> mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+                           size_t nmc, size_t len, mbstate *__restrict ps) {
+  if (*src == nullptr)
+    return 0;
+  // Checking if mbstate is valid
+  CharacterConverter char_conv(ps);
+  if (!char_conv.isValidState())
+    return Error(EINVAL);
+
+  StringConverter<char8_t> str_conv(reinterpret_cast<const char8_t *>(*src), ps,
+                                    len, nmc);
+  size_t dst_idx = 0;
+  ErrorOr<char32_t> converted = str_conv.popUTF32();
+  while (converted.has_value()) {
+    if (dst != nullptr)
+      dst[dst_idx] = converted.value();
+    // null terminator should not be counted in return value
+    if (converted.value() == L'\0') {
+      if (dst != nullptr)
+        *src = nullptr;
+      return dst_idx;
+    }
+    dst_idx++;
+    converted = str_conv.popUTF32();
+  }
+
+  if (converted.error() == -1) { // if we hit conversion limit
+    *src += str_conv.getSourceIndex();
+    return dst_idx;
+  }
+
+  return Error(converted.error());
+}
+
+} // namespace internal
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/wchar/mbsnrtowcs.h b/libc/src/__support/wchar/mbsnrtowcs.h
new file mode 100644
index 0000000000000..8ce497325fdad
--- /dev/null
+++ b/libc/src/__support/wchar/mbsnrtowcs.h
@@ -0,0 +1,29 @@
+//===-- Implementation header for mbsnrtowcs function -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_WCHAR_MBSNRTOWCS
+#define LLVM_LIBC_SRC___SUPPORT_WCHAR_MBSNRTOWCS
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/wchar/mbstate.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+ErrorOr<size_t> mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+                           size_t nmc, size_t len, mbstate *__restrict ps);
+
+} // namespace internal
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_WCHAR_MBSNRTOWCS
diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt
index 7ace1a6ca66ba..ac359064ec10c 100644
--- a/libc/src/wchar/CMakeLists.txt
+++ b/libc/src/wchar/CMakeLists.txt
@@ -159,6 +159,56 @@ add_entrypoint_object(
     libc.src.__support.wchar.mbstate
 )
 
+add_entrypoint_object(
+  mbstowcs
+  SRCS
+    mbstowcs.cpp
+  HDRS
+    mbstowcs.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.types.wchar_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.libc_errno
+    libc.src.__support.wchar.mbstate
+    libc.src.__support.wchar.mbsnrtowcs
+)
+
+add_entrypoint_object(
+  mbsrtowcs
+  SRCS
+    mbsrtowcs.cpp
+  HDRS
+    mbsrtowcs.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.types.wchar_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.libc_errno
+    libc.src.__support.wchar.mbstate
+    libc.src.__support.wchar.mbsnrtowcs
+    libc.src.__support.wchar.mbstate
+)
+
+add_entrypoint_object(
+  mbsnrtowcs
+  SRCS
+    mbsnrtowcs.cpp
+  HDRS
+    mbsnrtowcs.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.types.wchar_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.libc_errno
+    libc.src.__support.wchar.mbstate
+    libc.src.__support.wchar.mbsnrtowcs
+    libc.src.__support.wchar.mbstate
+)
+
 add_entrypoint_object(
   wmemset
   SRCS
diff --git a/libc/src/wchar/mbsnrtowcs.cpp b/libc/src/wchar/mbsnrtowcs.cpp
new file mode 100644
index 0000000000000..28e0ff31b26c4
--- /dev/null
+++ b/libc/src/wchar/mbsnrtowcs.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of mbsnrtowcs --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/mbsnrtowcs.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/wchar/mbsnrtowcs.h"
+#include "src/__support/wchar/mbstate.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(size_t, mbsnrtowcs,
+                   (wchar_t *__restrict dst, const char **__restrict src,
+                    size_t nmc, size_t len, mbstate_t *__restrict ps)) {
+  static internal::mbstate internal_mbstate;
+  // If destination is null, ignore len
+  len = dst == nullptr ? SIZE_MAX : len;
+  auto ret = internal::mbsnrtowcs(
+      dst, src, nmc, len,
+      ps == nullptr ? &internal_mbstate
+                    : reinterpret_cast<internal::mbstate *>(ps));
+  if (!ret.has_value()) {
+    // Encoding failure
+    libc_errno = ret.error();
+    return -1;
+  }
+  return ret.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/mbsnrtowcs.h b/libc/src/wchar/mbsnrtowcs.h
new file mode 100644
index 0000000000000..5c9687b20b3fa
--- /dev/null
+++ b/libc/src/wchar/mbsnrtowcs.h
@@ -0,0 +1,24 @@
+//===-- Implementation header for mbsnrtowcs ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_MBSNRTOWCS_H
+#define LLVM_LIBC_SRC_WCHAR_MBSNRTOWCS_H
+
+#include "hdr/types/mbstate_t.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+size_t mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+                 size_t nmc, size_t len, mbstate_t *__restrict ps);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_MBSNRTOWCS_H
diff --git a/libc/src/wchar/mbsrtowcs.cpp b/libc/src/wchar/mbsrtowcs.cpp
new file mode 100644
index 0000000000000..82ca25a3d863d
--- /dev/null
+++ b/libc/src/wchar/mbsrtowcs.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of mbsrtowcs ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/mbsrtowcs.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/wchar/mbsnrtowcs.h"
+#include "src/__support/wchar/mbstate.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(size_t, mbsrtowcs,
+                   (wchar_t *__restrict dst, const char **__restrict src,
+                    size_t len, mbstate_t *__restrict ps)) {
+  static internal::mbstate internal_mbstate;
+  // If destination is null, ignore len
+  len = dst == nullptr ? SIZE_MAX : len;
+  auto ret = internal::mbsnrtowcs(
+      dst, src, SIZE_MAX, len,
+      ps == nullptr ? &internal_mbstate
+                    : reinterpret_cast<internal::mbstate *>(ps));
+  if (!ret.has_value()) {
+    // Encoding failure
+    libc_errno = ret.error();
+    return -1;
+  }
+  return ret.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/mbsrtowcs.h b/libc/src/wchar/mbsrtowcs.h
new file mode 100644
index 0000000000000..f8d4cc26e63ae
--- /dev/null
+++ b/libc/src/wchar/mbsrtowcs.h
@@ -0,0 +1,24 @@
+//===-- Implementation header for mbsrtowcs -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_MBSRTOWCS_H
+#define LLVM_LIBC_SRC_WCHAR_MBSRTOWCS_H
+
+#include "hdr/types/mbstate_t.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+size_t mbsrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+                 size_t len, mbstate_t *__restrict ps);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_MBSRTOWCS_H
diff --git a/libc/src/wchar/mbstowcs.cpp b/libc/src/wchar/mbstowcs.cpp
new file mode 100644
index 0000000000000..1a3232847fa71
--- /dev/null
+++ b/libc/src/wchar/mbstowcs.cpp
@@ -0,0 +1,38 @@
+//===-- Implementation of mbstowcs ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/mbstowcs.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/wchar/mbsnrtowcs.h"
+#include "src/__support/wchar/mbstate.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(size_t, mbstowcs,
+                   (wchar_t *__restrict pwcs, const char *__restrict s,
+                    size_t n)) {
+  // If destination is null, ignore n
+  n = pwcs == nullptr ? SIZE_MAX : n;
+  static internal::mbstate internal_mbstate;
+  const char *temp = s;
+  auto ret = internal::mbsnrtowcs(pwcs, &temp, SIZE_MAX, n, &internal_mbstate);
+
+  if (!ret.has_value()) {
+    // Encoding failure
+    libc_errno = ret.error();
+    return -1;
+  }
+  return ret.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/mbstowcs.h b/libc/src/wchar/mbstowcs.h
new file mode 100644
index 0000000000000..7d08a838b2324
--- /dev/null
+++ b/libc/src/wchar/mbstowcs.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for mbstowcs --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_MBSTOWCS_H
+#define LLVM_LIBC_SRC_WCHAR_MBSTOWCS_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+size_t mbstowcs(wchar_t *__restrict pwcs, const char *__restrict s, size_t n);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_MBSTOWCS_H
diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt
index 176cf7c3487cd..1a8f9981fc5bb 100644
--- a/libc/test/src/wchar/CMakeLists.txt
+++ b/libc/test/src/wchar/CMakeLists.txt
@@ -64,6 +64,51 @@ add_libc_test(
     libc.test.UnitTest.ErrnoCheckingTest
 )
 
+add_libc_test(
+  mbstowcs_test
+  SUITE
+    libc_wchar_unittests
+  SRCS
+    mbstowcs_test.cpp
+  DEPENDS
+    libc.src.__support.libc_errno
+    libc.src.wchar.mbstowcs
+    libc.hdr.types.wchar_t
+    libc.test.UnitTest.ErrnoCheckingTest
+)
+
+add_libc_test(
+  mbsrtowcs_test
+  SUITE
+    libc_wchar_unittests
+  SRCS
+    mbsrtowcs_test.cpp
+  DEPENDS
+    libc.src.__support.libc_errno
+    libc.src.__support.wchar.mbstate
+    libc.src.string.memset
+    libc.src.wchar.mbsrtowcs
+    libc.hdr.types.mbstate_t
+    libc.hdr.types.wchar_t
+    libc.test.UnitTest.ErrnoCheckingTest
+)
+
+add_libc_test(
+  mbsnrtowcs_test
+  SUITE
+    libc_wchar_unittests
+  SRCS
+    mbsnrtowcs_test.cpp
+  DEPENDS
+    libc.src.__support.libc_errno
+    libc.src.__support.wchar.mbstate
+    libc.src.string.memset
+    libc.src.wchar.mbsnrtowcs
+    libc.hdr.types.mbstate_t
+    libc.hdr.types.wchar_t
+    libc.test.UnitTest.ErrnoCheckingTest
+)
+
 add_libc_test(
   wctob_test
   SUITE
diff --git a/libc/test/src/wchar/mbsnrtowcs_test.cpp b/libc/test/src/wchar/mbsnrtowcs_test.cpp
new file mode 100644
index 0000000000000..a042794997b9f
--- /dev/null
+++ b/libc/test/src/wchar/mbsnrtowcs_test.cpp
@@ -0,0 +1,203 @@
+//===-- Unittests for mbsetowcs -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/types/mbstate_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/wchar/mbstate.h"
+#include "src/string/memset.h"
+#include "src/wchar/mbsnrtowcs.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcMBSNRToWCSTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcMBSNRToWCSTest, OneByteOneChar) {
+  const char *ch = "A";
+  const char *original = ch;
+  wchar_t dest[2];
+  mbstate_t *mb;
+  LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
+  size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &ch, 1, 1, mb);
+  ASSERT_EQ(static_cast<char>(*dest), 'A');
+  ASSERT_EQ(static_cast<int>(n), 1);
+  // Should point to null terminator now
+  ASSERT_EQ(ch, original + 1);
+  ASSERT_ERRNO_SUCCESS();
+
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 1, &ch, 1, 1, mb);
+  ASSERT_EQ(static_cast<char>(dest[1]), '\0');
+  // Should not include null terminator
+  ASSERT_EQ(static_cast<int>(n), 0);
+  // Should now be a nullptr
+  ASSERT_EQ(ch, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcMBSNRToWCSTest, FourByteOneChar) {
+  const char *src = "\xf0\x9f\x98\xb9"; // laughing cat emoji 😹
+  const char *original = src;
+  wchar_t dest[2];
+  mbstate_t *mb;
+  LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
+  // Not enough bytes for the full character
+  size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 3, 2, mb);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(static_cast<int>(n), 0);
+  ASSERT_EQ(src, original + 3);
+  // Needs 2 more bytes (last byte of cat + null terminator)
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 2, 2, mb);
+  ASSERT_ERRNO_SUCCESS();
+  // Does not include null terminator
+  ASSERT_EQ(static_cast<int>(n), 1);
+  ASSERT_EQ(src, nullptr);
+  ASSERT_EQ(static_cast<int>(dest[0]), 128569);
+  ASSERT_TRUE(dest[1] == L'\0');
+}
+
+TEST_F(LlvmLibcMBSNRToWCSTest, MixedNumberOfBytes) {
+  // 'A', sigma symbol 'Σ', recycling symbol '♻', laughing cat emoji '😹'
+  const char *src = "A\xce\xa3\xe2\x99\xbb\xf0\x9f\x98\xb9";
+  const char *original = src;
+  wchar_t dest[5];
+  mbstate_t *mb;
+  LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
+  
+  // Read 'A'
+  size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 1, 1, mb);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(static_cast<char>(dest[0]), 'A');
+    ASSERT_EQ(static_cast<int>(n), 1);
+  ASSERT_EQ(src, original + 1);
+
+  // Read sigma 'Σ'
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 1, &src, 2, 1, mb);
+  ASSERT_ERRNO_SUCCESS();
+    ASSERT_EQ(static_cast<int>(dest[1]), 931);
+    ASSERT_EQ(static_cast<int>(n), 1);
+  ASSERT_EQ(src, original + 3);
+
+  // Read recycling '♻'
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 2, &src, 2, 5, mb);
+  ASSERT_ERRNO_SUCCESS();
+    ASSERT_EQ(static_cast<int>(n), 0);
+  ASSERT_EQ(src, original + 5);
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 2, &src, 1, 1, mb);
+ASSERT_ERRNO_SUCCESS();
+    ASSERT_EQ(static_cast<int>(n), 1);
+  ASSERT_EQ(src, original + 6);
+  ASSERT_EQ(static_cast<int>(dest[2]), 9851);
+
+  // Read laughing cat emoji '😹'
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 3, &src, 4, 5, mb);
+  ASSERT_ERRNO_SUCCESS();
+    ASSERT_EQ(static_cast<int>(n), 1);
+  ASSERT_EQ(src, original + 10);
+  ASSERT_EQ(static_cast<int>(dest[3]), 128569);
+
+
+  n = LIBC_NAMESPACE::mbsnrtowcs(dest + 4, &src, 4, 4, nullptr);
+  ASSERT_TRUE(dest[4] == L'\0');
+  ASSERT_ERRNO_SUCCESS();
+  // Should not count null terminator in number
+  ASSERT_EQ(static_cast<int>(n), 0);
+  // Should now be a nullptr
+  ASSERT_EQ(src, nullptr);
+}
+
+TEST_F(LlvmLibcMBSNRToWCSTest, ReadLessThanStringLength) {
+  // Four laughing cat emojis "😹😹😹😹"
+  const char *src =
+      "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9";
+  const char *original = src;
+  wchar_t dest[5] = {L'a', L'b', L'c', L'd', L'e'};
+  size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 100, 3, nullptr);
+  ASSERT_ERRNO...
[truncated]

@sribee8 sribee8 requested a review from uzairnawaz July 17, 2025 23:26
Copy link

github-actions bot commented Jul 17, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants