From 7528d8a3e7c5b86b7ceca1b413ea1c2108aa194c Mon Sep 17 00:00:00 2001 From: Sriya Pratipati Date: Fri, 30 May 2025 23:19:46 +0000 Subject: [PATCH 1/2] [libc] wcsncpy implementation Implemented wcsncpy and tests for the function. --- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/wchar.yaml | 10 +++- libc/src/wchar/CMakeLists.txt | 12 +++++ libc/src/wchar/wcsncpy.cpp | 33 ++++++++++++ libc/src/wchar/wcsncpy.h | 23 +++++++++ libc/test/src/wchar/CMakeLists.txt | 10 ++++ libc/test/src/wchar/wcsncpy_test.cpp | 66 ++++++++++++++++++++++++ 7 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 libc/src/wchar/wcsncpy.cpp create mode 100644 libc/src/wchar/wcsncpy.h create mode 100644 libc/test/src/wchar/wcsncpy_test.cpp diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 7ddeb4d31b466..746028e0b6ff7 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -370,6 +370,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.wchar.wcsspn libc.src.wchar.wmemcmp libc.src.wchar.wmemcpy + libc.src.wchar.wcsncpy # sys/uio.h entrypoints libc.src.sys.uio.writev diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index bd9105f69222c..45070d202325a 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -70,5 +70,13 @@ functions: return_type: wchar_t * arguments: - type: __restricted wchar_t * - - type: const __ restricted wchar_t * + - type: const __ restrict wchar_t * + - type: size_t + - name: wcsncpy + standards: + - stdc + return_type: wchar_t * + arguments: + - type: __restrict wchar_t * + - type: const __restrict wchar_t * - type: size_t diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 9db121762348b..c7f105abee871 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -104,3 +104,15 @@ add_entrypoint_object( libc.hdr.wchar_macros libc.src.__support.wctype_utils ) + +add_entrypoint_object( + wcsncpy + SRCS + wcsncpy.cpp + HDRS + wcsncpy.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.wchar_macros + libc.src.__support.wctype_utils +) diff --git a/libc/src/wchar/wcsncpy.cpp b/libc/src/wchar/wcsncpy.cpp new file mode 100644 index 0000000000000..e7ae9a4a0da79 --- /dev/null +++ b/libc/src/wchar/wcsncpy.cpp @@ -0,0 +1,33 @@ +//===-- Implementation of wcsncpy -----------------------------------------===// +// +// 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/wcsncpy.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/string/memory_utils/inline_memcpy.h" +#include "src/string/string_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wcsncpy, + (wchar_t *__restrict s1, const wchar_t *__restrict s2, + size_t n)) { + size_t i = 0; + // Copy up until \0 is found. + for (; i < n && s2[i] != L'\0'; ++i) + s1[i] = s2[i]; + // When s2 is shorter than n, append \0. + for (; i < n; ++i) + s1[i] = L'\0'; + return s1; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcsncpy.h b/libc/src/wchar/wcsncpy.h new file mode 100644 index 0000000000000..06c23f24bcde7 --- /dev/null +++ b/libc/src/wchar/wcsncpy.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcsncpy ---------------------------------===// +// +// 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_WCSNCPY_H +#define LLVM_LIBC_SRC_WCHAR_WCSNCPY_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wcsncpy(wchar_t *__restrict s1, const wchar_t *__restrict s2, + size_t n); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSNCPY_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 9bc230e0bddf3..f2a9106a1704e 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -94,3 +94,13 @@ add_libc_test( DEPENDS libc.src.wchar.wmemcpy ) + +add_libc_test( + wcsncpy_test + SUITE + libc_wchar_unittests + SRCS + wcsncpy_test.cpp + DEPENDS + libc.src.wchar.wcsncpy +) diff --git a/libc/test/src/wchar/wcsncpy_test.cpp b/libc/test/src/wchar/wcsncpy_test.cpp new file mode 100644 index 0000000000000..9b5ffbe20b4a1 --- /dev/null +++ b/libc/test/src/wchar/wcsncpy_test.cpp @@ -0,0 +1,66 @@ +//===-- Unittests for wcsncpy ---------------------------------------------===// +// +// 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/wchar_t.h" +#include "src/wchar/wcsncpy.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWCSNCpyTest, CopyZero) { + // Dest should remain unchanged. + wchar_t dest[3] = {L'a', L'b', L'\0'}; + const wchar_t *src = L"x"; + LIBC_NAMESPACE::wcsncpy(dest, src, 0); + ASSERT_TRUE(dest[0] == L'a'); + ASSERT_TRUE(dest[1] == L'b'); + ASSERT_TRUE(dest[2] == L'\0'); +} + +TEST(LlvmLibcWCSNCpyTest, CopyFullIntoEmpty) { + // Dest should be the exact same as src. + wchar_t dest[15]; + const wchar_t *src = L"aaaaabbbbccccc"; + LIBC_NAMESPACE::wcsncpy(dest, src, 15); + for (int i = 0; i < 15; i++) + ASSERT_TRUE(dest[i] == src[i]); +} + +TEST(LlvmLibcWCSNCpyTest, CopyPartial) { + // First two characters of dest should be the first two characters of src. + wchar_t dest[] = {L'a', L'b', L'c', L'd', L'\0'}; + const wchar_t *src = L"1234"; + LIBC_NAMESPACE::wcsncpy(dest, src, 2); + ASSERT_TRUE(dest[0] == L'1'); + ASSERT_TRUE(dest[1] == L'2'); + ASSERT_TRUE(dest[2] == L'c'); + ASSERT_TRUE(dest[3] == L'd'); + ASSERT_TRUE(dest[4] == L'\0'); +} + +TEST(LlvmLibcWCSNCpyTest, CopyNullTerminator) { + // Null terminator should copy into dest. + wchar_t dest[] = {L'a', L'b', L'c', L'd', L'\0'}; + const wchar_t src[] = {L'\0', L'y'}; + LIBC_NAMESPACE::wcsncpy(dest, src, 1); + ASSERT_TRUE(dest[0] == L'\0'); + ASSERT_TRUE(dest[1] == L'b'); + ASSERT_TRUE(dest[2] == L'c'); + ASSERT_TRUE(dest[3] == L'd'); + ASSERT_TRUE(dest[4] == L'\0'); +} + +TEST(LlvmLibcWCSNCpyTest, CopyPastSrc) { + // Copying past src should fill with null terminator. + wchar_t dest[] = {L'a', L'b', L'c', L'd', L'\0'}; + const wchar_t src[] = {L'x', L'\0'}; + LIBC_NAMESPACE::wcsncpy(dest, src, 4); + ASSERT_TRUE(dest[0] == L'x'); + ASSERT_TRUE(dest[1] == L'\0'); + ASSERT_TRUE(dest[2] == L'\0'); + ASSERT_TRUE(dest[3] == L'\0'); + ASSERT_TRUE(dest[4] == L'\0'); +} From 68b915e0c16c9f8b78e2e8a4ce87be6a4a878370 Mon Sep 17 00:00:00 2001 From: Sriya Pratipati Date: Fri, 30 May 2025 23:40:29 +0000 Subject: [PATCH 2/2] Fixed CMake for wcsncpy --- libc/src/wchar/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index c7f105abee871..4d501ec760c18 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -114,5 +114,6 @@ add_entrypoint_object( DEPENDS libc.hdr.types.size_t libc.hdr.wchar_macros - libc.src.__support.wctype_utils + libc.src.string.memory_utils.inline_memcpy + libc.src.string.string_utils )