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 @@ -27,6 +27,7 @@ libc.src.string.strcat libc.src.string.strlen libc.src.string.strcmp + libc.src.string.strdup # sys/mman.h entrypoints libc.src.sys.mman.mmap 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 @@ -44,6 +44,18 @@ libc.include.string ) +add_entrypoint_object( + strdup + SRCS + strdup.cpp + HDRS + strdup.h + DEPENDS + .memcpy + .strlen + libc.include.string +) + # 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/strdup.h b/libc/src/string/strdup.h new file mode 100644 --- /dev/null +++ b/libc/src/string/strdup.h @@ -0,0 +1,20 @@ +//===-- Implementation header for strdup ------------------------*- 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_STRDUP_H +#define LLVM_LIBC_SRC_STRING_STRDUP_H + +#include "include/string.h" + +namespace __llvm_libc { + +char *strdup(const char *src); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_STRDUP_H diff --git a/libc/src/string/strdup.cpp b/libc/src/string/strdup.cpp new file mode 100644 --- /dev/null +++ b/libc/src/string/strdup.cpp @@ -0,0 +1,24 @@ +//===-- Implementation of strdup ------------------------------------------===// +// +// 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/strdup.h" +#include "src/string/memcpy.h" +#include "src/string/strlen.h" +#include + +namespace __llvm_libc { + +char *LLVM_LIBC_ENTRYPOINT(strdup)(const char *src) { + const size_t length = __llvm_libc::strlen(s) + 1; + char *duplicate = new char[length]; + if (!duplicate) + return NULL; + return reinterpret_cast(memcpy(duplicate, s, length)); +} + +} // 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 @@ -42,6 +42,16 @@ libc.src.string.strcmp ) +add_libc_unittest( + strdup_test + SUITE + libc_string_unittests + SRCS + strdup_test.cpp + DEPENDS + libc.src.string.strdup +) + # Tests all implementations that can run on the host. function(add_libc_multi_impl_test name) get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations) diff --git a/libc/test/src/string/strdup_test.cpp b/libc/test/src/string/strdup_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/string/strdup_test.cpp @@ -0,0 +1,27 @@ +//===-- Unittests for strdup ----------------------------------------------===// +// +// 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/strdup.h" + +TEST(StrDupTest, NullTerminatorIsIncluded) { + const char *s = "foobar"; + const char *dup = __llvm_libc::strdup(s); + ASSERT_STREQ(s, dup); +} + +TEST(StrDupTest, DuplicateOfEmptyStringShouldBeEmptyString) { + const char *empty = ""; + const char *dup = __llvm_libc::strdup(empty); + ASSERT_STREQ(empty, dup); +} + +TEST(StrDupTest, DuplicateShouldBeEqualToOriginalString) { + const char *s = "abcd1234"; + const char *dup = __llvm_libc::strdup(s); + ASSERT_STREQ(s, dup); +}