Enabling the ieee1003.1-2001 clocale on Solaris 2 (was: RE: Solaris GCC maintainer question...)

Rainer Orth ro@TechFak.Uni-Bielefeld.DE
Fri Oct 2 17:43:00 GMT 2009


Rainer Orth writes:

> tscheresky@micron.com writes:
> 
> [I'm removing gcc@gcc.gnu.org from the Cc:  This is completely libstdc++
> specific, no point bothering the main list any further.]
> 
> > I'm very interested in your results.  Also, which version would you be
> 
> Things don't look good so far: the ieee_1003.1-2001 locale support has been
> left to bitrot to the point that it fails compilation all over the place.
> Me barely knowing any C++ and nothing about the libstdc++ implementation
> doesn't help either.  I'll see how far I can get with this, though.

I've at least managed to get libstdc++-v3 to compile and link with
--enable-clocale=iso1003.1-2001 on Solaris 10/x86.  To achieve that, I've
shamelessly stolen from the gnu and generic locale implementations.  I've
generally used the generic implementation since it lacked dependencies on
glibc and was more portable, removing code that restricted it to the C
locale.  Most of the changes should be obvious in that they were necessary
to get the code to compile at all and to allow the libstdc++ testsuite to
link successfully.

Only one change bears explanation: changing catalog from int to intptr_t in
struct message_base was necessary to get the 64-bit libstdc++ to compile,
otherwise I get the following failure:

In file included from /vol/gcc/obj/gcc-4.5.0-20090929/10-gcc-ieee_1003.1/i386-pc-solaris2.10/amd64/libstdc++-v3/include/bits/locale_facets_nonio.h:1905:0,
                 from /vol/gcc/obj/gcc-4.5.0-20090929/10-gcc-ieee_1003.1/i386-pc-solaris2.10/amd64/libstdc++-v3/include/locale:43,
                 from /vol/gcc/src/gcc-dist/libstdc++-v3/src/locale-inst.cc:30:
/vol/gcc/obj/gcc-4.5.0-20090929/10-gcc-ieee_1003.1/i386-pc-solaris2.10/amd64/libstdc++-v3/include/i386-pc-solaris2.10/bits/messages_members.h: In member function 'std::messages_base::catalog std::messages<_CharT>::do_open(const std::basic_string<char>&, const std::locale&) const [with _CharT = char, std::messages_base::catalog = int]':
/vol/gcc/src/gcc-dist/libstdc++-v3/src/locale-inst.cc:174:18: instantiated from here
/vol/gcc/obj/gcc-4.5.0-20090929/10-gcc-ieee_1003.1/i386-pc-solaris2.10/amd64/libstdc++-v3/include/i386-pc-solaris2.10/bits/messages_members.h:54:75:
error: cast from '_nl_catd_struct*' to 'std::messages_base::catalog' loses precision

Obviously an int cannot hold a 64-bit pointer.  I fear this change is
inacceptable as is since it probably changes the libstdc++.so ABI.

Testing didn't go too well, though: even after I installed the necessary
locales, there are many failures.  I'll upload libstdc++.log to bugzilla
for further inspection.

* One group of failures is obvious: Solaris 2 calls the ja_JP.eucjp locale
  ja_JP.eucJP instead.  This can probably be handled by an appropriate
  define.

* Other locales used in the testsuite have no equivalent on Solaris 2 at
  all: de_DE@euro, en_HK, en_PH, se_NO.UTF-8, ta_IN.  I've no idea what to
  do about them.

* I think that a test shouldn't FAIL if a necessary locale isn't installed,
  but be UNTESTED instead.

As I mentioned already, I barely no any C++ or the libstdc++-v3
implementation, so please bear with me.  Any comments and suggestions on
how to proceed from reviewing the testsuite failures?

If this can all be fixed, the next step woult be to enable this clocale
implemenatation by default on Solaris 2.  As of now, there's no configure
code to do this.  Before, I'll have to verify when the functions used were
introduced in Solaris 2 to avoid possibly breaking older releases.

	Rainer

-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University


