1169691Skan// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 297403Sobrien// Free Software Foundation, Inc. 397403Sobrien// 497403Sobrien// This file is part of the GNU ISO C++ Library. This library is free 597403Sobrien// software; you can redistribute it and/or modify it under the 697403Sobrien// terms of the GNU General Public License as published by the 797403Sobrien// Free Software Foundation; either version 2, or (at your option) 897403Sobrien// any later version. 997403Sobrien 1097403Sobrien// This library is distributed in the hope that it will be useful, 1197403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1297403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1397403Sobrien// GNU General Public License for more details. 1497403Sobrien 1597403Sobrien// You should have received a copy of the GNU General Public License along 1697403Sobrien// with this library; see the file COPYING. If not, write to the Free 17169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 1897403Sobrien// USA. 1997403Sobrien 2097403Sobrien// As a special exception, you may use this file as part of a free software 2197403Sobrien// library without restriction. Specifically, if other files instantiate 2297403Sobrien// templates or use macros or inline functions from this file, or you compile 2397403Sobrien// this file and link it with other files to produce an executable, this 2497403Sobrien// file does not by itself cause the resulting executable to be covered by 2597403Sobrien// the GNU General Public License. This exception does not however 2697403Sobrien// invalidate any other reasons why the executable file might be covered by 2797403Sobrien// the GNU General Public License. 2897403Sobrien 2997403Sobrien#include <clocale> 3097403Sobrien#include <cstring> 31132720Skan#include <cstdlib> // For getenv 3297403Sobrien#include <cctype> 3397403Sobrien#include <cwctype> // For towupper, etc. 3497403Sobrien#include <locale> 35169691Skan#include <ext/concurrence.h> 3697403Sobrien 37169691Skannamespace 38107606Sobrien{ 39169691Skan __gnu_cxx::__mutex locale_cache_mutex; 40169691Skan} // anonymous namespace 41169691Skan 42169691Skan// XXX GLIBCXX_ABI Deprecated 43169691Skan#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 44169691Skan# define _GLIBCXX_LOC_ID(mangled) extern std::locale::id mangled 45169691Skan_GLIBCXX_LOC_ID (_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 46169691Skan_GLIBCXX_LOC_ID (_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 47169691Skan_GLIBCXX_LOC_ID (_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 48169691Skan_GLIBCXX_LOC_ID (_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 49169691Skan# ifdef _GLIBCXX_USE_WCHAR_T 50169691Skan_GLIBCXX_LOC_ID (_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 51169691Skan_GLIBCXX_LOC_ID (_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 52169691Skan_GLIBCXX_LOC_ID (_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 53169691Skan_GLIBCXX_LOC_ID (_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 54169691Skan# endif 55169691Skan#endif 56169691Skan 57169691Skan_GLIBCXX_BEGIN_NAMESPACE(std) 58169691Skan 5997403Sobrien // Definitions for static const data members of locale. 6097403Sobrien const locale::category locale::none; 6197403Sobrien const locale::category locale::ctype; 6297403Sobrien const locale::category locale::numeric; 6397403Sobrien const locale::category locale::collate; 6497403Sobrien const locale::category locale::time; 6597403Sobrien const locale::category locale::monetary; 6697403Sobrien const locale::category locale::messages; 6797403Sobrien const locale::category locale::all; 6897403Sobrien 69132720Skan // These are no longer exported. 70132720Skan locale::_Impl* locale::_S_classic; 7197403Sobrien locale::_Impl* locale::_S_global; 7297403Sobrien 73132720Skan#ifdef __GTHREADS 74132720Skan __gthread_once_t locale::_S_once = __GTHREAD_ONCE_INIT; 7597403Sobrien#endif 7697403Sobrien 7797403Sobrien locale::locale(const locale& __other) throw() 78132720Skan : _M_impl(__other._M_impl) 79132720Skan { _M_impl->_M_add_reference(); } 8097403Sobrien 8197403Sobrien // This is used to initialize global and classic locales, and 8297403Sobrien // assumes that the _Impl objects are constructed correctly. 83107606Sobrien // The lack of a reference increment is intentional. 8497403Sobrien locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 8597403Sobrien { } 8697403Sobrien 87107606Sobrien locale::~locale() throw() 88107606Sobrien { _M_impl->_M_remove_reference(); } 89107606Sobrien 9097403Sobrien bool 9197403Sobrien locale::operator==(const locale& __rhs) const throw() 9297403Sobrien { 93169691Skan // Deal first with the common cases, fast to process: refcopies, 94169691Skan // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the 95169691Skan // categories same name, i.e., _M_names[0]). Otherwise fall back 96169691Skan // to the general locale::name(). 97169691Skan bool __ret; 98132720Skan if (_M_impl == __rhs._M_impl) 99132720Skan __ret = true; 100169691Skan else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] 101169691Skan || std::strcmp(_M_impl->_M_names[0], 102169691Skan __rhs._M_impl->_M_names[0]) != 0) 103169691Skan __ret = false; 104169691Skan else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) 105169691Skan __ret = true; 106132720Skan else 107169691Skan __ret = this->name() == __rhs.name(); 108132720Skan return __ret; 10997403Sobrien } 11097403Sobrien 11197403Sobrien const locale& 11297403Sobrien locale::operator=(const locale& __other) throw() 11397403Sobrien { 11497403Sobrien __other._M_impl->_M_add_reference(); 11597403Sobrien _M_impl->_M_remove_reference(); 11697403Sobrien _M_impl = __other._M_impl; 11797403Sobrien return *this; 11897403Sobrien } 11997403Sobrien 12097403Sobrien string 12197403Sobrien locale::name() const 12297403Sobrien { 12397403Sobrien string __ret; 124169691Skan if (!_M_impl->_M_names[0]) 125169691Skan __ret = '*'; 126169691Skan else if (_M_impl->_M_check_same_name()) 12797403Sobrien __ret = _M_impl->_M_names[0]; 12897403Sobrien else 12997403Sobrien { 130169691Skan __ret.reserve(128); 131107606Sobrien __ret += _S_categories[0]; 132117397Skan __ret += '='; 133107606Sobrien __ret += _M_impl->_M_names[0]; 134132720Skan for (size_t __i = 1; __i < _S_categories_size; ++__i) 13597403Sobrien { 136117397Skan __ret += ';'; 137107606Sobrien __ret += _S_categories[__i]; 138117397Skan __ret += '='; 139107606Sobrien __ret += _M_impl->_M_names[__i]; 14097403Sobrien } 14197403Sobrien } 14297403Sobrien return __ret; 14397403Sobrien } 14497403Sobrien 14597403Sobrien locale::category 14697403Sobrien locale::_S_normalize_category(category __cat) 14797403Sobrien { 14897403Sobrien int __ret = 0; 149241959Sdim if (__cat == none || ((__cat & all) && !(__cat & ~all))) 15097403Sobrien __ret = __cat; 15197403Sobrien else 15297403Sobrien { 15397403Sobrien // NB: May be a C-style "LC_ALL" category; convert. 15497403Sobrien switch (__cat) 15597403Sobrien { 15697403Sobrien case LC_COLLATE: 15797403Sobrien __ret = collate; 15897403Sobrien break; 15997403Sobrien case LC_CTYPE: 16097403Sobrien __ret = ctype; 16197403Sobrien break; 16297403Sobrien case LC_MONETARY: 16397403Sobrien __ret = monetary; 16497403Sobrien break; 16597403Sobrien case LC_NUMERIC: 16697403Sobrien __ret = numeric; 16797403Sobrien break; 16897403Sobrien case LC_TIME: 16997403Sobrien __ret = time; 17097403Sobrien break; 171132720Skan#ifdef _GLIBCXX_HAVE_LC_MESSAGES 17297403Sobrien case LC_MESSAGES: 17397403Sobrien __ret = messages; 17497403Sobrien break; 17597403Sobrien#endif 17697403Sobrien case LC_ALL: 17797403Sobrien __ret = all; 17897403Sobrien break; 17997403Sobrien default: 180132720Skan __throw_runtime_error(__N("locale::_S_normalize_category " 181132720Skan "category not found")); 18297403Sobrien } 18397403Sobrien } 18497403Sobrien return __ret; 18597403Sobrien } 18697403Sobrien 187132720Skan // locale::facet 188132720Skan __c_locale locale::facet::_S_c_locale; 189110614Skan 190132720Skan const char locale::facet::_S_c_name[2] = "C"; 19197403Sobrien 192132720Skan#ifdef __GTHREADS 193132720Skan __gthread_once_t locale::facet::_S_once = __GTHREAD_ONCE_INIT; 194132720Skan#endif 19597403Sobrien 196132720Skan void 197132720Skan locale::facet::_S_initialize_once() 198132720Skan { 199132720Skan // Initialize the underlying locale model. 200132720Skan _S_create_c_locale(_S_c_locale, _S_c_name); 201132720Skan } 20297403Sobrien 203132720Skan __c_locale 204132720Skan locale::facet::_S_get_c_locale() 20597403Sobrien { 206132720Skan#ifdef __GHTREADS 207132720Skan if (__gthread_active_p()) 208132720Skan __gthread_once(&_S_once, _S_initialize_once); 209132720Skan else 210132720Skan#endif 21197403Sobrien { 212132720Skan if (!_S_c_locale) 213132720Skan _S_initialize_once(); 21497403Sobrien } 215132720Skan return _S_c_locale; 21697403Sobrien } 21797403Sobrien 218132720Skan const char* 219132720Skan locale::facet::_S_get_c_name() 220132720Skan { return _S_c_name; } 22197403Sobrien 222132720Skan locale::facet:: 223132720Skan ~facet() { } 22497403Sobrien 225132720Skan // locale::_Impl 226132720Skan locale::_Impl:: 227132720Skan ~_Impl() throw() 228132720Skan { 229132720Skan if (_M_facets) 230132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 231132720Skan if (_M_facets[__i]) 232132720Skan _M_facets[__i]->_M_remove_reference(); 233132720Skan delete [] _M_facets; 23497403Sobrien 235132720Skan if (_M_caches) 236132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 237132720Skan if (_M_caches[__i]) 238132720Skan _M_caches[__i]->_M_remove_reference(); 239132720Skan delete [] _M_caches; 240132720Skan 241132720Skan if (_M_names) 242132720Skan for (size_t __i = 0; __i < _S_categories_size; ++__i) 243132720Skan delete [] _M_names[__i]; 244132720Skan delete [] _M_names; 245132720Skan } 246132720Skan 247132720Skan // Clone existing _Impl object. 248132720Skan locale::_Impl:: 249132720Skan _Impl(const _Impl& __imp, size_t __refs) 250132720Skan : _M_refcount(__refs), _M_facets(0), _M_facets_size(__imp._M_facets_size), 251132720Skan _M_caches(0), _M_names(0) 25297403Sobrien { 253132720Skan try 254132720Skan { 255132720Skan _M_facets = new const facet*[_M_facets_size]; 256132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 257132720Skan { 258132720Skan _M_facets[__i] = __imp._M_facets[__i]; 259132720Skan if (_M_facets[__i]) 260132720Skan _M_facets[__i]->_M_add_reference(); 261132720Skan } 262132720Skan _M_caches = new const facet*[_M_facets_size]; 263132720Skan for (size_t __j = 0; __j < _M_facets_size; ++__j) 264132720Skan { 265132720Skan _M_caches[__j] = __imp._M_caches[__j]; 266132720Skan if (_M_caches[__j]) 267132720Skan _M_caches[__j]->_M_add_reference(); 268132720Skan } 269132720Skan _M_names = new char*[_S_categories_size]; 270132720Skan for (size_t __k = 0; __k < _S_categories_size; ++__k) 271132720Skan _M_names[__k] = 0; 272117397Skan 273169691Skan // Name the categories. 274169691Skan for (size_t __l = 0; (__l < _S_categories_size 275169691Skan && __imp._M_names[__l]); ++__l) 276132720Skan { 277169691Skan const size_t __len = std::strlen(__imp._M_names[__l]) + 1; 278169691Skan _M_names[__l] = new char[__len]; 279169691Skan std::memcpy(_M_names[__l], __imp._M_names[__l], __len); 280132720Skan } 281132720Skan } 282132720Skan catch(...) 283132720Skan { 284132720Skan this->~_Impl(); 285132720Skan __throw_exception_again; 286132720Skan } 287132720Skan } 288117397Skan 289132720Skan void 290132720Skan locale::_Impl:: 291132720Skan _M_replace_category(const _Impl* __imp, 292132720Skan const locale::id* const* __idpp) 293132720Skan { 294132720Skan for (; *__idpp; ++__idpp) 295132720Skan _M_replace_facet(__imp, *__idpp); 29697403Sobrien } 29797403Sobrien 29897403Sobrien void 299132720Skan locale::_Impl:: 300132720Skan _M_replace_facet(const _Impl* __imp, const locale::id* __idp) 30197403Sobrien { 302132720Skan size_t __index = __idp->_M_id(); 303132720Skan if ((__index > (__imp->_M_facets_size - 1)) 304132720Skan || !__imp->_M_facets[__index]) 305132720Skan __throw_runtime_error(__N("locale::_Impl::_M_replace_facet")); 306132720Skan _M_install_facet(__idp, __imp->_M_facets[__index]); 307132720Skan } 30897403Sobrien 309132720Skan void 310132720Skan locale::_Impl:: 311132720Skan _M_install_facet(const locale::id* __idp, const facet* __fp) 312132720Skan { 313132720Skan if (__fp) 314132720Skan { 315132720Skan size_t __index = __idp->_M_id(); 31697403Sobrien 317132720Skan // Check size of facet vector to ensure adequate room. 318132720Skan if (__index > _M_facets_size - 1) 319132720Skan { 320132720Skan const size_t __new_size = __index + 4; 321132720Skan 322132720Skan // New facet array. 323132720Skan const facet** __oldf = _M_facets; 324132720Skan const facet** __newf; 325132720Skan __newf = new const facet*[__new_size]; 326132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 327132720Skan __newf[__i] = _M_facets[__i]; 328132720Skan for (size_t __l = _M_facets_size; __l < __new_size; ++__l) 329132720Skan __newf[__l] = 0; 330132720Skan 331132720Skan // New cache array. 332132720Skan const facet** __oldc = _M_caches; 333132720Skan const facet** __newc; 334132720Skan try 335132720Skan { 336132720Skan __newc = new const facet*[__new_size]; 337132720Skan } 338132720Skan catch(...) 339132720Skan { 340132720Skan delete [] __newf; 341132720Skan __throw_exception_again; 342132720Skan } 343132720Skan for (size_t __j = 0; __j < _M_facets_size; ++__j) 344132720Skan __newc[__j] = _M_caches[__j]; 345132720Skan for (size_t __k = _M_facets_size; __k < __new_size; ++__k) 346132720Skan __newc[__k] = 0; 347132720Skan 348132720Skan _M_facets_size = __new_size; 349132720Skan _M_facets = __newf; 350132720Skan _M_caches = __newc; 351132720Skan delete [] __oldf; 352132720Skan delete [] __oldc; 353132720Skan } 354132720Skan 355132720Skan __fp->_M_add_reference(); 356132720Skan const facet*& __fpr = _M_facets[__index]; 357132720Skan if (__fpr) 358132720Skan { 359132720Skan // Replacing an existing facet. Order matters. 360132720Skan __fpr->_M_remove_reference(); 361132720Skan __fpr = __fp; 362132720Skan } 363132720Skan else 364132720Skan { 365132720Skan // Installing a newly created facet into an empty 366132720Skan // _M_facets container, say a newly-constructed, 367132720Skan // swanky-fresh _Impl. 368132720Skan _M_facets[__index] = __fp; 369132720Skan } 370132720Skan 371132720Skan // Ideally, it would be nice to only remove the caches that 372132720Skan // are now incorrect. However, some of the caches depend on 373132720Skan // multiple facets, and we only know about one facet 374132720Skan // here. It's no great loss: the first use of the new facet 375132720Skan // will create a new, correctly cached facet anyway. 376132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 377132720Skan { 378132720Skan const facet* __cpr = _M_caches[__i]; 379132720Skan if (__cpr) 380132720Skan { 381132720Skan __cpr->_M_remove_reference(); 382132720Skan _M_caches[__i] = 0; 383132720Skan } 384132720Skan } 385132720Skan } 38697403Sobrien } 387132720Skan 388169691Skan void 389169691Skan locale::_Impl:: 390169691Skan _M_install_cache(const facet* __cache, size_t __index) 391169691Skan { 392169691Skan __gnu_cxx::__scoped_lock sentry(locale_cache_mutex); 393169691Skan if (_M_caches[__index] != 0) 394169691Skan { 395169691Skan // Some other thread got in first. 396169691Skan delete __cache; 397169691Skan } 398169691Skan else 399169691Skan { 400169691Skan __cache->_M_add_reference(); 401169691Skan _M_caches[__index] = __cache; 402169691Skan } 403169691Skan } 404132720Skan 405132720Skan // locale::id 406132720Skan // Definitions for static const data members of locale::id 407132720Skan _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker 408132720Skan 409132720Skan size_t 410132720Skan locale::id::_M_id() const 411132720Skan { 412132720Skan if (!_M_index) 413169691Skan { 414169691Skan // XXX GLIBCXX_ABI Deprecated 415169691Skan#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 416169691Skan locale::id *f = 0; 417169691Skan# define _GLIBCXX_SYNC_ID(facet, mangled) \ 418169691Skan if (this == &::mangled) \ 419169691Skan f = &facet::id 420169691Skan _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 421169691Skan _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 422169691Skan _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 423169691Skan _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 424169691Skan# ifdef _GLIBCXX_USE_WCHAR_T 425169691Skan _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 426169691Skan _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 427169691Skan _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 428169691Skan _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 429169691Skan# endif 430169691Skan if (f) 431169691Skan _M_index = 1 + f->_M_id(); 432169691Skan else 433169691Skan#endif 434169691Skan _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 435169691Skan 1); 436169691Skan } 437132720Skan return _M_index - 1; 438132720Skan } 43997403Sobrien 440169691Skan_GLIBCXX_END_NAMESPACE 441