xref: /llvm-project/libcxx/src/support/win32/locale_win32.cpp (revision 88cca8ea209bb034eaec6af09a0227fb8cc7303e)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <__locale_dir/support/windows.h>
10 #include <clocale> // std::localeconv() & friends
11 #include <cstdarg> // va_start & friends
12 #include <cstddef>
13 #include <cstdio>  // std::vsnprintf & friends
14 #include <cstdlib> // std::strtof & friends
15 #include <ctime>   // std::strftime
16 #include <cwchar>  // wide char manipulation
17 
18 _LIBCPP_BEGIN_NAMESPACE_STD
19 namespace __locale {
20 
21 //
22 // Locale management
23 //
24 // FIXME: base and mask currently unused. Needs manual work to construct the new locale
25 __locale_t __newlocale(int /*mask*/, const char* locale, __locale_t /*base*/) {
26   return {::_create_locale(LC_ALL, locale), locale};
27 }
28 
29 __lconv_t* __localeconv(__locale_t& loc) {
30   __locale_guard __current(loc);
31   lconv* lc = std::localeconv();
32   if (!lc)
33     return lc;
34   return loc.__store_lconv(lc);
35 }
36 
37 //
38 // Strtonum functions
39 //
40 #if !defined(_LIBCPP_MSVCRT)
41 float __strtof(const char* nptr, char** endptr, __locale_t loc) {
42   __locale_guard __current(loc);
43   return std::strtof(nptr, endptr);
44 }
45 
46 long double __strtold(const char* nptr, char** endptr, __locale_t loc) {
47   __locale_guard __current(loc);
48   return std::strtold(nptr, endptr);
49 }
50 #endif
51 
52 //
53 // Character manipulation functions
54 //
55 #if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800
56 size_t __strftime(char* ret, size_t n, const char* format, const struct tm* tm, __locale_t loc) {
57   __locale_guard __current(loc);
58   return std::strftime(ret, n, format, tm);
59 }
60 #endif
61 
62 //
63 // Other functions
64 //
65 decltype(MB_CUR_MAX) __mb_len_max(__locale_t __l) {
66 #if defined(_LIBCPP_MSVCRT)
67   return ::___mb_cur_max_l_func(__l);
68 #else
69   __locale_guard __current(__l);
70   return MB_CUR_MAX;
71 #endif
72 }
73 
74 wint_t __btowc(int c, __locale_t loc) {
75   __locale_guard __current(loc);
76   return std::btowc(c);
77 }
78 
79 int __wctob(wint_t c, __locale_t loc) {
80   __locale_guard __current(loc);
81   return std::wctob(c);
82 }
83 
84 size_t __wcsnrtombs(char* __restrict dst,
85                     const wchar_t** __restrict src,
86                     size_t nwc,
87                     size_t len,
88                     mbstate_t* __restrict ps,
89                     __locale_t loc) {
90   __locale_guard __current(loc);
91   return ::wcsnrtombs(dst, src, nwc, len, ps);
92 }
93 
94 size_t __wcrtomb(char* __restrict s, wchar_t wc, mbstate_t* __restrict ps, __locale_t loc) {
95   __locale_guard __current(loc);
96   return std::wcrtomb(s, wc, ps);
97 }
98 
99 size_t __mbsnrtowcs(wchar_t* __restrict dst,
100                     const char** __restrict src,
101                     size_t nms,
102                     size_t len,
103                     mbstate_t* __restrict ps,
104                     __locale_t loc) {
105   __locale_guard __current(loc);
106   return ::mbsnrtowcs(dst, src, nms, len, ps);
107 }
108 
109 size_t
110 __mbrtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n, mbstate_t* __restrict ps, __locale_t loc) {
111   __locale_guard __current(loc);
112   return std::mbrtowc(pwc, s, n, ps);
113 }
114 
115 size_t __mbrlen(const char* __restrict s, size_t n, mbstate_t* __restrict ps, __locale_t loc) {
116   __locale_guard __current(loc);
117   return std::mbrlen(s, n, ps);
118 }
119 
120 size_t __mbsrtowcs(
121     wchar_t* __restrict dst, const char** __restrict src, size_t len, mbstate_t* __restrict ps, __locale_t loc) {
122   __locale_guard __current(loc);
123   return std::mbsrtowcs(dst, src, len, ps);
124 }
125 
126 int __snprintf(char* ret, size_t n, __locale_t loc, const char* format, ...) {
127   va_list ap;
128   va_start(ap, format);
129 #if defined(_LIBCPP_MSVCRT)
130   // FIXME: Remove usage of internal CRT function and globals.
131   int result = ::__stdio_common_vsprintf(
132       _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS | _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, ret, n, format, loc, ap);
133 #else
134   __locale_guard __current(loc);
135   _LIBCPP_DIAGNOSTIC_PUSH
136   _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
137   int result = std::vsnprintf(ret, n, format, ap);
138   _LIBCPP_DIAGNOSTIC_POP
139 #endif
140   va_end(ap);
141   return result;
142 }
143 
144 // Like sprintf, but when return value >= 0 it returns
145 // a pointer to a malloc'd string in *sptr.
146 // If return >= 0, use free to delete *sptr.
147 int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) {
148   *sptr = nullptr;
149   // Query the count required.
150   va_list ap_copy;
151   va_copy(ap_copy, ap);
152   _LIBCPP_DIAGNOSTIC_PUSH
153   _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
154   int count = vsnprintf(nullptr, 0, format, ap_copy);
155   _LIBCPP_DIAGNOSTIC_POP
156   va_end(ap_copy);
157   if (count < 0)
158     return count;
159   size_t buffer_size = static_cast<size_t>(count) + 1;
160   char* p            = static_cast<char*>(malloc(buffer_size));
161   if (!p)
162     return -1;
163   // If we haven't used exactly what was required, something is wrong.
164   // Maybe bug in vsnprintf. Report the error and return.
165   _LIBCPP_DIAGNOSTIC_PUSH
166   _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
167   if (vsnprintf(p, buffer_size, format, ap) != count) {
168     _LIBCPP_DIAGNOSTIC_POP
169     free(p);
170     return -1;
171   }
172   // All good. This is returning memory to the caller not freeing it.
173   *sptr = p;
174   return count;
175 }
176 
177 int __asprintf(char** ret, __locale_t loc, const char* format, ...) {
178   va_list ap;
179   va_start(ap, format);
180   __locale_guard __current(loc);
181   return __libcpp_vasprintf(ret, format, ap);
182 }
183 
184 } // namespace __locale
185 _LIBCPP_END_NAMESPACE_STD
186