From 97bb07c5546dff792dd7f7f92e56874559d35889 Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski 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 // std::lconv +#include +#include +#include + +#include + +_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 // malloc, realloc +#include // va_copy, va_end +#include // 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 +#include + +_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 // size_t #include // mbstate_t #include // MB_LEN_MAX #include // 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 // mbstate_t #include // MB_LEN_MAX #include // MB_CUR_MAX, size_t #include // 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 -#include +#include <__locale_dir/support/zos.h> +#include -#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 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 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 + +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 // timespec + +int nanosleep(const struct timespec* , struct timespec* ); +#include 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 + +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 +#include +#include +#include + +// This test makes sure that various macro defined on z/OS in +// and which previously were in conflict +// with functions defined in libc++ 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(wlower) == towlower(wupper)); + assert(static_cast(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 +#include +#include +#include + +// This test makes sure that various macro defined on z/OS in +// and which previously were in conflict +// with functions defined in libc++ 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>(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>(loc); + assert(wlower == WF.tolower(wupper)); + assert(wupper == WF.toupper(wlower)); + } +#endif + + return 0; +} + From f8690f48a025f2dd1878e3396dde76c86dbf9562 Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski Date: Tue, 28 Oct 2025 17:22:38 +0000 Subject: [PATCH 2/3] Use C++ headers and reserved naming for vasprintf and fix CI/formatting --- libcxx/include/__locale_dir/locale_base_api.h | 2 +- libcxx/include/__locale_dir/support/zos.h | 3 +- libcxx/include/__support/ibm/vasprintf.h | 22 +-- 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 | 4 +- .../internal.zos.mbsnrtowcs.compile.pass.cpp | 18 +-- .../internal.zos.nanosleep.compile.pass.cpp | 2 +- .../internal.zos.wcsnrtombs.compile.pass.cpp | 18 +-- .../locale.ctype.byname/ctype.c.pass.cpp | 77 ++++++----- .../locale.ctype.byname/ctype.cxx.pass.cpp | 87 ++++++------ libcxx/utils/ci/run-buildbot | 2 + 14 files changed, 201 insertions(+), 206 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/include/__locale_dir/support/zos.h b/libcxx/include/__locale_dir/support/zos.h index 3ab85bc0fabd9..7df0c61cfbdf2 100644 --- a/libcxx/include/__locale_dir/support/zos.h +++ b/libcxx/include/__locale_dir/support/zos.h @@ -32,7 +32,6 @@ 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_); } @@ -299,7 +298,7 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __as va_list __va; va_start(__va, __format); __locale_guard __current(__loc); - int __res = std::__ibm::vasprintf(__s, __format, __va); // non-standard + int __res = std::__ibm::__vasprintf(__s, __format, __va); // non-standard va_end(__va); return __res; } diff --git a/libcxx/include/__support/ibm/vasprintf.h b/libcxx/include/__support/ibm/vasprintf.h index bf42ec7963f45..693a97fe82e86 100644 --- a/libcxx/include/__support/ibm/vasprintf.h +++ b/libcxx/include/__support/ibm/vasprintf.h @@ -9,17 +9,17 @@ #ifndef _LIBCPP___SUPPORT_IBMVASPRINTF_H #define _LIBCPP___SUPPORT_IBMVASPRINTF_H -#include // malloc, realloc -#include // va_copy, va_end -#include // vsnprintf +#include // va_copy, va_end +#include // vsnprintf +#include // malloc, realloc _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) { +_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) { + if ((*__strp = (char*)std::malloc(buff_size)) == nullptr) { return -1; } @@ -27,21 +27,21 @@ _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char // 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); + __builtin_zos_va_copy(ap_copy, __ap); # else - __builtin_va_copy(ap_copy, ap); + __builtin_va_copy(ap_copy, __ap); # endif #else - va_copy(ap_copy, ap); + va_copy(ap_copy, __ap); #endif - int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy); + 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) { + if ((*__strp = (char*)std::realloc(*__strp, str_size + 1)) == nullptr) { return -1; } - str_size = vsnprintf(*strp, str_size + 1, fmt, ap); + str_size = vsnprintf(*__strp, str_size + 1, __fmt, __ap); } return str_size; } 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(0); const size_t invalid_sequence = static_cast(-1); const size_t incomplete_sequence = static_cast(-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(-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..273ff44417001 100644 --- a/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp +++ b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp @@ -6,10 +6,12 @@ // //===----------------------------------------------------------------------===// +// REQUIRES: target={{.+}}-zos{{.*}} + // 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..bdb437cb6ad51 100644 --- a/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp +++ b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp @@ -6,20 +6,22 @@ // //===----------------------------------------------------------------------===// +// REQUIRES: target={{.+}}-zos{{.*}} + // 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 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 // timespec -int nanosleep(const struct timespec* , struct timespec* ); +int nanosleep(const struct timespec*, struct timespec*); #include diff --git a/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp index 1fabc7a433c86..f5bd379361d07 100644 --- a/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp +++ b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp @@ -6,20 +6,22 @@ // //===----------------------------------------------------------------------===// +// REQUIRES: target={{.+}}-zos{{.*}} + // 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 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(wlower) == towlower(wupper)); - assert(static_cast(wupper) == towupper(wlower)); - } + assert(static_cast(wlower) == towlower(wupper)); + assert(static_cast(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..8270fb1dca622 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>(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 >(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>(loc); - assert(wlower == WF.tolower(wupper)); - assert(wupper == WF.toupper(wlower)); - } + auto& WF = std::use_facet >(loc); + assert(wlower == WF.tolower(wupper)); + assert(wupper == WF.toupper(wlower)); + } #endif - return 0; + return 0; } - 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 ;; # From b1cf60313d623d12773a9bfa6992f07ec512195c Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski Date: Wed, 29 Oct 2025 19:06:33 +0000 Subject: [PATCH 3/3] Fix ctype.cxx.pass.cpp --- .../category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) 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 8270fb1dca622..643a812b1da4f 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 @@ -11,6 +11,8 @@ #include #include +#include "test_macros.h" + // This test makes sure that various macro defined on z/OS in // and which previously were in conflict // with functions defined in libc++ still