1// Copyright (C) 1997-2015 Free Software Foundation, Inc. 2// 3// This file is part of the GNU ISO C++ Library. This library is free 4// software; you can redistribute it and/or modify it under the 5// terms of the GNU General Public License as published by the 6// Free Software Foundation; either version 3, or (at your option) 7// any later version. 8 9// This library is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13 14// Under Section 7 of GPL version 3, you are granted additional 15// permissions described in the GCC Runtime Library Exception, version 16// 3.1, as published by the Free Software Foundation. 17 18// You should have received a copy of the GNU General Public License and 19// a copy of the GCC Runtime Library Exception along with this program; 20// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21// <http://www.gnu.org/licenses/>. 22 23#define _GLIBCXX_USE_CXX11_ABI 1 24#include <clocale> 25#include <cstring> 26#include <cstdlib> // For getenv 27#include <cctype> 28#include <cwctype> // For towupper, etc. 29#include <locale> 30#include <ext/concurrence.h> 31 32namespace 33{ 34 __gnu_cxx::__mutex& 35 get_locale_cache_mutex() 36 { 37 static __gnu_cxx::__mutex locale_cache_mutex; 38 return locale_cache_mutex; 39 } 40} // anonymous namespace 41 42// XXX GLIBCXX_ABI Deprecated 43#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 44# define _GLIBCXX_LOC_ID(mangled) extern std::locale::id mangled 45_GLIBCXX_LOC_ID (_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 46_GLIBCXX_LOC_ID (_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 47_GLIBCXX_LOC_ID (_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 48_GLIBCXX_LOC_ID (_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 49# ifdef _GLIBCXX_USE_WCHAR_T 50_GLIBCXX_LOC_ID (_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 51_GLIBCXX_LOC_ID (_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 52_GLIBCXX_LOC_ID (_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 53_GLIBCXX_LOC_ID (_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 54# endif 55#endif 56 57namespace std _GLIBCXX_VISIBILITY(default) 58{ 59_GLIBCXX_BEGIN_NAMESPACE_VERSION 60 61 // Definitions for static const data members of locale. 62 const locale::category locale::none; 63 const locale::category locale::ctype; 64 const locale::category locale::numeric; 65 const locale::category locale::collate; 66 const locale::category locale::time; 67 const locale::category locale::monetary; 68 const locale::category locale::messages; 69 const locale::category locale::all; 70 71 // These are no longer exported. 72 locale::_Impl* locale::_S_classic; 73 locale::_Impl* locale::_S_global; 74 75#ifdef __GTHREADS 76 __gthread_once_t locale::_S_once = __GTHREAD_ONCE_INIT; 77#endif 78 79 locale::locale(const locale& __other) throw() 80 : _M_impl(__other._M_impl) 81 { _M_impl->_M_add_reference(); } 82 83 // This is used to initialize global and classic locales, and 84 // assumes that the _Impl objects are constructed correctly. 85 // The lack of a reference increment is intentional. 86 locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 87 { } 88 89 locale::~locale() throw() 90 { _M_impl->_M_remove_reference(); } 91 92 bool 93 locale::operator==(const locale& __rhs) const throw() 94 { 95 // Deal first with the common cases, fast to process: refcopies, 96 // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the 97 // categories same name, i.e., _M_names[0]). Otherwise fall back 98 // to the general locale::name(). 99 bool __ret; 100 if (_M_impl == __rhs._M_impl) 101 __ret = true; 102 else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] 103 || std::strcmp(_M_impl->_M_names[0], 104 __rhs._M_impl->_M_names[0]) != 0) 105 __ret = false; 106 else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) 107 __ret = true; 108 else 109 __ret = this->name() == __rhs.name(); 110 return __ret; 111 } 112 113 const locale& 114 locale::operator=(const locale& __other) throw() 115 { 116 __other._M_impl->_M_add_reference(); 117 _M_impl->_M_remove_reference(); 118 _M_impl = __other._M_impl; 119 return *this; 120 } 121 122 _GLIBCXX_DEFAULT_ABI_TAG 123 string 124 locale::name() const 125 { 126 string __ret; 127 if (!_M_impl->_M_names[0]) 128 __ret = '*'; 129 else if (_M_impl->_M_check_same_name()) 130 __ret = _M_impl->_M_names[0]; 131 else 132 { 133 __ret.reserve(128); 134 __ret += _S_categories[0]; 135 __ret += '='; 136 __ret += _M_impl->_M_names[0]; 137 for (size_t __i = 1; __i < _S_categories_size; ++__i) 138 { 139 __ret += ';'; 140 __ret += _S_categories[__i]; 141 __ret += '='; 142 __ret += _M_impl->_M_names[__i]; 143 } 144 } 145 return __ret; 146 } 147 148 locale::category 149 locale::_S_normalize_category(category __cat) 150 { 151 int __ret = 0; 152 if (__cat == none || ((__cat & all) && !(__cat & ~all))) 153 __ret = __cat; 154 else 155 { 156 // NB: May be a C-style "LC_ALL" category; convert. 157 switch (__cat) 158 { 159 case LC_COLLATE: 160 __ret = collate; 161 break; 162 case LC_CTYPE: 163 __ret = ctype; 164 break; 165 case LC_MONETARY: 166 __ret = monetary; 167 break; 168 case LC_NUMERIC: 169 __ret = numeric; 170 break; 171 case LC_TIME: 172 __ret = time; 173 break; 174#ifdef _GLIBCXX_HAVE_LC_MESSAGES 175 case LC_MESSAGES: 176 __ret = messages; 177 break; 178#endif 179 case LC_ALL: 180 __ret = all; 181 break; 182 default: 183 __throw_runtime_error(__N("locale::_S_normalize_category " 184 "category not found")); 185 } 186 } 187 return __ret; 188 } 189 190 // locale::facet 191 __c_locale locale::facet::_S_c_locale; 192 193 const char locale::facet::_S_c_name[2] = "C"; 194 195#ifdef __GTHREADS 196 __gthread_once_t locale::facet::_S_once = __GTHREAD_ONCE_INIT; 197#endif 198 199 void 200 locale::facet::_S_initialize_once() 201 { 202 // Initialize the underlying locale model. 203 _S_create_c_locale(_S_c_locale, _S_c_name); 204 } 205 206 __c_locale 207 locale::facet::_S_get_c_locale() 208 { 209#ifdef __GTHREADS 210 if (__gthread_active_p()) 211 __gthread_once(&_S_once, _S_initialize_once); 212 else 213#endif 214 { 215 if (!_S_c_locale) 216 _S_initialize_once(); 217 } 218 return _S_c_locale; 219 } 220 221 const char* 222 locale::facet::_S_get_c_name() throw() 223 { return _S_c_name; } 224 225 locale::facet:: 226 ~facet() { } 227 228 // locale::_Impl 229 locale::_Impl:: 230 ~_Impl() throw() 231 { 232 if (_M_facets) 233 for (size_t __i = 0; __i < _M_facets_size; ++__i) 234 if (_M_facets[__i]) 235 _M_facets[__i]->_M_remove_reference(); 236 delete [] _M_facets; 237 238 if (_M_caches) 239 for (size_t __i = 0; __i < _M_facets_size; ++__i) 240 if (_M_caches[__i]) 241 _M_caches[__i]->_M_remove_reference(); 242 delete [] _M_caches; 243 244 if (_M_names) 245 for (size_t __i = 0; __i < _S_categories_size; ++__i) 246 delete [] _M_names[__i]; 247 delete [] _M_names; 248 } 249 250 // Clone existing _Impl object. 251 locale::_Impl:: 252 _Impl(const _Impl& __imp, size_t __refs) 253 : _M_refcount(__refs), _M_facets(0), _M_facets_size(__imp._M_facets_size), 254 _M_caches(0), _M_names(0) 255 { 256 __try 257 { 258 _M_facets = new const facet*[_M_facets_size]; 259 for (size_t __i = 0; __i < _M_facets_size; ++__i) 260 { 261 _M_facets[__i] = __imp._M_facets[__i]; 262 if (_M_facets[__i]) 263 _M_facets[__i]->_M_add_reference(); 264 } 265 _M_caches = new const facet*[_M_facets_size]; 266 for (size_t __j = 0; __j < _M_facets_size; ++__j) 267 { 268 _M_caches[__j] = __imp._M_caches[__j]; 269 if (_M_caches[__j]) 270 _M_caches[__j]->_M_add_reference(); 271 } 272 _M_names = new char*[_S_categories_size]; 273 for (size_t __k = 0; __k < _S_categories_size; ++__k) 274 _M_names[__k] = 0; 275 276 // Name the categories. 277 for (size_t __l = 0; (__l < _S_categories_size 278 && __imp._M_names[__l]); ++__l) 279 { 280 const size_t __len = std::strlen(__imp._M_names[__l]) + 1; 281 _M_names[__l] = new char[__len]; 282 std::memcpy(_M_names[__l], __imp._M_names[__l], __len); 283 } 284 } 285 __catch(...) 286 { 287 this->~_Impl(); 288 __throw_exception_again; 289 } 290 } 291 292 void 293 locale::_Impl:: 294 _M_replace_category(const _Impl* __imp, 295 const locale::id* const* __idpp) 296 { 297 for (; *__idpp; ++__idpp) 298 _M_replace_facet(__imp, *__idpp); 299 } 300 301 void 302 locale::_Impl:: 303 _M_replace_facet(const _Impl* __imp, const locale::id* __idp) 304 { 305 size_t __index = __idp->_M_id(); 306 if ((__index > (__imp->_M_facets_size - 1)) 307 || !__imp->_M_facets[__index]) 308 __throw_runtime_error(__N("locale::_Impl::_M_replace_facet")); 309 _M_install_facet(__idp, __imp->_M_facets[__index]); 310 } 311 312 void 313 locale::_Impl:: 314 _M_install_facet(const locale::id* __idp, const facet* __fp) 315 { 316 if (__fp) 317 { 318 size_t __index = __idp->_M_id(); 319 320 // Check size of facet vector to ensure adequate room. 321 if (__index > _M_facets_size - 1) 322 { 323 const size_t __new_size = __index + 4; 324 325 // New facet array. 326 const facet** __oldf = _M_facets; 327 const facet** __newf; 328 __newf = new const facet*[__new_size]; 329 for (size_t __i = 0; __i < _M_facets_size; ++__i) 330 __newf[__i] = _M_facets[__i]; 331 for (size_t __l = _M_facets_size; __l < __new_size; ++__l) 332 __newf[__l] = 0; 333 334 // New cache array. 335 const facet** __oldc = _M_caches; 336 const facet** __newc; 337 __try 338 { 339 __newc = new const facet*[__new_size]; 340 } 341 __catch(...) 342 { 343 delete [] __newf; 344 __throw_exception_again; 345 } 346 for (size_t __j = 0; __j < _M_facets_size; ++__j) 347 __newc[__j] = _M_caches[__j]; 348 for (size_t __k = _M_facets_size; __k < __new_size; ++__k) 349 __newc[__k] = 0; 350 351 _M_facets_size = __new_size; 352 _M_facets = __newf; 353 _M_caches = __newc; 354 delete [] __oldf; 355 delete [] __oldc; 356 } 357 358 __fp->_M_add_reference(); 359 const facet*& __fpr = _M_facets[__index]; 360 if (__fpr) 361 { 362#if _GLIBCXX_USE_DUAL_ABI 363 // If this is a twinned facet replace its twin with a shim. 364 for (const id* const* p = _S_twinned_facets; *p != 0; p += 2) 365 { 366 if (p[0]->_M_id() == __index) 367 { 368 // replacing the old ABI facet, also replace new ABI twin 369 const facet*& __fpr2 = _M_facets[p[1]->_M_id()]; 370 if (__fpr2) 371 { 372 const facet* __fp2 = __fp->_M_sso_shim(p[1]); 373 __fp2->_M_add_reference(); 374 __fpr2->_M_remove_reference(); 375 __fpr2 = __fp2; 376 } 377 break; 378 } 379 else if (p[1]->_M_id() == __index) 380 { 381 // replacing the new ABI facet, also replace old ABI twin 382 const facet*& __fpr2 = _M_facets[p[0]->_M_id()]; 383 if (__fpr2) 384 { 385 const facet* __fp2 = __fp->_M_cow_shim(p[0]); 386 __fp2->_M_add_reference(); 387 __fpr2->_M_remove_reference(); 388 __fpr2 = __fp2; 389 } 390 break; 391 } 392 } 393#endif 394 // Replacing an existing facet. Order matters. 395 __fpr->_M_remove_reference(); 396 __fpr = __fp; 397 } 398 else 399 { 400 // Installing a newly created facet into an empty 401 // _M_facets container, say a newly-constructed, 402 // swanky-fresh _Impl. 403 _M_facets[__index] = __fp; 404 } 405 406 // Ideally, it would be nice to only remove the caches that 407 // are now incorrect. However, some of the caches depend on 408 // multiple facets, and we only know about one facet 409 // here. It's no great loss: the first use of the new facet 410 // will create a new, correctly cached facet anyway. 411 for (size_t __i = 0; __i < _M_facets_size; ++__i) 412 { 413 const facet* __cpr = _M_caches[__i]; 414 if (__cpr) 415 { 416 __cpr->_M_remove_reference(); 417 _M_caches[__i] = 0; 418 } 419 } 420 } 421 } 422 423 void 424 locale::_Impl:: 425 _M_install_cache(const facet* __cache, size_t __index) 426 { 427 __gnu_cxx::__scoped_lock sentry(get_locale_cache_mutex()); 428#if _GLIBCXX_USE_DUAL_ABI 429 // If this cache is for one of the facets that is instantiated twice, 430 // for old and new std::string ABI, install it in both slots. 431 size_t __index2 = -1; 432 for (const id* const* p = _S_twinned_facets; *p != 0; p += 2) 433 { 434 if (p[0]->_M_id() == __index) 435 { 436 __index2 = p[1]->_M_id(); 437 break; 438 } 439 else if (p[1]->_M_id() == __index) 440 { 441 __index2 = __index; 442 __index = p[0]->_M_id(); 443 break; 444 } 445 } 446#endif 447 if (_M_caches[__index] != 0) 448 { 449 // Some other thread got in first. 450 delete __cache; 451 } 452 else 453 { 454 __cache->_M_add_reference(); 455 _M_caches[__index] = __cache; 456#if _GLIBCXX_USE_DUAL_ABI 457 if (__index2 != size_t(-1)) 458 { 459 __cache->_M_add_reference(); 460 _M_caches[__index2] = __cache; 461 } 462#endif 463 } 464 } 465 466 // locale::id 467 // Definitions for static const data members of locale::id 468 _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker 469 470 size_t 471 locale::id::_M_id() const throw() 472 { 473 if (!_M_index) 474 { 475 // XXX GLIBCXX_ABI Deprecated 476#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 477 locale::id *f = 0; 478# define _GLIBCXX_SYNC_ID(facet, mangled) \ 479 if (this == &::mangled) \ 480 f = &facet::id 481 _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 482 _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 483 _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 484 _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 485# ifdef _GLIBCXX_USE_WCHAR_T 486 _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 487 _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 488 _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 489 _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 490# endif 491 if (f) 492 _M_index = 1 + f->_M_id(); 493 else 494#endif 495 _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 496 1); 497 } 498 return _M_index - 1; 499 } 500 501_GLIBCXX_END_NAMESPACE_VERSION 502} // namespace 503