OSDN Git Service

2011-11-18 Paolo Carlini <paolo.carlini@oracle.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / localename.cc
index baa3bee..52e2282 100644 (file)
@@ -1,9 +1,11 @@
-// Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+// 2006, 2007, 2008, 2009, 2010
+// Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 // terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2, or (at your option)
+// Free Software Foundation; either version 3, or (at your option)
 // any later version.
 
 // This library is distributed in the hope that it will be useful,
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
 
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING.  If not, write to the Free
-// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
 
-// As a special exception, you may use this file as part of a free software
-// library without restriction.  Specifically, if other files instantiate
-// templates or use macros or inline functions from this file, or you compile
-// this file and link it with other files to produce an executable, this
-// file does not by itself cause the resulting executable to be covered by
-// the GNU General Public License.  This exception does not however
-// invalidate any other reasons why the executable file might be covered by
-// the GNU General Public License.
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
 
+#include <clocale>
+#include <cstring>
+#include <cstdlib>
+#include <locale>
 
-#include <bits/std_clocale.h>
-#include <bits/std_locale.h>
-#include <bits/std_cstring.h>
-#include <bits/std_cassert.h>
-#include <bits/std_vector.h>
-#include <bits/std_stdexcept.h>
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-namespace std {
+  using namespace __gnu_cxx;
 
-  locale::_Impl::
-  ~_Impl() throw()
+  locale::locale(const char* __s) : _M_impl(0)
   {
-    std::vector<facet*>::iterator it = _M_facets->begin();
-    for (; it != _M_facets->end(); ++it)
-      (*it)->_M_remove_reference();
-    delete _M_facets;
-    delete _M_category_names;
+    if (__s)
+      {
+       _S_initialize(); 
+       if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0)
+         (_M_impl = _S_classic)->_M_add_reference();
+       else if (std::strcmp(__s, "") != 0)
+         _M_impl = new _Impl(__s, 1);
+       else
+         {
+           // Get it from the environment.
+           char* __env = std::getenv("LC_ALL");
+           // If LC_ALL is set we are done.
+           if (__env && std::strcmp(__env, "") != 0)
+             {
+               if (std::strcmp(__env, "C") == 0 
+                   || std::strcmp(__env, "POSIX") == 0)
+                 (_M_impl = _S_classic)->_M_add_reference();
+               else
+                 _M_impl = new _Impl(__env, 1);
+             }
+           else
+             {
+               // LANG may set a default different from "C".
+               string __lang;
+               __env = std::getenv("LANG");
+               if (!__env || std::strcmp(__env, "") == 0 
+                   || std::strcmp(__env, "C") == 0 
+                   || std::strcmp(__env, "POSIX") == 0)
+                 __lang = "C";
+               else 
+                 __lang = __env;
+               
+               // Scan the categories looking for the first one
+               // different from LANG.
+               size_t __i = 0;
+               if (__lang == "C")
+                 for (; __i < _S_categories_size; ++__i)
+                   {
+                     __env = std::getenv(_S_categories[__i]);
+                     if (__env && std::strcmp(__env, "") != 0 
+                         && std::strcmp(__env, "C") != 0 
+                         && std::strcmp(__env, "POSIX") != 0)
+                       break;
+                   }
+               else
+                 for (; __i < _S_categories_size; ++__i)
+                   {
+                     __env = std::getenv(_S_categories[__i]);
+                     if (__env && std::strcmp(__env, "") != 0
+                         && __lang != __env)
+                       break;
+                   }
+       
+               // If one is found, build the complete string of
+               // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on...
+               if (__i < _S_categories_size)
+                 {
+                   string __str;
+                   __str.reserve(128);
+                   for (size_t __j = 0; __j < __i; ++__j)
+                     {
+                       __str += _S_categories[__j];
+                       __str += '=';
+                       __str += __lang;
+                       __str += ';';
+                     }
+                   __str += _S_categories[__i];
+                   __str += '=';
+                   __str += __env;
+                   __str += ';';
+                   ++__i;
+                   for (; __i < _S_categories_size; ++__i)
+                     {
+                       __env = std::getenv(_S_categories[__i]);
+                       __str += _S_categories[__i];
+                       if (!__env || std::strcmp(__env, "") == 0)
+                         {
+                           __str += '=';
+                           __str += __lang;
+                           __str += ';';
+                         }
+                       else if (std::strcmp(__env, "C") == 0
+                                || std::strcmp(__env, "POSIX") == 0)
+                         __str += "=C;";
+                       else
+                         {
+                           __str += '=';
+                           __str += __env;
+                           __str += ';';
+                         }
+                     }
+                   __str.erase(__str.end() - 1);
+                   _M_impl = new _Impl(__str.c_str(), 1);
+                 }
+               // ... otherwise either an additional instance of
+               // the "C" locale or LANG.
+               else if (__lang == "C")
+                 (_M_impl = _S_classic)->_M_add_reference();
+               else
+                 _M_impl = new _Impl(__lang.c_str(), 1);
+             }
+         }
+      }
+    else
+      __throw_runtime_error(__N("locale::locale null not valid"));
   }
 
