[libc-commits] [libc] e47d10f - [libc] Add wcscasecmp and wcsncasecmp implementations. (#222154)

via libc-commits libc-commits at lists.llvm.org
Thu Sep 10 11:06:01 PDT 2026


Author: Alex Strelnikov
Date: 2026-09-10T14:05:57-04:00
New Revision: e47d10f55719cb5bc7dac81d49277938813b5ee4

URL: https://github.com/llvm/llvm-project/commit/e47d10f55719cb5bc7dac81d49277938813b5ee4
DIFF: https://github.com/llvm/llvm-project/commit/e47d10f55719cb5bc7dac81d49277938813b5ee4.diff

LOG: [libc] Add wcscasecmp and wcsncasecmp implementations. (#222154)

Add a helper to wctype_utils.h for three-way comparison of individual
`wchar_t`s. As is the case in existing code, `wchar_t` is presumed to be
UTF-32.

Assisted-by: Automated tooling, human reviewed.

Added: 
    libc/src/wchar/wcscasecmp.cpp
    libc/src/wchar/wcscasecmp.h
    libc/src/wchar/wcsncasecmp.cpp
    libc/src/wchar/wcsncasecmp.h
    libc/test/src/wchar/wcscasecmp_test.cpp
    libc/test/src/wchar/wcsncasecmp_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/wchar.yaml
    libc/src/__support/wctype_utils.h
    libc/src/wchar/CMakeLists.txt
    libc/test/src/__support/wctype_utils_test.cpp
    libc/test/src/wchar/CMakeLists.txt
    libc/utils/docgen/wchar.yaml

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index f3a5ea588312f..77610d6d06057 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -464,6 +464,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.write
 
     # wchar.h entrypoints
+    libc.src.wchar.wcscasecmp
+    libc.src.wchar.wcsncasecmp
     libc.src.wchar.wcslen
     libc.src.wchar.wctob
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8a25173e43999..65b820e551be6 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -504,6 +504,8 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # wchar.h entrypoints
     libc.src.wchar.btowc
+    libc.src.wchar.wcscasecmp
+    libc.src.wchar.wcsncasecmp
     libc.src.wchar.wcslen
     libc.src.wchar.wcsnlen
     libc.src.wchar.wctob

diff  --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml
index 1017eb827cf45..2b321f6502ff1 100644
--- a/libc/include/wchar.yaml
+++ b/libc/include/wchar.yaml
@@ -117,6 +117,21 @@ functions:
     arguments:
       - type: const wchar_t *
       - type: const wchar_t *
+  - name: wcscasecmp
+    standards:
+      - posix
+    return_type: int
+    arguments:
+      - type: const wchar_t *
+      - type: const wchar_t *
+  - name: wcsncasecmp
+    standards:
+      - posix
+    return_type: int
+    arguments:
+      - type: const wchar_t *
+      - type: const wchar_t *
+      - type: size_t
   - name: wcscoll
     standards:
       - stdc

diff  --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index 4d0ecd2c1c0dc..633c9139f7369 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
 
 #include "hdr/types/wchar_t.h"
+#include "src/__support/CPP/bit.h"
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"
 
@@ -796,6 +797,17 @@ is_char_or_wchar(wchar_t ch, [[maybe_unused]] char, wchar_t wc_value) {
   return (ch == wc_value);
 }
 
+// Returns a three-way comparison between two wide character code points.
+LIBC_INLINE int threeway_cmp_single(wchar_t left, wchar_t right) {
+  // Valid UTF-32 code points are in [0, 0x10FFFF]. If invalid code points were
+  // treated as UB, the comparison below could done with 32-bit arithmetic.
+  if (left == right)
+    return 0;
+  if (left < right)
+    return -1;
+  return 1;
+}
+
 } // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
 

diff  --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt
index 722619d652500..938b7ad2e4c73 100644
--- a/libc/src/wchar/CMakeLists.txt
+++ b/libc/src/wchar/CMakeLists.txt
@@ -373,6 +373,35 @@ add_entrypoint_object(
     libc.hdr.types.size_t
 )
 
+add_entrypoint_object(
+  wcscasecmp
+  SRCS
+    wcscasecmp.cpp
+  HDRS
+    wcscasecmp.h
+  DEPENDS
+    libc.hdr.types.wchar_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.null_check
+    libc.src.__support.wctype_utils
+)
+
+add_entrypoint_object(
+  wcsncasecmp
+  SRCS
+    wcsncasecmp.cpp
+  HDRS
+    wcsncasecmp.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.hdr.types.wchar_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.null_check
+    libc.src.__support.wctype_utils
+)
+
 add_entrypoint_object(
   wcsspn
   SRCS

diff  --git a/libc/src/wchar/wcscasecmp.cpp b/libc/src/wchar/wcscasecmp.cpp
new file mode 100644
index 0000000000000..29c938c549a4a
--- /dev/null
+++ b/libc/src/wchar/wcscasecmp.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the wcscasecmp function implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/wcscasecmp.h"
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/wctype_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, wcscasecmp,
+                   (const wchar_t *left, const wchar_t *right)) {
+  LIBC_CRASH_ON_NULLPTR(left);
+  LIBC_CRASH_ON_NULLPTR(right);
+
+  for (;; ++left, ++right) {
+    wchar_t lc = *left;
+    if (lc == L'\0' || internal::tolower(lc) != internal::tolower(*right))
+      break;
+  }
+  return internal::threeway_cmp_single(internal::tolower(*left),
+                                       internal::tolower(*right));
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/wchar/wcscasecmp.h b/libc/src/wchar/wcscasecmp.h
new file mode 100644
index 0000000000000..51a6f1b415c56
--- /dev/null
+++ b/libc/src/wchar/wcscasecmp.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the wcscasecmp function declaration.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_WCSCASECMP_H
+#define LLVM_LIBC_SRC_WCHAR_WCSCASECMP_H
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int wcscasecmp(const wchar_t *left, const wchar_t *right);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSCASECMP_H

diff  --git a/libc/src/wchar/wcsncasecmp.cpp b/libc/src/wchar/wcsncasecmp.cpp
new file mode 100644
index 0000000000000..2fc29ff972896
--- /dev/null
+++ b/libc/src/wchar/wcsncasecmp.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the wcsncasecmp function implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/wcsncasecmp.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/wctype_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, wcsncasecmp,
+                   (const wchar_t *left, const wchar_t *right, size_t n)) {
+  LIBC_CRASH_ON_NULLPTR(left);
+  LIBC_CRASH_ON_NULLPTR(right);
+
+  if (n == 0)
+    return 0;
+
+  for (; n > 1; --n, ++left, ++right) {
+    wchar_t lc = *left;
+    if (lc == L'\0' || internal::tolower(lc) != internal::tolower(*right))
+      break;
+  }
+  return internal::threeway_cmp_single(internal::tolower(*left),
+                                       internal::tolower(*right));
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/wchar/wcsncasecmp.h b/libc/src/wchar/wcsncasecmp.h
new file mode 100644
index 0000000000000..754ac54ec2ae2
--- /dev/null
+++ b/libc/src/wchar/wcsncasecmp.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the wcsncasecmp function declaration.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_WCSNCASECMP_H
+#define LLVM_LIBC_SRC_WCHAR_WCSNCASECMP_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int wcsncasecmp(const wchar_t *left, const wchar_t *right, size_t n);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSNCASECMP_H

diff  --git a/libc/test/src/__support/wctype_utils_test.cpp b/libc/test/src/__support/wctype_utils_test.cpp
index b2140ab72a3be..ae4770a7765a2 100644
--- a/libc/test/src/__support/wctype_utils_test.cpp
+++ b/libc/test/src/__support/wctype_utils_test.cpp
@@ -553,4 +553,22 @@ TEST(LlvmLibcWctypeUtilsTest, IsCntrlUtf8) {
   }
 }
 
+TEST(LlvmLibcWctypeUtilsTest, ThreewayCmpSingle) {
+  using utf8_mode::LIBC_NAMESPACE::internal::threeway_cmp_single;
+
+  EXPECT_EQ(threeway_cmp_single(L'A', L'A'), 0);
+
+  EXPECT_LT(threeway_cmp_single(wchar_t{67}, wchar_t{120}), 0);
+  EXPECT_GT(threeway_cmp_single(wchar_t{120}, wchar_t{67}), 0);
+
+  EXPECT_LT(threeway_cmp_single(wchar_t{1}, WCHAR_MAX), 0);
+  EXPECT_GT(threeway_cmp_single(WCHAR_MAX, wchar_t{1}), 0);
+
+  EXPECT_LT(threeway_cmp_single(WCHAR_MIN, wchar_t{1}), 0);
+  EXPECT_GT(threeway_cmp_single(wchar_t{1}, WCHAR_MIN), 0);
+
+  EXPECT_LT(threeway_cmp_single(WCHAR_MIN, WCHAR_MAX), 0);
+  EXPECT_GT(threeway_cmp_single(WCHAR_MAX, WCHAR_MIN), 0);
+}
+
 } // namespace

