1 // std::numpunct implementation details, GNU version -*- C++ -*- 2 3 // Copyright (C) 2001-2020 Free Software Foundation, Inc. 4 // 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) 9 // any later version. 10 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. 15 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. 19 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/>. 24 25 // 26 // ISO C++ 14882: 22.2.3.1.2 numpunct virtual functions 27 // 28 29 // Written by Benjamin Kosnik <bkoz@redhat.com> 30 31 #include <locale> 32 #include <bits/c++locale_internal.h> 33 #include <iconv.h> 34 35 namespace std _GLIBCXX_VISIBILITY(default) 36 { 37 _GLIBCXX_BEGIN_NAMESPACE_VERSION 38 39 extern char __narrow_multibyte_chars(const char* s, __locale_t cloc); 40 41 // This file might be compiled twice, but we only want to define this once. 42 #if ! _GLIBCXX_USE_CXX11_ABI 43 char __narrow_multibyte_chars(const char * s,__locale_t cloc)44 __narrow_multibyte_chars(const char* s, __locale_t cloc) 45 { 46 const char* codeset = __nl_langinfo_l(CODESET, cloc); 47 if (!strcmp(codeset, "UTF-8")) 48 { 49 // optimize for some known cases 50 if (!strcmp(s, "\u202F")) // NARROW NO-BREAK SPACE 51 return ' '; 52 if (!strcmp(s, "\u2019")) // RIGHT SINGLE QUOTATION MARK 53 return '\''; 54 if (!strcmp(s, "\u066C")) // ARABIC THOUSANDS SEPARATOR 55 return '\''; 56 } 57 58 iconv_t cd = iconv_open("ASCII//TRANSLIT", codeset); 59 if (cd != (iconv_t)-1) 60 { 61 char c1; 62 size_t inbytesleft = strlen(s); 63 size_t outbytesleft = 1; 64 char* inbuf = const_cast<char*>(s); 65 char* outbuf = &c1; 66 size_t n = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 67 iconv_close(cd); 68 if (n != (size_t)-1) 69 { 70 cd = iconv_open(codeset, "ASCII"); 71 if (cd != (iconv_t)-1) 72 { 73 char c2; 74 inbuf = &c1; 75 inbytesleft = 1; 76 outbuf = &c2; 77 outbytesleft = 1; 78 n = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 79 iconv_close(cd); 80 if (n != (size_t)-1) 81 return c2; 82 } 83 } 84 } 85 return '\0'; 86 } 87 #endif 88 89 template<> 90 void _M_initialize_numpunct(__c_locale __cloc)91 numpunct<char>::_M_initialize_numpunct(__c_locale __cloc) 92 { 93 if (!_M_data) 94 _M_data = new __numpunct_cache<char>; 95 96 if (!__cloc) 97 { 98 // "C" locale 99 _M_data->_M_grouping = ""; 100 _M_data->_M_grouping_size = 0; 101 _M_data->_M_use_grouping = false; 102 103 _M_data->_M_decimal_point = '.'; 104 _M_data->_M_thousands_sep = ','; 105 106 for (size_t __i = 0; __i < __num_base::_S_oend; ++__i) 107 _M_data->_M_atoms_out[__i] = __num_base::_S_atoms_out[__i]; 108 109 for (size_t __j = 0; __j < __num_base::_S_iend; ++__j) 110 _M_data->_M_atoms_in[__j] = __num_base::_S_atoms_in[__j]; 111 } 112 else 113 { 114 // Named locale. 115 _M_data->_M_decimal_point = *(__nl_langinfo_l(DECIMAL_POINT, 116 __cloc)); 117 const char* thousands_sep = __nl_langinfo_l(THOUSANDS_SEP, __cloc); 118 119 if (thousands_sep[0] != '\0' && thousands_sep[1] != '\0') 120 _M_data->_M_thousands_sep = __narrow_multibyte_chars(thousands_sep, 121 __cloc); 122 else 123 _M_data->_M_thousands_sep = *thousands_sep; 124 125 // Check for NULL, which implies no grouping. 126 if (_M_data->_M_thousands_sep == '\0') 127 { 128 // Like in "C" locale. 129 _M_data->_M_grouping = ""; 130 _M_data->_M_grouping_size = 0; 131 _M_data->_M_use_grouping = false; 132 _M_data->_M_thousands_sep = ','; 133 } 134 else 135 { 136 const char* __src = __nl_langinfo_l(GROUPING, __cloc); 137 const size_t __len = strlen(__src); 138 if (__len) 139 { 140 __try 141 { 142 char* __dst = new char[__len + 1]; 143 memcpy(__dst, __src, __len + 1); 144 _M_data->_M_grouping = __dst; 145 } 146 __catch(...) 147 { 148 delete _M_data; 149 _M_data = 0; 150 __throw_exception_again; 151 } 152 } 153 else 154 { 155 _M_data->_M_grouping = ""; 156 _M_data->_M_use_grouping = false; 157 } 158 _M_data->_M_grouping_size = __len; 159 } 160 } 161 162 // NB: There is no way to extact this info from posix locales. 163 // _M_truename = __nl_langinfo_l(YESSTR, __cloc); 164 _M_data->_M_truename = "true"; 165 _M_data->_M_truename_size = 4; 166 // _M_falsename = __nl_langinfo_l(NOSTR, __cloc); 167 _M_data->_M_falsename = "false"; 168 _M_data->_M_falsename_size = 5; 169 } 170 171 template<> ~numpunct()172 numpunct<char>::~numpunct() 173 { 174 if (_M_data->_M_grouping_size) 175 delete [] _M_data->_M_grouping; 176 delete _M_data; 177 } 178 179 #ifdef _GLIBCXX_USE_WCHAR_T 180 template<> 181 void _M_initialize_numpunct(__c_locale __cloc)182 numpunct<wchar_t>::_M_initialize_numpunct(__c_locale __cloc) 183 { 184 if (!_M_data) 185 _M_data = new __numpunct_cache<wchar_t>; 186 187 if (!__cloc) 188 { 189 // "C" locale 190 _M_data->_M_grouping = ""; 191 _M_data->_M_grouping_size = 0; 192 _M_data->_M_use_grouping = false; 193 194 _M_data->_M_decimal_point = L'.'; 195 _M_data->_M_thousands_sep = L','; 196 197 // Use ctype::widen code without the facet... 198 for (size_t __i = 0; __i < __num_base::_S_oend; ++__i) 199 _M_data->_M_atoms_out[__i] = 200 static_cast<wchar_t>(__num_base::_S_atoms_out[__i]); 201 202 for (size_t __j = 0; __j < __num_base::_S_iend; ++__j) 203 _M_data->_M_atoms_in[__j] = 204 static_cast<wchar_t>(__num_base::_S_atoms_in[__j]); 205 } 206 else 207 { 208 // Named locale. 209 // NB: In the GNU model wchar_t is always 32 bit wide. 210 union { char *__s; wchar_t __w; } __u; 211 __u.__s = __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc); 212 _M_data->_M_decimal_point = __u.__w; 213 214 __u.__s = __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc); 215 _M_data->_M_thousands_sep = __u.__w; 216 217 // Check for NULL, which implies no grouping. 218 if (_M_data->_M_thousands_sep == L'\0') 219 { 220 // Like in "C" locale. 221 _M_data->_M_grouping = ""; 222 _M_data->_M_grouping_size = 0; 223 _M_data->_M_use_grouping = false; 224 _M_data->_M_thousands_sep = L','; 225 } 226 else 227 { 228 const char* __src = __nl_langinfo_l(GROUPING, __cloc); 229 const size_t __len = strlen(__src); 230 if (__len) 231 { 232 __try 233 { 234 char* __dst = new char[__len + 1]; 235 memcpy(__dst, __src, __len + 1); 236 _M_data->_M_grouping = __dst; 237 } 238 __catch(...) 239 { 240 delete _M_data; 241 _M_data = 0; 242 __throw_exception_again; 243 } 244 } 245 else 246 { 247 _M_data->_M_grouping = ""; 248 _M_data->_M_use_grouping = false; 249 } 250 _M_data->_M_grouping_size = __len; 251 } 252 } 253 254 // NB: There is no way to extact this info from posix locales. 255 // _M_truename = __nl_langinfo_l(YESSTR, __cloc); 256 _M_data->_M_truename = L"true"; 257 _M_data->_M_truename_size = 4; 258 // _M_falsename = __nl_langinfo_l(NOSTR, __cloc); 259 _M_data->_M_falsename = L"false"; 260 _M_data->_M_falsename_size = 5; 261 } 262 263 template<> ~numpunct()264 numpunct<wchar_t>::~numpunct() 265 { 266 if (_M_data->_M_grouping_size) 267 delete [] _M_data->_M_grouping; 268 delete _M_data; 269 } 270 #endif 271 272 _GLIBCXX_END_NAMESPACE_VERSION 273 } // namespace 274