1 // Definitions for <chrono> formatting -*- C++ -*-
3 // Copyright The GNU Toolchain Authors.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 #define _GLIBCXX_USE_CXX11_ABI 1
26 #include "../c++26/text_encoding.cc"
28 #ifdef _GLIBCXX_USE_NL_LANGINFO_L
31 # include <memory> // make_unique
32 # include <mutex> // mutex, lock_guard
33 # include <string.h> // strlen, strcpy
34 # ifdef _GLIBCXX_HAVE_ICONV
42 _GLIBCXX_BEGIN_NAMESPACE_VERSION
45 // Helpers for P2419R2
46 // (Clarify handling of encodings in localized formatting of chrono types)
47 // Convert a string from the locale's charset to UTF-8.
49 #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
52 #ifndef _GLIBCXX_HAS_GTHREADS
57 void unlock() const { }
61 // A non-standard locale::facet that caches the locale's std::text_encoding
62 // and an iconv descriptor for converting from that encoding to UTF-8.
63 struct __encoding
: locale::facet
68 __encoding(const text_encoding
& enc
, size_t refs
= 0)
69 : facet(refs
), _M_enc(enc
)
71 #ifdef _GLIBCXX_HAVE_ICONV
72 using enum text_encoding::id
;
79 _M_cd
= ::iconv_open("UTF-8", _M_enc
.name());
86 #ifdef _GLIBCXX_HAVE_ICONV
87 if (_M_cd
!= (::iconv_t
)-1)
93 #ifdef _GLIBCXX_HAVE_ICONV
94 ::iconv_t _M_cd
= (::iconv_t
)-1;
98 // Convert `input` to UTF-8, using `out` to hold the result.
100 conv(string_view input
, string
& out
) const
102 if (input
.empty()) [[unlikely
]]
103 return codecvt_base::noconv
;
105 #ifdef _GLIBCXX_HAVE_ICONV
106 if (_M_cd
== (::iconv_t
)-1)
107 return codecvt_base::error
;
109 size_t inbytesleft
= input
.size();
113 auto overwrite
= [&](char* p
, size_t n
) {
115 = const_cast<char*>(input
.data()) + input
.size() - inbytesleft
;
116 char* outbytes
= p
+ written
;
117 size_t outbytesleft
= n
- written
;
118 size_t res
= ::iconv(_M_cd
, &inbytes
, &inbytesleft
,
119 &outbytes
, &outbytesleft
);
120 if (res
== (size_t)-1)
124 ::iconv(_M_cd
, nullptr, 0, nullptr, 0); // reset
131 written
= outbytes
- p
;
136 lock_guard
<mutex
> lock(mx
);
139 // Estimate that we need 1.5 UTF-8 code units per char, but increase
140 // that every time the conversion fails due to insufficient space.
141 out
.resize_and_overwrite((inbytesleft
* 3 / 2) * mult
, overwrite
);
146 return out
.empty() ? codecvt_base::error
: codecvt_base::ok
;
148 return codecvt_base::error
;
153 locale::id
__encoding::id
;
155 inline const __encoding
*
156 __get_encoding_facet(const locale
& loc
)
158 // Don't need to use __try_use_facet with its dynamic_cast<const __encoding*>
159 // because we know there are no types derived from __encoding. We have the
160 // facet if the id is within the array bounds and the element is non-null.
161 const auto id
= __encoding::id
._M_id();
162 if (id
>= loc
._M_impl
->_M_facets_size
)
164 return static_cast<const __encoding
*>(loc
._M_impl
->_M_facets
[id
]);
170 __with_encoding_conversion(const locale
& loc
)
172 if (__get_encoding_facet(loc
))
175 string name
= loc
.name();
176 if (name
== "C" || name
== "*")
179 text_encoding locenc
= __locale_encoding(name
.c_str());
181 if (locenc
== text_encoding::UTF8
|| locenc
== text_encoding::ASCII
182 || locenc
== text_encoding::unknown
)
185 auto facetp
= std::make_unique
<__encoding
>(locenc
);
186 locale
loc2(loc
, facetp
.get()); // FIXME: PR libstdc++/113704
188 // FIXME: Ideally we wouldn't need to reallocate this string again,
189 // just don't delete[] it in the locale(locale, Facet*) constructor.
190 if (const char* name
= loc
._M_impl
->_M_names
[0])
192 loc2
._M_impl
->_M_names
[0] = new char[strlen(name
) + 1];
193 strcpy(loc2
._M_impl
->_M_names
[0], name
);
199 __locale_encoding_to_utf8(const locale
& loc
, string_view str
, void* poutbuf
)
201 string
& outbuf
= *static_cast<string
*>(poutbuf
);
202 if (auto enc_facet
= __get_encoding_facet(loc
))
204 auto result
= enc_facet
->conv(str
, outbuf
);
205 if (result
== codecvt_base::ok
)
206 str
= outbuf
; // UTF-8 output was written to outbuf.
207 // else result was noconv or error, return str unchanged.
213 __with_encoding_conversion(const locale
& loc
)
217 __locale_encoding_to_utf8(const locale
&, string_view str
, void*)
219 #endif // USE_NL_LANGINFO_L && CHAR_BIT == 8
220 } // namespace __format
221 _GLIBCXX_END_NAMESPACE_VERSION