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 @@ -26,6 +26,7 @@ libc.src.string.strcpy libc.src.string.strcat libc.src.string.strlen + libc.src.string.strcmp # 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 @@ -34,6 +34,16 @@ libc.include.string ) +add_entrypoint_object( + strcmp + SRCS + strcmp.cpp + HDRS + strcmp.h + DEPENDS + 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/strcmp.h b/libc/src/string/strcmp.h new file mode 100644 --- /dev/null +++ b/libc/src/string/strcmp.h @@ -0,0 +1,20 @@ +//===-- Implementation header for strcmp ------------------------*- 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_STRCMP_H +#define LLVM_LIBC_SRC_STRING_STRCMP_H + +#include "include/string.h" + +namespace __llvm_libc { + +int strcmp(const char *l, const char *r); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_STRCMP_H diff --git a/libc/src/string/strcmp.cpp b/libc/src/string/strcmp.cpp new file mode 100644 --- /dev/null +++ b/libc/src/string/strcmp.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of strcmp ------------------------------------------===// +// +// 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/strcmp.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +int LLVM_LIBC_ENTRYPOINT(strcmp)(const char *l, const char *r) { + while (*l) { + if (*l != *r) + break; + ++l; + ++r; + } + return *(const unsigned char *)l - *(const unsigned char *)r; +} + +} // 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 @@ -32,6 +32,16 @@ libc.src.string.strlen ) +add_libc_unittest( + strcmp_test + SUITE + libc_string_unittests + SRCS + strcmp_test.cpp + DEPENDS + libc.src.string.strcmp +) + # 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/strcmp_test.cpp b/libc/test/src/string/strcmp_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/string/strcmp_test.cpp @@ -0,0 +1,74 @@ +//===-- Unittests for strcmp ----------------------------------------------===// +// +// 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/strcmp.h" +#include "utils/UnitTest/Test.h" + +TEST(StrCmpTest, EmptyStringsShouldReturnZero) { + const char *s1 = ""; + const char *s2 = ""; + const int result = __llvm_libc::strcmp(s1, s2); + ASSERT_EQ(result, 0); +} + +TEST(StrCmpTest, EmptyStringShouldNotEqualNonEmptyString) { + const char *empty = ""; + const char *s2 = "abc"; + int result = __llvm_libc::strcmp(empty, s2); + // This should be '\0' - 'a' = -97 + ASSERT_EQ(result, -97); + + // Similar case if empty string is second argument. + const char *s3 = "123"; + result = __llvm_libc::strcmp(s3, empty); + // This should be '1' - '\0' = 49 + ASSERT_EQ(result, 49); +} + +TEST(StrCmpTest, EqualStringsShouldReturnZero) { + const char *s1 = "abc"; + const char *s2 = "abc"; + const int result = __llvm_libc::strcmp(s1, s2); + ASSERT_EQ(result, 0); +} + +TEST(StrCmpTest, ShouldReturnResultOfFirstDifference) { + const char *s1 = "___B42__"; + const char *s2 = "___C55__"; + const int result = __llvm_libc::strcmp(s1, s2); + // This should return 'B' - 'C' = -1. + ASSERT_EQ(result, -1); +} + +TEST(StrCmpTest, CapitalizedLetterShouldNotBeEqual) { + const char *s1 = "abcd"; + const char *s2 = "abCd"; + const int result = __llvm_libc::strcmp(s1, s2); + // 'c' - 'C' = 32. + ASSERT_EQ(result, 32); +} + +TEST(StrCmpTest, UnequalLengthStringsShouldNotReturnZero) { + const char *s1 = "abc"; + const char *s2 = "abcd"; + const int result = __llvm_libc::strcmp(s1, s2); + // '\0' - 'd' = -100. + ASSERT_EQ(result, -100); +} + +TEST(StrCmpTest, StringArgumentSwapChangesSign) { + const char *a = "a"; + const char *b = "b"; + int result = __llvm_libc::strcmp(b, a); + // 'b' - 'a' = 1. + ASSERT_EQ(result, 1); + + result = __llvm_libc::strcmp(a, b); + // 'a' - 'b' = -1. + ASSERT_EQ(result, -1); +}