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