OSDN Git Service

2003-12-04 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / localename.cc
index 867b063..2c12ba7 100644 (file)
@@ -1,4 +1,5 @@
-// Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+// 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
 // invalidate any other reasons why the executable file might be covered by
 // the GNU General Public License.
 
-#include <bits/std_clocale.h>
-#include <bits/std_locale.h>
-#include <bits/std_cstring.h>
-#include <bits/std_vector.h>
-#include <bits/std_stdexcept.h>
+#include <clocale>
+#include <cstring>
+#include <locale>
 
-namespace std {
-  locale::_Impl::
-  ~_Impl() throw()
-  {
-    __vec_facet::iterator it = _M_facets->begin();
-    for (; it != _M_facets->end(); ++it)
-      if (*it)
-       (*it)->_M_remove_reference();
-    delete _M_facets;
-    locale::facet::_S_destroy_c_locale(_M_c_locale);
-  }
+namespace std
+{
+  using namespace __gnu_cxx;
 
-  // Clone existing _Impl object.
-  locale::_Impl::
-  _Impl(const _Impl& __imp, size_t __refs)
-  : _M_references(__refs - 1), _M_facets(0), _M_c_locale(0) // XXX
+  
+  locale::locale(const char* __s)
   {
-    try
-      {  _M_facets = new __vec_facet(*(__imp._M_facets)); }
-    catch(...) 
+    if (__s)
       {
-       delete _M_facets;
-       throw;
+       _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 __res;
+               char* __env = std::getenv("LANG");
+               if (!__env || std::strcmp(__env, "") == 0 
+                   || std::strcmp(__env, "C") == 0 
+                   || std::strcmp(__env, "POSIX") == 0)
+                 __res = "C";
+               else 
+                 __res = __env;
+               
+               // Scan the categories looking for the first one
+               // different from LANG.
+               size_t __i = 0;
+               if (__res == "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
+                         && __res != __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;
+                   for (size_t __j = 0; __j < __i; ++__j)
+                     {
+                       __str += _S_categories[__j];
+                       __str += '=';
+                       __str += __res;
+                       __str += ';';
+                     }
+                   __str += _S_categories[__i];
+                   __str += '=';
+                   __str += __env;
+                   __str += ';';
+                   __i++;
+                   for (; __i < _S_categories_size; ++__i)
+                     {
+                       __env = std::getenv(_S_categories[__i]);
+                       if (!__env || std::strcmp(__env, "") == 0)
+                         {
+                           __str += _S_categories[__i];
+                           __str += '=';
+                           __str += __res;
+                           __str += ';';
+                         }
+                       else if (std::strcmp(__env, "C") == 0
+                                || std::strcmp(__env, "POSIX") == 0)
+                         {
+                           __str += _S_categories[__i];
+                           __str += "=C;";
+                         }
+                       else
+                         {
+                           __str += _S_categories[__i];
+                           __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 (__res == "C")
+                 (_M_impl = _S_classic)->_M_add_reference();
+               else
+                 _M_impl = new _Impl(__res.c_str(), 1);
+             }
+         }
       }
+    else
+      __throw_runtime_error("locale::locale NULL not valid");
+  }
+
+  locale::locale(const locale& __base, const char* __s, category __cat)
+  { 
+    // 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::locale(const locale& __base, const locale& __add, category __cat)
+  { _M_coalesce(__base, __add, __cat); }
 
-    for (size_t i = 0; i < _S_num_categories; ++i)
-      _M_names[i] = __imp._M_names[i];
+  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);  
 
-    __vec_facet::iterator __it = _M_facets->begin();
-    for (; __it != _M_facets->end(); ++__it)
-      if (*__it)
-       (*__it)->_M_add_reference();
+    try 
+      { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
+    catch (...) 
+      { 
+       _M_impl->_M_remove_reference(); 
+       __throw_exception_again;
+      }
   }
 
-  // Construct named _Impl, including the standard "C" locale.
+  // Construct named _Impl.
   locale::_Impl::
-  _Impl(string __str, size_t __refs)
-  : _M_references(__refs - 1), _M_facets(0)
+  _Impl(const char* __s, size_t __refs) 
+  : _M_references(__refs), _M_facets_size(_GLIBCXX_NUM_FACETS)
   {
     // Initialize the underlying locale model, which also checks to
     // see if the given name is valid.
-    if (__str != "C" && __str != "POSIX")
-      locale::facet::_S_create_c_locale(_M_c_locale, __str.c_str());
-    else
-      _M_c_locale = NULL;
+    __c_locale __cloc;
+    locale::facet::_S_create_c_locale(__cloc, __s);
 
-    // Allocate facet container.
+    _M_facets = _M_caches = 0;
+    _M_names = 0;
     try
-      {  _M_facets = new __vec_facet(_S_num_facets, NULL); }
-    catch(...) 
       {
-       delete _M_facets;
-       throw;
-      }
-
-    // Name all the categories.
-    for (size_t i = 0; i < _S_num_categories; ++i)
-      _M_names[i] = __str;
+       _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 __i = 0; __i < _M_facets_size; ++__i)
+         _M_caches[__i] = 0;
+       _M_names = new char*[_S_categories_size];
+       for (size_t __i = 0; __i < _S_categories_size; ++__i)
+         _M_names[__i] = 0;
 
-    // Construct all standard facets and add them to _M_facets.
-    // XXX Eventually, all should use __c_locale ctor like numpunct
-    _M_init_facet(new std::collate<char>);
-    _M_init_facet(new std::ctype<char>);
-    _M_init_facet(new codecvt<char, char, mbstate_t>);
-    _M_init_facet(new moneypunct<char, false>(_M_c_locale));
-    _M_init_facet(new moneypunct<char,true >);
-    _M_init_facet(new money_get<char>);
-    _M_init_facet(new money_put<char>);
-    _M_init_facet(new numpunct<char>(_M_c_locale));
-    _M_init_facet(new num_get<char>);
-    _M_init_facet(new num_put<char>);
-    _M_init_facet(new time_get<char>);
-    _M_init_facet(new time_put<char>);
-    _M_init_facet(new std::messages<char>);
-    
-#ifdef  _GLIBCPP_USE_WCHAR_T
-    _M_init_facet(new std::collate<wchar_t>);
-    _M_init_facet(new std::ctype<wchar_t>);
-    _M_init_facet(new codecvt<wchar_t, char, mbstate_t>);
-    _M_init_facet(new moneypunct<wchar_t, false>(_M_c_locale));
-    _M_init_facet(new moneypunct<wchar_t,true >);
-    _M_init_facet(new money_get<wchar_t>);
-    _M_init_facet(new money_put<wchar_t>);
-    _M_init_facet(new numpunct<wchar_t>(_M_c_locale));
-    _M_init_facet(new num_get<wchar_t>);
-    _M_init_facet(new num_put<wchar_t>);
-    _M_init_facet(new time_get<wchar_t>);
-    _M_init_facet(new time_put<wchar_t>);
-    _M_init_facet(new std::messages<wchar_t>);
+       // Name all the categories.
+       const size_t __len = std::strlen(__s);
+       if (!std::strchr(__s, ';'))
+         {
+           for (size_t __i = 0; __i < _S_categories_size; ++__i)
+             {
+               _M_names[__i] = new char[__len + 1];
+               std::strcpy(_M_names[__i], __s);
+             }
+         }
+       else
+         {
+           const char* __beg = __s;
+           for (size_t __i = 0; __i < _S_categories_size; ++__i)
+             {
+               __beg = std::strchr(__beg, '=') + 1;
+               const char* __end = std::strchr(__beg, ';');
+               if (!__end)
+                 __end = __s + __len;
+               char* __new = new char[__end - __beg + 1];
+               std::memcpy(__new, __beg, __end - __beg);
+               __new[__end - __beg] = '\0';
+               _M_names[__i] = __new;
+             }
+         }
+       // 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, __s));
+       _M_init_facet(new moneypunct<char, true>(__cloc, __s));
+       _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));
+       
+#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>(__cloc, __s));
+       _M_init_facet(new moneypunct<wchar_t, true>(__cloc, __s));
+       _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);
+      }
+    catch(...)
+      {
+       locale::facet::_S_destroy_c_locale(__cloc);
+       this->~_Impl();
+       __throw_exception_again;
+      }        
   }
