//===----------------------------------------------------------------------===// // // 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_dir/support/windows.h> #include // std::localeconv() & friends #include // va_start & friends #include #include // std::vsnprintf & friends #include // std::strtof & friends #include // std::strftime #include // wide char manipulation _LIBCPP_BEGIN_NAMESPACE_STD namespace __locale { // // Locale management // // FIXME: base and mask currently unused. Needs manual work to construct the new locale __locale_t __newlocale(int /*mask*/, const char* locale, __locale_t /*base*/) { return {::_create_locale(LC_ALL, locale), locale}; } __lconv_t* __localeconv(__locale_t& loc) { __locale_guard __current(loc); lconv* lc = std::localeconv(); if (!lc) return lc; return loc.__store_lconv(lc); } // // Strtonum functions // #if !defined(_LIBCPP_MSVCRT) float __strtof(const char* nptr, char** endptr, __locale_t loc) { __locale_guard __current(loc); return std::strtof(nptr, endptr); } long double __strtold(const char* nptr, char** endptr, __locale_t loc) { __locale_guard __current(loc); return std::strtold(nptr, endptr); } #endif // // Character manipulation functions // #if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800 size_t __strftime(char* ret, size_t n, const char* format, const struct tm* tm, __locale_t loc) { __locale_guard __current(loc); return std::strftime(ret, n, format, tm); } #endif // // Other functions // decltype(MB_CUR_MAX) __mb_len_max(__locale_t __l) { #if defined(_LIBCPP_MSVCRT) return ::___mb_cur_max_l_func(__l); #else __locale_guard __current(__l); return MB_CUR_MAX; #endif } wint_t __btowc(int c, __locale_t loc) { __locale_guard __current(loc); return std::btowc(c); } int __wctob(wint_t c, __locale_t loc) { __locale_guard __current(loc); return std::wctob(c); } size_t __wcsnrtombs(char* __restrict dst, const wchar_t** __restrict src, size_t nwc, size_t len, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return ::wcsnrtombs(dst, src, nwc, len, ps); } size_t __wcrtomb(char* __restrict s, wchar_t wc, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return std::wcrtomb(s, wc, ps); } size_t __mbsnrtowcs(wchar_t* __restrict dst, const char** __restrict src, size_t nms, size_t len, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return ::mbsnrtowcs(dst, src, nms, len, ps); } size_t __mbrtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return std::mbrtowc(pwc, s, n, ps); } size_t __mbrlen(const char* __restrict s, size_t n, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return std::mbrlen(s, n, ps); } size_t __mbsrtowcs( wchar_t* __restrict dst, const char** __restrict src, size_t len, mbstate_t* __restrict ps, __locale_t loc) { __locale_guard __current(loc); return std::mbsrtowcs(dst, src, len, ps); } int __snprintf(char* ret, size_t n, __locale_t loc, const char* format, ...) { va_list ap; va_start(ap, format); #if defined(_LIBCPP_MSVCRT) // FIXME: Remove usage of internal CRT function and globals. int result = ::__stdio_common_vsprintf( _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS | _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, ret, n, format, loc, ap); #else __locale_guard __current(loc); _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral") int result = std::vsnprintf(ret, n, format, ap); _LIBCPP_DIAGNOSTIC_POP #endif va_end(ap); return result; } // Like sprintf, but when return value >= 0 it returns // a pointer to a malloc'd string in *sptr. // If return >= 0, use free to delete *sptr. int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) { *sptr = nullptr; // Query the count required. va_list ap_copy; va_copy(ap_copy, ap); _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral") int count = vsnprintf(nullptr, 0, format, ap_copy); _LIBCPP_DIAGNOSTIC_POP va_end(ap_copy); if (count < 0) return count; size_t buffer_size = static_cast(count) + 1; char* p = static_cast(malloc(buffer_size)); if (!p) return -1; // If we haven't used exactly what was required, something is wrong. // Maybe bug in vsnprintf. Report the error and return. _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral") if (vsnprintf(p, buffer_size, format, ap) != count) { _LIBCPP_DIAGNOSTIC_POP free(p); return -1; } // All good. This is returning memory to the caller not freeing it. *sptr = p; return count; } int __asprintf(char** ret, __locale_t loc, const char* format, ...) { va_list ap; va_start(ap, format); __locale_guard __current(loc); return __libcpp_vasprintf(ret, format, ap); } } // namespace __locale _LIBCPP_END_NAMESPACE_STD