diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index aa2079faed409..8c6c540a67230 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -384,6 +384,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.wchar.wcsncat libc.src.wchar.wcscpy libc.src.wchar.wmemchr + libc.src.wchar.wcpcpy # sys/uio.h entrypoints libc.src.sys.uio.writev diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 84db73d8f01ea..2962984c254ce 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -157,3 +157,10 @@ functions: arguments: - type: wchar_t *__restrict - type: const wchar_t *__restrict + - name: wcpcpy + standards: + - stdc + return_type: wchar_t * + arguments: + - type: wchar_t *__restrict + - type: const wchar_t *__restrict diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 491dd5b34340a..65c38ac81a90f 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -45,6 +45,18 @@ add_entrypoint_object( libc.hdr.types.wchar_t ) +add_entrypoint_object( + wcpcpy + SRCS + wcpcpy.cpp + HDRS + wcpcpy.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.wchar_macros + libc.src.string.string_utils +) + add_entrypoint_object( wcschr SRCS diff --git a/libc/src/wchar/wcpcpy.cpp b/libc/src/wchar/wcpcpy.cpp new file mode 100644 index 0000000000000..9e2b12f09eb05 --- /dev/null +++ b/libc/src/wchar/wcpcpy.cpp @@ -0,0 +1,27 @@ +//===-- Implementation of wcpcpy ------------------------------------------===// +// +// 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/wcpcpy.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/string_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wcpcpy, + (wchar_t *__restrict s1, const wchar_t *__restrict s2)) { + size_t size = internal::string_length(s2); + __builtin_memcpy(s1, s2, (size + 1) * sizeof(wchar_t)); + wchar_t *result = s1 + size; + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcpcpy.h b/libc/src/wchar/wcpcpy.h new file mode 100644 index 0000000000000..333491fc13abb --- /dev/null +++ b/libc/src/wchar/wcpcpy.h @@ -0,0 +1,21 @@ +//===-- Implementation header for wcpcpy ----------------------------------===// +// +// 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_WCPCPY_H +#define LLVM_LIBC_SRC_WCHAR_WCPCPY_H + +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wcpcpy(wchar_t *__restrict ws1, const wchar_t *__restrict ws2); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCPCPY_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 4990b6953348b..d7444de94fe17 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -204,3 +204,13 @@ add_libc_test( DEPENDS libc.src.wchar.wcscpy ) + +add_libc_test( + wcpcpy_test + SUITE + libc_wchar_unittests + SRCS + wcpcpy_test.cpp + DEPENDS + libc.src.wchar.wcpcpy +) diff --git a/libc/test/src/wchar/wcpcpy_test.cpp b/libc/test/src/wchar/wcpcpy_test.cpp new file mode 100644 index 0000000000000..c59b61fb131b2 --- /dev/null +++ b/libc/test/src/wchar/wcpcpy_test.cpp @@ -0,0 +1,50 @@ +//===-- Unittests for wcpcpy ---------------------------------------------===// +// +// 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/wcpcpy.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWCPCpyTest, EmptySrc) { + // Empty src should lead to empty destination. + wchar_t dest[4] = {L'a', L'b', L'c', L'\0'}; + const wchar_t *src = L""; + LIBC_NAMESPACE::wcpcpy(dest, src); + ASSERT_TRUE(dest[0] == src[0]); + ASSERT_TRUE(dest[0] == L'\0'); +} + +TEST(LlvmLibcWCPCpyTest, EmptyDest) { + // Empty dest should result in src + const wchar_t *src = L"abc"; + wchar_t dest[4]; + wchar_t *result = LIBC_NAMESPACE::wcpcpy(dest, src); + ASSERT_EQ(dest + 3, result); + ASSERT_TRUE(result[0] == L'\0'); + ASSERT_TRUE(dest[0] == L'a'); + ASSERT_TRUE(dest[1] == L'b'); + ASSERT_TRUE(dest[2] == L'c'); +} + +TEST(LlvmLibcWCPCpyTest, OffsetDest) { + // Offsetting should result in a concatenation. + const wchar_t *src = L"abc"; + wchar_t dest[7]; + dest[0] = L'x'; + dest[1] = L'y'; + dest[2] = L'z'; + wchar_t *result = LIBC_NAMESPACE::wcpcpy(dest + 3, src); + ASSERT_TRUE(dest[0] == L'x'); + ASSERT_TRUE(dest[1] == L'y'); + ASSERT_TRUE(dest[2] == L'z'); + ASSERT_TRUE(dest[3] == src[0]); + ASSERT_TRUE(dest[4] == src[1]); + ASSERT_TRUE(dest[5] == src[2]); + ASSERT_TRUE(result[0] == L'\0'); + ASSERT_EQ(dest + 6, result); +}