2009-09-29  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	PR libstdc++/41495
	* config/locale/ieee_1003.1-2001/c_locale.cc: Include <cmath>,
	<cstdlib>, <limits>.
	Use _GLIBCXX_BEGIN_NAMESPACE.
	(__convert_to_v(const char*, float&, ios_base::iostate&, const
	__c_locale&): New.
	(__convert_to_v(const char*, double&, ios_base::iostate&, const
	__c_locale&)): Likewise.
	(__convert_to_v(const char*, long double&, ios_base::iostate&,
	const __c_locale&)): Likewise
	(locale::facet::_S_create_c_locale): Correct prototype.
	(locale::facet::_S_lc_ctype_c_locale(__c_locale, const char*)): New.
	(numpunct<char>::_M_initialize_numpunct): Remove.
	(numpunct<wchar_t>::_M_initialize_numpunct): Likewise.
	(moneypunct<char>::_M_initialize_moneypunct): Likewise.
	(moneypunct<wchar_t>::_M_initialize_moneypunct): Likewise.
	(category_names): New.
	(locale::_S_categories): Likewise.
	* config/locale/ieee_1003.1-2001/c_locale.h: Wrap in
	_GLIBCXX_CXX_LOCALE_H.
	(_GLIBCXX_NUM_CATEGORIES): Define.
	(__convert_from_v(const __c_locale&, char*, const int, const
	char*, ...)): Define.
	* config/locale/ieee_1003.1-2001/messages_members.cc
	(messages<wchar_t>::do_get): Add parameter names.
	* config/locale/ieee_1003.1-2001/messages_members.h
	(messages<_CharT>::messages(size_t): Define.
	(messages<_CharT>::messages(__c_locale, const char*, size_t):
	Likewise.
	(messages_byname<_CharT>::messages_byname(const char*, size_t):
	Likewise.
	* include/bits/locale_facets_nonio.h (messages_base): Change
	catalog to intptr_t.

Index: libstdc++-v3/include/bits/locale_facets_nonio.h
===================================================================
--- libstdc++-v3/include/bits/locale_facets_nonio.h	(revision 152285)
+++ libstdc++-v3/include/bits/locale_facets_nonio.h	(working copy)
@@ -1643,7 +1643,7 @@
    */
   struct messages_base
   {
-    typedef int catalog;
+    typedef intptr_t catalog;
   };
 
   /**
Index: libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.cc
===================================================================
--- libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.cc	(revision 152285)
+++ libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.cc	(working copy)
@@ -28,12 +28,149 @@
 
 // Written by Benjamin Kosnik <bkoz@redhat.com>
 
+#include <cmath>  // For isinf, finite, finitef, fabs
+#include <cstdlib>  // For strof, strtold
 #include <locale>
+#include <limits>  // For numeric_limits
 
-namespace std 
-{
+_GLIBCXX_BEGIN_NAMESPACE(std)
+
+  template<>
+    void
+    __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err, 
+		   const __c_locale&) 	      
+    {
+      char* __sanity;
+      bool __overflow = false;
+
+#if !__FLT_HAS_INFINITY__
+      errno = 0;
+#endif
+
+#ifdef _GLIBCXX_HAVE_STRTOF
+      __v = strtof(__s, &__sanity);
+#else
+      double __d = strtod(__s, &__sanity);
+      __v = static_cast<float>(__d);
+#ifdef _GLIBCXX_HAVE_FINITEF
+      if (!finitef (__v))
+	__overflow = true;
+#elif defined (_GLIBCXX_HAVE_FINITE)
+      if (!finite (static_cast<double> (__v)))
+	__overflow = true;
+#elif defined (_GLIBCXX_HAVE_ISINF)
+      if (isinf (static_cast<double> (__v)))
+	__overflow = true;
+#else
+      if (fabs(__d) > numeric_limits<float>::max())
+	__overflow = true;
+#endif
+#endif // _GLIBCXX_HAVE_STRTOF
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 23. Num_get overflow result.
+      if (__sanity == __s || *__sanity != '\0')
+	{
+	  __v = 0.0f;
+	  __err = ios_base::failbit;
+	}
+      else if (__overflow
+#if __FLT_HAS_INFINITY__
+	       || __v == numeric_limits<float>::infinity()
+	       || __v == -numeric_limits<float>::infinity()
+#else
+	       || ((__v > 1.0f || __v < -1.0f) && errno == ERANGE)
+#endif
+	      )
+	{
+	  if (__v > 0.0f)
+	    __v = numeric_limits<float>::max();
+	  else
+	    __v = -numeric_limits<float>::max();
+	  __err = ios_base::failbit;
+	}
+    }
+
+  template<>
+    void
+    __convert_to_v(const char* __s, double& __v, ios_base::iostate& __err, 
+		   const __c_locale&) 
+    {
+      char* __sanity;
+
+#if !__DBL_HAS_INFINITY__
+      errno = 0;
+#endif
+
+      __v = strtod(__s, &__sanity);
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 23. Num_get overflow result.
+      if (__sanity == __s || *__sanity != '\0')
+	{
+	  __v = 0.0;
+	  __err = ios_base::failbit;
+	}
+      else if (
+#if __DBL_HAS_INFINITY__
+	       __v == numeric_limits<double>::infinity()
+	       || __v == -numeric_limits<double>::infinity())
+#else          
+	       (__v > 1.0 || __v < -1.0) && errno == ERANGE)
+#endif
+	{
+	  if (__v > 0.0)
+	    __v = numeric_limits<double>::max();
+	  else
+	    __v = -numeric_limits<double>::max();
+	  __err = ios_base::failbit;
+	}
+    }
+
+  template<>
+    void
+    __convert_to_v(const char* __s, long double& __v, 
+		   ios_base::iostate& __err, const __c_locale&) 
+    {
+#if !__LDBL_HAS_INFINITY__
+      errno = 0;
+#endif
+
+#if defined(_GLIBCXX_HAVE_STRTOLD) && !defined(_GLIBCXX_HAVE_BROKEN_STRTOLD)
+      char* __sanity;
+      __v = strtold(__s, &__sanity);
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 23. Num_get overflow result.
+      if (__sanity == __s || *__sanity != '\0')
+#else
+      typedef char_traits<char>::int_type int_type;
+      int __p = sscanf(__s, "%Lf", &__v);
+
+      if (!__p || static_cast<int_type>(__p) == char_traits<char>::eof())
+#endif
+	{
+	  __v = 0.0l;
+	  __err = ios_base::failbit;
+	}
+       else if (
+#if __LDBL_HAS_INFINITY__
+	        __v == numeric_limits<long double>::infinity()
+	        || __v == -numeric_limits<long double>::infinity())
+#else
+	        (__v > 1.0l || __v < -1.0l) && errno == ERANGE)
+#endif
+	{
+	  if (__v > 0.0l)
+	    __v = numeric_limits<long double>::max();
+	  else
+	    __v = -numeric_limits<long double>::max();
+	  __err = ios_base::failbit;
+	}
+    }
+
   void
-  locale::facet::_S_create_c_locale(__c_locale&, const char*, __c_locale*)
+  locale::facet::_S_create_c_locale(__c_locale&, const char*, __c_locale)
   { }
 
   void
@@ -44,64 +181,30 @@
   locale::facet::_S_clone_c_locale(__c_locale&)
   { return __c_locale(); }
 
-  template<> 
-    void
-    numpunct<char>::_M_initialize_numpunct(__c_locale)
-    {
-      // "C" locale
-      _M_decimal_point = '.';
-      _M_thousands_sep = ',';
-      _M_grouping = "";
-      _M_truename = "true";
-      _M_falsename = "false";
-    }
-      
-#ifdef _GLIBCXX_USE_WCHAR_T
-  template<> 
-    void
-    numpunct<wchar_t>::_M_initialize_numpunct(__c_locale)
-    {
-      // "C" locale
-      _M_decimal_point = L'.';
-      _M_thousands_sep = L',';
-      _M_grouping = "";
-      _M_truename = L"true";
-      _M_falsename = L"false";
-    }
-#endif
 
-  template<> 
-    void
-    moneypunct<char>::_M_initialize_moneypunct(__c_locale)
-    {
-      // "C" locale
-      _M_decimal_point = '.';
-      _M_thousands_sep = ',';
-      _M_grouping = "";
-      _M_curr_symbol = string_type();
-      _M_positive_sign = string_type();
-      _M_negative_sign = string_type();
-      _M_frac_digits = 0;
-      _M_pos_format = money_base::_S_default_pattern;
-      _M_neg_format = money_base::_S_default_pattern;
-    }
+  __c_locale
+  locale::facet::_S_lc_ctype_c_locale(__c_locale, const char*)
+  { return __c_locale(); }
 
-#ifdef _GLIBCXX_USE_WCHAR_T
-  template<> 
-    void
-    moneypunct<wchar_t>::_M_initialize_moneypunct(__c_locale)
+_GLIBCXX_END_NAMESPACE
+
+_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
+
+  const char* const category_names[6 + _GLIBCXX_NUM_CATEGORIES] =
     {
-      // "C" locale
-      _M_decimal_point = L'.';
-      _M_thousands_sep = L',';
-      _M_grouping = "";
-      _M_curr_symbol = string_type();
-      _M_positive_sign = string_type();
-      _M_negative_sign = string_type();
-      _M_frac_digits = 0;
-      _M_pos_format = money_base::_S_default_pattern;
-      _M_neg_format = money_base::_S_default_pattern;
-    }
-#endif
-}  // namespace std
+      "LC_CTYPE", 
+      "LC_NUMERIC",
+      "LC_TIME",   
+      "LC_COLLATE", 
+      "LC_MONETARY",
+      "LC_MESSAGES"
+    };
 
+_GLIBCXX_END_NAMESPACE
+
+_GLIBCXX_BEGIN_NAMESPACE(std)
+
+  const char* const* const locale::_S_categories = __gnu_cxx::category_names;
+
+_GLIBCXX_END_NAMESPACE
+
Index: libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.cc
===================================================================
--- libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.cc	(revision 152285)
+++ libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.cc	(working copy)
@@ -45,7 +45,8 @@
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<>
     wstring
-    messages<wchar_t>::do_get(catalog, int, int, const wstring& __dfault) const
+    messages<wchar_t>::do_get(catalog __c, int __setid, int __msgid,
+			      const wstring& __dfault) const
     {
       nl_catd __nlc = reinterpret_cast<nl_catd>(__c);
       char* __msg = catgets(__nlc, __setid, __msgid, 
Index: libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.h
===================================================================
--- libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.h	(revision 152285)
+++ libstdc++-v3/config/locale/ieee_1003.1-2001/c_locale.h	(working copy)
@@ -33,14 +33,60 @@
 
 // Written by Benjamin Kosnik <bkoz@redhat.com>
 
+#ifndef _GLIBCXX_CXX_LOCALE_H
+#define _GLIBCXX_CXX_LOCALE_H 1
+
+#pragma GCC system_header
+
 #include <clocale>
 #include <langinfo.h>		// For codecvt
 #include <iconv.h>		// For codecvt using iconv, iconv_t
 #include <nl_types.h> 		// For messages
 
+#define _GLIBCXX_NUM_CATEGORIES 0
+
 _GLIBCXX_BEGIN_NAMESPACE(std)
 
   typedef int*			__c_locale;
 
+  // Convert numeric value of type double and long double to string and
+  // return length of string.  If vsnprintf is available use it, otherwise
+  // fall back to the unsafe vsprintf which, in general, can be dangerous
+  // and should be avoided.
+  inline int
+  __convert_from_v(const __c_locale&, char* __out, 
+		   const int __size __attribute__((__unused__)),
+		   const char* __fmt, ...)
+  {
+    char* __old = std::setlocale(LC_NUMERIC, NULL);
+    char* __sav = NULL;
+    if (__builtin_strcmp(__old, "C"))
+      {
+	const size_t __len = __builtin_strlen(__old) + 1;
+	__sav = new char[__len];
+	__builtin_memcpy(__sav, __old, __len);
+	std::setlocale(LC_NUMERIC, "C");
+      }
+
+    __builtin_va_list __args;
+    __builtin_va_start(__args, __fmt);
+
+#ifdef _GLIBCXX_USE_C99
+    const int __ret = __builtin_vsnprintf(__out, __size, __fmt, __args);
+#else
+    const int __ret = __builtin_vsprintf(__out, __fmt, __args);
+#endif
+
+    __builtin_va_end(__args);
+
+    if (__sav)
+      {
+	std::setlocale(LC_NUMERIC, __sav);
+	delete [] __sav;
+      }
+    return __ret;
+  }
+
 _GLIBCXX_END_NAMESPACE
 
+#endif
Index: libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.h
===================================================================
--- libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.h	(revision 152285)
+++ libstdc++-v3/config/locale/ieee_1003.1-2001/messages_members.h	(working copy)
@@ -37,6 +37,16 @@
 
   // Non-virtual member functions.
   template<typename _CharT>
+     messages<_CharT>::messages(size_t __refs)
+     : facet(__refs)
+     { _M_c_locale_messages = _S_get_c_locale(); }
+
+  template<typename _CharT>
+     messages<_CharT>::messages(__c_locale, const char*, size_t __refs) 
+     : facet(__refs)
+     { _M_c_locale_messages = _S_get_c_locale(); }
+
+  template<typename _CharT>
     typename messages<_CharT>::catalog 
     messages<_CharT>::open(const basic_string<char>& __s, const locale& __loc, 
 			   const char*) const
@@ -69,4 +79,31 @@
     messages<_CharT>::do_close(catalog __c) const 
     { catclose(reinterpret_cast<nl_catd>(__c)); }
 
+   // messages_byname
+   template<typename _CharT>
+     messages_byname<_CharT>::messages_byname(const char* __s, size_t __refs)
+     : messages<_CharT>(__refs) 
+     { 
+       if (this->_M_name_messages != locale::facet::_S_get_c_name())
+	 {
+	   delete [] this->_M_name_messages;
+	   if (__builtin_strcmp(__s, locale::facet::_S_get_c_name()) != 0)
+	     {
+	       const size_t __len = __builtin_strlen(__s) + 1;
+	       char* __tmp = new char[__len];
+	       __builtin_memcpy(__tmp, __s, __len);
+	       this->_M_name_messages = __tmp;
+	     }
+	   else
+	     this->_M_name_messages = locale::facet::_S_get_c_name();
+	 }
+
+       if (__builtin_strcmp(__s, "C") != 0
+	   && __builtin_strcmp(__s, "POSIX") != 0)
+	 {
+	   this->_S_destroy_c_locale(this->_M_c_locale_messages);
+	   this->_S_create_c_locale(this->_M_c_locale_messages, __s); 
+	 }
+     }
+
 _GLIBCXX_END_NAMESPACE



More information about the Libstdc++ mailing list