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