[libcxx-commits] [libcxx] [libc++][z/OS] Move z/OS to new locale API and resolve all name collisions (PR #165428)
Zibi Sarbinowski via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 28 12:09:52 PDT 2025
https://github.com/zibi2 updated https://github.com/llvm/llvm-project/pull/165428
>From 97bb07c5546dff792dd7f7f92e56874559d35889 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Tue, 28 Oct 2025 16:12:01 +0000
Subject: [PATCH 1/3] Move z/OS to new locale API and resolve all name
collisions
---
libcxx/include/CMakeLists.txt | 2 +
libcxx/include/__locale_dir/locale_base_api.h | 9 +-
libcxx/include/__locale_dir/support/zos.h | 318 ++++++++++++++
libcxx/include/__support/ibm/vasprintf.h | 51 +++
libcxx/include/__undef_macros | 76 ++++
libcxx/include/module.modulemap.in | 1 +
libcxx/include/wchar.h | 4 +-
libcxx/src/support/ibm/localeconv.cpp | 46 ++
libcxx/src/support/ibm/mbsnrtowcs.cpp | 18 +-
libcxx/src/support/ibm/wcsnrtombs.cpp | 18 +-
libcxx/src/support/ibm/xlocale_zos.cpp | 403 +++++++++++++-----
...internal.zos.locale.funcs.compile.pass.cpp | 26 ++
.../internal.zos.mbsnrtowcs.compile.pass.cpp | 25 ++
.../internal.zos.nanosleep.compile.pass.cpp | 15 +
.../internal.zos.wcsnrtombs.compile.pass.cpp | 25 ++
.../locale.ctype.byname/ctype.c.pass.cpp | 66 +++
.../locale.ctype.byname/ctype.cxx.pass.cpp | 71 +++
17 files changed, 1069 insertions(+), 105 deletions(-)
create mode 100644 libcxx/include/__locale_dir/support/zos.h
create mode 100644 libcxx/include/__support/ibm/vasprintf.h
create mode 100644 libcxx/src/support/ibm/localeconv.cpp
create mode 100644 libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
create mode 100644 libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
create mode 100644 libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
create mode 100644 libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
create mode 100644 libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
create mode 100644 libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 37259a7e6e7dd..b7871e4b6ff70 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -532,6 +532,7 @@ set(files
__locale_dir/support/no_locale/characters.h
__locale_dir/support/no_locale/strtonum.h
__locale_dir/support/windows.h
+ __locale_dir/support/zos.h
__locale_dir/time.h
__locale_dir/wbuffer_convert.h
__locale_dir/wstring_convert.h
@@ -755,6 +756,7 @@ set(files
__support/ibm/gettod_zos.h
__support/ibm/locale_mgmt_zos.h
__support/ibm/nanosleep.h
+ __support/ibm/vasprintf.h
__support/xlocale/__nop_locale_mgmt.h
__support/xlocale/__posix_l_fallback.h
__support/xlocale/__strtonum_fallback.h
diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h
index 9f3ce02a3af20..6f99e40a9dee2 100644
--- a/libcxx/include/__locale_dir/locale_base_api.h
+++ b/libcxx/include/__locale_dir/locale_base_api.h
@@ -15,6 +15,9 @@
# pragma GCC system_header
#endif
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
// The platform-specific headers have to provide the following interface.
//
// These functions are equivalent to their C counterparts, except that __locale::__locale_t
@@ -121,13 +124,15 @@
# include <__locale_dir/support/fuchsia.h>
# elif defined(__linux__)
# include <__locale_dir/support/linux.h>
+# elif defined(__MVS__)
+# include <__locale_dir/support/zos.h>
# else
// TODO: This is a temporary definition to bridge between the old way we defined the locale base API
// (by providing global non-reserved names) and the new API. As we move individual platforms
// towards the new way of defining the locale base API, this should disappear since each platform
// will define those directly.
-# if defined(_AIX) || defined(__MVS__)
+# if defined(_AIX)
# include <__locale_dir/locale_base_api/ibm.h>
# elif defined(__OpenBSD__)
# include <__locale_dir/locale_base_api/openbsd.h>
@@ -317,4 +322,6 @@ _LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_LOCALIZATION
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_H
diff --git a/libcxx/include/__locale_dir/support/zos.h b/libcxx/include/__locale_dir/support/zos.h
new file mode 100644
index 0000000000000..3ab85bc0fabd9
--- /dev/null
+++ b/libcxx/include/__locale_dir/support/zos.h
@@ -0,0 +1,318 @@
+//===-----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___LOCALE_DIR_SUPPORT_IBM_H
+#define _LIBCPP___LOCALE_DIR_SUPPORT_IBM_H
+
+#include <__support/ibm/locale_mgmt_zos.h>
+#include <__support/ibm/vasprintf.h>
+
+#include "cstdlib"
+#include <clocale> // std::lconv
+#include <locale.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <wctype.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// These functions are exported within std namespace
+// for compatibility with previous versions.
+_LIBCPP_EXPORTED_FROM_ABI int isdigit_l(int, locale_t);
+_LIBCPP_EXPORTED_FROM_ABI int isxdigit_l(int, locale_t);
+
+namespace __locale {
+struct __locale_guard {
+ _LIBCPP_HIDE_FROM_ABI __locale_guard(locale_t& __loc) : __old_loc_(std::uselocale(__loc)) {}
+
+ _LIBCPP_HIDE_FROM_ABI ~__locale_guard() {
+ // if (__old_loc_)
+ if (__old_loc_ != (locale_t)0)
+ std::uselocale(__old_loc_);
+ }
+
+ locale_t __old_loc_;
+
+ __locale_guard(__locale_guard const&) = delete;
+ __locale_guard& operator=(__locale_guard const&) = delete;
+};
+
+//
+// Locale management
+//
+#define _LIBCPP_COLLATE_MASK LC_COLLATE_MASK
+#define _LIBCPP_CTYPE_MASK LC_CTYPE_MASK
+#define _LIBCPP_MONETARY_MASK LC_MONETARY_MASK
+#define _LIBCPP_NUMERIC_MASK LC_NUMERIC_MASK
+#define _LIBCPP_TIME_MASK LC_TIME_MASK
+#define _LIBCPP_MESSAGES_MASK LC_MESSAGES_MASK
+#define _LIBCPP_ALL_MASK LC_ALL_MASK
+#define _LIBCPP_LC_ALL LC_ALL
+
+#define _LIBCPP_CLOC std::__c_locale()
+#ifndef _LIBCPP_LC_GLOBAL_LOCALE
+# define _LIBCPP_LC_GLOBAL_LOCALE ((locale_t) - 1)
+#endif
+
+using __locale_t _LIBCPP_NODEBUG = locale_t;
+
+#if defined(_LIBCPP_BUILDING_LIBRARY)
+using __lconv_t _LIBCPP_NODEBUG = std::lconv;
+
+inline _LIBCPP_HIDE_FROM_ABI __locale_t __newlocale(int __category_mask, const char* __locale, __locale_t __base) {
+ return newlocale(__category_mask, __locale, __base);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI void __freelocale(__locale_t __loc) { freelocale(__loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, char const* __locale) {
+ return ::setlocale(__category, __locale);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) {
+ __locale_guard __current(__loc);
+ return std::localeconv();
+}
+#endif // _LIBCPP_BUILDING_LIBRARY
+
+// The following are not POSIX routines. These are quick-and-dirty hacks
+// to make things pretend to work
+
+//
+// Strtonum functions
+//
+inline _LIBCPP_HIDE_FROM_ABI float __strtof(const char* __nptr, char** __endptr, __locale_t __loc) {
+ __locale_guard __newloc(__loc);
+ return ::strtof(__nptr, __endptr);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr, __locale_t __loc) {
+ __locale_guard __newloc(__loc);
+ return ::strtod(__nptr, __endptr);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __endptr, __locale_t __loc) {
+ __locale_guard __newloc(__loc);
+ return ::strtold(__nptr, __endptr);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
+ __locale_guard __newloc(__loc);
+ return ::strtoll(__nptr, __endptr, __base);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI unsigned long long
+__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
+ __locale_guard __newloc(__loc);
+ return ::strtoull(__nptr, __endptr, __base);
+}
+
+//
+// Character manipulation functions
+//
+namespace __ibm {
+_LIBCPP_HIDE_FROM_ABI int islower_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isupper_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswalpha_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswblank_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswcntrl_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswdigit_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswlower_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswprint_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswpunct_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswspace_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswupper_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswxdigit_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int toupper_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int tolower_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI wint_t towupper_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI wint_t towlower_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int strcoll_l(const char*, const char*, __locale_t);
+_LIBCPP_HIDE_FROM_ABI size_t strxfrm_l(char*, const char*, size_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI size_t strftime_l(char*, size_t, const char*, const struct tm*, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int wcscoll_l(const wchar_t*, const wchar_t*, __locale_t);
+_LIBCPP_HIDE_FROM_ABI size_t wcsxfrm_l(wchar_t*, const wchar_t*, size_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswctype_l(wint_t, wctype_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI size_t mbsnrtowcs(wchar_t*, const char**, size_t, size_t, mbstate_t*);
+_LIBCPP_HIDE_FROM_ABI size_t wcsnrtombs(char*, const wchar_t**, size_t, size_t, mbstate_t*);
+
+// These functions are not used internally by libcxx
+// and are included for completness.
+_LIBCPP_HIDE_FROM_ABI int isalnum_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isalpha_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isblank_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iscntrl_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isgraph_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isprint_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int ispunct_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int isspace_l(int, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswalnum_l(wint_t, __locale_t);
+_LIBCPP_HIDE_FROM_ABI int iswgraph_l(wint_t, __locale_t);
+} // namespace __ibm
+
+using namespace __ibm;
+
+#if defined(_LIBCPP_BUILDING_LIBRARY)
+inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return islower_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return isupper_l(__c, __loc); }
+#endif
+
+inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return isdigit_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return isxdigit_l(__c, __loc); }
+
+#if defined(_LIBCPP_BUILDING_LIBRARY)
+inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return toupper_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __c, __locale_t __loc) { return tolower_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __strcoll(const char* __s1, const char* __s2, __locale_t __loc) {
+ return strcoll_l(__s1, __s2, __loc);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, size_t __n, __locale_t __loc) {
+ return strxfrm_l(__dest, __src, __n, __loc);
+}
+
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+inline _LIBCPP_HIDE_FROM_ABI int __iswctype(wint_t __c, wctype_t __type, __locale_t __loc) {
+ return iswctype_l(__c, __type, __loc);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswspace(wint_t __c, __locale_t __loc) { return iswspace_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswprint(wint_t __c, __locale_t __loc) { return iswprint_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswcntrl(wint_t __c, __locale_t __loc) { return iswcntrl_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswupper(wint_t __c, __locale_t __loc) { return iswupper_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswlower(wint_t __c, __locale_t __loc) { return iswlower_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswalpha(wint_t __c, __locale_t __loc) { return iswalpha_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswblank(wint_t __c, __locale_t __loc) { return iswblank_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswdigit(wint_t __c, __locale_t __loc) { return iswdigit_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswpunct(wint_t __c, __locale_t __loc) { return iswpunct_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __iswxdigit(wint_t __c, __locale_t __loc) { return iswxdigit_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI wint_t __towupper(wint_t __c, __locale_t __loc) { return towupper_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI wint_t __towlower(wint_t __c, __locale_t __loc) { return towlower_l(__c, __loc); }
+
+inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __ws1, const wchar_t* __ws2, __locale_t __loc) {
+ return wcscoll_l(__ws1, __ws2, __loc);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t __wcsxfrm(wchar_t* __dest, const wchar_t* __src, size_t __n, __locale_t __loc) {
+ return wcsxfrm_l(__dest, __src, __n, __loc);
+}
+# endif // _LIBCPP_HAS_WIDE_CHARACTERS
+
+inline _LIBCPP_HIDE_FROM_ABI
+size_t __strftime(char* __s, size_t __max, const char* __format, const struct tm* __tm, __locale_t __loc) {
+ return strftime_l(__s, __max, __format, __tm, __loc);
+}
+
+//
+// Other functions
+//
+inline _LIBCPP_HIDE_FROM_ABI decltype(MB_CUR_MAX) __mb_len_max(__locale_t __loc) {
+ __locale_guard __current(__loc);
+ return MB_CUR_MAX;
+}
+
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __c, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::btowc(__c);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __c, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::wctob(__c);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t
+__wcsnrtombs(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return wcsnrtombs(__dest, __src, __nwc, __len, __ps); // non-standard
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t __wcrtomb(char* __s, wchar_t __wc, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::wcrtomb(__s, __wc, __ps);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t
+__mbsnrtowcs(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return mbsnrtowcs(__dest, __src, __nms, __len, __ps); // non-standard
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t
+__mbrtowc(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::mbrtowc(__pwc, __s, __n, __ps);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI int __mbtowc(wchar_t* __pwc, const char* __pmb, size_t __max, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::mbtowc(__pwc, __pmb, __max);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t __mbrlen(const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::mbrlen(__s, __n, __ps);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI size_t
+__mbsrtowcs(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, __locale_t __loc) {
+ __locale_guard __current(__loc);
+ return std::mbsrtowcs(__dest, __src, __len, __ps);
+}
+# endif // _LIBCPP_BUILDING_LIBRARY
+#endif // _LIBCPP_HAS_WIDE_CHARACTERS
+
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __snprintf(
+ char* __s, size_t __n, __locale_t __loc, const char* __format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ __locale_guard __current(__loc);
+ int __res = std::vsnprintf(__s, __n, __format, __va);
+ va_end(__va);
+ return __res;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(
+ char** __s, __locale_t __loc, const char* __format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ __locale_guard __current(__loc);
+ int __res = std::__ibm::vasprintf(__s, __format, __va); // non-standard
+ va_end(__va);
+ return __res;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
+ const char* __s, __locale_t __loc, const char* __format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ __locale_guard __current(__loc);
+ int __res = std::vsscanf(__s, __format, __va);
+ va_end(__va);
+ return __res;
+}
+} // namespace __locale
+_LIBCPP_END_NAMESPACE_STD
+#endif // _LIBCPP___LOCALE_DIR_SUPPORT_IBM_H
diff --git a/libcxx/include/__support/ibm/vasprintf.h b/libcxx/include/__support/ibm/vasprintf.h
new file mode 100644
index 0000000000000..bf42ec7963f45
--- /dev/null
+++ b/libcxx/include/__support/ibm/vasprintf.h
@@ -0,0 +1,51 @@
+//===-----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___SUPPORT_IBMVASPRINTF_H
+#define _LIBCPP___SUPPORT_IBMVASPRINTF_H
+
+#include <cstdlib> // malloc, realloc
+#include <stdarg.h> // va_copy, va_end
+#include <stdio.h> // vsnprintf
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __ibm {
+
+inline _LIBCPP_HIDE_FROM_ABI
+_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char* fmt, va_list ap) {
+ const size_t buff_size = 256;
+ if ((*strp = (char*)malloc(buff_size)) == nullptr) {
+ return -1;
+ }
+
+ va_list ap_copy;
+ // va_copy may not be provided by the C library in C++03 mode.
+#if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy)
+# if defined(__MVS__) && !defined(_VARARG_EXT_)
+ __builtin_zos_va_copy(ap_copy, ap);
+# else
+ __builtin_va_copy(ap_copy, ap);
+# endif
+#else
+ va_copy(ap_copy, ap);
+#endif
+ int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy);
+ va_end(ap_copy);
+
+ if ((size_t)str_size >= buff_size) {
+ if ((*strp = (char*)realloc(*strp, str_size + 1)) == nullptr) {
+ return -1;
+ }
+ str_size = vsnprintf(*strp, str_size + 1, fmt, ap);
+ }
+ return str_size;
+}
+
+} // namespace __ibm
+_LIBCPP_END_NAMESPACE_STD
+#endif // _LIBCPP___SUPPORT_IBMVASPRINTF_H
diff --git a/libcxx/include/__undef_macros b/libcxx/include/__undef_macros
index 29ab327e1c375..f02547841e621 100644
--- a/libcxx/include/__undef_macros
+++ b/libcxx/include/__undef_macros
@@ -26,3 +26,79 @@
#ifdef erase
# undef erase
#endif
+
+#ifdef __islower
+# undef __islower
+#endif
+
+#ifdef __isupper
+# undef __isupper
+#endif
+
+#ifdef __isdigit
+# undef __isdigit
+#endif
+
+#ifdef __isxdigit
+# undef __isxdigit
+#endif
+
+#ifdef __toupper
+# undef __toupper
+#endif
+
+#ifdef __tolower
+# undef __tolower
+#endif
+
+#ifdef __iswctype
+# undef __iswctype
+#endif
+
+#ifdef __iswspace
+# undef __iswspace
+#endif
+
+#ifdef __iswprint
+# undef __iswprint
+#endif
+
+#ifdef __iswcntrl
+# undef __iswcntrl
+#endif
+
+#ifdef __iswupper
+# undef __iswupper
+#endif
+
+#ifdef __iswlower
+# undef __iswlower
+#endif
+
+#ifdef __iswalpha
+# undef __iswalpha
+#endif
+
+#ifdef __iswblank
+# undef __iswblank
+#endif
+
+#ifdef __iswdigit
+# undef __iswdigit
+#endif
+
+#ifdef __iswpunct
+# undef __iswpunct
+#endif
+
+#ifdef __iswxdigit
+# undef __iswxdigit
+#endif
+
+#ifdef __towupper
+# undef __towupper
+#endif
+
+#ifdef __towlower
+# undef __towlower
+#endif
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index a86d6c6a43d0e..28ea168dbb8c8 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1587,6 +1587,7 @@ module std [system] {
textual header "__locale_dir/support/freebsd.h"
textual header "__locale_dir/support/fuchsia.h"
textual header "__locale_dir/support/linux.h"
+ textual header "__locale_dir/support/zos.h"
textual header "__locale_dir/support/no_locale/characters.h"
textual header "__locale_dir/support/no_locale/strtonum.h"
textual header "__locale_dir/support/windows.h"
diff --git a/libcxx/include/wchar.h b/libcxx/include/wchar.h
index a932dd266b862..82984143aa6c5 100644
--- a/libcxx/include/wchar.h
+++ b/libcxx/include/wchar.h
@@ -193,14 +193,14 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD wchar_t* wmemchr(wchar_t
}
# endif
-# if defined(__cplusplus) && (defined(_LIBCPP_MSVCRT_LIKE) || defined(__MVS__))
+# if defined(__cplusplus) && defined(_LIBCPP_MSVCRT_LIKE)
extern "C" {
size_t mbsnrtowcs(
wchar_t* __restrict __dst, const char** __restrict __src, size_t __nmc, size_t __len, mbstate_t* __restrict __ps);
size_t wcsnrtombs(
char* __restrict __dst, const wchar_t** __restrict __src, size_t __nwc, size_t __len, mbstate_t* __restrict __ps);
} // extern "C"
-# endif // __cplusplus && (_LIBCPP_MSVCRT || __MVS__)
+# endif // __cplusplus && _LIBCPP_MSVCRT
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
# endif // _LIBCPP_WCHAR_H
diff --git a/libcxx/src/support/ibm/localeconv.cpp b/libcxx/src/support/ibm/localeconv.cpp
new file mode 100644
index 0000000000000..4ab6b7a75f618
--- /dev/null
+++ b/libcxx/src/support/ibm/localeconv.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <__locale>
+#include <__locale_dir/support/zos.h> // __locale_guard
+#include <memory>
+#include <stdlib.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+lconv *__libcpp_localeconv_l(locale_t& __l)
+{
+ __locale::__locale_guard __current(__l);
+
+ lconv * lc = localeconv();
+ static lconv newlc;
+ newlc = *lc;
+
+ enum {max_char_num = 20};
+#define DeepCopy(mbr) \
+ static char buf_##mbr[max_char_num]; \
+ strncpy(buf_##mbr, lc->mbr, max_char_num); \
+ newlc.mbr = buf_##mbr;
+
+ DeepCopy(decimal_point);
+ DeepCopy(thousands_sep);
+ DeepCopy(grouping);
+ DeepCopy(int_curr_symbol);
+ DeepCopy(currency_symbol);
+ DeepCopy(mon_decimal_point);
+ DeepCopy(mon_thousands_sep);
+ DeepCopy(mon_grouping);
+ DeepCopy(positive_sign);
+ DeepCopy(negative_sign);
+ DeepCopy(__left_parenthesis);
+ DeepCopy(__right_parenthesis);
+
+ return &newlc;
+}
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/src/support/ibm/mbsnrtowcs.cpp b/libcxx/src/support/ibm/mbsnrtowcs.cpp
index d0006a8468aad..590ac0617a67d 100644
--- a/libcxx/src/support/ibm/mbsnrtowcs.cpp
+++ b/libcxx/src/support/ibm/mbsnrtowcs.cpp
@@ -6,11 +6,16 @@
//
//===----------------------------------------------------------------------===//
+#include <__locale>
+#include <__locale_dir/support/zos.h> // __locale_guard
#include <cstddef> // size_t
#include <cwchar> // mbstate_t
#include <limits.h> // MB_LEN_MAX
#include <string.h> // wmemcpy
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __locale {
+namespace __ibm {
// Returns the number of wide characters found in the multi byte sequence `src`
// (of `src_size_bytes`), that fit in the buffer `dst` (of `max_dest_chars`
// elements size). The count returned excludes the null terminator.
@@ -18,7 +23,7 @@
// Returns (size_t) -1 when an invalid sequence is encountered.
// Leaves *`src` pointing to the next character to convert or NULL
// if a null character was converted from *`src`.
-_LIBCPP_EXPORTED_FROM_ABI size_t mbsnrtowcs(
+size_t mbsnrtowcs(
wchar_t* __restrict dst,
const char** __restrict src,
size_t src_size_bytes,
@@ -95,3 +100,14 @@ _LIBCPP_EXPORTED_FROM_ABI size_t mbsnrtowcs(
return dest_converted;
}
+
+size_t __libcpp_mbsnrtowcs_l(wchar_t * dest, const char **src, size_t nms,
+ size_t len, mbstate_t *ps, locale_t l)
+{
+ __locale::__locale_guard current(l);
+ return mbsnrtowcs(dest, src, nms, len, ps);
+}
+
+} // namespace __ibm
+} // namespace __locale
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/src/support/ibm/wcsnrtombs.cpp b/libcxx/src/support/ibm/wcsnrtombs.cpp
index df87b9ea07f85..437ea52ecf1ac 100644
--- a/libcxx/src/support/ibm/wcsnrtombs.cpp
+++ b/libcxx/src/support/ibm/wcsnrtombs.cpp
@@ -6,18 +6,23 @@
//
//===----------------------------------------------------------------------===//
+#include <__locale>
+#include <__locale_dir/support/zos.h> // __locale_guard
#include <cwchar> // mbstate_t
#include <limits.h> // MB_LEN_MAX
#include <stdlib.h> // MB_CUR_MAX, size_t
#include <string.h> // memcpy
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __locale {
+namespace __ibm {
// Converts `max_source_chars` from the wide character buffer pointer to by *`src`,
// into the multi byte character sequence buffer stored at `dst`, which must be
// `dst_size_bytes` bytes in size. Returns the number of bytes in the sequence
// converted from *src, excluding the null terminator.
// Returns (size_t) -1 if an error occurs and sets errno.
// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.
-_LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(
+size_t wcsnrtombs(
char* __restrict dst,
const wchar_t** __restrict src,
size_t max_source_chars,
@@ -92,3 +97,14 @@ _LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(
return dest_converted;
}
+
+size_t __libcpp_wcsnrtombs_l(char *dest, const wchar_t **src, size_t nwc,
+ size_t len, mbstate_t *ps, locale_t l)
+{
+ __locale::__locale_guard __current(l);
+ return wcsnrtombs(dest, src, nwc, len, ps);
+}
+
+} // namespace __ibm
+} // namespace __locale
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/src/support/ibm/xlocale_zos.cpp b/libcxx/src/support/ibm/xlocale_zos.cpp
index 136999ec0b02f..22bc0b0f72feb 100644
--- a/libcxx/src/support/ibm/xlocale_zos.cpp
+++ b/libcxx/src/support/ibm/xlocale_zos.cpp
@@ -6,125 +6,328 @@
//
//===----------------------------------------------------------------------===//
+#include "include/ibm_xlocale.h"
+
#include <__assert>
-#include <__support/ibm/xlocale.h>
-#include <sstream>
-#include <vector>
+#include <__locale_dir/support/zos.h>
+#include <errno.h>
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
+_LIBCPP_BEGIN_NAMESPACE_STD
-locale_t newlocale(int category_mask, const char* locale, locale_t base) {
- // Maintain current locale name(s) to restore later.
- std::string current_loc_name(setlocale(LC_ALL, 0));
+#define CategoryList(pair, sep) \
+ pair(LC_COLLATE, lc_collate) sep \
+ pair(LC_CTYPE, lc_ctype) sep \
+ pair(LC_MONETARY, lc_monetary) sep \
+ pair(LC_NUMERIC, lc_numeric) sep \
+ pair(LC_TIME, lc_time) sep \
+ pair(LC_MESSAGES, lc_messages)
+
+// check ids and masks agree
+#define check_ids_and_masks_agree(id, _) \
+ static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id); \
+ static_assert((1 << id) == _CATMASK(id), "mask does not have expected value for " #id);
+CategoryList(check_ids_and_masks_agree,)
+#undef check_ids_and_masks_agree
+
+// check that LC_ALL_MASK is defined as expected
+#define get_mask(id, _) id##_MASK
+static_assert(LC_ALL_MASK == (CategoryList(get_mask, |)), "LC_ALL_MASK does not have the expected value. Check that its definition includes all supported categories");
+#undef get_mask
+
+
+// initialize c_locale
+#define init_clocale(id, locale_member) "C",
+static locale_struct c_locale = { LC_ALL_MASK, CategoryList(init_clocale, ) };
+#undef init_clocale
- // Check for errors.
- if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) {
+static locale_t current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
+
+
+locale_t __c_locale() {
+ return &c_locale;
+}
+
+// locale
+locale_t newlocale(int category_mask, const char* locale, locale_t base) {
+ // start with some basic checks
+ if (! locale) {
errno = EINVAL;
- return (locale_t)0;
- } else {
- for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
- if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == nullptr) {
- setlocale(LC_ALL, current_loc_name.c_str());
- errno = EINVAL;
- return (locale_t)0;
- }
- }
+ return (locale_t) 0;
+ }
+ if (category_mask & ~LC_ALL_MASK) {
+ // then there are bits in category_mask that does not correspond
+ // to a valid category
+ errno = EINVAL;
+ return (locale_t) 0;
}
- // Create new locale.
- locale_t newloc = new locale_struct();
+ locale_t new_loc = new locale_struct;
+ int num_locales_not_found = 0;
+
+ if (base && base != _LIBCPP_LC_GLOBAL_LOCALE)
+ *new_loc = *base;
+
+ auto set_for_category = [&](int id, int mask, std::string &setting) {
+ const char *setting_to_apply = nullptr;
+
+ if (category_mask & mask)
+ setting_to_apply = locale;
+ else if (!base)
+ setting_to_apply = "C";
- if (base) {
- if (category_mask != LC_ALL_MASK) {
- // Copy base when it will not be overwritten.
- memcpy(newloc, base, sizeof(locale_struct));
- newloc->category_mask = category_mask | base->category_mask;
+ if (setting_to_apply) {
+ // setlocale takes the id, not the mask
+ const char *saved_setting = setlocale(id, nullptr);
+ if (setlocale(id, setting_to_apply)) {
+ // then setting_to_apply is valid for this category
+ // restore the saved setting
+ setlocale(id, saved_setting);
+
+ new_loc->category_mask |= mask;
+ setting = setting_to_apply;
+ } else {
+ // unknown locale for this category
+ num_locales_not_found++;
+ }
}
- delete base;
- } else {
- newloc->category_mask = category_mask;
+ };
+
+ // now overlay values
+#define Set(id, locale_member) set_for_category(id, id##_MASK, new_loc->locale_member)
+ CategoryList(Set, ;);
+#undef Set
+
+ if (num_locales_not_found != 0) {
+ delete new_loc;
+ errno = ENOENT;
+ new_loc = (locale_t) 0;
}
- if (category_mask & LC_COLLATE_MASK)
- newloc->lc_collate = locale;
- if (category_mask & LC_CTYPE_MASK)
- newloc->lc_ctype = locale;
- if (category_mask & LC_MONETARY_MASK)
- newloc->lc_monetary = locale;
- if (category_mask & LC_NUMERIC_MASK)
- newloc->lc_numeric = locale;
- if (category_mask & LC_TIME_MASK)
- newloc->lc_time = locale;
- if (category_mask & LC_MESSAGES_MASK)
- newloc->lc_messages = locale;
-
- // Restore current locale.
- setlocale(LC_ALL, current_loc_name.c_str());
- return (locale_t)newloc;
-}
-
-void freelocale(locale_t locobj) { delete locobj; }
-
-locale_t uselocale(locale_t newloc) {
- // Maintain current locale name(s).
- std::string current_loc_name(setlocale(LC_ALL, 0));
-
- if (newloc) {
- // Set locales and check for errors.
- bool is_error =
- (newloc->category_mask & LC_COLLATE_MASK && setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == nullptr) ||
- (newloc->category_mask & LC_CTYPE_MASK && setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == nullptr) ||
- (newloc->category_mask & LC_MONETARY_MASK && setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == nullptr) ||
- (newloc->category_mask & LC_NUMERIC_MASK && setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == nullptr) ||
- (newloc->category_mask & LC_TIME_MASK && setlocale(LC_TIME, newloc->lc_time.c_str()) == nullptr) ||
- (newloc->category_mask & LC_MESSAGES_MASK && setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == nullptr);
-
- if (is_error) {
- setlocale(LC_ALL, current_loc_name.c_str());
+ return new_loc;
+}
+
+void freelocale(locale_t locobj) {
+ if (locobj != nullptr && locobj != &c_locale && locobj != _LIBCPP_LC_GLOBAL_LOCALE)
+ delete locobj;
+}
+
+locale_t uselocale(locale_t new_loc) {
+ locale_t prev_loc = current_locale;
+
+ if (new_loc == _LIBCPP_LC_GLOBAL_LOCALE) {
+ current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
+ } else if (new_loc != nullptr) {
+ locale_struct saved_locale;
+ saved_locale.category_mask = 0;
+
+ auto apply_category = [&](int id, int mask, std::string &setting, std::string &save_setting)-> bool {
+ if (new_loc->category_mask & mask) {
+ const char *old_setting = setlocale(id, setting.c_str());
+ if (old_setting) {
+ // we were able to set for this category. Save the old setting
+ // in case a subsequent category fails, and we need to restore
+ // all earlier settings.
+ saved_locale.category_mask |= mask;
+ save_setting = old_setting;
+ return true;
+ }
+ return false;
+ }
+ return true;
+ };
+
+#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale. locale_member)
+ bool is_ok = CategoryList(Apply, &&);
+#undef Apply
+
+ if (!is_ok) {
+ auto restore = [&](int id, int mask, std::string &setting) {
+ if (saved_locale.category_mask & mask)
+ setlocale(id, setting.c_str());
+ };
+#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale. locale_member);
+ CategoryList(Restore,);
+#undef Restore
errno = EINVAL;
- return (locale_t)0;
+ return nullptr;
}
+ current_locale = new_loc;
}
- // Construct and return previous locale.
- locale_t previous_loc = new locale_struct();
+ return prev_loc;
+}
- // current_loc_name might be a comma-separated locale name list.
- if (current_loc_name.find(',') != std::string::npos) {
- // Tokenize locale name list.
- const char delimiter = ',';
- std::vector<std::string> tokenized;
- std::stringstream ss(current_loc_name);
- std::string s;
+int isdigit_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isdigit(__c);
+}
- while (std::getline(ss, s, delimiter)) {
- tokenized.push_back(s);
- }
+int isxdigit_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isxdigit(__c);
+}
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short");
-
- previous_loc->lc_collate = tokenized[LC_COLLATE];
- previous_loc->lc_ctype = tokenized[LC_CTYPE];
- previous_loc->lc_monetary = tokenized[LC_MONETARY];
- previous_loc->lc_numeric = tokenized[LC_NUMERIC];
- previous_loc->lc_time = tokenized[LC_TIME];
- // Skip LC_TOD.
- previous_loc->lc_messages = tokenized[LC_MESSAGES];
- } else {
- previous_loc->lc_collate = current_loc_name;
- previous_loc->lc_ctype = current_loc_name;
- previous_loc->lc_monetary = current_loc_name;
- previous_loc->lc_numeric = current_loc_name;
- previous_loc->lc_time = current_loc_name;
- previous_loc->lc_messages = current_loc_name;
- }
+namespace __locale {
+namespace __ibm {
+int isalnum_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isalnum(__c);
+}
+
+int isalpha_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isalpha(__c);
+}
+
+int isblank_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isblank(__c);
+}
+
+int iscntrl_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iscntrl(__c);
+}
+
+int isgraph_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isgraph(__c);
+}
+
+int islower_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::islower(__c);
+}
+
+int isprint_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isprint(__c);
+}
+
+int ispunct_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::ispunct(__c);
+}
+
+int isspace_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isspace(__c);
+}
+
+int isupper_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::isupper(__c);
+}
+
+int iswalnum_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswalnum(__c);
+}
+
+int iswalpha_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswalpha(__c);
+}
+
+int iswblank_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswblank(__c);
+}
+
+int iswcntrl_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswcntrl(__c);
+}
+
+int iswdigit_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswdigit(__c);
+}
+
+int iswgraph_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswgraph(__c);
+}
+
+int iswlower_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswlower(__c);
+}
+
+int iswprint_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswprint(__c);
+}
+
+int iswpunct_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswpunct(__c);
+}
+
+int iswspace_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswspace(__c);
+}
+
+int iswupper_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswupper(__c);
+}
+
+int iswxdigit_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswxdigit(__c);
+}
+
+int toupper_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::toupper(__c);
+}
+
+int tolower_l(int __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::tolower(__c);
+}
+
+wint_t towupper_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::towupper(__c);
+}
+
+wint_t towlower_l(wint_t __c, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::towlower(__c);
+}
+
+int strcoll_l(const char *__s1, const char *__s2, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::strcoll(__s1, __s2);
+}
+
+size_t strxfrm_l(char *__dest, const char *__src, size_t __n, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::strxfrm(__dest, __src, __n);
+}
+
+size_t strftime_l(char* __s, size_t __max, const char* __format, const struct tm* __tm, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::strftime(__s, __max, __format, __tm);
+}
+
+int wcscoll_l(const wchar_t *__ws1, const wchar_t *__ws2, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::wcscoll(__ws1, __ws2);
+}
- previous_loc->category_mask = LC_ALL_MASK;
- return previous_loc;
+size_t wcsxfrm_l(wchar_t *__dest, const wchar_t *__src, size_t __n, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::wcsxfrm(__dest, __src, __n);
}
-#ifdef __cplusplus
+int iswctype_l(wint_t __c, wctype_t __type, locale_t __l) {
+ __locale::__locale_guard __newloc(__l);
+ return ::iswctype(__c, __type);
}
-#endif // __cplusplus
+} // namespace __ibm
+} // namespace __locale
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
new file mode 100644
index 0000000000000..846cdf6862c0c
--- /dev/null
+++ b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that version of the POSIX functions provided outside of libc++ don't
+// cause compilation errors.
+
+struct locale_t { };
+locale_t newlocale(int category_mask, const char* locale, locale_t base);
+void freelocale(locale_t locobj);
+locale_t uselocale(locale_t newloc);
+
+#ifdef _LP64
+typedef unsigned long size_t;
+#else
+typedef unsigned int size_t;
+#endif
+typedef short mbstate_t;
+size_t mbsnrtowcs(wchar_t*, const char**, size_t, size_t, mbstate_t*);
+size_t wcsnrtombs(char*, const wchar_t**, size_t, size_t, mbstate_t*);
+
+#include <locale>
diff --git a/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
new file mode 100644
index 0000000000000..fc5e5d8be790f
--- /dev/null
+++ b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Validating the following declaration of mbsnrtowcs resides in std::__locale::__ibm namespace.
+// size_t mbsnrtowcs(wchar_t*, const char**, size_t, size_t, mbstate_t*);
+
+#include <locale>
+
+int main(int, char**) {
+ const char* mb_string = "Hello, World!";
+ wchar_t w_string[20];
+ mbstate_t state;
+ size_t mb_chars = strlen(mb_string);
+ size_t w_chars = 0;
+
+ // Convert the multibyte string to a wide-character string
+ w_chars = std::__locale::__ibm::mbsnrtowcs(w_string, &mb_string, mb_chars, 13, &state);
+
+ return w_chars == 13;
+}
diff --git a/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
new file mode 100644
index 0000000000000..b7a6385b496f8
--- /dev/null
+++ b/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure the following libcxx override can coexists with standard C function.
+// std::__ibm int nanosleep(const struct timespec* , struct timespec* );
+
+#include <time.h> // timespec
+
+int nanosleep(const struct timespec* , struct timespec* );
+#include <mutex>
diff --git a/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
new file mode 100644
index 0000000000000..1fabc7a433c86
--- /dev/null
+++ b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Validating the following declaration of wcsnrtombs resides in std::__locale::__ibm namespace.
+// size_t wcsnrtombs(char*, const wchar_t**, size_t, size_t, mbstate_t*);
+
+#include <locale>
+
+int main(int, char**) {
+ const wchar_t* w_string = L"Hello, World!";
+ mbstate_t state;
+ char mb_string[20];
+ size_t w_chars = wcslen(w_string);
+ size_t mb_chars = 0;
+
+ // Convert the wide-character string to a multibyte string
+ mb_chars = std::__locale::__ibm::wcsnrtombs(mb_string, &w_string, w_chars, 13, &state);
+
+ return mb_chars == 13;
+}
diff --git a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
new file mode 100644
index 0000000000000..cc7c9298f12ce
--- /dev/null
+++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <ctype.h>
+#include <wctype.h>
+#include <assert.h>
+#include <locale>
+
+// This test makes sure that various macro defined on z/OS in
+// <ctype.h> and <cwtype.h> which previously were in conflict
+// with functions defined in libc++ <locale_base_api.h> still
+// work even though they are undefined in <__undef_macros>
+// to remove name collisions.
+
+int main(int, char**) {
+ setlocale(LC_ALL, "C");
+ {
+ char upper = 'A';
+ char lower = 'a';
+ assert(islower(lower));
+ assert(tolower(upper) == lower);
+ assert(isupper(upper));
+ assert(toupper(lower) == upper);
+ assert(isdigit('1'));
+ assert(isxdigit('b'));
+ }
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ {
+ wchar_t wspace = L' ';
+ wchar_t wprint = L'^';
+ wchar_t wcntrl = L'';
+ wchar_t wupper = L'A';
+ wchar_t wlower = L'a';
+ wchar_t walpha = L'z';
+ wchar_t wblank = L' ';
+ wchar_t wdigit = L'1';
+ wchar_t wpunct = L',';
+ wchar_t wxdigit = L'B';
+
+ assert(iswctype(L'A', wctype("alpha")));
+ assert(iswctype(L'1', wctype("digit")));
+ assert(iswspace(wspace));
+ assert(iswprint(wprint));
+ assert(iswcntrl(wcntrl));
+ assert(iswupper(wupper));
+ assert(iswlower(wlower));
+ assert(iswalpha(walpha));
+ assert(iswblank(wblank));
+ assert(iswdigit(wdigit));
+ assert(iswpunct(wpunct));
+ assert(iswxdigit(wxdigit));
+
+ assert(static_cast<wint_t>(wlower) == towlower(wupper));
+ assert(static_cast<wint_t>(wupper) == towupper(wlower));
+ }
+#endif
+
+ return 0;
+}
+
diff --git a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
new file mode 100644
index 0000000000000..fed9c683d1fbc
--- /dev/null
+++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <locale>
+#include <cctype>
+#include <cwctype>
+#include <cassert>
+
+// This test makes sure that various macro defined on z/OS in
+// <ctype.h> and <cwtype.h> which previously were in conflict
+// with functions defined in libc++ <locale_base_api.h> still
+// work even though they are undefined in <__undef_macros>
+// to remove name collisions.
+
+int main(int, char**) {
+ std::locale loc("C");
+ {
+ char upper = 'A';
+ char lower = 'a';
+ char digit = '1';
+ char xdigit = 'b';
+ auto& CF = std::use_facet<std::ctype_byname<char>>(loc);
+ assert(CF.is(std::ctype_base::lower, lower));
+ assert(CF.is(std::ctype_base::upper, upper));
+ assert(CF.is(std::ctype_base::digit, digit));
+ assert(CF.is(std::ctype_base::xdigit, xdigit));
+ assert(lower == CF.tolower(upper));
+ assert(upper == CF.toupper(lower));
+ }
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ {
+ wchar_t wctype = L'A';
+ wchar_t wspace = L' ';
+ wchar_t wprint = L'^';
+ wchar_t wcntrl = L'';
+ wchar_t wupper = L'A';
+ wchar_t wlower = L'a';
+ wchar_t walpha = L'z';
+ wchar_t wblank = L' ';
+ wchar_t wdigit = L'1';
+ wchar_t wpunct = L',';
+ wchar_t wxdigit = L'B';
+
+ assert(std::iswctype(wctype, std::wctype("alpha")));
+ assert(std::iswctype(wdigit, std::wctype("digit")));
+ assert(std::iswspace(wspace));
+ assert(std::iswprint(wprint));
+ assert(std::iswcntrl(wcntrl));
+ assert(std::iswupper(wupper));
+ assert(std::iswlower(wlower));
+ assert(std::iswalpha(walpha));
+ assert(std::iswblank(wblank));
+ assert(std::iswdigit(wdigit));
+ assert(std::iswpunct(wpunct));
+ assert(std::iswxdigit(wxdigit));
+
+ auto& WF = std::use_facet<std::ctype_byname<wchar_t>>(loc);
+ assert(wlower == WF.tolower(wupper));
+ assert(wupper == WF.toupper(wlower));
+ }
+#endif
+
+ return 0;
+}
+
>From c88a34907f54fc12e30efc95d11e2c3866d289e8 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Tue, 28 Oct 2025 17:22:38 +0000
Subject: [PATCH 2/3] fixed formatting
---
libcxx/include/__locale_dir/locale_base_api.h | 2 +-
libcxx/src/support/ibm/localeconv.cpp | 13 +-
libcxx/src/support/ibm/mbsnrtowcs.cpp | 15 +-
libcxx/src/support/ibm/wcsnrtombs.cpp | 15 +-
libcxx/src/support/ibm/xlocale_zos.cpp | 129 +++++++++---------
...internal.zos.locale.funcs.compile.pass.cpp | 2 +-
.../internal.zos.mbsnrtowcs.compile.pass.cpp | 16 +--
.../internal.zos.nanosleep.compile.pass.cpp | 2 +-
.../internal.zos.wcsnrtombs.compile.pass.cpp | 16 +--
.../locale.ctype.byname/ctype.c.pass.cpp | 77 ++++++-----
.../locale.ctype.byname/ctype.cxx.pass.cpp | 87 ++++++------
11 files changed, 181 insertions(+), 193 deletions(-)
diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h
index 6f99e40a9dee2..b88a065aeffe4 100644
--- a/libcxx/include/__locale_dir/locale_base_api.h
+++ b/libcxx/include/__locale_dir/locale_base_api.h
@@ -132,7 +132,7 @@ _LIBCPP_PUSH_MACROS
// (by providing global non-reserved names) and the new API. As we move individual platforms
// towards the new way of defining the locale base API, this should disappear since each platform
// will define those directly.
-# if defined(_AIX)
+# if defined(_AIX)
# include <__locale_dir/locale_base_api/ibm.h>
# elif defined(__OpenBSD__)
# include <__locale_dir/locale_base_api/openbsd.h>
diff --git a/libcxx/src/support/ibm/localeconv.cpp b/libcxx/src/support/ibm/localeconv.cpp
index 4ab6b7a75f618..85d0b2c1e3236 100644
--- a/libcxx/src/support/ibm/localeconv.cpp
+++ b/libcxx/src/support/ibm/localeconv.cpp
@@ -13,18 +13,17 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-lconv *__libcpp_localeconv_l(locale_t& __l)
-{
+lconv* __libcpp_localeconv_l(locale_t& __l) {
__locale::__locale_guard __current(__l);
- lconv * lc = localeconv();
+ lconv* lc = localeconv();
static lconv newlc;
newlc = *lc;
- enum {max_char_num = 20};
-#define DeepCopy(mbr) \
- static char buf_##mbr[max_char_num]; \
- strncpy(buf_##mbr, lc->mbr, max_char_num); \
+ enum { max_char_num = 20 };
+#define DeepCopy(mbr) \
+ static char buf_##mbr[max_char_num]; \
+ strncpy(buf_##mbr, lc->mbr, max_char_num); \
newlc.mbr = buf_##mbr;
DeepCopy(decimal_point);
diff --git a/libcxx/src/support/ibm/mbsnrtowcs.cpp b/libcxx/src/support/ibm/mbsnrtowcs.cpp
index 590ac0617a67d..6e870cff793a2 100644
--- a/libcxx/src/support/ibm/mbsnrtowcs.cpp
+++ b/libcxx/src/support/ibm/mbsnrtowcs.cpp
@@ -23,12 +23,11 @@ namespace __ibm {
// Returns (size_t) -1 when an invalid sequence is encountered.
// Leaves *`src` pointing to the next character to convert or NULL
// if a null character was converted from *`src`.
-size_t mbsnrtowcs(
- wchar_t* __restrict dst,
- const char** __restrict src,
- size_t src_size_bytes,
- size_t max_dest_chars,
- mbstate_t* __restrict ps) {
+size_t mbsnrtowcs(wchar_t* __restrict dst,
+ const char** __restrict src,
+ size_t src_size_bytes,
+ size_t max_dest_chars,
+ mbstate_t* __restrict ps) {
const size_t terminated_sequence = static_cast<size_t>(0);
const size_t invalid_sequence = static_cast<size_t>(-1);
const size_t incomplete_sequence = static_cast<size_t>(-2);
@@ -101,9 +100,7 @@ size_t mbsnrtowcs(
return dest_converted;
}
-size_t __libcpp_mbsnrtowcs_l(wchar_t * dest, const char **src, size_t nms,
- size_t len, mbstate_t *ps, locale_t l)
-{
+size_t __libcpp_mbsnrtowcs_l(wchar_t* dest, const char** src, size_t nms, size_t len, mbstate_t* ps, locale_t l) {
__locale::__locale_guard current(l);
return mbsnrtowcs(dest, src, nms, len, ps);
}
diff --git a/libcxx/src/support/ibm/wcsnrtombs.cpp b/libcxx/src/support/ibm/wcsnrtombs.cpp
index 437ea52ecf1ac..c9d6744d568f3 100644
--- a/libcxx/src/support/ibm/wcsnrtombs.cpp
+++ b/libcxx/src/support/ibm/wcsnrtombs.cpp
@@ -22,12 +22,11 @@ namespace __ibm {
// converted from *src, excluding the null terminator.
// Returns (size_t) -1 if an error occurs and sets errno.
// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.
-size_t wcsnrtombs(
- char* __restrict dst,
- const wchar_t** __restrict src,
- size_t max_source_chars,
- size_t dst_size_bytes,
- mbstate_t* __restrict ps) {
+size_t wcsnrtombs(char* __restrict dst,
+ const wchar_t** __restrict src,
+ size_t max_source_chars,
+ size_t dst_size_bytes,
+ mbstate_t* __restrict ps) {
const size_t invalid_wchar = static_cast<size_t>(-1);
size_t source_converted;
@@ -98,9 +97,7 @@ size_t wcsnrtombs(
return dest_converted;
}
-size_t __libcpp_wcsnrtombs_l(char *dest, const wchar_t **src, size_t nwc,
- size_t len, mbstate_t *ps, locale_t l)
-{
+size_t __libcpp_wcsnrtombs_l(char* dest, const wchar_t** src, size_t nwc, size_t len, mbstate_t* ps, locale_t l) {
__locale::__locale_guard __current(l);
return wcsnrtombs(dest, src, nwc, len, ps);
}
diff --git a/libcxx/src/support/ibm/xlocale_zos.cpp b/libcxx/src/support/ibm/xlocale_zos.cpp
index 22bc0b0f72feb..2e4cca41fe2bb 100644
--- a/libcxx/src/support/ibm/xlocale_zos.cpp
+++ b/libcxx/src/support/ibm/xlocale_zos.cpp
@@ -14,61 +14,58 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#define CategoryList(pair, sep) \
- pair(LC_COLLATE, lc_collate) sep \
- pair(LC_CTYPE, lc_ctype) sep \
- pair(LC_MONETARY, lc_monetary) sep \
- pair(LC_NUMERIC, lc_numeric) sep \
- pair(LC_TIME, lc_time) sep \
- pair(LC_MESSAGES, lc_messages)
+#define CategoryList(pair, sep) \
+ pair(LC_COLLATE, lc_collate) sep pair(LC_CTYPE, lc_ctype) \
+ sep pair(LC_MONETARY, lc_monetary) \
+ sep pair(LC_NUMERIC, lc_numeric) \
+ sep pair(LC_TIME, lc_time) \
+ sep pair(LC_MESSAGES, lc_messages)
// check ids and masks agree
-#define check_ids_and_masks_agree(id, _) \
- static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id); \
+#define check_ids_and_masks_agree(id, _) \
+ static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id); \
static_assert((1 << id) == _CATMASK(id), "mask does not have expected value for " #id);
-CategoryList(check_ids_and_masks_agree,)
+CategoryList(check_ids_and_masks_agree, )
#undef check_ids_and_masks_agree
// check that LC_ALL_MASK is defined as expected
#define get_mask(id, _) id##_MASK
-static_assert(LC_ALL_MASK == (CategoryList(get_mask, |)), "LC_ALL_MASK does not have the expected value. Check that its definition includes all supported categories");
+ static_assert(
+ LC_ALL_MASK == (CategoryList(get_mask, |)),
+ "LC_ALL_MASK does not have the expected value. Check that its definition includes all supported categories");
#undef get_mask
-
// initialize c_locale
#define init_clocale(id, locale_member) "C",
-static locale_struct c_locale = { LC_ALL_MASK, CategoryList(init_clocale, ) };
+static locale_struct c_locale = {LC_ALL_MASK, CategoryList(init_clocale, )};
#undef init_clocale
static locale_t current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
-
-locale_t __c_locale() {
- return &c_locale;
-}
+locale_t __c_locale() { return &c_locale; }
// locale
locale_t newlocale(int category_mask, const char* locale, locale_t base) {
// start with some basic checks
- if (! locale) {
+ if (!locale) {
errno = EINVAL;
- return (locale_t) 0;
+ return (locale_t)0;
}
if (category_mask & ~LC_ALL_MASK) {
// then there are bits in category_mask that does not correspond
// to a valid category
errno = EINVAL;
- return (locale_t) 0;
+ return (locale_t)0;
}
- locale_t new_loc = new locale_struct;
+ locale_t new_loc = new locale_struct;
int num_locales_not_found = 0;
if (base && base != _LIBCPP_LC_GLOBAL_LOCALE)
*new_loc = *base;
- auto set_for_category = [&](int id, int mask, std::string &setting) {
- const char *setting_to_apply = nullptr;
+ auto set_for_category = [&](int id, int mask, std::string& setting) {
+ const char* setting_to_apply = nullptr;
if (category_mask & mask)
setting_to_apply = locale;
@@ -77,7 +74,7 @@ locale_t newlocale(int category_mask, const char* locale, locale_t base) {
if (setting_to_apply) {
// setlocale takes the id, not the mask
- const char *saved_setting = setlocale(id, nullptr);
+ const char* saved_setting = setlocale(id, nullptr);
if (setlocale(id, setting_to_apply)) {
// then setting_to_apply is valid for this category
// restore the saved setting
@@ -99,8 +96,8 @@ locale_t newlocale(int category_mask, const char* locale, locale_t base) {
if (num_locales_not_found != 0) {
delete new_loc;
- errno = ENOENT;
- new_loc = (locale_t) 0;
+ errno = ENOENT;
+ new_loc = (locale_t)0;
}
return new_loc;
@@ -117,12 +114,12 @@ locale_t uselocale(locale_t new_loc) {
if (new_loc == _LIBCPP_LC_GLOBAL_LOCALE) {
current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
} else if (new_loc != nullptr) {
- locale_struct saved_locale;
+ locale_struct saved_locale;
saved_locale.category_mask = 0;
- auto apply_category = [&](int id, int mask, std::string &setting, std::string &save_setting)-> bool {
+ auto apply_category = [&](int id, int mask, std::string& setting, std::string& save_setting) -> bool {
if (new_loc->category_mask & mask) {
- const char *old_setting = setlocale(id, setting.c_str());
+ const char* old_setting = setlocale(id, setting.c_str());
if (old_setting) {
// we were able to set for this category. Save the old setting
// in case a subsequent category fails, and we need to restore
@@ -136,17 +133,17 @@ locale_t uselocale(locale_t new_loc) {
return true;
};
-#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale. locale_member)
+#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale.locale_member)
bool is_ok = CategoryList(Apply, &&);
#undef Apply
if (!is_ok) {
- auto restore = [&](int id, int mask, std::string &setting) {
+ auto restore = [&](int id, int mask, std::string& setting) {
if (saved_locale.category_mask & mask)
setlocale(id, setting.c_str());
};
-#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale. locale_member);
- CategoryList(Restore,);
+#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale.locale_member);
+ CategoryList(Restore, );
#undef Restore
errno = EINVAL;
return nullptr;
@@ -157,154 +154,154 @@ locale_t uselocale(locale_t new_loc) {
return prev_loc;
}
-int isdigit_l(int __c, locale_t __l) {
+int isdigit_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isdigit(__c);
}
-int isxdigit_l(int __c, locale_t __l) {
+int isxdigit_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isxdigit(__c);
}
namespace __locale {
namespace __ibm {
-int isalnum_l(int __c, locale_t __l) {
+int isalnum_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isalnum(__c);
}
-int isalpha_l(int __c, locale_t __l) {
+int isalpha_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isalpha(__c);
}
-int isblank_l(int __c, locale_t __l) {
+int isblank_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isblank(__c);
}
-int iscntrl_l(int __c, locale_t __l) {
+int iscntrl_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iscntrl(__c);
}
-int isgraph_l(int __c, locale_t __l) {
+int isgraph_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isgraph(__c);
}
-int islower_l(int __c, locale_t __l) {
+int islower_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::islower(__c);
}
-int isprint_l(int __c, locale_t __l) {
+int isprint_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isprint(__c);
}
-int ispunct_l(int __c, locale_t __l) {
+int ispunct_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::ispunct(__c);
}
-int isspace_l(int __c, locale_t __l) {
+int isspace_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isspace(__c);
}
-int isupper_l(int __c, locale_t __l) {
+int isupper_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::isupper(__c);
}
-int iswalnum_l(wint_t __c, locale_t __l) {
+int iswalnum_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswalnum(__c);
}
-int iswalpha_l(wint_t __c, locale_t __l) {
+int iswalpha_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswalpha(__c);
}
-int iswblank_l(wint_t __c, locale_t __l) {
+int iswblank_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswblank(__c);
}
-int iswcntrl_l(wint_t __c, locale_t __l) {
+int iswcntrl_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswcntrl(__c);
}
-int iswdigit_l(wint_t __c, locale_t __l) {
+int iswdigit_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswdigit(__c);
}
-int iswgraph_l(wint_t __c, locale_t __l) {
+int iswgraph_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswgraph(__c);
}
-int iswlower_l(wint_t __c, locale_t __l) {
+int iswlower_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswlower(__c);
}
-int iswprint_l(wint_t __c, locale_t __l) {
+int iswprint_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswprint(__c);
}
-int iswpunct_l(wint_t __c, locale_t __l) {
+int iswpunct_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswpunct(__c);
}
-int iswspace_l(wint_t __c, locale_t __l) {
+int iswspace_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswspace(__c);
}
-int iswupper_l(wint_t __c, locale_t __l) {
+int iswupper_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswupper(__c);
}
-int iswxdigit_l(wint_t __c, locale_t __l) {
+int iswxdigit_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswxdigit(__c);
}
-int toupper_l(int __c, locale_t __l) {
+int toupper_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::toupper(__c);
}
-int tolower_l(int __c, locale_t __l) {
+int tolower_l(int __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::tolower(__c);
}
-wint_t towupper_l(wint_t __c, locale_t __l) {
+wint_t towupper_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::towupper(__c);
}
-wint_t towlower_l(wint_t __c, locale_t __l) {
+wint_t towlower_l(wint_t __c, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::towlower(__c);
}
-int strcoll_l(const char *__s1, const char *__s2, locale_t __l) {
+int strcoll_l(const char* __s1, const char* __s2, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::strcoll(__s1, __s2);
}
-size_t strxfrm_l(char *__dest, const char *__src, size_t __n, locale_t __l) {
+size_t strxfrm_l(char* __dest, const char* __src, size_t __n, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::strxfrm(__dest, __src, __n);
}
@@ -314,17 +311,17 @@ size_t strftime_l(char* __s, size_t __max, const char* __format, const struct tm
return ::strftime(__s, __max, __format, __tm);
}
-int wcscoll_l(const wchar_t *__ws1, const wchar_t *__ws2, locale_t __l) {
+int wcscoll_l(const wchar_t* __ws1, const wchar_t* __ws2, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::wcscoll(__ws1, __ws2);
}
-size_t wcsxfrm_l(wchar_t *__dest, const wchar_t *__src, size_t __n, locale_t __l) {
+size_t wcsxfrm_l(wchar_t* __dest, const wchar_t* __src, size_t __n, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::wcsxfrm(__dest, __src, __n);
}
-int iswctype_l(wint_t __c, wctype_t __type, locale_t __l) {
+int iswctype_l(wint_t __c, wctype_t __type, locale_t __l) {
__locale::__locale_guard __newloc(__l);
return ::iswctype(__c, __type);
}
diff --git a/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
index 846cdf6862c0c..9ca3b157253cb 100644
--- a/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
+++ b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp
@@ -9,7 +9,7 @@
// Test that version of the POSIX functions provided outside of libc++ don't
// cause compilation errors.
-struct locale_t { };
+struct locale_t {};
locale_t newlocale(int category_mask, const char* locale, locale_t base);
void freelocale(locale_t locobj);
locale_t uselocale(locale_t newloc);
diff --git a/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
index fc5e5d8be790f..59ff3a1fc8194 100644
--- a/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
+++ b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp
@@ -12,14 +12,14 @@
#include <locale>
int main(int, char**) {
- const char* mb_string = "Hello, World!";
- wchar_t w_string[20];
- mbstate_t state;
- size_t mb_chars = strlen(mb_string);
- size_t w_chars = 0;
+ const char* mb_string = "Hello, World!";
+ wchar_t w_string[20];
+ mbstate_t state;
+ size_t mb_chars = strlen(mb_string);
+ size_t w_chars = 0;
- // Convert the multibyte string to a wide-character string
- w_chars = std::__locale::__ibm::mbsnrtowcs(w_string, &mb_string, mb_chars, 13, &state);
+ // Convert the multibyte string to a wide-character string
+ w_chars = std::__locale::__ibm::mbsnrtowcs(w_string, &mb_string, mb_chars, 13, &state);
- return w_chars == 13;
+ return w_chars == 13;
}
diff --git a/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
index b7a6385b496f8..1f3e94a1074a4 100644
--- a/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
+++ b/libcxx/test/libcxx/internal.zos.nanosleep.compile.pass.cpp
@@ -11,5 +11,5 @@
#include <time.h> // timespec
-int nanosleep(const struct timespec* , struct timespec* );
+int nanosleep(const struct timespec*, struct timespec*);
#include <mutex>
diff --git a/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
index 1fabc7a433c86..efbc1e2e1cf6d 100644
--- a/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
+++ b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp
@@ -12,14 +12,14 @@
#include <locale>
int main(int, char**) {
- const wchar_t* w_string = L"Hello, World!";
- mbstate_t state;
- char mb_string[20];
- size_t w_chars = wcslen(w_string);
- size_t mb_chars = 0;
+ const wchar_t* w_string = L"Hello, World!";
+ mbstate_t state;
+ char mb_string[20];
+ size_t w_chars = wcslen(w_string);
+ size_t mb_chars = 0;
- // Convert the wide-character string to a multibyte string
- mb_chars = std::__locale::__ibm::wcsnrtombs(mb_string, &w_string, w_chars, 13, &state);
+ // Convert the wide-character string to a multibyte string
+ mb_chars = std::__locale::__ibm::wcsnrtombs(mb_string, &w_string, w_chars, 13, &state);
- return mb_chars == 13;
+ return mb_chars == 13;
}
diff --git a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
index cc7c9298f12ce..dc2132de8ce1c 100644
--- a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp
@@ -18,49 +18,48 @@
// to remove name collisions.
int main(int, char**) {
- setlocale(LC_ALL, "C");
- {
- char upper = 'A';
- char lower = 'a';
- assert(islower(lower));
- assert(tolower(upper) == lower);
- assert(isupper(upper));
- assert(toupper(lower) == upper);
- assert(isdigit('1'));
- assert(isxdigit('b'));
- }
+ setlocale(LC_ALL, "C");
+ {
+ char upper = 'A';
+ char lower = 'a';
+ assert(islower(lower));
+ assert(tolower(upper) == lower);
+ assert(isupper(upper));
+ assert(toupper(lower) == upper);
+ assert(isdigit('1'));
+ assert(isxdigit('b'));
+ }
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- {
- wchar_t wspace = L' ';
- wchar_t wprint = L'^';
- wchar_t wcntrl = L'';
- wchar_t wupper = L'A';
- wchar_t wlower = L'a';
- wchar_t walpha = L'z';
- wchar_t wblank = L' ';
- wchar_t wdigit = L'1';
- wchar_t wpunct = L',';
- wchar_t wxdigit = L'B';
+ {
+ wchar_t wspace = L' ';
+ wchar_t wprint = L'^';
+ wchar_t wcntrl = L'';
+ wchar_t wupper = L'A';
+ wchar_t wlower = L'a';
+ wchar_t walpha = L'z';
+ wchar_t wblank = L' ';
+ wchar_t wdigit = L'1';
+ wchar_t wpunct = L',';
+ wchar_t wxdigit = L'B';
- assert(iswctype(L'A', wctype("alpha")));
- assert(iswctype(L'1', wctype("digit")));
- assert(iswspace(wspace));
- assert(iswprint(wprint));
- assert(iswcntrl(wcntrl));
- assert(iswupper(wupper));
- assert(iswlower(wlower));
- assert(iswalpha(walpha));
- assert(iswblank(wblank));
- assert(iswdigit(wdigit));
- assert(iswpunct(wpunct));
- assert(iswxdigit(wxdigit));
+ assert(iswctype(L'A', wctype("alpha")));
+ assert(iswctype(L'1', wctype("digit")));
+ assert(iswspace(wspace));
+ assert(iswprint(wprint));
+ assert(iswcntrl(wcntrl));
+ assert(iswupper(wupper));
+ assert(iswlower(wlower));
+ assert(iswalpha(walpha));
+ assert(iswblank(wblank));
+ assert(iswdigit(wdigit));
+ assert(iswpunct(wpunct));
+ assert(iswxdigit(wxdigit));
- assert(static_cast<wint_t>(wlower) == towlower(wupper));
- assert(static_cast<wint_t>(wupper) == towupper(wlower));
- }
+ assert(static_cast<wint_t>(wlower) == towlower(wupper));
+ assert(static_cast<wint_t>(wupper) == towupper(wlower));
+ }
#endif
- return 0;
+ return 0;
}
-
diff --git a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
index fed9c683d1fbc..07f5cbc9f4dab 100644
--- a/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp
@@ -18,54 +18,53 @@
// to remove name collisions.
int main(int, char**) {
- std::locale loc("C");
- {
- char upper = 'A';
- char lower = 'a';
- char digit = '1';
- char xdigit = 'b';
- auto& CF = std::use_facet<std::ctype_byname<char>>(loc);
- assert(CF.is(std::ctype_base::lower, lower));
- assert(CF.is(std::ctype_base::upper, upper));
- assert(CF.is(std::ctype_base::digit, digit));
- assert(CF.is(std::ctype_base::xdigit, xdigit));
- assert(lower == CF.tolower(upper));
- assert(upper == CF.toupper(lower));
- }
+ std::locale loc("C");
+ {
+ char upper = 'A';
+ char lower = 'a';
+ char digit = '1';
+ char xdigit = 'b';
+ auto& CF = std::use_facet<std::ctype_byname<char>>(loc);
+ assert(CF.is(std::ctype_base::lower, lower));
+ assert(CF.is(std::ctype_base::upper, upper));
+ assert(CF.is(std::ctype_base::digit, digit));
+ assert(CF.is(std::ctype_base::xdigit, xdigit));
+ assert(lower == CF.tolower(upper));
+ assert(upper == CF.toupper(lower));
+ }
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- {
- wchar_t wctype = L'A';
- wchar_t wspace = L' ';
- wchar_t wprint = L'^';
- wchar_t wcntrl = L'';
- wchar_t wupper = L'A';
- wchar_t wlower = L'a';
- wchar_t walpha = L'z';
- wchar_t wblank = L' ';
- wchar_t wdigit = L'1';
- wchar_t wpunct = L',';
- wchar_t wxdigit = L'B';
+ {
+ wchar_t wctype = L'A';
+ wchar_t wspace = L' ';
+ wchar_t wprint = L'^';
+ wchar_t wcntrl = L'';
+ wchar_t wupper = L'A';
+ wchar_t wlower = L'a';
+ wchar_t walpha = L'z';
+ wchar_t wblank = L' ';
+ wchar_t wdigit = L'1';
+ wchar_t wpunct = L',';
+ wchar_t wxdigit = L'B';
- assert(std::iswctype(wctype, std::wctype("alpha")));
- assert(std::iswctype(wdigit, std::wctype("digit")));
- assert(std::iswspace(wspace));
- assert(std::iswprint(wprint));
- assert(std::iswcntrl(wcntrl));
- assert(std::iswupper(wupper));
- assert(std::iswlower(wlower));
- assert(std::iswalpha(walpha));
- assert(std::iswblank(wblank));
- assert(std::iswdigit(wdigit));
- assert(std::iswpunct(wpunct));
- assert(std::iswxdigit(wxdigit));
+ assert(std::iswctype(wctype, std::wctype("alpha")));
+ assert(std::iswctype(wdigit, std::wctype("digit")));
+ assert(std::iswspace(wspace));
+ assert(std::iswprint(wprint));
+ assert(std::iswcntrl(wcntrl));
+ assert(std::iswupper(wupper));
+ assert(std::iswlower(wlower));
+ assert(std::iswalpha(walpha));
+ assert(std::iswblank(wblank));
+ assert(std::iswdigit(wdigit));
+ assert(std::iswpunct(wpunct));
+ assert(std::iswxdigit(wxdigit));
- auto& WF = std::use_facet<std::ctype_byname<wchar_t>>(loc);
- assert(wlower == WF.tolower(wupper));
- assert(wupper == WF.toupper(wlower));
- }
+ auto& WF = std::use_facet<std::ctype_byname<wchar_t>>(loc);
+ assert(wlower == WF.tolower(wupper));
+ assert(wupper == WF.toupper(wlower));
+ }
#endif
- return 0;
+ return 0;
}
-
>From 26e4eaccc1923cd2919522cefea81018d1f718f0 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <zibi at ca.ibm.com>
Date: Tue, 28 Oct 2025 19:17:04 +0000
Subject: [PATCH 3/3] Exclude 2 tests with non-alphnumeric characters
---
libcxx/utils/ci/run-buildbot | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 57ecf1e49dbf2..ad4a6700111ea 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -282,6 +282,8 @@ check-generated-output)
--exclude 'ostream.pass.cpp' \
--exclude 'transcoding.pass.cpp' \
--exclude 'underflow.pass.cpp' \
+ --exclude 'ctype.cxx.pass.cpp' \
+ --exclude 'ctype.c.pass.cpp' \
|| false
;;
#
More information about the libcxx-commits
mailing list