1 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2 // 2006, 2007, 2008, 2009, 2010 3 // 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 #include <clocale> 26 #include <cstring> 27 #include <cstdlib> // For getenv 28 #include <cctype> 29 #include <cwctype> // For towupper, etc. 30 #include <locale> 31 #include <ext/concurrence.h> 32 33 namespace 34 { 35 __gnu_cxx::__mutex& 36 get_locale_cache_mutex() 37 { 38 static __gnu_cxx::__mutex locale_cache_mutex; 39 return locale_cache_mutex; 40 } 41 } // anonymous namespace 42 43 // XXX GLIBCXX_ABI Deprecated 44 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 45 # define _GLIBCXX_LOC_ID(mangled) extern std::locale::id mangled 46 _GLIBCXX_LOC_ID (_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 47 _GLIBCXX_LOC_ID (_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 48 _GLIBCXX_LOC_ID (_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 49 _GLIBCXX_LOC_ID (_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 50 # ifdef _GLIBCXX_USE_WCHAR_T 51 _GLIBCXX_LOC_ID (_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 52 _GLIBCXX_LOC_ID (_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 53 _GLIBCXX_LOC_ID (_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 54 _GLIBCXX_LOC_ID (_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 55 # endif 56 #endif 57 58 namespace std _GLIBCXX_VISIBILITY(default) 59 { 60 _GLIBCXX_BEGIN_NAMESPACE_VERSION 61 62 // Definitions for static const data members of locale. 63 const locale::category locale::none; 64 const locale::category locale::ctype; 65 const locale::category locale::numeric; 66 const locale::category locale::collate; 67 const locale::category locale::time; 68 const locale::category locale::monetary; 69 const locale::category locale::messages; 70 const locale::category locale::all; 71 72 // These are no longer exported. 73 locale::_Impl* locale::_S_classic; 74 locale::_Impl* locale::_S_global; 75 76 #ifdef __GTHREADS 77 __gthread_once_t locale::_S_once = __GTHREAD_ONCE_INIT; 78 #endif 79 80 locale::locale(const locale& __other) throw() 81 : _M_impl(__other._M_impl) 82 { _M_impl->_M_add_reference(); } 83 84 // This is used to initialize global and classic locales, and 85 // assumes that the _Impl objects are constructed correctly. 86 // The lack of a reference increment is intentional. 87 locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 88 { } 89 90 locale::~locale() throw() 91 { _M_impl->_M_remove_reference(); } 92 93 bool 94 locale::operator==(const locale& __rhs) const throw() 95 { 96 // Deal first with the common cases, fast to process: refcopies, 97 // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the 98 // categories same name, i.e., _M_names[0]). Otherwise fall back 99 // to the general locale::name(). 100 bool __ret; 101 if (_M_impl == __rhs._M_impl) 102 __ret = true; 103 else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] 104 || std::strcmp(_M_impl->_M_names[0], 105 __rhs._M_impl->_M_names[0]) != 0) 106 __ret = false; 107 else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) 108 __ret = true; 109 else 110 __ret = this->name() == __rhs.name(); 111 return __ret; 112 } 113 114 const locale& 115 locale::operator=(const locale& __other) throw() 116 { 117 __other._M_impl->_M_add_reference(); 118 _M_impl->_M_remove_reference(); 119 _M_impl = __other._M_impl; 120 return *this; 121 } 122 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 // Replacing an existing facet. Order matters. 363 __fpr->_M_remove_reference(); 364 __fpr = __fp; 365 } 366 else 367 { 368 // Installing a newly created facet into an empty 369 // _M_facets container, say a newly-constructed, 370 // swanky-fresh _Impl. 371 _M_facets[__index] = __fp; 372 } 373 374 // Ideally, it would be nice to only remove the caches that 375 // are now incorrect. However, some of the caches depend on 376 // multiple facets, and we only know about one facet 377 // here. It's no great loss: the first use of the new facet 378 // will create a new, correctly cached facet anyway. 379 for (size_t __i = 0; __i < _M_facets_size; ++__i) 380 { 381 const facet* __cpr = _M_caches[__i]; 382 if (__cpr) 383 { 384 __cpr->_M_remove_reference(); 385 _M_caches[__i] = 0; 386 } 387 } 388 } 389 } 390 391 void 392 locale::_Impl:: 393 _M_install_cache(const facet* __cache, size_t __index) 394 { 395 __gnu_cxx::__scoped_lock sentry(get_locale_cache_mutex()); 396 if (_M_caches[__index] != 0) 397 { 398 // Some other thread got in first. 399 delete __cache; 400 } 401 else 402 { 403 __cache->_M_add_reference(); 404 _M_caches[__index] = __cache; 405 } 406 } 407 408 // locale::id 409 // Definitions for static const data members of locale::id 410 _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker 411 412 size_t 413 locale::id::_M_id() const throw() 414 { 415 if (!_M_index) 416 { 417 // XXX GLIBCXX_ABI Deprecated 418 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 419 locale::id *f = 0; 420 # define _GLIBCXX_SYNC_ID(facet, mangled) \ 421 if (this == &::mangled) \ 422 f = &facet::id 423 _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 424 _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 425 _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 426 _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 427 # ifdef _GLIBCXX_USE_WCHAR_T 428 _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 429 _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 430 _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 431 _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 432 # endif 433 if (f) 434 _M_index = 1 + f->_M_id(); 435 else 436 #endif 437 _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 438 1); 439 } 440 return _M_index - 1; 441 } 442 443 _GLIBCXX_END_NAMESPACE_VERSION 444 } // namespace 445