-  // This constructor is used to correctly initialize the standard,
-  // required facets.
-  locale::_Impl::
-  _Impl(size_t __numfacets, size_t __refs, bool __has_name = false, 
-       string __name = "*")
-  : _M_references(__refs - 1), _M_facets(0), _M_category_names(0), 
-    _M_has_name(__has_name), _M_name(__name)
+  locale::locale(const locale& __base, const char* __s, category __cat)
+  : _M_impl(0)
   { 
-    typedef vector<facet*, allocator<facet*> > __vec_facet;
-    typedef vector<string, allocator<string> > __vec_string;
-
-    auto_ptr<__vec_facet> __pvf(new __vec_facet(__numfacets, (facet*)0));
-    auto_ptr<__vec_string> __pcn(new __vec_string(_S_num_categories, _M_name));
-    _M_facets = __pvf.release();
-    _M_category_names = __pcn.release();
+    // NB: There are complicated, yet more efficient ways to do
+    // this. Building up locales on a per-category way is tedious, so
+    // let's do it this way until people complain.
+    locale __add(__s);
+    _M_coalesce(__base, __add, __cat);
   }
-  
-  locale::_Impl::
-  _Impl(const _Impl& __other, size_t __refs)
-  : _M_references(__refs - 1), _M_facets(0), _M_category_names(0), 
-    _M_has_name(__other._M_has_name), _M_name(__other._M_name)
-  {
-    typedef vector<facet*, allocator<facet*> > __vec_facet;
-    typedef vector<string, allocator<string> > __vec_string;
 
-    auto_ptr<__vec_facet> __pvf(new __vec_facet(*(__other._M_facets)));
-    auto_ptr<__vec_string> 
-      __pcn(new __vec_string(*(__other._M_category_names)));
+  locale::locale(const locale& __base, const locale& __add, category __cat)
+  : _M_impl(0)
+  { _M_coalesce(__base, __add, __cat); }
 
-    std::vector<facet*>::iterator __it = __pvf->begin();
-    for (; __it != __pvf->end(); ++__it)
-      (*__it)->_M_add_reference();
+  void
+  locale::_M_coalesce(const locale& __base, const locale& __add, 
+                     category __cat)
+  {
+    __cat = _S_normalize_category(__cat);  
+    _M_impl = new _Impl(*__base._M_impl, 1);  
 
-    // These must be last since in the presence of an exception, the 
-    // destructor for 'this' won't run until AFTER execution has passed  
-    // the closing brace of the constructor.
-    _M_facets = __pvf.release();
-    _M_category_names = __pcn.release();
+    __try 
+      { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
+    __catch(...) 
+      { 
+       _M_impl->_M_remove_reference(); 
+       __throw_exception_again;
+      }
   }
 
-  // Construct specific categories, leaving unselected ones alone
+  // Construct named _Impl.
   locale::_Impl::
-  _Impl(const _Impl& __other, const string& __name, category __cat, 
-       size_t __refs)
-    : _M_references(__refs - 1)
-    //  , _M_facets(other._M_facets)
-    //  , _M_category_names(other._M_category_names)
-    , _M_has_name(__other._M_has_name), _M_name(__other._M_name)
+  _Impl(const char* __s, size_t __refs)
+  : _M_refcount(__refs), _M_facets(0), _M_facets_size(_GLIBCXX_NUM_FACETS),
+    _M_caches(0), _M_names(0)
   {
-#if 1
-    typedef vector<facet*, allocator<facet*> > __vec_facet;
-    typedef vector<string, allocator<string> > __vec_string;
-    try {
-      _M_facets = new __vec_facet(*(__other._M_facets));
-    }
-    catch (...) {
-      delete _M_facets;
-      throw;
-    }
-    try {
-       _M_category_names = new __vec_string(*(__other._M_category_names));
-    }
-    catch (...) {
-      delete _M_category_names;
-      throw;
-    }
-#endif
-    // XXX Nathan what are you doing here? Is this supposed to be const?
-    // static void(_Impl::* const ctors[]) (const char*) = 
-    static void(_Impl::* ctors[]) (const char*) = 
-    {
-      //  NB: Order must match the decl order in class locale.
-      &locale::_Impl::_M_construct_collate,
-      &locale::_Impl::_M_construct_ctype,
-      &locale::_Impl::_M_construct_monetary,
-      &locale::_Impl::_M_construct_numeric,
-      &locale::_Impl::_M_construct_time,
-      &locale::_Impl::_M_construct_messages,
-      0
-    };
-    
-    _S_initialize();
-    std::vector<facet*>::iterator __it = _M_facets->begin();
-    for (; __it != _M_facets->end(); ++__it)
-      (*__it)->_M_add_reference();
+    // Initialize the underlying locale model, which also checks to
+    // see if the given name is valid.
+    __c_locale __cloc;
+    locale::facet::_S_create_c_locale(__cloc, __s);
+    __c_locale __clocm = __cloc;
 
-    try {
-      category __ccategory = _S_normalize_category(__cat);  // might throw
-      _M_normalize_category_names(__name, __ccategory);
-       
-      unsigned mask = (locale::all & -(unsigned)locale::all);
-      for (unsigned ix = 0; (-mask & __cat) != 0; ++ix, (mask <<= 1))
-       {
-         if (!(mask & __cat))
-           continue;
-         
-         if (mask & __ccategory)
-           _M_replace_category(_S_classic, _S_facet_categories[ix]);
-         else
-           (this->*ctors[ix]) (__name.c_str());
-       }
-    }
-    catch (...) {
-      __it = _M_facets->begin();
-      for (; __it != _M_facets->end(); ++__it)
-       (*__it)->_M_remove_reference();
-      throw;
-    }
-  }
-  
-  void
-  locale::_Impl::
-  _M_replace_categories(const _Impl* __other, category __cat)
-  {
-    assert((__cat & locale::all) && !(__cat & ~locale::all));
-    
-    unsigned int __mask = locale::all & -static_cast<unsigned int>(locale::all);
-    for (unsigned int __ix = 0; (-__mask & __cat) != 0; ++__ix, (__mask <<= 1))
+    __try
       {
-       if (__mask & __cat)
+       _M_facets = new const facet*[_M_facets_size];
+       for (size_t __i = 0; __i < _M_facets_size; ++__i)
+         _M_facets[__i] = 0;
+       _M_caches = new const facet*[_M_facets_size];
+       for (size_t __j = 0; __j < _M_facets_size; ++__j)
+         _M_caches[__j] = 0;
+       _M_names = new char*[_S_categories_size];
+       for (size_t __k = 0; __k < _S_categories_size; ++__k)
+         _M_names[__k] = 0;
+
+       // Name the categories.
+       const char* __smon = __s;
+       const size_t __len = std::strlen(__s);
+       if (!std::memchr(__s, ';', __len))
          {
-           _M_replace_category(__other, _S_facet_categories[__ix]);
-           (*_M_category_names)[__ix] = (*(__other->_M_category_names))[__ix];
+           _M_names[0] = new char[__len + 1];
+           std::memcpy(_M_names[0], __s, __len + 1);
          }
-      }
-  }
+       else
+         {
+           const char* __end = __s;
+           bool __found_ctype = false;
+           bool __found_monetary = false;
+           size_t __ci = 0, __mi = 0;
+           for (size_t __i = 0; __i < _S_categories_size; ++__i)
+             {
+               const char* __beg = std::strchr(__end + 1, '=') + 1;
+               __end = std::strchr(__beg, ';');
+               if (!__end)
+                 __end = __s + __len;
+               _M_names[__i] = new char[__end - __beg + 1];
+               std::memcpy(_M_names[__i], __beg, __end - __beg);
+               _M_names[__i][__end - __beg] = '\0';
+               if (!__found_ctype
+                   && *(__beg - 2) == 'E' && *(__beg - 3) == 'P')
+                 {
+                   __found_ctype = true;
+                   __ci = __i;
+                 }
+               else if (!__found_monetary && *(__beg - 2) == 'Y')
+                 {
+                   __found_monetary = true;
+                   __mi = __i;
+                 }
+             }
 
-  void
-  locale::_Impl::
-  _M_replace_category(const _Impl* __other, const locale::id* const* __idpp)
-  {
-    for (; *__idpp; ++__idpp)
-      _M_replace_facet(__other, *__idpp);
-  }
-  
-  void
-  locale::_Impl::
-  _M_replace_facet(const _Impl* __other, const locale::id* __idp)
-  {
-    size_t __index = __idp->_M_index;
-    if (__index == 0 
-       || __other->_M_facets->size() <= __index 
-       || (*(__other->_M_facets))[__index] == 0)
-      throw runtime_error("no locale facet");
+           if (std::strcmp(_M_names[__ci], _M_names[__mi]))
+             {
+               __smon = _M_names[__mi];
+               __clocm = locale::facet::_S_lc_ctype_c_locale(__cloc,
+                                                             __smon);
+             }
+         }
+       // Construct all standard facets and add them to _M_facets.
+       _M_init_facet(new std::ctype<char>(__cloc, 0, false));
+       _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc));
+       _M_init_facet(new numpunct<char>(__cloc));
+       _M_init_facet(new num_get<char>);
+       _M_init_facet(new num_put<char>);
+       _M_init_facet(new std::collate<char>(__cloc));
+       _M_init_facet(new moneypunct<char, false>(__cloc, 0));
+       _M_init_facet(new moneypunct<char, true>(__cloc, 0));
+       _M_init_facet(new money_get<char>);
+       _M_init_facet(new money_put<char>);
+       _M_init_facet(new __timepunct<char>(__cloc, __s));
+       _M_init_facet(new time_get<char>);
+       _M_init_facet(new time_put<char>);
+       _M_init_facet(new std::messages<char>(__cloc, __s));
        
-    _M_install_facet(__idp, (*(__other->_M_facets))[__index]); 
+#ifdef  _GLIBCXX_USE_WCHAR_T
+       _M_init_facet(new std::ctype<wchar_t>(__cloc));
+       _M_init_facet(new codecvt<wchar_t, char, mbstate_t>(__cloc));
+       _M_init_facet(new numpunct<wchar_t>(__cloc));
+       _M_init_facet(new num_get<wchar_t>);
+       _M_init_facet(new num_put<wchar_t>);
+       _M_init_facet(new std::collate<wchar_t>(__cloc));
+       _M_init_facet(new moneypunct<wchar_t, false>(__clocm, __smon));
+       _M_init_facet(new moneypunct<wchar_t, true>(__clocm, __smon));
+       _M_init_facet(new money_get<wchar_t>);
+       _M_init_facet(new money_put<wchar_t>);
+       _M_init_facet(new __timepunct<wchar_t>(__cloc, __s));
+       _M_init_facet(new time_get<wchar_t>);
+       _M_init_facet(new time_put<wchar_t>);
+       _M_init_facet(new std::messages<wchar_t>(__cloc, __s));
+#endif   
+       locale::facet::_S_destroy_c_locale(__cloc);
+       if (__clocm != __cloc)
+         locale::facet::_S_destroy_c_locale(__clocm);
+      }
+    __catch(...)
+      {
+       locale::facet::_S_destroy_c_locale(__cloc);
+       if (__clocm != __cloc)
+         locale::facet::_S_destroy_c_locale(__clocm);
+       this->~_Impl();
+       __throw_exception_again;
+      }        
   }
 
   void
   locale::_Impl::