diff  --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt
index 1183d5c44d685..d511a1f0f4541 100644
--- a/libc/test/src/wchar/CMakeLists.txt
+++ b/libc/test/src/wchar/CMakeLists.txt
@@ -221,6 +221,28 @@ add_libc_test(
     libc.src.wchar.wcsncmp
 )
 
+add_libc_test(
+  wcscasecmp_test
+  SUITE
+    libc_wchar_unittests
+  SRCS
+    wcscasecmp_test.cpp
+  DEPENDS
+    libc.src.__support.wctype_utils
+    libc.src.wchar.wcscasecmp
+)
+
+add_libc_test(
+  wcsncasecmp_test
+  SUITE
+    libc_wchar_unittests
+  SRCS
+    wcsncasecmp_test.cpp
+  DEPENDS
+    libc.src.__support.wctype_utils
+    libc.src.wchar.wcsncasecmp
+)
+
 add_libc_test(
   wcscmp_test
   SUITE

diff  --git a/libc/test/src/wchar/wcscasecmp_test.cpp b/libc/test/src/wchar/wcscasecmp_test.cpp
new file mode 100644
index 0000000000000..0e9af12fc1174
--- /dev/null
+++ b/libc/test/src/wchar/wcscasecmp_test.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains unit tests for wcscasecmp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/wctype_utils.h"
+#include "src/wchar/wcscasecmp.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWcscasecmpTest, EmptyStrings) {
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"", L""), 0);
+}
+
+TEST(LlvmLibcWcscasecmpTest, EmptyVsNonEmptyStrings) {
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"", L"a"), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"a", L""), 0);
+}
+
+TEST(LlvmLibcWcscasecmpTest, Substrings) {
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"aβc", L"aβ"), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"aβc", L"a"), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"aβc", L""), 0);
+
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"aβ", L"aβc"), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"a", L"aβc"), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"", L"aβc"), 0);
+}
+
+TEST(LlvmLibcWcscasecmpTest, MatchingStringsIgnoreCase) {
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abc", L"abc"), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"Abc", L"abc"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"aBc", L"abc"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abC", L"abc"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"ABC", L"abc"), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abc", L"Abc"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abc", L"aBc"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abc", L"abC"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"abc", L"ABC"), 0);
+
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"Βγδ", L"βγδ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βΓδ", L"βγδ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βγΔ", L"βγδ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"ΒΓΔ", L"βγδ"), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βγδ", L"Βγδ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βγδ", L"βΓδ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βγδ", L"βγΔ"), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcscasecmp(L"βγδ", L"ΒΓΔ"), 0);
+#endif // LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+}
+
+TEST(LlvmLibcWcscasecmpTest, NonMatchingStrings) {
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"Δbc", L"abc"), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"aΔc", L"abc"), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcscasecmp(L"abΔ", L"abc"), 0);
+
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"abc", L"Δbc"), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"abc", L"aΔc"), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcscasecmp(L"abc", L"abΔ"), 0);
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcWcscasecmpTest, CrashOnNullPtr) {
+  EXPECT_DEATH([] { LIBC_NAMESPACE::wcscasecmp(L"hello", nullptr); },
+               WITH_SIGNAL(-1));
+  EXPECT_DEATH([] { LIBC_NAMESPACE::wcscasecmp(nullptr, L"hello"); },
+               WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS

diff  --git a/libc/test/src/wchar/wcsncasecmp_test.cpp b/libc/test/src/wchar/wcsncasecmp_test.cpp
new file mode 100644
index 0000000000000..dec2ec8255638
--- /dev/null
+++ b/libc/test/src/wchar/wcsncasecmp_test.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains unit tests for wcsncasecmp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/limits_macros.h"
+#include "src/__support/wctype_utils.h"
+#include "src/wchar/wcsncasecmp.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWcsncasecmpTest, EmptyStrings) {
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"", L"", 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"", L"", INT_MAX), 0);
+}
+
+TEST(LlvmLibcWcsncasecmpTest, EmptyVsNonEmptyStringsUnlimited) {
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"", L"a", INT_MAX), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"a", L"", INT_MAX), 0);
+}
+
+TEST(LlvmLibcWcsncasecmpTest, SubstringsUnlimited) {
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"aβc", L"aβ", INT_MAX), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"aβc", L"a", INT_MAX), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"aβc", L"", INT_MAX), 0);
+
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"aβ", L"aβc", INT_MAX), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"a", L"aβc", INT_MAX), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"", L"aβc", INT_MAX), 0);
+}
+
+TEST(LlvmLibcWcsncasecmpTest, MatchingStringsIgnoreCaseUnlimited) {
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"abc", INT_MAX), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"Abc", L"abc", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"aBc", L"abc", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abC", L"abc", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"ABC", L"abc", INT_MAX), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"Abc", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"aBc", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"abC", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"ABC", INT_MAX), 0);
+
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"Βγδ", L"βγδ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βΓδ", L"βγδ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγΔ", L"βγδ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"ΒΓΔ", L"βγδ", INT_MAX), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"Βγδ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"βΓδ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"βγΔ", INT_MAX), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"ΒΓΔ", INT_MAX), 0);
+#endif // LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+}
+
+TEST(LlvmLibcWcsncasecmpTest, NonMatchingStringsUnlimited) {
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"Δbc", L"abc", INT_MAX), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"aΔc", L"abc", INT_MAX), 0);
+  EXPECT_GT(LIBC_NAMESPACE::wcsncasecmp(L"abΔ", L"abc", INT_MAX), 0);
+
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"Δbc", INT_MAX), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"aΔc", INT_MAX), 0);
+  EXPECT_LT(LIBC_NAMESPACE::wcsncasecmp(L"abc", L"abΔ", INT_MAX), 0);
+}
+
+TEST(LlvmLibcWcsncasecmpTest, CompareAtMostStartingMatch) {
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"", 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"", L"def", 0), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"def", 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"βde", 1), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::wcsncasecmp(L"βγδ", L"βγd", 2), 0);
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcWcsncasecmpTest, CrashOnNullPtr) {
+  EXPECT_DEATH([] { LIBC_NAMESPACE::wcsncasecmp(L"hello", nullptr, 1); },
+               WITH_SIGNAL(-1));
+  EXPECT_DEATH([] { LIBC_NAMESPACE::wcsncasecmp(nullptr, L"hello", 1); },
+               WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS

diff  --git a/libc/utils/docgen/wchar.yaml b/libc/utils/docgen/wchar.yaml
index dcc8963efdd35..85bfbe31085d1 100644
--- a/libc/utils/docgen/wchar.yaml
+++ b/libc/utils/docgen/wchar.yaml
@@ -57,6 +57,10 @@ functions:
     c-definition: 7.31.4.6.2
   wcscmp:
     c-definition: 7.31.4.5.2
+  wcscasecmp:
+    in-latest-posix: ''
+  wcsncasecmp:
+    in-latest-posix: ''
   wcscoll:
     c-definition: 7.31.4.5.3
   wcscpy:


        


More information about the libc-commits mailing list