# locale.cc

    00001 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    00002 // Free Software Foundation, Inc.
    00003 //
    00004 // This file is part of the GNU ISO C++ Library.  This library is free
    00005 // software; you can redistribute it and/or modify it under the
    00006 // terms of the GNU General Public License as published by the
    00007 // Free Software Foundation; either version 2, or (at your option)
    00008 // any later version.
    00009
    00010 // This library is distributed in the hope that it will be useful,
    00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00013 // GNU General Public License for more details.
    00014
    00015 // You should have received a copy of the GNU General Public License along
    00016 // with this library; see the file COPYING.  If not, write to the Free
    00017 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
    00018 // USA.
    00019
    00020 // As a special exception, you may use this file as part of a free software
    00021 // library without restriction.  Specifically, if other files instantiate
    00022 // templates or use macros or inline functions from this file, or you compile
    00023 // this file and link it with other files to produce an executable, this
    00024 // file does not by itself cause the resulting executable to be covered by
    00025 // the GNU General Public License.  This exception does not however
    00026 // invalidate any other reasons why the executable file might be covered by
    00027 // the GNU General Public License.
    00028
    00029 #include <clocale>
    00030 #include <cstring>
    00031 #include <cstdlib>     // For getenv
    00032 #include <cctype>
    00033 #include <cwctype>     // For towupper, etc.
    00034 #include <locale>
    00035 #include <bits/atomicity.h>
    00036
    00037 namespace std
    00038 {
    00039   // Definitions for static const data members of locale.
    00040   const locale::category    locale::none;
    00041   const locale::category    locale::ctype;
    00042   const locale::category    locale::numeric;
    00043   const locale::category    locale::collate;
    00044   const locale::category    locale::time;
    00045   const locale::category    locale::monetary;
    00046   const locale::category    locale::messages;
    00047   const locale::category    locale::all;
    00048
    00049   // These are no longer exported.
    00050   locale::_Impl*                locale::_S_classic;
    00051   locale::_Impl*        locale::_S_global;
    00052   const size_t          locale::_S_categories_size;
    00053
    00054 #ifdef __GTHREADS
    00055   __gthread_once_t      locale::_S_once = __GTHREAD_ONCE_INIT;
    00056 #endif
    00057
    00058   locale::locale(const locale& __other) throw()
    00059   : _M_impl(__other._M_impl)
    00060   { _M_impl->_M_add_reference(); }
    00061
    00062   // This is used to initialize global and classic locales, and
    00063   // assumes that the _Impl objects are constructed correctly.
    00064   // The lack of a reference increment is intentional.
    00065   locale::locale(_Impl* __ip) throw() : _M_impl(__ip)
    00066   { }
    00067
    00068   locale::~locale() throw()
    00069   { _M_impl->_M_remove_reference(); }
    00070
    00071   bool
    00072   locale::operator==(const locale& __rhs) const throw()
    00073   {
    00074     // Deal first with the common cases, fast to process: refcopies,
    00075     // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the
    00076     // categories same name, i.e., _M_names[0]). Otherwise fall back
    00077     // to the general locale::name().
    00078     bool __ret;
    00079     if (_M_impl == __rhs._M_impl)
    00080       __ret = true;
    00081     else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0]
    00082          || std::strcmp(_M_impl->_M_names[0],
    00083                 __rhs._M_impl->_M_names[0]) != 0)
    00084       __ret = false;
    00085     else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1])
    00086       __ret = true;
    00087     else
    00088       __ret = this->name() == __rhs.name();
    00089     return __ret;
    00090   }
    00091
    00092   const locale&
    00093   locale::operator=(const locale& __other) throw()
    00094   {
    00095     __other._M_impl->_M_add_reference();
    00096     _M_impl->_M_remove_reference();
    00097     _M_impl = __other._M_impl;
    00098     return *this;
    00099   }
    00100
    00101   string
    00102   locale::name() const
    00103   {
    00104     string __ret;
    00105     if (!_M_impl->_M_names[0])
    00106       __ret = '*';
    00107     else if (_M_impl->_M_check_same_name())
    00108       __ret = _M_impl->_M_names[0];
    00109     else
    00110       {
    00111     __ret.reserve(128);
    00112     __ret += _S_categories[0];
    00113     __ret += '=';
    00114     __ret += _M_impl->_M_names[0];
    00115     for (size_t __i = 1; __i < _S_categories_size; ++__i)
    00116       {
    00117         __ret += ';';
    00118         __ret += _S_categories[__i];
    00119         __ret += '=';
    00120         __ret += _M_impl->_M_names[__i];
    00121       }
    00122       }
    00123     return __ret;
    00124   }
    00125
    00126   locale::category
    00127   locale::_S_normalize_category(category __cat)
    00128   {
    00129     int __ret = 0;
    00130     if (__cat == none || (__cat & all) && !(__cat & ~all))
    00131       __ret = __cat;
    00132     else
    00133       {
    00134     // NB: May be a C-style "LC_ALL" category; convert.
    00135     switch (__cat)
    00136       {
    00137       case LC_COLLATE:
    00138         __ret = collate;
    00139         break;
    00140       case LC_CTYPE:
    00141         __ret = ctype;
    00142         break;
    00143       case LC_MONETARY:
    00144         __ret = monetary;
    00145         break;
    00146       case LC_NUMERIC:
    00147         __ret = numeric;
    00148         break;
    00149       case LC_TIME:
    00150         __ret = time;
    00151         break;
    00152 #ifdef _GLIBCXX_HAVE_LC_MESSAGES
    00153       case LC_MESSAGES:
    00154         __ret = messages;
    00155         break;
    00156 #endif
    00157       case LC_ALL:
    00158         __ret = all;
    00159         break;
    00160       default:
    00161         __throw_runtime_error(__N("locale::_S_normalize_category "
    00162                   "category not found"));
    00163       }
    00164       }
    00165     return __ret;
    00166   }
    00167
    00168   // locale::facet
    00169   __c_locale locale::facet::_S_c_locale;
    00170
    00171   const char locale::facet::_S_c_name[2] = "C";
    00172
    00173 #ifdef __GTHREADS
    00174   __gthread_once_t locale::facet::_S_once = __GTHREAD_ONCE_INIT;
    00175 #endif
    00176
    00177   void
    00178   locale::facet::_S_initialize_once()
    00179   {
    00180     // Initialize the underlying locale model.
    00181     _S_create_c_locale(_S_c_locale, _S_c_name);
    00182   }
    00183
    00184   __c_locale
    00185   locale::facet::_S_get_c_locale()
    00186   {
    00187 #ifdef __GHTREADS
    00188     if (__gthread_active_p())
    00189       __gthread_once(&_S_once, _S_initialize_once);
    00190     else
    00191 #endif
    00192       {
    00193     if (!_S_c_locale)
    00194       _S_initialize_once();
    00195       }
    00196     return _S_c_locale;
    00197   }
    00198
    00199   const char*
    00200   locale::facet::_S_get_c_name()
    00201   { return _S_c_name; }
    00202
    00203   locale::facet::
    00204   ~facet() { }
    00205
    00206   // locale::_Impl
    00207   locale::_Impl::
    00208   ~_Impl() throw()
    00209   {
    00210     if (_M_facets)
    00211       for (size_t __i = 0; __i < _M_facets_size; ++__i)
    00212     if (_M_facets[__i])
    00213       _M_facets[__i]->_M_remove_reference();
    00214     delete [] _M_facets;
    00215
    00216     if (_M_caches)
    00217       for (size_t __i = 0; __i < _M_facets_size; ++__i)
    00218     if (_M_caches[__i])
    00219       _M_caches[__i]->_M_remove_reference();
    00220     delete [] _M_caches;
    00221
    00222     if (_M_names)
    00223       for (size_t __i = 0; __i < _S_categories_size; ++__i)
    00224     delete [] _M_names[__i];
    00225     delete [] _M_names;
    00226   }
    00227
    00228   // Clone existing _Impl object.
    00229   locale::_Impl::
    00230   _Impl(const _Impl& __imp, size_t __refs)
    00231   : _M_refcount(__refs), _M_facets(0), _M_facets_size(__imp._M_facets_size),
    00232   _M_caches(0), _M_names(0)
    00233   {
    00234     try
    00235       {
    00236     _M_facets = new const facet*[_M_facets_size];
    00237     for (size_t __i = 0; __i < _M_facets_size; ++__i)
    00238       {
    00239         _M_facets[__i] = __imp._M_facets[__i];
    00240         if (_M_facets[__i])
    00241           _M_facets[__i]->_M_add_reference();
    00242       }
    00243     _M_caches = new const facet*[_M_facets_size];
    00244     for (size_t __j = 0; __j < _M_facets_size; ++__j)
    00245       {
    00246         _M_caches[__j] = __imp._M_caches[__j];
    00247         if (_M_caches[__j])
    00248           _M_caches[__j]->_M_add_reference();
    00249       }
    00250     _M_names = new char*[_S_categories_size];
    00251     for (size_t __k = 0; __k < _S_categories_size; ++__k)
    00252       _M_names[__k] = 0;
    00253
    00254     // Name the categories.
    00255     for (size_t __l = 0; (__l < _S_categories_size
    00256                   && __imp._M_names[__l]); ++__l)
    00257       {
    00258         const size_t __len = std::strlen(__imp._M_names[__l]) + 1;
    00259         _M_names[__l] = new char[__len];
    00260         std::memcpy(_M_names[__l], __imp._M_names[__l], __len);
    00261       }
    00262       }
    00263     catch(...)
    00264       {
    00265     this->~_Impl();
    00266     __throw_exception_again;
    00267       }
    00268   }
    00269
    00270   void
    00271   locale::_Impl::
    00272   _M_replace_category(const _Impl* __imp,
    00273               const locale::id* const* __idpp)
    00274   {
    00275     for (; *__idpp; ++__idpp)
    00276       _M_replace_facet(__imp, *__idpp);
    00277   }
    00278
    00279   void
    00280   locale::_Impl::
    00281   _M_replace_facet(const _Impl* __imp, const locale::id* __idp)
    00282   {
    00283     size_t __index = __idp->_M_id();
    00284     if ((__index > (__imp->_M_facets_size - 1))
    00285     || !__imp->_M_facets[__index])
    00286       __throw_runtime_error(__N("locale::_Impl::_M_replace_facet"));
    00287     _M_install_facet(__idp, __imp->_M_facets[__index]);
    00288   }
    00289
    00290   void
    00291   locale::_Impl::
    00292   _M_install_facet(const locale::id* __idp, const facet* __fp)
    00293   {
    00294     if (__fp)
    00295       {
    00296     size_t __index = __idp->_M_id();
    00297
    00298     // Check size of facet vector to ensure adequate room.
    00299     if (__index > _M_facets_size - 1)
    00300       {
    00301         const size_t __new_size = __index + 4;
    00302
    00303         // New facet array.
    00304         const facet** __oldf = _M_facets;
    00305         const facet** __newf;
    00306         __newf = new const facet*[__new_size];
    00307         for (size_t __i = 0; __i < _M_facets_size; ++__i)
    00308           __newf[__i] = _M_facets[__i];
    00309         for (size_t __l = _M_facets_size; __l < __new_size; ++__l)
    00310           __newf[__l] = 0;
    00311
    00312         // New cache array.
    00313         const facet** __oldc = _M_caches;
    00314         const facet** __newc;
    00315         try
    00316           {
    00317         __newc = new const facet*[__new_size];
    00318           }
    00319         catch(...)
    00320           {
    00321         delete [] __newf;
    00322         __throw_exception_again;
    00323           }
    00324         for (size_t __j = 0; __j < _M_facets_size; ++__j)
    00325           __newc[__j] = _M_caches[__j];
    00326         for (size_t __k = _M_facets_size; __k < __new_size; ++__k)
    00327           __newc[__k] = 0;
    00328
    00329         _M_facets_size = __new_size;
    00330         _M_facets = __newf;
    00331         _M_caches = __newc;
    00332         delete [] __oldf;
    00333         delete [] __oldc;
    00334       }
    00335
    00336     __fp->_M_add_reference();
    00337     const facet*& __fpr = _M_facets[__index];
    00338     if (__fpr)
    00339       {
    00340         // Replacing an existing facet. Order matters.
    00341         __fpr->_M_remove_reference();
    00342         __fpr = __fp;
    00343       }
    00344     else
    00345       {
    00346         // Installing a newly created facet into an empty
    00347         // _M_facets container, say a newly-constructed,
    00348         // swanky-fresh _Impl.
    00349         _M_facets[__index] = __fp;
    00350       }
    00351
    00352     // Ideally, it would be nice to only remove the caches that
    00353     // are now incorrect. However, some of the caches depend on
    00354     // multiple facets, and we only know about one facet
    00355     // here. It's no great loss: the first use of the new facet
    00356     // will create a new, correctly cached facet anyway.
    00357     for (size_t __i = 0; __i < _M_facets_size; ++__i)
    00358       {
    00359         const facet* __cpr = _M_caches[__i];
    00360         if (__cpr)
    00361           {
    00362         __cpr->_M_remove_reference();
    00363         _M_caches[__i] = 0;
    00364           }
    00365       }
    00366       }
    00367   }
    00368
    00369   // locale::id
    00370   // Definitions for static const data members of locale::id
    00371   _Atomic_word locale::id::_S_refcount;  // init'd to 0 by linker
    00372
    00373   size_t
    00374   locale::id::_M_id() const
    00375   {
    00376     if (!_M_index)
    00377       _M_index = 1 + __gnu_cxx::__exchange_and_add(&_S_refcount, 1);
    00378     return _M_index - 1;
    00379   }
    00380 } // namespace std
    00381
    00382