-  _M_install_facet(const locale::id* __idp, facet* __fp)
+  _M_replace_categories(const _Impl* __imp, category __cat)
   {
-    if (__fp == 0)
-      return;
-
-    size_t& __index = __idp->_M_index;
-    if (!__index)
-      __index = ++locale::id::_S_highwater;  // XXX MT
-
-    if (__index >= _M_facets->size())
-      _M_facets->resize(__index + 1, 0);  // might throw
-    facet*& __fpr = (*_M_facets)[__index];
-    // Order matters, here:
-    __fp->_M_add_reference();
-    if (__fpr) 
-      __fpr->_M_remove_reference();
-    __fpr = __fp;
-  }
-  locale::category
-  locale::_Impl::_M_normalize_category_names(const string&, 
-                                            locale::category __cat)
-  {
-    // The problem to be solved here is that locale names
-    // generally have one of two forms: they might have
-    // only one component, such as "en_US"; or they might
-    // have six, such as "en_US fr_FR en_US C C C", where
-    // each component names a category.  Each vendor has
-    // a different order of categories.  Each vendor uses
-    // a different format:
-    //    AIX uses "C C C C C C"
-    //    Sun uses "/C/C/C/C/C/C"
-    //    HP uses  "/0:C;1:C;2:C;3:C;4:C;5:C;6:C;/"
-    //    (where the 0th element is for LC_ALL.)
-    // Most systems (except AIX) permit the long form only for
-    // setlocale(LC_ALL,...), and require the short form for
-    // other calls.  All this matters because locale names are
-    // supposed to be compatible between locale("") and
-    // setlocale(..., "") constructors.
-    
-    return __cat;
-#if 0 /* XXX not done */
-    unsigned mask = (locale::all & -(unsigned)locale::all);
-    for (unsigned ix = 0; (-mask & __cat) != 0; ++ix, (mask <<= 1))
+    category __mask = 1;
+    if (!_M_names[0] || !__imp->_M_names[0])
       {
-       
-      }
-#endif
-  }
+       if (_M_names[0])
+         {
+           delete [] _M_names[0];
+           _M_names[0] = 0;   // Unnamed.
+         }
 
