[libc-commits] [libc] d00a49f - [libc] Add iswctype and wctype (#191178)

via libc-commits libc-commits at lists.llvm.org
Fri Apr 17 03:52:25 PDT 2026


Author: Elio
Date: 2026-04-17T11:52:20+01:00
New Revision: d00a49fc3495f260d8b3125b5d9f4e263ac13166

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

LOG: [libc] Add iswctype and wctype (#191178)

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

---------

Co-authored-by: Zile Xiong <xiongzile99 at gmail.com>

Added: 
    libc/hdr/types/wctype_t.h
    libc/hdr/wctype_overlay.h
    libc/include/llvm-libc-types/wctype_t.h
    libc/src/wctype/iswctype.cpp
    libc/src/wctype/iswctype.h
    libc/src/wctype/wctype.cpp
    libc/src/wctype/wctype.h
    libc/test/src/wctype/iswctype_test.cpp
    libc/test/src/wctype/wctype_test.cpp

Modified: 
    libc/config/baremetal/arm/entrypoints.txt
    libc/config/baremetal/riscv/entrypoints.txt
    libc/config/darwin/aarch64/entrypoints.txt
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/arm/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/config/windows/entrypoints.txt
    libc/hdr/types/CMakeLists.txt
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/include/wctype.yaml
    libc/src/__support/wctype_utils.h
    libc/src/wctype/CMakeLists.txt
    libc/test/src/__support/wctype_utils_test.cpp
    libc/test/src/wctype/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 9c0e71b2beec0..41c80efc64227 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -314,6 +314,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 5c88bc4ae1fb7..88eacfae12969 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -311,6 +311,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 c93ba47a6f2d6..914d2b7918da1 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -114,6 +114,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 6f7567cf3789f..87bd5461496b3 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -386,6 +386,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 167d762f36cb9..8a4d88b5ba98c 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -206,6 +206,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 1856d8edba7de..ea117c1d83c24 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -390,6 +390,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 fe5991c695e25..5c69c8808b2c1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -440,6 +440,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 c6db359933f08..94d1d00e676d9 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -120,6 +120,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..39f33b87f3e15
--- /dev/null
+++ b/libc/hdr/types/wctype_t.h
@@ -0,0 +1,23 @@
+//===-- 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..3ae7fbe24ec8d
--- /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 ab1d4967d4183..74d31025f9f4d 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -887,6 +887,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 e40f6e194ab3a..021e0a29555cf 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -191,6 +191,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..47840df02fc46
--- /dev/null
+++ b/libc/include/llvm-libc-types/wctype_t.h
@@ -0,0 +1,14 @@
+//===-- 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..9c66990f8b9d7 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -10,6 +10,9 @@
 #define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
 
 #include "hdr/types/wchar_t.h"
+#include "hdr/types/wctype_t.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/string_view.h"
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"
 
@@ -551,7 +554,6 @@ LIBC_INLINE constexpr bool isprint(wchar_t wch) {
   return lookup_properties(wch) & PropertyFlag::PRINT;
 #endif
 }
-
 LIBC_INLINE constexpr bool isxdigit(wchar_t wch) {
   // Hexadecimal digits are the same in C.UTF8 as in ASCII
   return ascii::isxdigit(wch);
@@ -579,6 +581,85 @@ LIBC_INLINE constexpr bool ispunct(wchar_t wch) {
 #endif
 }
 
+struct wctype_mapping {
+  cpp::string_view name;
+  wctype_t desc;
+};
+
+LIBC_INLINE constexpr wctype_t WCTYPE_INVALID = 0;
+LIBC_INLINE constexpr wctype_t WCTYPE_ALNUM = 1;
+LIBC_INLINE constexpr wctype_t WCTYPE_ALPHA = 2;
+LIBC_INLINE constexpr wctype_t WCTYPE_BLANK = 3;
+LIBC_INLINE constexpr wctype_t WCTYPE_CNTRL = 4;
+LIBC_INLINE constexpr wctype_t WCTYPE_DIGIT = 5;
+LIBC_INLINE constexpr wctype_t WCTYPE_GRAPH = 6;
+LIBC_INLINE constexpr wctype_t WCTYPE_LOWER = 7;
+LIBC_INLINE constexpr wctype_t WCTYPE_PRINT = 8;
+LIBC_INLINE constexpr wctype_t WCTYPE_PUNCT = 9;
+LIBC_INLINE constexpr wctype_t WCTYPE_SPACE = 10;
+LIBC_INLINE constexpr wctype_t WCTYPE_UPPER = 11;
+LIBC_INLINE constexpr wctype_t WCTYPE_XDIGIT = 12;
+
+LIBC_INLINE constexpr cpp::array<wctype_mapping, 12> mappings = {{
+    {"alnum", WCTYPE_ALNUM},
+    {"alpha", WCTYPE_ALPHA},
+    {"blank", WCTYPE_BLANK},
+    {"cntrl", WCTYPE_CNTRL},
+    {"digit", WCTYPE_DIGIT},
+    {"graph", WCTYPE_GRAPH},
+    {"lower", WCTYPE_LOWER},
+    {"print", WCTYPE_PRINT},
+    {"punct", WCTYPE_PUNCT},
+    {"space", WCTYPE_SPACE},
+    {"upper", WCTYPE_UPPER},
+    {"xdigit", WCTYPE_XDIGIT},
+}};
+
+LIBC_INLINE constexpr wctype_t wctype(const char *property) {
+  if (!property)
+    return WCTYPE_INVALID;
+
+  cpp::string_view prop(property);
+
+  for (const auto &wc : mappings) {
+    if (wc.name == prop) {
+      return wc.desc;
+    }
+  }
+  return WCTYPE_INVALID;
+}
+
+LIBC_INLINE constexpr int iswctype(wchar_t c, wctype_t desc) {
+  switch (desc) {
+  case WCTYPE_ALNUM:
+    return isalnum(c);
+  case WCTYPE_ALPHA:
+    return isalpha(c);
+  case WCTYPE_BLANK:
+    return isblank(c);
+  case WCTYPE_CNTRL:
+    return iscntrl(c);
+  case WCTYPE_DIGIT:
+    return isdigit(c);
+  case WCTYPE_GRAPH:
+    return isgraph(c);
+  case WCTYPE_LOWER:
+    return islower(c);
+  case WCTYPE_PRINT:
+    return isprint(c);
+  case WCTYPE_PUNCT:
+    return ispunct(c);
+  case WCTYPE_SPACE:
+    return isspace(c);
+  case WCTYPE_UPPER:
+    return isupper(c);
+  case WCTYPE_XDIGIT:
+    return isxdigit(c);
+  default:
+    return 0;
+  }
+}
+
 LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) {
 #if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
   return ascii::tolower(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..1604836225fee
--- /dev/null
+++ b/libc/src/wctype/iswctype.cpp
@@ -0,0 +1,22 @@
+//===-- 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), 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/__support/wctype_utils_test.cpp b/libc/test/src/__support/wctype_utils_test.cpp
index 9bc7e818cdbc6..88cd56cc0cae5 100644
--- a/libc/test/src/__support/wctype_utils_test.cpp
+++ b/libc/test/src/__support/wctype_utils_test.cpp
@@ -1,7 +1,15 @@
+//===-- Unittests for wctype utils ----------------------------------------===//
+//
+// 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/types/wctype_t.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/wctype/wctype_classification_utils.h"
 #include "test/UnitTest/Test.h"
-
 namespace {
 
 namespace ascii_mode {
@@ -9,7 +17,12 @@ namespace ascii_mode {
 #define LIBC_CONF_WCTYPE_MODE LIBC_WCTYPE_MODE_ASCII
 
 #undef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp = ::LIBC_NAMESPACE::cpp;
+} // namespace LIBC_NAMESPACE_DECL
 #include "src/__support/wctype_utils.h"
+
 } // namespace ascii_mode
 
 namespace utf8_mode {
@@ -19,9 +32,11 @@ namespace utf8_mode {
 namespace LIBC_NAMESPACE_DECL {
 using ::LIBC_NAMESPACE::lookup_properties;
 using ::LIBC_NAMESPACE::PropertyFlag;
+namespace cpp = ::LIBC_NAMESPACE::cpp;
 } // namespace LIBC_NAMESPACE_DECL
 
 #undef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
+
 #include "src/__support/wctype_utils.h"
 } // namespace utf8_mode
 

diff  --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index a5f85856dfb38..f7cdcc77482e4 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -121,3 +121,24 @@ 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
+    libc.src.wctype.wctype
+)
+
+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..4aed4d047b619
--- /dev/null
+++ b/libc/test/src/wctype/iswctype_test.cpp
@@ -0,0 +1,181 @@
+//===-- 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 "src/wctype/wctype.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibciswctype, Alnum) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("alnum");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'Z', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'5', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'!', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Alpha) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("alpha");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'Z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Blank) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("blank");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\t', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\r', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Cntrl) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("cntrl");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\t', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\r', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(0x1f, desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(0x7f, desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Digit) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("digit");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'9', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'/', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L':', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Graph) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("graph");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'!', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'~', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\t', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Lower) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("lower");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Print) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("print");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'~', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\t', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'\0', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Punct) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("punct");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'!', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'?', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'_', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'[', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Space) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("space");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\t', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\n', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\v', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\f', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'\r', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'!', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Upper) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("upper");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'Z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, XDigit) {
+  const wctype_t desc = LIBC_NAMESPACE::wctype("xdigit");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'9', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'f', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(L'F', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'g', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'G', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'?', desc), 0);
+}
+
+TEST(LlvmLibciswctype, InvalidDescriptor) {
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'a', 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L'0', 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(L' ', 0), 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..e4aa1bb6694d6
--- /dev/null
+++ b/libc/test/src/wctype/wctype_test.cpp
@@ -0,0 +1,35 @@
+//===-- 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"
+
+TEST(LlvmLibcwctype, ValidPropertiesReturnNonZero) {
+  EXPECT_NE(LIBC_NAMESPACE::wctype("alnum"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("alpha"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("blank"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("cntrl"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("digit"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("graph"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("lower"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("print"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("punct"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("space"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("upper"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("xdigit"), static_cast<wctype_t>(0));
+}
+
+TEST(LlvmLibcwctype, InvalidPropertiesReturnZero) {
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(nullptr), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(""), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("foo"), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("Alpha"), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("xdigit "), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(" alnum"), static_cast<wctype_t>(0));
+}


        


More information about the libc-commits mailing list