summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorAlex Brachet <abrachet@google.com>2023-01-11 05:38:33 +0000
committerAlex Brachet <abrachet@google.com>2023-01-11 05:38:33 +0000
commite9d571d3b6829f668e424d9dfce09f9ed7f297d9 (patch)
tree6c83db6dbdad46495432e6982adcc84d88367927 /libc
parentfae63a9a227aa341c4410dbd9e4650844a2c8961 (diff)
downloadllvm-e9d571d3b6829f668e424d9dfce09f9ed7f297d9.tar.gz
[libc] Implement str{,n}casecmp
Differential Revision: https://reviews.llvm.org/D141236
Diffstat (limited to 'libc')
-rw-r--r--libc/config/baremetal/entrypoints.txt2
-rw-r--r--libc/config/darwin/arm/entrypoints.txt2
-rw-r--r--libc/config/gpu/entrypoints.txt2
-rw-r--r--libc/config/linux/aarch64/entrypoints.txt2
-rw-r--r--libc/config/linux/arm/entrypoints.txt2
-rw-r--r--libc/config/linux/x86_64/entrypoints.txt2
-rw-r--r--libc/config/windows/entrypoints.txt2
-rw-r--r--libc/spec/bsd_ext.td20
-rw-r--r--libc/src/__support/ctype_utils.h6
-rw-r--r--libc/src/ctype/tolower.cpp6
-rw-r--r--libc/src/string/CMakeLists.txt22
-rw-r--r--libc/src/string/strcasecmp.cpp25
-rw-r--r--libc/src/string/strcasecmp.h18
-rw-r--r--libc/src/string/strncasecmp.cpp26
-rw-r--r--libc/src/string/strncasecmp.h20
-rw-r--r--libc/test/src/string/CMakeLists.txt20
-rw-r--r--libc/test/src/string/strcasecmp_test.cpp46
-rw-r--r--libc/test/src/string/strcmp_test.cpp11
-rw-r--r--libc/test/src/string/strncasecmp_test.cpp48
-rw-r--r--libc/test/src/string/strncmp_test.cpp11
20 files changed, 288 insertions, 5 deletions
diff --git a/libc/config/baremetal/entrypoints.txt b/libc/config/baremetal/entrypoints.txt
index 6efa4484b8ab..db645c06fe26 100644
--- a/libc/config/baremetal/entrypoints.txt
+++ b/libc/config/baremetal/entrypoints.txt
@@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt
index 4a9af696f728..cf2931963cfa 100644
--- a/libc/config/darwin/arm/entrypoints.txt
+++ b/libc/config/darwin/arm/entrypoints.txt
@@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index 8b058df246c6..57b314f3d231 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -30,6 +30,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -38,6 +39,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 14e0cc934bb2..7223975eb835 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -51,6 +52,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 725365231af5..f4228f120146 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 138c574cf489..2c1c938c5fff 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -40,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -52,6 +53,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 61f28fae5bbc..01c33f9d68d4 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -31,6 +31,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.memset
libc.src.string.stpcpy
libc.src.string.stpncpy
+ libc.src.string.strcasecmp
libc.src.string.strcat
libc.src.string.strchr
libc.src.string.strcmp
@@ -39,6 +40,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strlcat
libc.src.string.strlcpy
libc.src.string.strlen
+ libc.src.string.strncasecmp
libc.src.string.strncat
libc.src.string.strncmp
libc.src.string.strncpy
diff --git a/libc/spec/bsd_ext.td b/libc/spec/bsd_ext.td
index 5779ab79c4f1..9ee07ce4e182 100644
--- a/libc/spec/bsd_ext.td
+++ b/libc/spec/bsd_ext.td
@@ -18,6 +18,25 @@ def BsdExtensions : StandardSpec<"BSDExtensions"> {
]
>;
+ HeaderSpec Strings = HeaderSpec<
+ "strings.h",
+ [], // Macros
+ [], // Types
+ [], // Enumerations
+ [
+ FunctionSpec<
+ "strcasecmp",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>]
+ >,
+ FunctionSpec<
+ "strncasecmp",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<SizeTType>]
+ >,
+ ]
+ >;
+
HeaderSpec SysWait = HeaderSpec<
"sys/wait.h",
[], // Macros
@@ -34,6 +53,7 @@ def BsdExtensions : StandardSpec<"BSDExtensions"> {
let Headers = [
String,
+ Strings,
SysWait,
];
}
diff --git a/libc/src/__support/ctype_utils.h b/libc/src/__support/ctype_utils.h
index f3f4b366d91d..f67398122443 100644
--- a/libc/src/__support/ctype_utils.h
+++ b/libc/src/__support/ctype_utils.h
@@ -36,6 +36,12 @@ static constexpr bool isspace(unsigned ch) {
return ch == ' ' || (ch - '\t') < 5;
}
+static constexpr int tolower(int ch) {
+ if (isupper(ch))
+ return ch + ('a' - 'A');
+ return ch;
+}
+
} // namespace internal
} // namespace __llvm_libc
diff --git a/libc/src/ctype/tolower.cpp b/libc/src/ctype/tolower.cpp
index 8fbb5aaded48..2c4b851a615e 100644
--- a/libc/src/ctype/tolower.cpp
+++ b/libc/src/ctype/tolower.cpp
@@ -15,10 +15,6 @@ namespace __llvm_libc {
// TODO: Currently restricted to default locale.
// These should be extended using locale information.
-LLVM_LIBC_FUNCTION(int, tolower, (int c)) {
- if (internal::isupper(c))
- return c + ('a' - 'A');
- return c;
-}
+LLVM_LIBC_FUNCTION(int, tolower, (int c)) { return internal::tolower(c); }
} // namespace __llvm_libc
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index cdce0bc69ec3..ec61735f4154 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -116,6 +116,17 @@ add_entrypoint_object(
)
add_entrypoint_object(
+ strcasecmp
+ SRCS
+ strcasecmp.cpp
+ HDRS
+ strcasecmp.h
+ DEPENDS
+ .memory_utils.strcmp_implementation
+ libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
strcoll
SRCS
strcoll.cpp
@@ -233,6 +244,17 @@ add_entrypoint_object(
)
add_entrypoint_object(
+ strncasecmp
+ SRCS
+ strncasecmp.cpp
+ HDRS
+ strncasecmp.h
+ DEPENDS
+ .memory_utils.strcmp_implementation
+ libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
strncpy
SRCS
strncpy.cpp
diff --git a/libc/src/string/strcasecmp.cpp b/libc/src/string/strcasecmp.cpp
new file mode 100644
index 000000000000..d7a080aec949
--- /dev/null
+++ b/libc/src/string/strcasecmp.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of strcasecmp --------------------------------------===//
+//
+// 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/strcasecmp.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/string/memory_utils/strcmp_implementations.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, strcasecmp, (const char *left, const char *right)) {
+ auto case_cmp = [](char a, char b) {
+ return __llvm_libc::internal::tolower(a) -
+ __llvm_libc::internal::tolower(b);
+ };
+ return strcmp_implementation(left, right, case_cmp);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/strcasecmp.h b/libc/src/string/strcasecmp.h
new file mode 100644
index 000000000000..ce0a4e5b613c
--- /dev/null
+++ b/libc/src/string/strcasecmp.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for strcasecmp --------------------*- 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_STRCASECMP_H
+#define LLVM_LIBC_SRC_STRING_STRCASECMP_H
+
+namespace __llvm_libc {
+
+int strcasecmp(const char *left, const char *right);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRCASECMP_H
diff --git a/libc/src/string/strncasecmp.cpp b/libc/src/string/strncasecmp.cpp
new file mode 100644
index 000000000000..0fb2f81b17fe
--- /dev/null
+++ b/libc/src/string/strncasecmp.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of strncasecmp -------------------------------------===//
+//
+// 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/strncasecmp.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/string/memory_utils/strcmp_implementations.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, strncasecmp,
+ (const char *left, const char *right, size_t n)) {
+ auto case_cmp = [](char a, char b) {
+ return __llvm_libc::internal::tolower(a) -
+ __llvm_libc::internal::tolower(b);
+ };
+ return strncmp_implementation(left, right, n, case_cmp);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/strncasecmp.h b/libc/src/string/strncasecmp.h
new file mode 100644
index 000000000000..5ef2dcd4cd12
--- /dev/null
+++ b/libc/src/string/strncasecmp.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strcasecmp --------------------*- 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_STRCASECMP_H
+#define LLVM_LIBC_SRC_STRING_STRCASECMP_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+int strncasecmp(const char *left, const char *right, size_t n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRCASECMP_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index b5de08b2fbb0..99dfabbd93a3 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -105,6 +105,16 @@ add_libc_unittest(
)
add_libc_unittest(
+ strcasecmp_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ strcasecmp_test.cpp
+ DEPENDS
+ libc.src.string.strcasecmp
+)
+
+add_libc_unittest(
strcoll_test
SUITE
libc_string_unittests
@@ -219,6 +229,16 @@ add_libc_unittest(
)
add_libc_unittest(
+ strncasecmp_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ strncasecmp_test.cpp
+ DEPENDS
+ libc.src.string.strncasecmp
+)
+
+add_libc_unittest(
strncpy_test
SUITE
libc_string_unittests
diff --git a/libc/test/src/string/strcasecmp_test.cpp b/libc/test/src/string/strcasecmp_test.cpp
new file mode 100644
index 000000000000..a8200104d22c
--- /dev/null
+++ b/libc/test/src/string/strcasecmp_test.cpp
@@ -0,0 +1,46 @@
+//===-- Unittests for strcasecmp ------------------------------------------===//
+//
+// 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/strcasecmp.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcStrCaseCmpTest, EmptyStringsShouldReturnZero) {
+ const char *s1 = "";
+ const char *s2 = "";
+ int result = __llvm_libc::strcasecmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcasecmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcStrCaseCmpTest, EmptyStringShouldNotEqualNonEmptyString) {
+ const char *empty = "";
+ const char *s2 = "abc";
+ int result = __llvm_libc::strcasecmp(empty, s2);
+ // This should be '\0' - 'a' = -97
+ ASSERT_LT(result, 0);
+
+ // Similar case if empty string is second argument.
+ const char *s3 = "123";
+ result = __llvm_libc::strcasecmp(s3, empty);
+ // This should be '1' - '\0' = 49
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcStrCaseCmpTest, Case) {
+ const char *s1 = "aB";
+ const char *s2 = "ab";
+ int result = __llvm_libc::strcasecmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcasecmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
diff --git a/libc/test/src/string/strcmp_test.cpp b/libc/test/src/string/strcmp_test.cpp
index f80cdfa3d44d..9f707dbf1581 100644
--- a/libc/test/src/string/strcmp_test.cpp
+++ b/libc/test/src/string/strcmp_test.cpp
@@ -95,3 +95,14 @@ TEST(LlvmLibcStrCmpTest, StringArgumentSwapChangesSign) {
// 'a' - 'b' = -1.
ASSERT_EQ(result, -1);
}
+
+TEST(LlvmLibcStrCmpTest, Case) {
+ const char *s1 = "aB";
+ const char *s2 = "ab";
+ int result = __llvm_libc::strcmp(s1, s2);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ ASSERT_GT(result, 0);
+}
diff --git a/libc/test/src/string/strncasecmp_test.cpp b/libc/test/src/string/strncasecmp_test.cpp
new file mode 100644
index 000000000000..0188c7fca74e
--- /dev/null
+++ b/libc/test/src/string/strncasecmp_test.cpp
@@ -0,0 +1,48 @@
+//===-- Unittests for strncasecmp -----------------------------------------===//
+//
+// 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/strncasecmp.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcStrNCaseCmpTest,
+ EmptyStringsShouldReturnZeroWithSufficientLength) {
+ const char *s1 = "";
+ const char *s2 = "";
+ int result = __llvm_libc::strncasecmp(s1, s2, 1);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strncasecmp(s2, s1, 1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcStrNCaseCmpTest,
+ EmptyStringShouldNotEqualNonEmptyStringWithSufficientLength) {
+ const char *empty = "";
+ const char *s2 = "abc";
+ int result = __llvm_libc::strncasecmp(empty, s2, 3);
+ // This should be '\0' - 'a' = -97
+ ASSERT_LT(result, 0);
+
+ // Similar case if empty string is second argument.
+ const char *s3 = "123";
+ result = __llvm_libc::strncasecmp(s3, empty, 3);
+ // This should be '1' - '\0' = 49
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcStrNCaseCmpTest, Case) {
+ const char *s1 = "aB";
+ const char *s2 = "ab";
+ int result = __llvm_libc::strncasecmp(s1, s2, 2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strncasecmp(s2, s1, 2);
+ ASSERT_EQ(result, 0);
+}
diff --git a/libc/test/src/string/strncmp_test.cpp b/libc/test/src/string/strncmp_test.cpp
index 8855e0f59db0..52add6b516e8 100644
--- a/libc/test/src/string/strncmp_test.cpp
+++ b/libc/test/src/string/strncmp_test.cpp
@@ -156,3 +156,14 @@ TEST(LlvmLibcStrNCmpTest, StringComparisonEndsOnNullByteEvenWithLongerLength) {
result = __llvm_libc::strncmp(s2, s1, 7);
ASSERT_EQ(result, 0);
}
+
+TEST(LlvmLibcStrNCmpTest, Case) {
+ const char *s1 = "aB";
+ const char *s2 = "ab";
+ int result = __llvm_libc::strncmp(s1, s2, 2);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strncmp(s2, s1, 2);
+ ASSERT_GT(result, 0);
+}