diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt --- a/libc/config/linux/riscv64/entrypoints.txt +++ b/libc/config/linux/riscv64/entrypoints.txt @@ -71,6 +71,7 @@ libc.src.string.strstr libc.src.string.strtok libc.src.string.strtok_r + libc.src.string.strxfrm # inttypes.h entrypoints libc.src.inttypes.imaxabs diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -71,6 +71,7 @@ libc.src.string.strstr libc.src.string.strtok libc.src.string.strtok_r + libc.src.string.strxfrm # inttypes.h entrypoints libc.src.inttypes.imaxabs diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -375,6 +375,17 @@ .string_utils ) +add_entrypoint_object( + strxfrm + SRCS + strxfrm.cpp + HDRS + strxfrm.h + DEPENDS + .string_utils + .memory_utils.memcpy_implementation +) + # Helper to define a function with multiple implementations # - Computes flags to satisfy required/rejected features and arch, # - Declares an entry point, diff --git a/libc/src/string/strxfrm.h b/libc/src/string/strxfrm.h new file mode 100644 --- /dev/null +++ b/libc/src/string/strxfrm.h @@ -0,0 +1,21 @@ +//===-- Implementation header for strxfrm -----------------------*- 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_STRING_STRXFRM_H +#define LLVM_LIBC_SRC_STRING_STRXFRM_H + +#include // For size_t +#include + +namespace __llvm_libc { + +size_t strxfrm(char *dest, const char *src, size_t n); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_STRCPY_H diff --git a/libc/src/string/strxfrm.cpp b/libc/src/string/strxfrm.cpp new file mode 100644 --- /dev/null +++ b/libc/src/string/strxfrm.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of strxfrm -----------------------------------------===// +// +// 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/string/strxfrm.h" +#include "src/string/memory_utils/memcpy_implementations.h" +#include "src/string/string_utils.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +// TODO: Add support for locales. +LLVM_LIBC_FUNCTION(size_t, strxfrm, (char *dest, const char *src, size_t n)) { + size_t len = internal::string_length(src); + if (n > len) + inline_memcpy(dest, src, len + 1); + return len; +} + +} // namespace __llvm_libc diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -358,6 +358,16 @@ libc.src.string.strtok_r ) +add_libc_unittest( + strxfrm_test + SUITE + libc_string_unittests + SRCS + strxfrm_test.cpp + DEPENDS + libc.src.string.strxfrm +) + # Tests all implementations that can run on the target CPU. function(add_libc_multi_impl_test name) get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations) diff --git a/libc/test/src/string/strxfrm_test.cpp b/libc/test/src/string/strxfrm_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/string/strxfrm_test.cpp @@ -0,0 +1,45 @@ +//===-- Unittests for strxfrm ---------------------------------------------===// +// +// 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/string/strxfrm.h" +#include "test/UnitTest/Test.h" + +#include "src/string/string_utils.h" + +// TODO: Add more comprehensive tests once locale support is added. + +TEST(LlvmLibcStrxfrmTest, SimpleTestSufficientlySizedN) { + const char *src = "abc"; + const size_t n = 5; + + char dest[n]; + size_t result = __llvm_libc::strxfrm(dest, src, n); + ASSERT_EQ(result, __llvm_libc::internal::string_length(src)); + ASSERT_STREQ(dest, src); +} + +TEST(LlvmLibcStrxfrmTest, SimpleTestExactSizedN) { + const char *src = "abc"; + const size_t n = 4; + + char dest[n]; + size_t result = __llvm_libc::strxfrm(dest, src, n); + ASSERT_EQ(result, __llvm_libc::internal::string_length(src)); + ASSERT_STREQ(dest, src); +} + +TEST(LlvmLibcStrxfrmTest, SimpleTestInsufficientlySizedN) { + const char *src = "abc"; + const size_t n = 3; + + // Verify strxfrm does not modify dest if src len >= n + char dest[n] = {'x', 'x', '\0'}; + size_t result = __llvm_libc::strxfrm(dest, src, n); + ASSERT_GE(result, n); + ASSERT_STREQ(dest, "xx"); +}