1 // Wrapper for underlying C-language localization -*- C++ -*- 2 3 // Copyright (C) 2001-2021 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.8 Standard locale categories. 27 // 28 29 // Written by Benjamin Kosnik <bkoz@redhat.com> 30 31 #include <locale> 32 #include <stdexcept> 33 #include <limits> 34 #include <algorithm> 35 #include <langinfo.h> 36 #include <bits/c++locale_internal.h> 37 38 #include <backward/auto_ptr.h> 39 40 namespace std _GLIBCXX_VISIBILITY(default) 41 { 42 _GLIBCXX_BEGIN_NAMESPACE_VERSION 43 44 template<> 45 void __convert_to_v(const char * __s,float & __v,ios_base::iostate & __err,const __c_locale & __cloc)46 __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err, 47 const __c_locale& __cloc) throw() 48 { 49 char* __sanity; 50 __v = __strtof_l(__s, &__sanity, __cloc); 51 52 // _GLIBCXX_RESOLVE_LIB_DEFECTS 53 // 23. Num_get overflow result. 54 if (__sanity == __s || *__sanity != '\0') 55 { 56 __v = 0.0f; 57 __err = ios_base::failbit; 58 } 59 else if (__v == numeric_limits<float>::infinity()) 60 { 61 __v = numeric_limits<float>::max(); 62 __err = ios_base::failbit; 63 } 64 else if (__v == -numeric_limits<float>::infinity()) 65 { 66 __v = -numeric_limits<float>::max(); 67 __err = ios_base::failbit; 68 } 69 } 70 71 template<> 72 void __convert_to_v(const char * __s,double & __v,ios_base::iostate & __err,const __c_locale & __cloc)73 __convert_to_v(const char* __s, double& __v, ios_base::iostate& __err, 74 const __c_locale& __cloc) throw() 75 { 76 char* __sanity; 77 __v = __strtod_l(__s, &__sanity, __cloc); 78 79 // _GLIBCXX_RESOLVE_LIB_DEFECTS 80 // 23. Num_get overflow result. 81 if (__sanity == __s || *__sanity != '\0') 82 { 83 __v = 0.0; 84 __err = ios_base::failbit; 85 } 86 else if (__v == numeric_limits<double>::infinity()) 87 { 88 __v = numeric_limits<double>::max(); 89 __err = ios_base::failbit; 90 } 91 else if (__v == -numeric_limits<double>::infinity()) 92 { 93 __v = -numeric_limits<double>::max(); 94 __err = ios_base::failbit; 95 } 96 } 97 98 template<> 99 void __convert_to_v(const char * __s,long double & __v,ios_base::iostate & __err,const __c_locale & __cloc)100 __convert_to_v(const char* __s, long double& __v, ios_base::iostate& __err, 101 const __c_locale& __cloc) throw() 102 { 103 char* __sanity; 104 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 105 // Prefer strtold_l, as __strtold_l isn't prototyped in more recent 106 // glibc versions. 107 __v = strtold_l(__s, &__sanity, __cloc); 108 #else 109 __v = __strtold_l(__s, &__sanity, __cloc); 110 #endif 111 112 // _GLIBCXX_RESOLVE_LIB_DEFECTS 113 // 23. Num_get overflow result. 114 if (__sanity == __s || *__sanity != '\0') 115 { 116 __v = 0.0l; 117 __err = ios_base::failbit; 118 } 119 else if (__v == numeric_limits<long double>::infinity()) 120 { 121 __v = numeric_limits<long double>::max(); 122 __err = ios_base::failbit; 123 } 124 else if (__v == -numeric_limits<long double>::infinity()) 125 { 126 __v = -numeric_limits<long double>::max(); 127 __err = ios_base::failbit; 128 } 129 } 130 131 void _S_create_c_locale(__c_locale & __cloc,const char * __s,__c_locale __old)132 locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s, 133 __c_locale __old) 134 { 135 __cloc = __newlocale(1 << LC_ALL, __s, __old); 136 if (!__cloc) 137 { 138 // This named locale is not supported by the underlying OS. 139 __throw_runtime_error(__N("locale::facet::_S_create_c_locale " 140 "name not valid")); 141 } 142 } 143 144 void _S_destroy_c_locale(__c_locale & __cloc)145 locale::facet::_S_destroy_c_locale(__c_locale& __cloc) 146 { 147 if (__cloc && _S_get_c_locale() != __cloc) 148 __freelocale(__cloc); 149 } 150 151 __c_locale _S_clone_c_locale(__c_locale & __cloc)152 locale::facet::_S_clone_c_locale(__c_locale& __cloc) throw() 153 { return __duplocale(__cloc); } 154 155 __c_locale _S_lc_ctype_c_locale(__c_locale __cloc,const char * __s)156 locale::facet::_S_lc_ctype_c_locale(__c_locale __cloc, const char* __s) 157 { 158 __c_locale __dup = __duplocale(__cloc); 159 if (__dup == __c_locale(0)) 160 __throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale " 161 "duplocale error")); 162 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 163 __c_locale __changed = __newlocale(LC_CTYPE_MASK, __s, __dup); 164 #else 165 __c_locale __changed = __newlocale(1 << LC_CTYPE, __s, __dup); 166 #endif 167 if (__changed == __c_locale(0)) 168 { 169 __freelocale(__dup); 170 __throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale " 171 "newlocale error")); 172 } 173 return __changed; 174 } 175 176 struct _CatalogIdComp 177 { 178 bool operator ()std::_CatalogIdComp179 operator()(messages_base::catalog __cat, const Catalog_info* __info) const 180 { return __cat < __info->_M_id; } 181 182 bool operator ()std::_CatalogIdComp183 operator()(const Catalog_info* __info, messages_base::catalog __cat) const 184 { return __info->_M_id < __cat; } 185 }; 186 ~Catalogs()187 Catalogs::~Catalogs() 188 { 189 for (vector<Catalog_info*>::iterator __it = _M_infos.begin(); 190 __it != _M_infos.end(); ++__it) 191 delete *__it; 192 } 193 194 messages_base::catalog _M_add(const char * __domain,locale __l)195 Catalogs::_M_add(const char* __domain, locale __l) 196 { 197 __gnu_cxx::__scoped_lock lock(_M_mutex); 198 199 // The counter is not likely to roll unless catalogs keep on being 200 // opened/closed which is consider as an application mistake for the 201 // moment. 202 if (_M_catalog_counter == numeric_limits<messages_base::catalog>::max()) 203 return -1; 204 205 auto_ptr<Catalog_info> info(new Catalog_info(_M_catalog_counter++, 206 __domain, __l)); 207 208 // Check if we managed to allocate memory for domain. 209 if (!info->_M_domain) 210 return -1; 211 212 _M_infos.push_back(info.get()); 213 return info.release()->_M_id; 214 } 215 216 void _M_erase(messages_base::catalog __c)217 Catalogs::_M_erase(messages_base::catalog __c) 218 { 219 __gnu_cxx::__scoped_lock lock(_M_mutex); 220 221 vector<Catalog_info*>::iterator __res = 222 lower_bound(_M_infos.begin(), _M_infos.end(), __c, _CatalogIdComp()); 223 if (__res == _M_infos.end() || (*__res)->_M_id != __c) 224 return; 225 226 delete *__res; 227 _M_infos.erase(__res); 228 229 // Just in case closed catalog was the last open. 230 if (__c == _M_catalog_counter - 1) 231 --_M_catalog_counter; 232 } 233 234 const Catalog_info* _M_get(messages_base::catalog __c) const235 Catalogs::_M_get(messages_base::catalog __c) const 236 { 237 __gnu_cxx::__scoped_lock lock(_M_mutex); 238 239 vector<Catalog_info*>::const_iterator __res = 240 lower_bound(_M_infos.begin(), _M_infos.end(), __c, _CatalogIdComp()); 241 242 if (__res != _M_infos.end() && (*__res)->_M_id == __c) 243 return *__res; 244 245 return 0; 246 } 247 248 Catalogs& get_catalogs()249 get_catalogs() 250 { 251 static Catalogs __catalogs; 252 return __catalogs; 253 } 254 255 _GLIBCXX_END_NAMESPACE_VERSION 256 } // namespace 257 258 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 259 { 260 _GLIBCXX_BEGIN_NAMESPACE_VERSION 261 262 const char* const category_names[6 + _GLIBCXX_NUM_CATEGORIES] = 263 { 264 "LC_CTYPE", 265 "LC_NUMERIC", 266 "LC_TIME", 267 "LC_COLLATE", 268 "LC_MONETARY", 269 "LC_MESSAGES", 270 "LC_PAPER", 271 "LC_NAME", 272 "LC_ADDRESS", 273 "LC_TELEPHONE", 274 "LC_MEASUREMENT", 275 "LC_IDENTIFICATION" 276 }; 277 278 _GLIBCXX_END_NAMESPACE_VERSION 279 } // namespace 280 281 namespace std _GLIBCXX_VISIBILITY(default) 282 { 283 _GLIBCXX_BEGIN_NAMESPACE_VERSION 284 285 const char* const* const locale::_S_categories = __gnu_cxx::category_names; 286 287 _GLIBCXX_END_NAMESPACE_VERSION 288 } // namespace 289 290 // XXX GLIBCXX_ABI Deprecated 291 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 292 #pragma GCC diagnostic ignored "-Wattribute-alias" 293 #define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \ 294 extern "C" void ldbl (void) __attribute__ ((alias (#dbl))) 295 _GLIBCXX_LDBL_COMPAT(_ZSt14__convert_to_vIdEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct, _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct); 296 #endif // _GLIBCXX_LONG_DOUBLE_COMPAT 297