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..b88a065aeffe4 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..7df0c61cfbdf2 --- /dev/null +++ b/libcxx/include/__locale_dir/support/zos.h @@ -0,0 +1,317 @@ +//===-----------------------------------------------------------------------===// +// +// 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_ != (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..693a97fe82e86 --- /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 // 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) { + const size_t buff_size = 256; + if ((*__strp = (char*)std::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*)std::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..85d0b2c1e3236 --- /dev/null +++ b/libcxx/src/support/ibm/localeconv.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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..6e870cff793a2 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,12 +23,11 @@ // 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( - 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); @@ -95,3 +99,12 @@ _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..c9d6744d568f3 100644 --- a/libcxx/src/support/ibm/wcsnrtombs.cpp +++ b/libcxx/src/support/ibm/wcsnrtombs.cpp @@ -6,23 +6,27 @@ // //===----------------------------------------------------------------------===// +#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( - 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; @@ -92,3 +96,12 @@ _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..2e4cca41fe2bb 100644 --- a/libcxx/src/support/ibm/xlocale_zos.cpp +++ b/libcxx/src/support/ibm/xlocale_zos.cpp @@ -6,125 +6,325 @@ // //===----------------------------------------------------------------------===// +#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 + +static locale_t current_locale = _LIBCPP_LC_GLOBAL_LOCALE; - // Check for errors. - if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) { +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; + } + 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; - } 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; - } - } } - // 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 (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 (category_mask & mask) + setting_to_apply = locale; + else if (!base) + setting_to_apply = "C"; + + 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; +} + +int isdigit_l(int __c, locale_t __l) { + __locale::__locale_guard __newloc(__l); + return ::isdigit(__c); +} - // 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 isxdigit_l(int __c, locale_t __l) { + __locale::__locale_guard __newloc(__l); + return ::isxdigit(__c); +} - while (std::getline(ss, s, delimiter)) { - tokenized.push_back(s); - } +namespace __locale { +namespace __ibm { +int isalnum_l(int __c, locale_t __l) { + __locale::__locale_guard __newloc(__l); + return ::isalnum(__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; - } +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..273ff44417001 --- /dev/null +++ b/libcxx/test/libcxx/internal.zos.locale.funcs.compile.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: target={{.+}}-zos{{.*}} + +// 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..bdb437cb6ad51 --- /dev/null +++ b/libcxx/test/libcxx/internal.zos.mbsnrtowcs.compile.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// 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; + + // 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..1f3e94a1074a4 --- /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..f5bd379361d07 --- /dev/null +++ b/libcxx/test/libcxx/internal.zos.wcsnrtombs.compile.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// 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; + + // 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..dc2132de8ce1c --- /dev/null +++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.c.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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..643a812b1da4f --- /dev/null +++ b/libcxx/test/std/localization/locale.categories/category.ctype/locale.ctype.byname/ctype.cxx.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#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 +// 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; +} 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 ;; #