locale.cc revision 169691
177298Sobrien// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 277298Sobrien// Free Software Foundation, Inc. 377298Sobrien// 477298Sobrien// This file is part of the GNU ISO C++ Library. This library is free 577298Sobrien// software; you can redistribute it and/or modify it under the 677298Sobrien// terms of the GNU General Public License as published by the 777298Sobrien// Free Software Foundation; either version 2, or (at your option) 877298Sobrien// any later version. 977298Sobrien 1077298Sobrien// This library is distributed in the hope that it will be useful, 1177298Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1277298Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1377298Sobrien// GNU General Public License for more details. 1477298Sobrien 1577298Sobrien// You should have received a copy of the GNU General Public License along 1677298Sobrien// with this library; see the file COPYING. If not, write to the Free 1777298Sobrien// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 1877298Sobrien// USA. 1977298Sobrien 2077298Sobrien// As a special exception, you may use this file as part of a free software 2177298Sobrien// library without restriction. Specifically, if other files instantiate 2277298Sobrien// templates or use macros or inline functions from this file, or you compile 2377298Sobrien// this file and link it with other files to produce an executable, this 2477298Sobrien// file does not by itself cause the resulting executable to be covered by 2577298Sobrien// the GNU General Public License. This exception does not however 2677298Sobrien// invalidate any other reasons why the executable file might be covered by 2777298Sobrien// the GNU General Public License. 2877298Sobrien 2977298Sobrien#include <clocale> 3077298Sobrien#include <cstring> 3177298Sobrien#include <cstdlib> // For getenv 3277298Sobrien#include <cctype> 3377298Sobrien#include <cwctype> // For towupper, etc. 3477298Sobrien#include <locale> 3577298Sobrien#include <ext/concurrence.h> 3677298Sobrien 3777298Sobriennamespace 3877298Sobrien{ 3977298Sobrien __gnu_cxx::__mutex locale_cache_mutex; 4077298Sobrien} // anonymous namespace 4177298Sobrien 4277298Sobrien// XXX GLIBCXX_ABI Deprecated 4377298Sobrien#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 4477298Sobrien# define _GLIBCXX_LOC_ID(mangled) extern std::locale::id mangled 4577298Sobrien_GLIBCXX_LOC_ID (_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 4677298Sobrien_GLIBCXX_LOC_ID (_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 4777298Sobrien_GLIBCXX_LOC_ID (_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 4877298Sobrien_GLIBCXX_LOC_ID (_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 4977298Sobrien# ifdef _GLIBCXX_USE_WCHAR_T 5077298Sobrien_GLIBCXX_LOC_ID (_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 5177298Sobrien_GLIBCXX_LOC_ID (_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 5277298Sobrien_GLIBCXX_LOC_ID (_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 5377298Sobrien_GLIBCXX_LOC_ID (_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 5477298Sobrien# endif 5577298Sobrien#endif 5677298Sobrien 5777298Sobrien_GLIBCXX_BEGIN_NAMESPACE(std) 5877298Sobrien 5977298Sobrien // Definitions for static const data members of locale. 6077298Sobrien const locale::category locale::none; 6177298Sobrien const locale::category locale::ctype; 6277298Sobrien const locale::category locale::numeric; 6377298Sobrien const locale::category locale::collate; 6477298Sobrien const locale::category locale::time; 6577298Sobrien const locale::category locale::monetary; 6677298Sobrien const locale::category locale::messages; 6777298Sobrien const locale::category locale::all; 6877298Sobrien 6977298Sobrien // These are no longer exported. 7077298Sobrien locale::_Impl* locale::_S_classic; 7177298Sobrien locale::_Impl* locale::_S_global; 7277298Sobrien 7377298Sobrien#ifdef __GTHREADS 7477298Sobrien __gthread_once_t locale::_S_once = __GTHREAD_ONCE_INIT; 7577298Sobrien#endif 7677298Sobrien 7777298Sobrien locale::locale(const locale& __other) throw() 7877298Sobrien : _M_impl(__other._M_impl) 7977298Sobrien { _M_impl->_M_add_reference(); } 8077298Sobrien 8177298Sobrien // This is used to initialize global and classic locales, and 8277298Sobrien // assumes that the _Impl objects are constructed correctly. 8377298Sobrien // The lack of a reference increment is intentional. 8477298Sobrien locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 8577298Sobrien { } 8677298Sobrien 8777298Sobrien locale::~locale() throw() 8877298Sobrien { _M_impl->_M_remove_reference(); } 8989857Sobrien 9089857Sobrien bool 9189857Sobrien locale::operator==(const locale& __rhs) const throw() 9277298Sobrien { 9377298Sobrien // Deal first with the common cases, fast to process: refcopies, 9477298Sobrien // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the 9577298Sobrien // categories same name, i.e., _M_names[0]). Otherwise fall back 9677298Sobrien // to the general locale::name(). 9777298Sobrien bool __ret; 9877298Sobrien if (_M_impl == __rhs._M_impl) 9977298Sobrien __ret = true; 10077298Sobrien else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] 10177298Sobrien || std::strcmp(_M_impl->_M_names[0], 10277298Sobrien __rhs._M_impl->_M_names[0]) != 0) 10377298Sobrien __ret = false; 10477298Sobrien else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) 10577298Sobrien __ret = true; 10677298Sobrien else 10777298Sobrien __ret = this->name() == __rhs.name(); 10877298Sobrien return __ret; 10977298Sobrien } 11077298Sobrien 11177298Sobrien const locale& 11277298Sobrien locale::operator=(const locale& __other) throw() 11377298Sobrien { 11477298Sobrien __other._M_impl->_M_add_reference(); 11577298Sobrien _M_impl->_M_remove_reference(); 11677298Sobrien _M_impl = __other._M_impl; 11777298Sobrien return *this; 11877298Sobrien } 11977298Sobrien 12077298Sobrien string 12177298Sobrien locale::name() const 12277298Sobrien { 12377298Sobrien string __ret; 12477298Sobrien if (!_M_impl->_M_names[0]) 12577298Sobrien __ret = '*'; 12677298Sobrien else if (_M_impl->_M_check_same_name()) 12777298Sobrien __ret = _M_impl->_M_names[0]; 12877298Sobrien else 12977298Sobrien { 13077298Sobrien __ret.reserve(128); 13177298Sobrien __ret += _S_categories[0]; 13277298Sobrien __ret += '='; 13377298Sobrien __ret += _M_impl->_M_names[0]; 13477298Sobrien for (size_t __i = 1; __i < _S_categories_size; ++__i) 13577298Sobrien { 13677298Sobrien __ret += ';'; 13777298Sobrien __ret += _S_categories[__i]; 13877298Sobrien __ret += '='; 13977298Sobrien __ret += _M_impl->_M_names[__i]; 14077298Sobrien } 14177298Sobrien } 14277298Sobrien return __ret; 14377298Sobrien } 14477298Sobrien 14577298Sobrien locale::category 14677298Sobrien locale::_S_normalize_category(category __cat) 14777298Sobrien { 14877298Sobrien int __ret = 0; 14977298Sobrien if (__cat == none || (__cat & all) && !(__cat & ~all)) 15077298Sobrien __ret = __cat; 15177298Sobrien else 15277298Sobrien { 15377298Sobrien // NB: May be a C-style "LC_ALL" category; convert. 15477298Sobrien switch (__cat) 15577298Sobrien { 15677298Sobrien case LC_COLLATE: 15777298Sobrien __ret = collate; 15877298Sobrien break; 15977298Sobrien case LC_CTYPE: 16077298Sobrien __ret = ctype; 16177298Sobrien break; 16277298Sobrien case LC_MONETARY: 16377298Sobrien __ret = monetary; 16477298Sobrien break; 16577298Sobrien case LC_NUMERIC: 16677298Sobrien __ret = numeric; 16777298Sobrien break; 16877298Sobrien case LC_TIME: 16977298Sobrien __ret = time; 17077298Sobrien break; 17177298Sobrien#ifdef _GLIBCXX_HAVE_LC_MESSAGES 17277298Sobrien case LC_MESSAGES: 17377298Sobrien __ret = messages; 17477298Sobrien break; 17577298Sobrien#endif 17677298Sobrien case LC_ALL: 17777298Sobrien __ret = all; 17877298Sobrien break; 17977298Sobrien default: 18077298Sobrien __throw_runtime_error(__N("locale::_S_normalize_category " 18189857Sobrien "category not found")); 18289857Sobrien } 18377298Sobrien } 18477298Sobrien return __ret; 18577298Sobrien } 18677298Sobrien 18777298Sobrien // locale::facet 18877298Sobrien __c_locale locale::facet::_S_c_locale; 18977298Sobrien 19077298Sobrien const char locale::facet::_S_c_name[2] = "C"; 19177298Sobrien 19277298Sobrien#ifdef __GTHREADS 19377298Sobrien __gthread_once_t locale::facet::_S_once = __GTHREAD_ONCE_INIT; 19477298Sobrien#endif 19577298Sobrien 19677298Sobrien void 19777298Sobrien locale::facet::_S_initialize_once() 19877298Sobrien { 19977298Sobrien // Initialize the underlying locale model. 20077298Sobrien _S_create_c_locale(_S_c_locale, _S_c_name); 20177298Sobrien } 20277298Sobrien 20377298Sobrien __c_locale 20477298Sobrien locale::facet::_S_get_c_locale() 20577298Sobrien { 20677298Sobrien#ifdef __GHTREADS 20777298Sobrien if (__gthread_active_p()) 20877298Sobrien __gthread_once(&_S_once, _S_initialize_once); 20977298Sobrien else 21077298Sobrien#endif 21177298Sobrien { 21277298Sobrien if (!_S_c_locale) 21377298Sobrien _S_initialize_once(); 21477298Sobrien } 21577298Sobrien return _S_c_locale; 21677298Sobrien } 21777298Sobrien 21877298Sobrien const char* 21977298Sobrien locale::facet::_S_get_c_name() 22077298Sobrien { return _S_c_name; } 22177298Sobrien 22277298Sobrien locale::facet:: 22377298Sobrien ~facet() { } 22477298Sobrien 22577298Sobrien // locale::_Impl 22677298Sobrien locale::_Impl:: 22777298Sobrien ~_Impl() throw() 22877298Sobrien { 22977298Sobrien if (_M_facets) 23077298Sobrien for (size_t __i = 0; __i < _M_facets_size; ++__i) 23177298Sobrien if (_M_facets[__i]) 23277298Sobrien _M_facets[__i]->_M_remove_reference(); 23377298Sobrien delete [] _M_facets; 23477298Sobrien 23577298Sobrien if (_M_caches) 23677298Sobrien for (size_t __i = 0; __i < _M_facets_size; ++__i) 23777298Sobrien if (_M_caches[__i]) 23877298Sobrien _M_caches[__i]->_M_remove_reference(); 23977298Sobrien delete [] _M_caches; 24077298Sobrien 24177298Sobrien if (_M_names) 24277298Sobrien for (size_t __i = 0; __i < _S_categories_size; ++__i) 24377298Sobrien delete [] _M_names[__i]; 24477298Sobrien delete [] _M_names; 24577298Sobrien } 24677298Sobrien 24777298Sobrien // Clone existing _Impl object. 24877298Sobrien locale::_Impl:: 24977298Sobrien _Impl(const _Impl& __imp, size_t __refs) 25077298Sobrien : _M_refcount(__refs), _M_facets(0), _M_facets_size(__imp._M_facets_size), 25177298Sobrien _M_caches(0), _M_names(0) 25277298Sobrien { 25377298Sobrien try 25477298Sobrien { 25577298Sobrien _M_facets = new const facet*[_M_facets_size]; 25677298Sobrien for (size_t __i = 0; __i < _M_facets_size; ++__i) 25777298Sobrien { 25877298Sobrien _M_facets[__i] = __imp._M_facets[__i]; 25977298Sobrien if (_M_facets[__i]) 26077298Sobrien _M_facets[__i]->_M_add_reference(); 26177298Sobrien } 26277298Sobrien _M_caches = new const facet*[_M_facets_size]; 26377298Sobrien for (size_t __j = 0; __j < _M_facets_size; ++__j) 26477298Sobrien { 26577298Sobrien _M_caches[__j] = __imp._M_caches[__j]; 26677298Sobrien if (_M_caches[__j]) 26777298Sobrien _M_caches[__j]->_M_add_reference(); 26877298Sobrien } 26977298Sobrien _M_names = new char*[_S_categories_size]; 27077298Sobrien for (size_t __k = 0; __k < _S_categories_size; ++__k) 27177298Sobrien _M_names[__k] = 0; 27277298Sobrien 27377298Sobrien // Name the categories. 27477298Sobrien for (size_t __l = 0; (__l < _S_categories_size 27577298Sobrien && __imp._M_names[__l]); ++__l) 27677298Sobrien { 27777298Sobrien const size_t __len = std::strlen(__imp._M_names[__l]) + 1; 27877298Sobrien _M_names[__l] = new char[__len]; 27977298Sobrien std::memcpy(_M_names[__l], __imp._M_names[__l], __len); 28077298Sobrien } 28177298Sobrien } 28277298Sobrien catch(...) 28377298Sobrien { 28477298Sobrien this->~_Impl(); 28577298Sobrien __throw_exception_again; 28677298Sobrien } 28777298Sobrien } 28877298Sobrien 28977298Sobrien void 29077298Sobrien locale::_Impl:: 29177298Sobrien _M_replace_category(const _Impl* __imp, 29277298Sobrien const locale::id* const* __idpp) 29377298Sobrien { 29477298Sobrien for (; *__idpp; ++__idpp) 29577298Sobrien _M_replace_facet(__imp, *__idpp); 29677298Sobrien } 29777298Sobrien 29877298Sobrien void 29977298Sobrien locale::_Impl:: 30077298Sobrien _M_replace_facet(const _Impl* __imp, const locale::id* __idp) 30177298Sobrien { 30277298Sobrien size_t __index = __idp->_M_id(); 30377298Sobrien if ((__index > (__imp->_M_facets_size - 1)) 30477298Sobrien || !__imp->_M_facets[__index]) 30577298Sobrien __throw_runtime_error(__N("locale::_Impl::_M_replace_facet")); 30677298Sobrien _M_install_facet(__idp, __imp->_M_facets[__index]); 30777298Sobrien } 30877298Sobrien 30977298Sobrien void 31077298Sobrien locale::_Impl:: 31177298Sobrien _M_install_facet(const locale::id* __idp, const facet* __fp) 31277298Sobrien { 31377298Sobrien if (__fp) 31477298Sobrien { 31577298Sobrien size_t __index = __idp->_M_id(); 31677298Sobrien 31777298Sobrien // Check size of facet vector to ensure adequate room. 31877298Sobrien if (__index > _M_facets_size - 1) 31977298Sobrien { 32077298Sobrien const size_t __new_size = __index + 4; 32177298Sobrien 32277298Sobrien // New facet array. 32377298Sobrien const facet** __oldf = _M_facets; 32477298Sobrien const facet** __newf; 32577298Sobrien __newf = new const facet*[__new_size]; 32677298Sobrien for (size_t __i = 0; __i < _M_facets_size; ++__i) 32777298Sobrien __newf[__i] = _M_facets[__i]; 32877298Sobrien for (size_t __l = _M_facets_size; __l < __new_size; ++__l) 32977298Sobrien __newf[__l] = 0; 33077298Sobrien 33177298Sobrien // New cache array. 33277298Sobrien const facet** __oldc = _M_caches; 33377298Sobrien const facet** __newc; 33477298Sobrien try 33577298Sobrien { 33677298Sobrien __newc = new const facet*[__new_size]; 33777298Sobrien } 33877298Sobrien catch(...) 33977298Sobrien { 34077298Sobrien delete [] __newf; 34177298Sobrien __throw_exception_again; 34277298Sobrien } 34377298Sobrien for (size_t __j = 0; __j < _M_facets_size; ++__j) 34477298Sobrien __newc[__j] = _M_caches[__j]; 34577298Sobrien for (size_t __k = _M_facets_size; __k < __new_size; ++__k) 34677298Sobrien __newc[__k] = 0; 34777298Sobrien 34877298Sobrien _M_facets_size = __new_size; 34977298Sobrien _M_facets = __newf; 35077298Sobrien _M_caches = __newc; 35177298Sobrien delete [] __oldf; 35277298Sobrien delete [] __oldc; 35377298Sobrien } 35477298Sobrien 35577298Sobrien __fp->_M_add_reference(); 35677298Sobrien const facet*& __fpr = _M_facets[__index]; 35777298Sobrien if (__fpr) 35877298Sobrien { 35977298Sobrien // Replacing an existing facet. Order matters. 36077298Sobrien __fpr->_M_remove_reference(); 36177298Sobrien __fpr = __fp; 36277298Sobrien } 36377298Sobrien else 36477298Sobrien { 36577298Sobrien // Installing a newly created facet into an empty 36677298Sobrien // _M_facets container, say a newly-constructed, 36777298Sobrien // swanky-fresh _Impl. 36877298Sobrien _M_facets[__index] = __fp; 36977298Sobrien } 37077298Sobrien 37177298Sobrien // Ideally, it would be nice to only remove the caches that 37277298Sobrien // are now incorrect. However, some of the caches depend on 37377298Sobrien // multiple facets, and we only know about one facet 37477298Sobrien // here. It's no great loss: the first use of the new facet 37577298Sobrien // will create a new, correctly cached facet anyway. 37677298Sobrien for (size_t __i = 0; __i < _M_facets_size; ++__i) 37777298Sobrien { 37877298Sobrien const facet* __cpr = _M_caches[__i]; 37977298Sobrien if (__cpr) 38077298Sobrien { 38177298Sobrien __cpr->_M_remove_reference(); 38277298Sobrien _M_caches[__i] = 0; 38377298Sobrien } 38477298Sobrien } 38577298Sobrien } 38677298Sobrien } 38777298Sobrien 38877298Sobrien void 38977298Sobrien locale::_Impl:: 39077298Sobrien _M_install_cache(const facet* __cache, size_t __index) 39177298Sobrien { 39277298Sobrien __gnu_cxx::__scoped_lock sentry(locale_cache_mutex); 39377298Sobrien if (_M_caches[__index] != 0) 39477298Sobrien { 39577298Sobrien // Some other thread got in first. 39677298Sobrien delete __cache; 39777298Sobrien } 39877298Sobrien else 39977298Sobrien { 40077298Sobrien __cache->_M_add_reference(); 40177298Sobrien _M_caches[__index] = __cache; 40277298Sobrien } 40377298Sobrien } 40477298Sobrien 40577298Sobrien // locale::id 40677298Sobrien // Definitions for static const data members of locale::id 40777298Sobrien _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker 40877298Sobrien 40977298Sobrien size_t 41077298Sobrien locale::id::_M_id() const 41177298Sobrien { 41277298Sobrien if (!_M_index) 41377298Sobrien { 41477298Sobrien // XXX GLIBCXX_ABI Deprecated 41577298Sobrien#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 41677298Sobrien locale::id *f = 0; 41777298Sobrien# define _GLIBCXX_SYNC_ID(facet, mangled) \ 41877298Sobrien if (this == &::mangled) \ 41977298Sobrien f = &facet::id 42077298Sobrien _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 42177298Sobrien _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 42277298Sobrien _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 42377298Sobrien _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 42477298Sobrien# ifdef _GLIBCXX_USE_WCHAR_T 42577298Sobrien _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 42677298Sobrien _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 42777298Sobrien _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 42877298Sobrien _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 42977298Sobrien# endif 43077298Sobrien if (f) 43177298Sobrien _M_index = 1 + f->_M_id(); 43277298Sobrien else 43377298Sobrien#endif 43477298Sobrien _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 43577298Sobrien 1); 43677298Sobrien } 43777298Sobrien return _M_index - 1; 43877298Sobrien } 43977298Sobrien 44077298Sobrien_GLIBCXX_END_NAMESPACE 44177298Sobrien