[libc-commits] [libc] ab22f65 - [libc] implement `strings/str{n}casecmp_l` (#130407)
via libc-commits
libc-commits at lists.llvm.org
Tue Mar 11 19:49:08 PDT 2025
Author: Connector Switch
Date: 2025-03-12T10:49:04+08:00
New Revision: ab22f652a4dfcaf5b6884a85e498d7ca077937ca
URL: https://github.com/llvm/llvm-project/commit/ab22f652a4dfcaf5b6884a85e498d7ca077937ca
DIFF: https://github.com/llvm/llvm-project/commit/ab22f652a4dfcaf5b6884a85e498d7ca077937ca.diff
LOG: [libc] implement `strings/str{n}casecmp_l` (#130407)
ref:
https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcasecmp_l.html
This patch introduces the `strcasecmp_l` function. At present, the
locale parameter is ignored, making it a stub implementation. This is
consistent with how other locale-related functions, such as `islower_l`,
are treated in our codebase as well as in
[musl](https://github.com/bminor/musl/blob/master/src/string/strcasecmp.c)
and
[bionic](https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/bionic/strings_l.cpp).
---------
Co-authored-by: Michael Jones <michaelrj at google.com>
Added:
libc/src/strings/strcasecmp_l.cpp
libc/src/strings/strcasecmp_l.h
libc/src/strings/strncasecmp_l.cpp
libc/src/strings/strncasecmp_l.h
libc/test/src/strings/strcasecmp_l_test.cpp
libc/test/src/strings/strncasecmp_l_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/strings.yaml
libc/src/strings/CMakeLists.txt
libc/test/src/strings/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index c7beb3ef3fdfc..ab1917259519b 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -911,6 +911,10 @@ if(LLVM_LIBC_FULL_BUILD)
# sched.h entrypoints
libc.src.sched.__sched_getcpucount
+ # strings.h entrypoints
+ libc.src.strings.strcasecmp_l
+ libc.src.strings.strncasecmp_l
+
# setjmp.h entrypoints
libc.src.setjmp.longjmp
libc.src.setjmp.setjmp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 12dc87bf945fd..a29478898fe70 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -938,6 +938,10 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.string.strcoll_l
libc.src.string.strxfrm_l
+ # strings.h entrypoints
+ libc.src.strings.strcasecmp_l
+ libc.src.strings.strncasecmp_l
+
# assert.h entrypoints
libc.src.assert.__assert_fail
diff --git a/libc/include/strings.yaml b/libc/include/strings.yaml
index 802f6533585f8..855800d9dbc3d 100644
--- a/libc/include/strings.yaml
+++ b/libc/include/strings.yaml
@@ -3,6 +3,7 @@ header_template: strings.h.def
macros: []
types:
- type_name: size_t
+ - type_name: locale_t
enums: []
objects: []
functions:
@@ -68,6 +69,14 @@ functions:
arguments:
- type: const char *
- type: const char *
+ - name: strcasecmp_l
+ standards:
+ - BSDExtensions
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: locale_t
- name: strncasecmp
standards:
- BSDExtensions
@@ -76,3 +85,12 @@ functions:
- type: const char *
- type: const char *
- type: size_t
+ - name: strncasecmp_l
+ standards:
+ - BSDExtensions
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: size_t
+ - type: locale_t
diff --git a/libc/src/strings/CMakeLists.txt b/libc/src/strings/CMakeLists.txt
index 6d86680e8e71f..d312495ae8d91 100644
--- a/libc/src/strings/CMakeLists.txt
+++ b/libc/src/strings/CMakeLists.txt
@@ -115,6 +115,18 @@ add_entrypoint_object(
libc.src.string.memory_utils.inline_strcmp
)
+add_entrypoint_object(
+ strcasecmp_l
+ SRCS
+ strcasecmp_l.cpp
+ HDRS
+ strcasecmp_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+ libc.src.__support.ctype_utils
+ libc.src.string.memory_utils.inline_strcmp
+)
+
add_entrypoint_object(
strncasecmp
SRCS
@@ -125,3 +137,15 @@ add_entrypoint_object(
libc.src.__support.ctype_utils
libc.src.string.memory_utils.inline_strcmp
)
+
+add_entrypoint_object(
+ strncasecmp_l
+ SRCS
+ strncasecmp_l.cpp
+ HDRS
+ strncasecmp_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+ libc.src.__support.ctype_utils
+ libc.src.string.memory_utils.inline_strcmp
+)
diff --git a/libc/src/strings/strcasecmp_l.cpp b/libc/src/strings/strcasecmp_l.cpp
new file mode 100644
index 0000000000000..95117cb27a564
--- /dev/null
+++ b/libc/src/strings/strcasecmp_l.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of strcasecmp_l ------------------------------------===//
+//
+// 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/strings/strcasecmp_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_strcmp.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, strcasecmp_l,
+ (const char *left, const char *right, locale_t)) {
+ auto case_cmp = [](char a, char b) {
+ return LIBC_NAMESPACE::internal::tolower(a) -
+ LIBC_NAMESPACE::internal::tolower(b);
+ };
+ return inline_strcmp(left, right, case_cmp);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/strings/strcasecmp_l.h b/libc/src/strings/strcasecmp_l.h
new file mode 100644
index 0000000000000..48074460205ce
--- /dev/null
+++ b/libc/src/strings/strcasecmp_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strcasecmp_l ------------------*- 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_STRINGS_STRCASECMP_L_H
+#define LLVM_LIBC_SRC_STRINGS_STRCASECMP_L_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int strcasecmp_l(const char *left, const char *right, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STRINGS_STRCASECMP_L_H
diff --git a/libc/src/strings/strncasecmp_l.cpp b/libc/src/strings/strncasecmp_l.cpp
new file mode 100644
index 0000000000000..91ac7e5e89107
--- /dev/null
+++ b/libc/src/strings/strncasecmp_l.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of strncasecmp_l -----------------------------------===//
+//
+// 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/strings/strncasecmp_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_strcmp.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, strncasecmp_l,
+ (const char *left, const char *right, size_t n, locale_t)) {
+ auto case_cmp = [](char a, char b) {
+ return LIBC_NAMESPACE::internal::tolower(a) -
+ LIBC_NAMESPACE::internal::tolower(b);
+ };
+ return inline_strncmp(left, right, n, case_cmp);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/strings/strncasecmp_l.h b/libc/src/strings/strncasecmp_l.h
new file mode 100644
index 0000000000000..6c6c7f17b4438
--- /dev/null
+++ b/libc/src/strings/strncasecmp_l.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for strncasecmp_l -----------------*- 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_STRINGS_STRNCASECMP_L_H
+#define LLVM_LIBC_SRC_STRINGS_STRNCASECMP_L_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+#include <stddef.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int strncasecmp_l(const char *left, const char *right, size_t n,
+ locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STRINGS_STRNCASECMP_L_H
diff --git a/libc/test/src/strings/CMakeLists.txt b/libc/test/src/strings/CMakeLists.txt
index baa22bb449c6c..5f70dc024f6ce 100644
--- a/libc/test/src/strings/CMakeLists.txt
+++ b/libc/test/src/strings/CMakeLists.txt
@@ -74,6 +74,19 @@ add_libc_test(
libc.src.strings.strcasecmp
)
+add_libc_test(
+ strcasecmp_l_test
+ SUITE
+ libc-strings-tests
+ SRCS
+ strcasecmp_l_test.cpp
+ DEPENDS
+ libc.hdr.locale_macros
+ libc.src.locale.freelocale
+ libc.src.locale.newlocale
+ libc.src.strings.strcasecmp_l
+)
+
add_libc_test(
strncasecmp_test
SUITE
@@ -84,5 +97,18 @@ add_libc_test(
libc.src.strings.strncasecmp
)
+add_libc_test(
+ strncasecmp_l_test
+ SUITE
+ libc-strings-tests
+ SRCS
+ strncasecmp_l_test.cpp
+ DEPENDS
+ libc.hdr.locale_macros
+ libc.src.locale.freelocale
+ libc.src.locale.newlocale
+ libc.src.strings.strncasecmp_l
+)
+
add_libc_multi_impl_test(bcmp libc-strings-tests SRCS bcmp_test.cpp)
add_libc_multi_impl_test(bzero libc-strings-tests SRCS bzero_test.cpp)
diff --git a/libc/test/src/strings/strcasecmp_l_test.cpp b/libc/test/src/strings/strcasecmp_l_test.cpp
new file mode 100644
index 0000000000000..33a47b6547d68
--- /dev/null
+++ b/libc/test/src/strings/strcasecmp_l_test.cpp
@@ -0,0 +1,21 @@
+//===-- Unittests for strcasecmp_l ----------------------------------------===//
+//
+// 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 "hdr/locale_macros.h"
+#include "src/locale/freelocale.h"
+#include "src/locale/newlocale.h"
+#include "src/strings/strcasecmp_l.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcStrCaseCmpLTest, Case) {
+ locale_t locale = LIBC_NAMESPACE::newlocale(LC_ALL, "C", nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::strcasecmp_l("hello", "HELLO", locale), 0);
+ ASSERT_LT(LIBC_NAMESPACE::strcasecmp_l("hello1", "hello2", locale), 0);
+ ASSERT_GT(LIBC_NAMESPACE::strcasecmp_l("hello2", "hello1", locale), 0);
+ LIBC_NAMESPACE::freelocale(locale);
+}
diff --git a/libc/test/src/strings/strncasecmp_l_test.cpp b/libc/test/src/strings/strncasecmp_l_test.cpp
new file mode 100644
index 0000000000000..271f31808c7c3
--- /dev/null
+++ b/libc/test/src/strings/strncasecmp_l_test.cpp
@@ -0,0 +1,22 @@
+//===-- Unittests for strncasecmp_l ---------------------------------------===//
+//
+// 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 "hdr/locale_macros.h"
+#include "src/locale/freelocale.h"
+#include "src/locale/newlocale.h"
+#include "src/strings/strncasecmp_l.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcStrNCaseCmpLTest, Case) {
+ locale_t locale = LIBC_NAMESPACE::newlocale(LC_ALL, "C", nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::strncasecmp_l("hello", "HELLO", 3, locale), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::strncasecmp_l("abcXX", "ABCYY", 3, locale), 0);
+ ASSERT_LT(LIBC_NAMESPACE::strncasecmp_l("hello1", "hello2", 6, locale), 0);
+ ASSERT_GT(LIBC_NAMESPACE::strncasecmp_l("hello2", "hello1", 6, locale), 0);
+ LIBC_NAMESPACE::freelocale(locale);
+}
More information about the libc-commits
mailing list