-  void 
-  locale::_Impl::_M_construct_collate(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::collate_byname<char>(__name));
-    _M_facet_init(new std::collate_byname<wchar_t>(__name));
-#endif
-  }
+       for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1)
+         {
+           if (__mask & __cat)
+             // Need to replace entry in _M_facets with other locale's info.
+             _M_replace_category(__imp, _S_facet_categories[__ix]);
+         }
+      }
+    else
+      {
+       if (!_M_names[1])
+         {
+           // A full set of _M_names must be prepared, all identical
+           // to _M_names[0] to begin with. Then, below, a few will
+           // be replaced by the corresponding __imp->_M_names. I.e.,
+           // not a "simple" locale anymore (see locale::operator==).
+           const size_t __len = std::strlen(_M_names[0]) + 1;
+           for (size_t __i = 1; __i < _S_categories_size; ++__i)
+             {
+               _M_names[__i] = new char[__len];
+               std::memcpy(_M_names[__i], _M_names[0], __len);
+             }
+         }
 
-  void 
-  locale::_Impl::_M_construct_ctype(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::ctype_byname<char>(__name));
-    _M_facet_init(new std::ctype_byname<wchar_t>(__name));
-    _M_facet_init(new std::codecvt_byname<char, char, mbstate_t>(__name));
-    _M_facet_init(new std::codecvt_byname<wchar_t, char, mbstate_t>(__name));
-#endif
-  }
-    
-  void 
-  locale::_Impl::_M_construct_monetary(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::moneypunct_byname<char, false>(__name));
-    _M_facet_init(new std::moneypunct_byname<wchar_t, false>(__name));
-    _M_facet_init(new std::moneypunct_byname<char, true >(__name));
-    _M_facet_init(new std::moneypunct_byname<wchar_t, true >(__name));
+       for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1)
+         {
+           if (__mask & __cat)
+             {
+               // Need to replace entry in _M_facets with other locale's info.
+               _M_replace_category(__imp, _S_facet_categories[__ix]);
 
-    locale::_M_initialize();
-    _M_replace_facet(locale::_S_classic, &std::money_get<char>(__name)::id);
-    _M_replace_facet(locale::_S_classic, &std::money_get<wchar_t>(__name)::id);
-    _M_replace_facet(locale::_S_classic, &std::money_put<char>(__name)::id);
-    _M_replace_facet(locale::_S_classic, &std::money_put<wchar_t>(__name)::id);
-#endif
-  }
-    
-  void 
-  locale::_Impl::_M_construct_numeric(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::numpunct_byname<char>(__name));
-    _M_facet_init(new std::numpunct_byname<wchar_t>(__name));
+               // FIXME: Hack for libstdc++/29217: the numerical encodings
+               // of the time and collate categories are swapped vs the
+               // order of the names in locale::_S_categories.  We'd like to
+               // adjust the former (the latter is dictated by compatibility
+               // with glibc) but we can't for binary compatibility.
+               size_t __ix_name = __ix;
+               if (__ix == 2 || __ix == 3)
+                 __ix_name = 5 - __ix;
 
-    locale::_M_initialize();
-    _M_replace_facet(locale::_S_classic, &std::num_get<char>::id);
-    _M_replace_facet(locale::_S_classic, &std::num_get<wchar_t>::id);
-    _M_replace_facet(locale::_S_classic, &std::num_put<char>::id);
-    _M_replace_facet(locale::_S_classic, &std::num_put<wchar_t>::id);
-#endif
-  }
-    
-  void 
-  locale::_Impl::_M_construct_time(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::time_get_byname<char>(__name));
-    _M_facet_init(new std::time_get_byname<wchar_t>(__name));
-    _M_facet_init(new std::time_put_byname<char>(__name));
-    _M_facet_init(new std::time_put_byname<wchar_t>(__name));
-#endif
-  }
-    
-  void 
-  locale::_Impl::_M_construct_messages(const char* /*__name*/)
-  {
-#if 0
-    _M_facet_init(new std::messages_byname<char>(__name));
-    _M_facet_init(new std::messages_byname<wchar_t>(__name));
-#endif
+               char* __src = __imp->_M_names[__ix_name] ?
+                             __imp->_M_names[__ix_name] : __imp->_M_names[0];
+               const size_t __len = std::strlen(__src) + 1;
+               char* __new = new char[__len];
+               std::memcpy(__new, __src, __len);
+               delete [] _M_names[__ix_name];
+               _M_names[__ix_name] = __new;
+             }
+         }
+      }
   }
-}
-
-
 
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace