[libc-commits] [libc] 9b6f8b9 - [libc] add stpcpy and stpncpy
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Nov 4 11:39:30 PDT 2021
Author: Michael Jones
Date: 2021-11-04T11:39:26-07:00
New Revision: 9b6f8b985c6a22f16a7c6a611d239198cf1d1504
URL: https://github.com/llvm/llvm-project/commit/9b6f8b985c6a22f16a7c6a611d239198cf1d1504
DIFF: https://github.com/llvm/llvm-project/commit/9b6f8b985c6a22f16a7c6a611d239198cf1d1504.diff
LOG: [libc] add stpcpy and stpncpy
Adds an implementation for stpcpy and stpncpy, which are posix extension
functions.
Reviewed By: sivachandra, lntue
Differential Revision: https://reviews.llvm.org/D111913
Added:
libc/src/string/stpcpy.cpp
libc/src/string/stpcpy.h
libc/src/string/stpncpy.cpp
libc/src/string/stpncpy.h
libc/test/src/string/stpcpy_test.cpp
libc/test/src/string/stpncpy_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/posix.td
libc/src/string/CMakeLists.txt
libc/test/src/string/CMakeLists.txt
libc/test/src/string/strcpy_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bce6cbf1ee65..a757dc35b5d2 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -31,6 +31,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.mempcpy
libc.src.string.memrchr
libc.src.string.memset
+ libc.src.string.stpcpy
+ libc.src.string.stpncpy
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 45d12fa23992..e1fc63367c6a 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -235,6 +235,19 @@ def POSIX : StandardSpec<"POSIX"> {
ArgSpec<ConstVoidRestrictedPtr>,
ArgSpec<SizeTType>]
>,
+ FunctionSpec<
+ "stpcpy",
+ RetValSpec<CharPtr>,
+ [ArgSpec<RestrictedCharPtr>,
+ ArgSpec<ConstRestrictedCharPtr>]
+ >,
+ FunctionSpec<
+ "stpncpy",
+ RetValSpec<CharPtr>,
+ [ArgSpec<RestrictedCharPtr>,
+ ArgSpec<ConstRestrictedCharPtr>,
+ ArgSpec<SizeTType>]
+ >,
FunctionSpec<
"strnlen",
RetValSpec<SizeTType>,
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 5a130fc6ecc7..d5cfb1742018 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -56,6 +56,27 @@ add_entrypoint_object(
memrchr.h
)
+add_entrypoint_object(
+ stpcpy
+ SRCS
+ stpcpy.cpp
+ HDRS
+ stpcpy.h
+ DEPENDS
+ .mempcpy
+ .string_utils
+)
+
+add_entrypoint_object(
+ stpncpy
+ SRCS
+ stpncpy.cpp
+ HDRS
+ stpncpy.h
+ DEPENDS
+ .bzero
+)
+
add_entrypoint_object(
strcat
SRCS
diff --git a/libc/src/string/stpcpy.cpp b/libc/src/string/stpcpy.cpp
new file mode 100644
index 000000000000..dd48f3cfb5e8
--- /dev/null
+++ b/libc/src/string/stpcpy.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of stpcpy ------------------------------------------===//
+//
+// 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/stpcpy.h"
+#include "src/string/mempcpy.h"
+#include "src/string/string_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/sanitizer.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, stpcpy,
+ (char *__restrict dest, const char *__restrict src)) {
+ size_t size = internal::string_length(src) + 1;
+ char *result =
+ reinterpret_cast<char *>(__llvm_libc::mempcpy(dest, src, size));
+
+ if (result != nullptr)
+ return result - 1;
+ return nullptr;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/stpcpy.h b/libc/src/string/stpcpy.h
new file mode 100644
index 000000000000..84d5738f0e2b
--- /dev/null
+++ b/libc/src/string/stpcpy.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stpcpy ------------------------*- 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_STPCPY_H
+#define LLVM_LIBC_SRC_STRING_STPCPY_H
+
+namespace __llvm_libc {
+
+char *stpcpy(char *__restrict dest, const char *__restrict src);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STPCPY_H
diff --git a/libc/src/string/stpncpy.cpp b/libc/src/string/stpncpy.cpp
new file mode 100644
index 000000000000..374330ede2ca
--- /dev/null
+++ b/libc/src/string/stpncpy.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of stpncpy -----------------------------------------===//
+//
+// 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/stpncpy.h"
+#include "src/string/bzero.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, stpncpy,
+ (char *__restrict dest, const char *__restrict src,
+ size_t n)) {
+ size_t i;
+ // Copy up until \0 is found.
+ for (i = 0; i < n && src[i] != '\0'; ++i)
+ dest[i] = src[i];
+ // When n>strlen(src), n-strlen(src) \0 are appended.
+ if (n > i)
+ __llvm_libc::bzero(dest + i, n - i);
+ return dest + i;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/stpncpy.h b/libc/src/string/stpncpy.h
new file mode 100644
index 000000000000..6320a290b1dd
--- /dev/null
+++ b/libc/src/string/stpncpy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for stpncpy -----------------------*- 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_STPNCPY_H
+#define LLVM_LIBC_SRC_STRING_STPNCPY_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+char *stpncpy(char *__restrict dest, const char *__restrict src, size_t n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STPNCPY_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index a5b931d768d3..6713bd73b724 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -42,6 +42,26 @@ add_libc_unittest(
libc.src.string.memrchr
)
+add_libc_unittest(
+ stpcpy_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ stpcpy_test.cpp
+ DEPENDS
+ libc.src.string.stpcpy
+)
+
+add_libc_unittest(
+ stpncpy_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ stpncpy_test.cpp
+ DEPENDS
+ libc.src.string.stpncpy
+)
+
add_libc_unittest(
strcat_test
SUITE
diff --git a/libc/test/src/string/stpcpy_test.cpp b/libc/test/src/string/stpcpy_test.cpp
new file mode 100644
index 000000000000..90ec5311b9b9
--- /dev/null
+++ b/libc/test/src/string/stpcpy_test.cpp
@@ -0,0 +1,45 @@
+//===-- Unittests for stpcpy ----------------------------------------------===//
+//
+// 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/stpcpy.h"
+#include "utils/UnitTest/Test.h"
+
+#include "src/string/string_utils.h"
+
+TEST(LlvmLibcStpCpyTest, EmptySrc) {
+ const char *empty = "";
+ size_t srcSize = __llvm_libc::internal::string_length(empty);
+ char dest[4] = {'a', 'b', 'c', '\0'};
+
+ char *result = __llvm_libc::stpcpy(dest, empty);
+ ASSERT_EQ(dest + srcSize, result);
+ ASSERT_EQ(result[0], '\0');
+ ASSERT_STREQ(dest, empty);
+}
+
+TEST(LlvmLibcStpCpyTest, EmptyDest) {
+ const char *abc = "abc";
+ size_t srcSize = __llvm_libc::internal::string_length(abc);
+ char dest[4];
+
+ char *result = __llvm_libc::stpcpy(dest, abc);
+ ASSERT_EQ(dest + srcSize, result);
+ ASSERT_EQ(result[0], '\0');
+ ASSERT_STREQ(dest, abc);
+}
+
+TEST(LlvmLibcStpCpyTest, OffsetDest) {
+ const char *abc = "abc";
+ size_t srcSize = __llvm_libc::internal::string_length(abc);
+ char dest[7] = {'x', 'y', 'z'};
+
+ char *result = __llvm_libc::stpcpy(dest + 3, abc);
+ ASSERT_EQ(dest + 3 + srcSize, result);
+ ASSERT_EQ(result[0], '\0');
+ ASSERT_STREQ(dest, "xyzabc");
+}
diff --git a/libc/test/src/string/stpncpy_test.cpp b/libc/test/src/string/stpncpy_test.cpp
new file mode 100644
index 000000000000..855be58941ce
--- /dev/null
+++ b/libc/test/src/string/stpncpy_test.cpp
@@ -0,0 +1,73 @@
+//===-- Unittests for stpncpy ---------------------------------------------===//
+//
+// 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/CPP/ArrayRef.h"
+#include "src/string/stpncpy.h"
+#include "utils/UnitTest/Test.h"
+#include <stddef.h> // For size_t.
+
+class LlvmLibcStpncpyTest : public __llvm_libc::testing::Test {
+public:
+ void check_stpncpy(__llvm_libc::cpp::MutableArrayRef<char> dst,
+ const __llvm_libc::cpp::ArrayRef<char> src, size_t n,
+ const __llvm_libc::cpp::ArrayRef<char> expected,
+ size_t expectedCopied) {
+ // Making sure we don't overflow buffer.
+ ASSERT_GE(dst.size(), n);
+ // Making sure stpncpy returns a pointer to the end of dst.
+ ASSERT_EQ(__llvm_libc::stpncpy(dst.data(), src.data(), n),
+ dst.data() + expectedCopied);
+ // Expected must be of the same size as dst.
+ ASSERT_EQ(dst.size(), expected.size());
+ // Expected and dst are the same.
+ for (size_t i = 0; i < expected.size(); ++i)
+ ASSERT_EQ(expected[i], dst[i]);
+ }
+};
+
+TEST_F(LlvmLibcStpncpyTest, Untouched) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', '\0'};
+ const char expected[] = {'a', 'b'};
+ check_stpncpy(dst, src, 0, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyOne) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'b'}; // no \0 is appended
+ check_stpncpy(dst, src, 1, expected, 1);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyNull) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'\0', 'y'};
+ const char expected[] = {'\0', 'b'};
+ check_stpncpy(dst, src, 1, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyPastSrc) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'\0', 'y'};
+ const char expected[] = {'\0', '\0'};
+ check_stpncpy(dst, src, 2, expected, 0);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyTwoNoNull) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'y'};
+ check_stpncpy(dst, src, 2, expected, 2);
+}
+
+TEST_F(LlvmLibcStpncpyTest, CopyTwoWithNull) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', '\0'};
+ const char expected[] = {'x', '\0'};
+ check_stpncpy(dst, src, 2, expected, 1);
+}
diff --git a/libc/test/src/string/strcpy_test.cpp b/libc/test/src/string/strcpy_test.cpp
index 14fa86c994d9..1b6c47741b17 100644
--- a/libc/test/src/string/strcpy_test.cpp
+++ b/libc/test/src/string/strcpy_test.cpp
@@ -9,6 +9,16 @@
#include "src/string/strcpy.h"
#include "utils/UnitTest/Test.h"
+TEST(LlvmLibcStrCpyTest, EmptySrc) {
+ const char *empty = "";
+ char dest[4] = {'a', 'b', 'c', '\0'};
+
+ char *result = __llvm_libc::strcpy(dest, empty);
+ ASSERT_EQ(dest, result);
+ ASSERT_STREQ(dest, result);
+ ASSERT_STREQ(dest, empty);
+}
+
TEST(LlvmLibcStrCpyTest, EmptyDest) {
const char *abc = "abc";
char dest[4];
More information about the libc-commits
mailing list