From e151ed9c707b4fb550b026f5cdba1446fd9022a2 Mon Sep 17 00:00:00 2001 From: Sriya Pratipati Date: Tue, 1 Jul 2025 18:26:02 +0000 Subject: [PATCH 1/3] [libc] wcslcat implementation implemented wcslcat and tests. --- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/wchar.yaml | 8 +++ libc/src/wchar/CMakeLists.txt | 12 ++++ libc/src/wchar/wcslcat.cpp | 39 +++++++++++++ libc/src/wchar/wcslcat.h | 23 ++++++++ libc/test/src/wchar/CMakeLists.txt | 11 ++++ libc/test/src/wchar/wcslcat_test.cpp | 72 ++++++++++++++++++++++++ 7 files changed, 166 insertions(+) create mode 100644 libc/src/wchar/wcslcat.cpp create mode 100644 libc/src/wchar/wcslcat.h create mode 100644 libc/test/src/wchar/wcslcat_test.cpp diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 59c248871f83a..1aa07f3750ca9 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.wcscat libc.src.wchar.wcsstr libc.src.wchar.wcsncat + libc.src.wchar.wcslcat libc.src.wchar.wcscpy libc.src.wchar.wmemchr libc.src.wchar.wcpcpy diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml index 02e1ba331b7cc..0cf72ea923344 100644 --- a/libc/include/wchar.yaml +++ b/libc/include/wchar.yaml @@ -166,6 +166,14 @@ functions: arguments: - type: wchar_t *__restrict - type: const wchar_t *__restrict + - name: wcslcat + standards: + - stdc + return_type: size_t + arguments: + - type: wchar_t *__restrict + - type: const wchar_t *__restrict + - type: size_t - name: wcsstr standards: - stdc diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index f2f4b1d38f0f3..40d94576ac9e1 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -307,6 +307,18 @@ add_entrypoint_object( libc.src.string.string_utils ) +add_entrypoint_object( + wcslcat + SRCS + wcslcat.cpp + HDRS + wcslcat.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.wchar_macros + libc.src.string.string_utils +) + add_entrypoint_object( wmemchr SRCS diff --git a/libc/src/wchar/wcslcat.cpp b/libc/src/wchar/wcslcat.cpp new file mode 100644 index 0000000000000..eff3974f8dff8 --- /dev/null +++ b/libc/src/wchar/wcslcat.cpp @@ -0,0 +1,39 @@ +//===-- Implementation of wcslcat -----------------------------------------===// +// +// 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/wcslcat.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(size_t, wcslcat, + (wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize)) { + size_t dstlen = internal::string_length(dst); + size_t srclen = internal::string_length(src); + size_t limit = dstsize - dstlen - 1; + + if (static_cast(limit) < 0) + return (dstsize < dstlen ? dstsize : dstlen) + srclen; + size_t i = 0; + for (; i < limit && src[i] != L'\0'; ++i) { + dst[dstlen + i] = src[i]; + } + + // appending null terminator if there is room + if (dstlen + i < dstlen + dstsize) + dst[dstlen + i] = L'\0'; + return (dstsize < dstlen ? dstsize : dstlen) + srclen; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcslcat.h b/libc/src/wchar/wcslcat.h new file mode 100644 index 0000000000000..fd964e1af49d5 --- /dev/null +++ b/libc/src/wchar/wcslcat.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcslcat ---------------------------------===// +// +// 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_WCSLCAT_H +#define LLVM_LIBC_SRC_WCHAR_WCSLCAT_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 wcslcat(wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSLCAT_H diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index 657343d072158..baae1e822e854 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -283,6 +283,17 @@ add_libc_test( libc.src.wchar.wcsncat ) +add_libc_test( + wcslcat_test + SUITE + libc_wchar_unittests + SRCS + wcslcat_test.cpp + DEPENDS + libc.src.wchar.wcslcat + libc.hdr.types.size_t +) + add_libc_test( wcscpy_test SUITE diff --git a/libc/test/src/wchar/wcslcat_test.cpp b/libc/test/src/wchar/wcslcat_test.cpp new file mode 100644 index 0000000000000..34b5af7767346 --- /dev/null +++ b/libc/test/src/wchar/wcslcat_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for wcslcat ---------------------------------------------===// +// +// 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/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/wchar/wcslcat.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcWCSLCatTest, TooBig) { + const wchar_t *src = L"cd"; + wchar_t dst[4]{L"ab"}; + size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 3); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'\0'); + // Should still return src length + dst length + ASSERT_EQ(res, size_t(4)); + // Not enough space to copy d + res = LIBC_NAMESPACE::wcslcat(dst, src, 4); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'c'); + ASSERT_TRUE(dst[3] == L'\0'); + ASSERT_EQ(res, size_t(4)); +} + +TEST(LlvmLibcWCSLCatTest, Smaller) { + const wchar_t *src = L"cd"; + wchar_t dst[7]{L"ab"}; + size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 7); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'c'); + ASSERT_TRUE(dst[3] == L'd'); + ASSERT_TRUE(dst[4] == L'\0'); + ASSERT_EQ(res, size_t(4)); +} + +TEST(LlvmLibcWCSLCatTest, SmallerNoOverwriteAfter0) { + const wchar_t *src = L"cd"; + wchar_t dst[8]{L"ab\0\0efg"}; + size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 8); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'c'); + ASSERT_TRUE(dst[3] == L'd'); + ASSERT_TRUE(dst[4] == L'\0'); + ASSERT_TRUE(dst[5] == L'f'); + ASSERT_TRUE(dst[6] == L'g'); + ASSERT_TRUE(dst[7] == L'\0'); + ASSERT_EQ(res, size_t(4)); +} + +TEST(LlvmLibcWCSLCatTest, No0) { + const wchar_t *src = L"cd"; + wchar_t dst[7]{L"ab"}; + size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 1); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'\0'); + ASSERT_EQ(res, size_t(3)); + res = LIBC_NAMESPACE::wcslcat(dst, src, 2); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'\0'); + ASSERT_EQ(res, size_t(4)); +} From 7f69a1e4639c4eadd25277e81a35f3ba3e83f978 Mon Sep 17 00:00:00 2001 From: Sriya Pratipati Date: Tue, 1 Jul 2025 18:28:47 +0000 Subject: [PATCH 2/3] added wcslcat to bazel files --- utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 13 +++++++++++++ .../libc/test/src/wchar/BUILD.bazel | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 2484a2f1e2bd7..6dadb0b6a78ca 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -5827,6 +5827,19 @@ libc_function( ], ) +libc_function( + name = "wcslcat", + srcs = ["src/wchar/wcslcat.cpp"], + hdrs = ["src/wchar/wcslcat.h"], + deps = [ + ":__support_common", + ":__support_macros_config", + ":string_utils", + ":types_size_t", + ":types_wchar_t", + ], +) + libc_function( name = "wcslen", srcs = ["src/wchar/wcslen.cpp"], diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/wchar/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/wchar/BUILD.bazel index f94065237ef4f..fb2ffa3f8ebb6 100644 --- a/utils/bazel/llvm-project-overlay/libc/test/src/wchar/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/src/wchar/BUILD.bazel @@ -83,6 +83,17 @@ libc_test( ], ) + +libc_test( + name = "wcslcat_test", + srcs = ["wcslcat_test.cpp"], + deps = [ + "//libc:types_size_t", + "//libc:types_wchar_t", + "//libc:wcslcat", + ], +) + libc_test( name = "wcslen_test", srcs = ["wcslen_test.cpp"], From 40d20d15529867821f5c29be2e48940ada83521e Mon Sep 17 00:00:00 2001 From: Sriya Pratipati Date: Tue, 1 Jul 2025 18:29:31 +0000 Subject: [PATCH 3/3] fixed formatting --- libc/src/wchar/wcslcat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/wchar/wcslcat.cpp b/libc/src/wchar/wcslcat.cpp index eff3974f8dff8..aa8f7c04023c6 100644 --- a/libc/src/wchar/wcslcat.cpp +++ b/libc/src/wchar/wcslcat.cpp @@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(size_t, wcslcat, for (; i < limit && src[i] != L'\0'; ++i) { dst[dstlen + i] = src[i]; } - + // appending null terminator if there is room if (dstlen + i < dstlen + dstsize) dst[dstlen + i] = L'\0';