mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 17:46:41 +00:00
[libc] Implement str{,n}casecmp
Differential Revision: https://reviews.llvm.org/D141236
This commit is contained in:
parent
fae63a9a22
commit
e9d571d3b6
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
];
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -115,6 +115,17 @@ add_entrypoint_object(
|
||||
.memory_utils.strcmp_implementation
|
||||
)
|
||||
|
||||
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
|
||||
@ -232,6 +243,17 @@ add_entrypoint_object(
|
||||
.memory_utils.strcmp_implementation
|
||||
)
|
||||
|
||||
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
|
||||
|
25
libc/src/string/strcasecmp.cpp
Normal file
25
libc/src/string/strcasecmp.cpp
Normal file
@ -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
|
18
libc/src/string/strcasecmp.h
Normal file
18
libc/src/string/strcasecmp.h
Normal file
@ -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
|
26
libc/src/string/strncasecmp.cpp
Normal file
26
libc/src/string/strncasecmp.cpp
Normal file
@ -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
|
20
libc/src/string/strncasecmp.h
Normal file
20
libc/src/string/strncasecmp.h
Normal file
@ -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
|
@ -104,6 +104,16 @@ add_libc_unittest(
|
||||
libc.src.string.strcmp
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strcasecmp_test
|
||||
SUITE
|
||||
libc_string_unittests
|
||||
SRCS
|
||||
strcasecmp_test.cpp
|
||||
DEPENDS
|
||||
libc.src.string.strcasecmp
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strcoll_test
|
||||
SUITE
|
||||
@ -218,6 +228,16 @@ add_libc_unittest(
|
||||
libc.src.string.strncmp
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strncasecmp_test
|
||||
SUITE
|
||||
libc_string_unittests
|
||||
SRCS
|
||||
strncasecmp_test.cpp
|
||||
DEPENDS
|
||||
libc.src.string.strncasecmp
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strncpy_test
|
||||
SUITE
|
||||
|
46
libc/test/src/string/strcasecmp_test.cpp
Normal file
46
libc/test/src/string/strcasecmp_test.cpp
Normal file
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
48
libc/test/src/string/strncasecmp_test.cpp
Normal file
48
libc/test/src/string/strncasecmp_test.cpp
Normal file
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user