-  
+
   void
   locale::_Impl::
   _M_replace_categories(const _Impl* __imp, category __cat)
   {
-    const string __none("*");
-    category __mask;
-    for (unsigned int __ix = 0; __ix < _S_num_categories; ++__ix)
+    for (size_t __ix = 0; __ix < _S_categories_size; ++__ix)
       {
-       __mask = 1 << __ix;
+       const category __mask = 1 << __ix;
        if (__mask & __cat)
          {
            // Need to replace entry in _M_facets with other locale's info.
            _M_replace_category(__imp, _S_facet_categories[__ix]);
            // If both have names, go ahead and mangle.
-           if (_M_names[__ix] != __none && __imp->_M_names[__ix] != __none)
-             _M_names[__ix] = __imp->_M_names[__ix];
-         }
-      }
-  }
-
-  void
-  locale::_Impl::
-  _M_replace_category(const _Impl* __imp, const locale::id* const* __idpp)
-  {
-    for (; *__idpp; ++__idpp)
-      _M_replace_facet(__imp, *__idpp);
-  }
-  
-  void
-  locale::_Impl::
-  _M_replace_facet(const _Impl* __imp, const locale::id* __idp)
-  {
-    size_t __index = __idp->_M_index;
-    if (__index == 0 
-       || __imp->_M_facets->size() <= __index 
-       || (*(__imp->_M_facets))[__index] == 0)
-      throw runtime_error("no locale facet");
-       
-    _M_install_facet(__idp, (*(__imp->_M_facets))[__index]); 
-  }
-
-  void
-  locale::_Impl::
-  _M_install_facet(const locale::id* __idp, facet* __fp)
-  {
-    if (__fp)
-      {
-       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];
-       if (__fpr)
-         {
-           // Replacing an existing facet.
-           // Order matters, here:
-           __fp->_M_add_reference();
-           if (__fpr) 
-             __fpr->_M_remove_reference();
-           __fpr = __fp;
-         }
-       else
-         {
-           // Installing a newly created facet into an empty
-           // _M_facets container, say a newly-constructed,
-           // swanky-fresh _Impl.
-           (*_M_facets)[__index] = __fp;
+           if (std::strcmp(_M_names[__ix], "*") != 0 
+               && std::strcmp(__imp->_M_names[__ix], "*") != 0)
+             {
+               char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1];
+               std::strcpy(__new, __imp->_M_names[__ix]);
+               delete [] _M_names[__ix];
+               _M_names[__ix] = __new;
+             }
          }
       }
   }
-}
-
-
-
-
+} // namespace std