forked from OSchip/llvm-project
[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
This commit is contained in:
parent
a320f877ce
commit
9b6f8b985c
|
@ -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
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue