OSDN Git Service

2011-11-18 Paolo Carlini <paolo.carlini@oracle.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / localename.cc
index 431a8c1..52e2282 100644 (file)
@@ -1,10 +1,11 @@
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+// 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-// 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>
 
-namespace std
+namespace std _GLIBCXX_VISIBILITY(default)
 {
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
   using namespace __gnu_cxx;
 
   locale::locale(const char* __s) : _M_impl(0)
@@ -140,7 +139,7 @@ namespace std
          }
       }
     else
-      __throw_runtime_error(__N("locale::locale NULL not valid"));
+      __throw_runtime_error(__N("locale::locale null not valid"));
   }
 
   locale::locale(const locale& __base, const char* __s, category __cat)
@@ -164,9 +163,9 @@ namespace std
     __cat = _S_normalize_category(__cat);  
     _M_impl = new _Impl(*__base._M_impl, 1);  
 
-    try 
+    __try 
       { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
-    catch (...) 
+    __catch(...) 
       { 
        _M_impl->_M_remove_reference(); 
        __throw_exception_again;
@@ -183,8 +182,9 @@ namespace std
     // see if the given name is valid.
     __c_locale __cloc;
     locale::facet::_S_create_c_locale(__cloc, __s);
+    __c_locale __clocm = __cloc;
 
-    try
+    __try
       {
        _M_facets = new const facet*[_M_facets_size];
        for (size_t __i = 0; __i < _M_facets_size; ++__i)
@@ -197,15 +197,19 @@ namespace std
          _M_names[__k] = 0;
 
        // Name the categories.
+       const char* __smon = __s;
        const size_t __len = std::strlen(__s);
        if (!std::memchr(__s, ';', __len))
          {
            _M_names[0] = new char[__len + 1];
-           std::memcpy(_M_names[0], __s, __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;
@@ -215,6 +219,24 @@ namespace std
                _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;
+                 }
+             }
+
+           if (std::strcmp(_M_names[__ci], _M_names[__mi]))
+             {
+               __smon = _M_names[__mi];
+               __clocm = locale::facet::_S_lc_ctype_c_locale(__cloc,
+                                                             __smon);
              }
          }
  
@@ -225,8 +247,8 @@ namespace std
        _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 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));
@@ -241,8 +263,8 @@ namespace std
        _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 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));
@@ -251,10 +273,14 @@ namespace std
        _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(...)
+    __catch(...)
       {
        locale::facet::_S_destroy_c_locale(__cloc);
+       if (__clocm != __cloc)
+         locale::facet::_S_destroy_c_locale(__clocm);
        this->~_Impl();
        __throw_exception_again;
       }        
@@ -265,38 +291,64 @@ namespace std
   _M_replace_categories(const _Impl* __imp, category __cat)
   {
     category __mask = 1;
-    const bool __have_names = _M_names[0] && __imp->_M_names[0];
-    for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1)
+    if (!_M_names[0] || !__imp->_M_names[0])
+      {
+       if (_M_names[0])
+         {
+           delete [] _M_names[0];
+           _M_names[0] = 0;   // Unnamed.
+         }
+
+       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 (__mask & __cat)
+       if (!_M_names[1])
          {
-           // 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 (__have_names)
+           // 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)
              {
-               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);
-                     }
-                 }
-               char* __src = __imp->_M_names[__ix] ? __imp->_M_names[__ix]
-                                                   : __imp->_M_names[0];
+               _M_names[__i] = new char[__len];
+               std::memcpy(_M_names[__i], _M_names[0], __len);
+             }
+         }
+
+       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]);
+
+               // 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;
+
+               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];
-               _M_names[__ix] = __new;
+               delete [] _M_names[__ix_name];
+               _M_names[__ix_name] = __new;
              }
          }
       }
   }
-} // namespace std
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace