[libc-commits] [libc] [libc] Add iswctype and wctype (PR #191178)
Zile Xiong via libc-commits
libc-commits at lists.llvm.org
Thu Apr 9 07:59:54 PDT 2026
https://github.com/xiongzile updated https://github.com/llvm/llvm-project/pull/191178
>From 760a5bb9e9a0968f48f2923057e1ae675287baf9 Mon Sep 17 00:00:00 2001
From: Zile Xiong <xiongzile99 at gmail.com>
Date: Thu, 9 Apr 2026 15:03:36 +0800
Subject: [PATCH] [libc] Add iswctype and wctype
Implement the iswctype and wctype functions from <wctype.h>.
- Add wctype_t type definition.
- Implement wctype to map property strings to classification descriptors.
- Implement iswctype as a dispatcher over existing wide character
classification functions.
- Add corresponding entrypoints and unit tests.
Refs: https://github.com/llvm/llvm-project/issues/191076
---
libc/config/baremetal/arm/entrypoints.txt | 2 +
libc/config/baremetal/riscv/entrypoints.txt | 2 +
libc/config/darwin/aarch64/entrypoints.txt | 2 +
libc/config/linux/aarch64/entrypoints.txt | 2 +
libc/config/linux/arm/entrypoints.txt | 2 +
libc/config/linux/riscv/entrypoints.txt | 2 +
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/config/windows/entrypoints.txt | 2 +
libc/hdr/types/CMakeLists.txt | 9 ++
libc/hdr/types/wctype_t.h | 24 +++++
libc/hdr/wctype_overlay.h | 69 ++++++++++++
libc/include/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/wctype_t.h | 15 +++
libc/include/wctype.yaml | 14 +++
libc/src/__support/wctype_utils.h | 79 ++++++++++++++
libc/src/wctype/CMakeLists.txt | 21 ++++
libc/src/wctype/iswctype.cpp | 23 ++++
libc/src/wctype/iswctype.h | 22 ++++
libc/src/wctype/wctype.cpp | 21 ++++
libc/src/wctype/wctype.h | 22 ++++
libc/test/src/wctype/CMakeLists.txt | 20 ++++
libc/test/src/wctype/iswctype_test.cpp | 110 ++++++++++++++++++++
libc/test/src/wctype/wctype_test.cpp | 63 +++++++++++
24 files changed, 530 insertions(+)
create mode 100644 libc/hdr/types/wctype_t.h
create mode 100644 libc/hdr/wctype_overlay.h
create mode 100644 libc/include/llvm-libc-types/wctype_t.h
create mode 100644 libc/src/wctype/iswctype.cpp
create mode 100644 libc/src/wctype/iswctype.h
create mode 100644 libc/src/wctype/wctype.cpp
create mode 100644 libc/src/wctype/wctype.h
create mode 100644 libc/test/src/wctype/iswctype_test.cpp
create mode 100644 libc/test/src/wctype/wctype_test.cpp
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 4cf34764916f7..a2c22ac32e3ac 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -313,6 +313,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
# internal entrypoints
libc.startup.baremetal.init
libc.startup.baremetal.fini
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index c4a11c6f87337..d5fc6258aff11 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -310,6 +310,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
# internal entrypoints
libc.startup.baremetal.init
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 0888f4b0d922b..033183427de79 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -113,6 +113,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
)
if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 567848795be49..73d1b5d307a97 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -385,6 +385,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
# sys/uio.h entrypoints
libc.src.sys.uio.writev
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 31dcb31c67c7a..997263f364524 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -205,6 +205,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
)
if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 997c08ee7de9b..4c12be578b0e5 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -389,6 +389,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
# sys/uio.h entrypoints
libc.src.sys.uio.writev
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ea1cd80a1d0f1..9bf2248e49dd9 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -439,6 +439,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
# sys/uio.h entrypoints
libc.src.sys.uio.writev
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index e8080bc97c59a..7d32fab21fdb4 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -119,6 +119,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswxdigit
libc.src.wctype.iswpunct
libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
)
set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 7e1a8974fa486..7395f70c0d2aa 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -443,6 +443,15 @@ add_proxy_header_library(
libc.include.wchar
)
+
+add_proxy_header_library(
+ wctype_t
+ HDRS
+ wctype_t.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.wctype_t
+)
+
add_proxy_header_library(
uid_t
HDRS
diff --git a/libc/hdr/types/wctype_t.h b/libc/hdr/types/wctype_t.h
new file mode 100644
index 0000000000000..f8e09969227dd
--- /dev/null
+++ b/libc/hdr/types/wctype_t.h
@@ -0,0 +1,24 @@
+//===-- Definition of wctype_t.h
+//--------------------------------------------===//
+//
+// 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_HDR_TYPES_WCTYPE_T_H
+#define LLVM_LIBC_HDR_TYPES_WCTYPE_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/wctype_t.h"
+
+#else // overlay mode
+
+#include "hdr/wctype_overlay.h"
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_WCTYPE_T_H
diff --git a/libc/hdr/wctype_overlay.h b/libc/hdr/wctype_overlay.h
new file mode 100644
index 0000000000000..6249d9f7242ed
--- /dev/null
+++ b/libc/hdr/wctype_overlay.h
@@ -0,0 +1,69 @@
+//===-- Including wctype.h in overlay mode ---------------------------------===//
+//
+// 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_HDR_WCTYPE_OVERLAY_H
+#define LLVM_LIBC_HDR_WCTYPE_OVERLAY_H
+
+#ifdef LIBC_FULL_BUILD
+#error "This header should only be included in overlay mode"
+#endif
+
+// Overlay mode
+
+// glibc <wctype.h> header might provide extern inline definitions for few
+// functions, causing external alias errors. They are guarded by
+// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES`
+// macro by defining `__NO_INLINE__` before including <wctype.h>.
+// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled
+// with `_FORTIFY_SOURCE`.
+
+#ifdef _FORTIFY_SOURCE
+#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+
+#ifndef __NO_INLINE__
+#define __NO_INLINE__ 1
+#define LIBC_SET_NO_INLINE
+#endif
+
+#ifdef __USE_EXTERN_INLINES
+#define LIBC_OLD_USE_EXTERN_INLINES
+#undef __USE_EXTERN_INLINES
+#endif
+
+#ifdef __USE_FORTIFY_LEVEL
+#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL
+#undef __USE_FORTIFY_LEVEL
+#define __USE_FORTIFY_LEVEL 0
+#endif
+
+#include <wctype.h>
+
+#ifdef LIBC_OLD_FORTIFY_SOURCE
+#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE
+#undef LIBC_OLD_FORTIFY_SOURCE
+#endif
+
+#ifdef LIBC_SET_NO_INLINE
+#undef __NO_INLINE__
+#undef LIBC_SET_NO_INLINE
+#endif
+
+#ifdef LIBC_OLD_USE_FORTIFY_LEVEL
+#undef __USE_FORTIFY_LEVEL
+#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL
+#undef LIBC_OLD_USE_FORTIFY_LEVEL
+#endif
+
+#ifdef LIBC_OLD_USE_EXTERN_INLINES
+#define __USE_EXTERN_INLINES
+#undef LIBC_OLD_USE_EXTERN_INLINES
+#endif
+
+#endif // LLVM_LIBC_HDR_WCTYPE_OVERLAY_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 3375e4e21e338..66c5a0e6462c5 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -867,6 +867,7 @@ add_header_macro(
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.wint_t
+ .llvm-libc-types.wctype_t
)
add_header_macro(
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 0d6bc0982b847..ea9a507836735 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -166,6 +166,7 @@ add_header(
libc.include.llvm-libc-macros.stdint_macros
)
add_header(wint_t HDR wint_t.h)
+add_header(wctype_t HDR wctype_t.h)
add_header(sa_family_t HDR sa_family_t.h)
add_header(socklen_t HDR socklen_t.h)
add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t)
diff --git a/libc/include/llvm-libc-types/wctype_t.h b/libc/include/llvm-libc-types/wctype_t.h
new file mode 100644
index 0000000000000..b096c0061984a
--- /dev/null
+++ b/libc/include/llvm-libc-types/wctype_t.h
@@ -0,0 +1,15 @@
+//===-- Definition of wctype_t types
+//----------------------------------------===//
+//
+// 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_TYPES_WCTYPE_T_H
+#define LLVM_LIBC_TYPES_WCTYPE_T_H
+
+typedef unsigned int wctype_t;
+
+#endif // LLVM_LIBC_TYPES_WCTYPE_T_H
diff --git a/libc/include/wctype.yaml b/libc/include/wctype.yaml
index 932ff6ac1b138..a5163ecc2d3f2 100644
--- a/libc/include/wctype.yaml
+++ b/libc/include/wctype.yaml
@@ -1,6 +1,7 @@
header: wctype.h
types:
- type_name: wint_t
+ - type_name: wctype_t
functions:
- name: iswalpha
standards:
@@ -74,3 +75,16 @@ functions:
return_type: int
arguments:
- type: wint_t
+ - name: iswctype
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: wint_t
+ - type: wctype_t
+ - name: wctype
+ standards:
+ - stdc
+ return_type: wctype_t
+ arguments:
+ - type: const char*
diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index a80c78d54c796..fd6a0ec9f4f8d 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -454,6 +454,77 @@ LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
}
}
+LIBC_INLINE constexpr int simple_strcmp(const char *s1, const char *s2) {
+ while (*s1 && (*s1 == *s2)) {
+ ++s1;
+ ++s2;
+ }
+ return *(const char *)s1 - *(const char *)s2;
+}
+
+LIBC_INLINE constexpr unsigned int wctype(const char *property) {
+ if (!property)
+ return 0; // WCTYPE_INVALID
+
+ if (simple_strcmp(property, "alnum") == 0)
+ return 1; // WCTYPE_ALNUM
+ if (simple_strcmp(property, "alpha") == 0)
+ return 2; // WCTYPE_ALPHA
+ if (simple_strcmp(property, "blank") == 0)
+ return 3; // WCTYPE_BLANK
+ if (simple_strcmp(property, "cntrl") == 0)
+ return 4; // WCTYPE_CNTRL
+ if (simple_strcmp(property, "digit") == 0)
+ return 5; // WCTYPE_DIGIT
+ if (simple_strcmp(property, "graph") == 0)
+ return 6; // WCTYPE_GRAPH
+ if (simple_strcmp(property, "lower") == 0)
+ return 7; // WCTYPE_LOWER
+ if (simple_strcmp(property, "print") == 0)
+ return 8; // WCTYPE_PRINT
+ if (simple_strcmp(property, "punct") == 0)
+ return 9; // WCTYPE_PUNCT
+ if (simple_strcmp(property, "space") == 0)
+ return 10; // WCTYPE_SPACE
+ if (simple_strcmp(property, "upper") == 0)
+ return 11; // WCTYPE_UPPER
+ if (simple_strcmp(property, "xdigit") == 0)
+ return 12; // WCTYPE_XDIGIT
+
+ return 0; // WCTYPE_INVALID
+}
+
+LIBC_INLINE constexpr int iswctype(wchar_t c, unsigned int desc) {
+ switch (desc) {
+ case 1:
+ return isalnum(c); // alnum
+ case 2:
+ return isalpha(c); // alpha
+ case 3:
+ return isblank(c); // blank
+ case 4:
+ return iscntrl(c); // cntrl
+ case 5:
+ return isdigit(c); // digit
+ case 6:
+ return isgraph(c); // graph
+ case 7:
+ return islower(c); // lower
+ case 8:
+ return isprint(c); // print
+ case 9:
+ return ispunct(c); // punct
+ case 10:
+ return isspace(c); // space
+ case 11:
+ return isupper(c); // upper
+ case 12:
+ return isxdigit(c); // xdigit
+ default:
+ return 0;
+ }
+}
+
} // namespace ascii
LIBC_INLINE constexpr bool islower(wchar_t wch) {
@@ -552,6 +623,14 @@ LIBC_INLINE constexpr bool isprint(wchar_t wch) {
#endif
}
+LIBC_INLINE constexpr bool iswctype(wchar_t c, unsigned int desc) {
+ return ascii::iswctype(c, desc);
+}
+
+LIBC_INLINE constexpr unsigned int wctype(const char *property) {
+ return ascii::wctype(property);
+}
+
LIBC_INLINE constexpr bool isxdigit(wchar_t wch) {
// Hexadecimal digits are the same in C.UTF8 as in ASCII
return ascii::isxdigit(wch);
diff --git a/libc/src/wctype/CMakeLists.txt b/libc/src/wctype/CMakeLists.txt
index 07bfed39980c2..57f9e7753a9f5 100644
--- a/libc/src/wctype/CMakeLists.txt
+++ b/libc/src/wctype/CMakeLists.txt
@@ -130,3 +130,24 @@ add_entrypoint_object(
libc.src.__support.wctype_utils
libc.hdr.types.wint_t
)
+
+add_entrypoint_object(
+ iswctype
+ SRCS
+ iswctype.cpp
+ HDRS
+ iswctype.h
+ DEPENDS
+ libc.src.__support.wctype_utils
+ libc.hdr.types.wint_t
+)
+
+add_entrypoint_object(
+ wctype
+ SRCS
+ wctype.cpp
+ HDRS
+ wctype.h
+ DEPENDS
+ libc.src.__support.wctype_utils
+)
diff --git a/libc/src/wctype/iswctype.cpp b/libc/src/wctype/iswctype.cpp
new file mode 100644
index 0000000000000..87bf0e31fe463
--- /dev/null
+++ b/libc/src/wctype/iswctype.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of iswctype ----------------------------------------===//
+//
+// 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/wctype/iswctype.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, iswctype, (wint_t c, wctype_t desc)) {
+ return internal::iswctype(static_cast<wchar_t>(c),
+ static_cast<unsigned int>(desc));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/iswctype.h b/libc/src/wctype/iswctype.h
new file mode 100644
index 0000000000000..10a0f3e969c8d
--- /dev/null
+++ b/libc/src/wctype/iswctype.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for iswctype ----------------------*- 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_WCTYPE_ISWCTYPE_H
+#define LLVM_LIBC_SRC_WCTYPE_ISWCTYPE_H
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int iswctype(wint_t c, wctype_t desc);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_ISWCTYPE_H
diff --git a/libc/src/wctype/wctype.cpp b/libc/src/wctype/wctype.cpp
new file mode 100644
index 0000000000000..59c28dcf5a437
--- /dev/null
+++ b/libc/src/wctype/wctype.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of wctype ----------------------------------------===//
+//
+// 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/wctype/wctype.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+#include "hdr/types/wctype_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wctype_t, wctype, (const char *property)) {
+ return internal::wctype(property);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/wctype.h b/libc/src/wctype/wctype.h
new file mode 100644
index 0000000000000..98300e49f7e03
--- /dev/null
+++ b/libc/src/wctype/wctype.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for iswctype ----------------------*- 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_WCTYPE_WCTYPE_H
+#define LLVM_LIBC_SRC_WCTYPE_WCTYPE_H
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wctype_t wctype(const char *property);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_WCTYPE_H
diff --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index a5f85856dfb38..2d02888ad2833 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -121,3 +121,23 @@ add_libc_test(
DEPENDS
libc.src.wctype.iswprint
)
+
+add_libc_test(
+ iswctype_test
+ SUITE
+ libc_wctype_unittests
+ SRCS
+ iswctype_test.cpp
+ DEPENDS
+ libc.src.wctype.iswctype
+)
+
+add_libc_test(
+ wctype_test
+ SUITE
+ libc_wctype_unittests
+ SRCS
+ wctype_test.cpp
+ DEPENDS
+ libc.src.wctype.wctype
+)
diff --git a/libc/test/src/wctype/iswctype_test.cpp b/libc/test/src/wctype/iswctype_test.cpp
new file mode 100644
index 0000000000000..39ff350ab6673
--- /dev/null
+++ b/libc/test/src/wctype/iswctype_test.cpp
@@ -0,0 +1,110 @@
+//===-- Unittests for iswctype --------------------------------------------===//
+//
+// 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/wctype/iswctype.h"
+
+#include "test/UnitTest/Test.h"
+
+// Simple tests, already properly tested in
+// libc/test/src/__support/wctype_utils_test.cpp
+
+static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
+static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
+static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
+static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
+static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
+static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
+static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
+static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
+static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
+static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
+static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
+static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
+static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
+
+TEST(LlvmLibciswctype, SimpleTest) {
+ using LIBC_NAMESPACE::iswctype;
+
+ // alnum
+ EXPECT_NE(iswctype('a', WCTYPE_ALNUM), 0);
+ EXPECT_NE(iswctype('Z', WCTYPE_ALNUM), 0);
+ EXPECT_NE(iswctype('5', WCTYPE_ALNUM), 0);
+ EXPECT_EQ(iswctype('!', WCTYPE_ALNUM), 0);
+
+ // alpha
+ EXPECT_NE(iswctype('a', WCTYPE_ALPHA), 0);
+ EXPECT_NE(iswctype('Z', WCTYPE_ALPHA), 0);
+ EXPECT_EQ(iswctype('1', WCTYPE_ALPHA), 0);
+ EXPECT_EQ(iswctype(' ', WCTYPE_ALPHA), 0);
+
+ // blank
+ EXPECT_NE(iswctype(' ', WCTYPE_BLANK), 0);
+ EXPECT_NE(iswctype('\t', WCTYPE_BLANK), 0);
+ EXPECT_EQ(iswctype('\n', WCTYPE_BLANK), 0);
+ EXPECT_EQ(iswctype('A', WCTYPE_BLANK), 0);
+
+ // cntrl
+ EXPECT_NE(iswctype('\0', WCTYPE_CNTRL), 0);
+ EXPECT_NE(iswctype('\n', WCTYPE_CNTRL), 0);
+ EXPECT_NE(iswctype(0x7f, WCTYPE_CNTRL), 0);
+ EXPECT_EQ(iswctype('A', WCTYPE_CNTRL), 0);
+
+ // digit
+ EXPECT_NE(iswctype('0', WCTYPE_DIGIT), 0);
+ EXPECT_NE(iswctype('9', WCTYPE_DIGIT), 0);
+ EXPECT_EQ(iswctype('a', WCTYPE_DIGIT), 0);
+ EXPECT_EQ(iswctype(' ', WCTYPE_DIGIT), 0);
+
+ // graph
+ EXPECT_NE(iswctype('A', WCTYPE_GRAPH), 0);
+ EXPECT_NE(iswctype('1', WCTYPE_GRAPH), 0);
+ EXPECT_NE(iswctype('!', WCTYPE_GRAPH), 0);
+ EXPECT_EQ(iswctype(' ', WCTYPE_GRAPH), 0);
+
+ // lower
+ EXPECT_NE(iswctype('a', WCTYPE_LOWER), 0);
+ EXPECT_NE(iswctype('z', WCTYPE_LOWER), 0);
+ EXPECT_EQ(iswctype('A', WCTYPE_LOWER), 0);
+ EXPECT_EQ(iswctype('1', WCTYPE_LOWER), 0);
+
+ // print
+ EXPECT_NE(iswctype(' ', WCTYPE_PRINT), 0);
+ EXPECT_NE(iswctype('A', WCTYPE_PRINT), 0);
+ EXPECT_NE(iswctype('~', WCTYPE_PRINT), 0);
+ EXPECT_EQ(iswctype('\n', WCTYPE_PRINT), 0);
+
+ // punct
+ EXPECT_NE(iswctype('!', WCTYPE_PUNCT), 0);
+ EXPECT_NE(iswctype('?', WCTYPE_PUNCT), 0);
+ EXPECT_EQ(iswctype('a', WCTYPE_PUNCT), 0);
+ EXPECT_EQ(iswctype('1', WCTYPE_PUNCT), 0);
+
+ // space
+ EXPECT_NE(iswctype(' ', WCTYPE_SPACE), 0);
+ EXPECT_NE(iswctype('\t', WCTYPE_SPACE), 0);
+ EXPECT_NE(iswctype('\n', WCTYPE_SPACE), 0);
+ EXPECT_EQ(iswctype('A', WCTYPE_SPACE), 0);
+
+ // upper
+ EXPECT_NE(iswctype('A', WCTYPE_UPPER), 0);
+ EXPECT_NE(iswctype('Z', WCTYPE_UPPER), 0);
+ EXPECT_EQ(iswctype('a', WCTYPE_UPPER), 0);
+ EXPECT_EQ(iswctype('1', WCTYPE_UPPER), 0);
+
+ // xdigit
+ EXPECT_NE(iswctype('0', WCTYPE_XDIGIT), 0);
+ EXPECT_NE(iswctype('9', WCTYPE_XDIGIT), 0);
+ EXPECT_NE(iswctype('a', WCTYPE_XDIGIT), 0);
+ EXPECT_NE(iswctype('F', WCTYPE_XDIGIT), 0);
+ EXPECT_EQ(iswctype('g', WCTYPE_XDIGIT), 0);
+ EXPECT_EQ(iswctype('?', WCTYPE_XDIGIT), 0);
+
+ // invalid descriptor
+ EXPECT_EQ(iswctype('a', WCTYPE_INVALID), 0);
+ EXPECT_EQ(iswctype('a', static_cast<wctype_t>(999)), 0);
+}
diff --git a/libc/test/src/wctype/wctype_test.cpp b/libc/test/src/wctype/wctype_test.cpp
new file mode 100644
index 0000000000000..22a3f6d1e7e2e
--- /dev/null
+++ b/libc/test/src/wctype/wctype_test.cpp
@@ -0,0 +1,63 @@
+//===-- Unittests for wctype --------------------------------------------===//
+//
+// 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/wctype/wctype.h"
+
+#include "test/UnitTest/Test.h"
+
+// wctype descriptors (must match implementation)
+static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
+static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
+static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
+static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
+static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
+static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
+static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
+static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
+static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
+static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
+static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
+static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
+static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
+
+TEST(LlvmLibcwctype, SimpleTest) {
+ using LIBC_NAMESPACE::wctype;
+
+ auto alnum = wctype("alnum");
+ auto alpha = wctype("alpha");
+ auto blank = wctype("blank");
+ auto cntrl = wctype("cntrl");
+ auto digit = wctype("digit");
+ auto graph = wctype("graph");
+ auto lower = wctype("lower");
+ auto print = wctype("print");
+ auto punct = wctype("punct");
+ auto space = wctype("space");
+ auto upper = wctype("upper");
+ auto xdigit = wctype("xdigit");
+
+ // valid descriptors should be nonzero
+ EXPECT_EQ(alnum, WCTYPE_ALNUM);
+ EXPECT_EQ(alpha, WCTYPE_ALPHA);
+ EXPECT_EQ(blank, WCTYPE_BLANK);
+ EXPECT_EQ(cntrl, WCTYPE_CNTRL);
+ EXPECT_EQ(digit, WCTYPE_DIGIT);
+ EXPECT_EQ(graph, WCTYPE_GRAPH);
+ EXPECT_EQ(lower, WCTYPE_LOWER);
+ EXPECT_EQ(print, WCTYPE_PRINT);
+ EXPECT_EQ(punct, WCTYPE_PUNCT);
+ EXPECT_EQ(space, WCTYPE_SPACE);
+ EXPECT_EQ(upper, WCTYPE_UPPER);
+ EXPECT_EQ(xdigit, WCTYPE_XDIGIT);
+
+ // invalid properties should return zero
+ EXPECT_EQ(wctype(""), WCTYPE_INVALID);
+ EXPECT_EQ(wctype("invalid"), WCTYPE_INVALID);
+ EXPECT_EQ(wctype("Alpha"), WCTYPE_INVALID);
+ EXPECT_EQ(wctype("unknown"), WCTYPE_INVALID);
+}
More information about the libc-commits
mailing list