This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] First draft of the POSIX locale::name patch


Hi again,

the below fixes a couple of bugs of the previous one
in the treatment of LC_ALL. I'm also trying again
to post the Changelog properly formatted...

Ciao, Paolo.

////////////

   * include/bits/localefwd.h (class locale): Add static
   member _S_num_c_categories, encoding the number of
   additional C only categories.
   (class locale::_Impl): Add _M_c_cats.
   (class locale::_Impl::_M_names): Change to array of chars.
   (class locale::_Impl::_M_check_same_name):
   Use _S_num_c_categories, tweak.
   (locale::locale(const locale&, _Facet*)): Ditto.
   * src/locale.cc (locale::locale(const char* )):
   Rewrite to deal with the environment in a POSIX-compliant
   way while being thread safe.
   (locale::name()): Update to output POSIX environment strings.
   * src/localename.cc
   (locale::_Impl::_Impl(const _Impl&, size_t): Use
   _S_num_c_categories, tweak.
   (locale::_Impl::_Impl(facet**, size_t, bool)): Ditto.
   (locale::_Impl::_Impl(const char*, size_t)): Name
   each category individually, both C++ ones and C only.
   (locale::_Impl::_M_replace_categories): Use strcpy.
   * testsuite/22_locale/ctor_copy_dtor.cc: Add test04.

diff -prN libstdc++-v3-orig/include/bits/CVS/Entries libstdc++-v3/include/bits/CVS/Entries
*** libstdc++-v3-orig/include/bits/CVS/Entries	Tue Oct  1 20:45:16 2002
--- libstdc++-v3/include/bits/CVS/Entries	Tue Oct  1 20:45:49 2002
***************
*** 62,66 ****
  /valarray_meta.h/1.11/Fri Aug  2 23:08:39 2002//
  /vector.tcc/1.2/Fri Aug  9 16:51:15 2002//
  /locale_facets.tcc/1.81/Fri Sep 27 18:31:03 2002//
! /c++config/1.499/Tue Oct  1 18:45:16 2002//
  D
--- 62,66 ----
  /valarray_meta.h/1.11/Fri Aug  2 23:08:39 2002//
  /vector.tcc/1.2/Fri Aug  9 16:51:15 2002//
  /locale_facets.tcc/1.81/Fri Sep 27 18:31:03 2002//
! /c++config/1.499/Tue Oct  1 18:45:49 2002//
  D
diff -prN libstdc++-v3-orig/include/bits/localefwd.h libstdc++-v3/include/bits/localefwd.h
*** libstdc++-v3-orig/include/bits/localefwd.h	Fri Sep  6 21:52:38 2002
--- libstdc++-v3/include/bits/localefwd.h	Wed Oct  2 17:27:42 2002
*************** namespace std
*** 269,274 ****
--- 269,277 ----
  
      static const size_t	_S_num_categories = 6;
  
+     // Additional C only categories: 6 for the newest libc
+     static const size_t	_S_num_c_categories = 6;
+ 
      explicit 
      locale(_Impl*) throw();
  
*************** namespace std
*** 308,314 ****
      _Atomic_word			_M_references;
      facet** 				_M_facets;
      size_t 				_M_facets_size;
!     const char* 			_M_names[_S_num_categories];
      static const locale::id* const 	_S_id_ctype[];
      static const locale::id* const 	_S_id_numeric[];
      static const locale::id* const 	_S_id_collate[];
--- 311,320 ----
      _Atomic_word			_M_references;
      facet** 				_M_facets;
      size_t 				_M_facets_size;
!     // Twenty chars for each category should suffice even for
!     // the longest names (currently sr_YU@cyrillic)
!     char                                _M_names[_S_num_categories
! 						 + _S_num_c_categories][20];
      static const locale::id* const 	_S_id_ctype[];
      static const locale::id* const 	_S_id_numeric[];
      static const locale::id* const 	_S_id_collate[];
*************** namespace std
*** 348,358 ****
      _M_check_same_name()
      {
        bool __ret = true;
!       for (size_t i = 0; __ret && i < _S_num_categories - 1; ++i)
  	__ret &= (strcmp(_M_names[i], _M_names[i + 1]) == 0);
        return __ret;
      }
  
      void 
      _M_replace_categories(const _Impl*, category);
  
--- 354,377 ----
      _M_check_same_name()
      {
        bool __ret = true;
!       for (size_t i = 0; __ret && i < _S_num_categories
! 	     + _S_num_c_categories - 1; ++i)
  	__ret &= (strcmp(_M_names[i], _M_names[i + 1]) == 0);
        return __ret;
      }
  
+     // XXX The entries beyond the sixth one are C only, present in the
+     // most recent libc implementations but non standard.
+     const char*
+     _M_c_cats(size_t __cat)
+     {
+       static char *__names[_S_num_categories + _S_num_c_categories] = {
+ 	"LC_CTYPE", "LC_NUMERIC", "LC_COLLATE", "LC_TIME", "LC_MONETARY",
+ 	"LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS",
+ 	"LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION" };
+       return __names[__cat];
+     }
+ 
      void 
      _M_replace_categories(const _Impl*, category);
  
*************** namespace std
*** 376,383 ****
      {
        _M_impl = new _Impl(*__other._M_impl, 1);
        _M_impl->_M_install_facet(&_Facet::id, __f);
!       for (size_t __i = 0; __i < _S_num_categories; ++__i)
! 	_M_impl->_M_names[__i] = "*";
      }
  
    // 22.1.1.1.2  Class locale::facet
--- 395,403 ----
      {
        _M_impl = new _Impl(*__other._M_impl, 1);
        _M_impl->_M_install_facet(&_Facet::id, __f);
!       for (size_t __i = 0; __i < _S_num_categories
! 	     + _S_num_c_categories; ++__i)
! 	strcpy(_M_impl->_M_names[__i], "*");
      }
  
    // 22.1.1.1.2  Class locale::facet
diff -prN libstdc++-v3-orig/src/locale.cc libstdc++-v3/src/locale.cc
*** libstdc++-v3-orig/src/locale.cc	Wed Sep 11 05:36:45 2002
--- libstdc++-v3/src/locale.cc	Wed Oct  2 18:42:16 2002
*************** namespace std 
*** 192,206 ****
  	_S_initialize(); 
  	if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0)
  	  (_M_impl = _S_classic)->_M_add_reference();
  	else if (strcmp(__s, "") == 0)
  	  {
  	    char* __env = getenv("LC_ALL");
! 	    if (__env)
! 	      _M_impl = new _Impl(__env, 1);
! 	    else if ((__env = getenv("LANG")))
! 	      _M_impl = new _Impl(__env, 1);
  	    else
! 	      (_M_impl = _S_classic)->_M_add_reference();
  	  }
  	else
  	  _M_impl = new _Impl(__s, 1);
--- 192,295 ----
  	_S_initialize(); 
  	if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0)
  	  (_M_impl = _S_classic)->_M_add_reference();
+ 	// Get it from the environment.
  	else if (strcmp(__s, "") == 0)
  	  {
  	    char* __env = getenv("LC_ALL");
! 	    // If LC_ALL is set we are done.
! 	    if (__env && strcmp(__env, "") != 0)
! 	      {
! 		if (strcmp(__env, "C") == 0 || strcmp(__env, "POSIX") == 0)
! 		  (_M_impl = _S_classic)->_M_add_reference();
! 		else
! 		  _M_impl = new _Impl(__env, 1);
! 	      }
  	    else
! 	      {
! 		char* __res;
! 		// LANG may set a default different from "C".
! 		char* __env = getenv("LANG");
! 		if (!__env || strcmp(__env, "") == 0
! 		    || strcmp(__env, "C") == 0
! 		    || strcmp(__env, "POSIX") == 0)
! 		  __res = strdup("C");
! 		else __res = strdup(__env);
! 		
! 		// Scan the categories looking for the first one
! 		// different from LANG.
! 		size_t __i = 0;
! 		if (strcmp(__res, "C") == 0)
! 		  for (__i = 0; __i < _S_num_categories
! 			 + _S_num_c_categories; ++__i)
! 		    {
! 		      __env = getenv(_M_impl->_M_c_cats(__i));
! 		      if (__env && strcmp(__env, "") != 0
! 			  && strcmp(__env, "C") != 0
! 			  && strcmp(__env, "POSIX") != 0) break;
! 		    }
! 		else
! 		  for (__i = 0; __i < _S_num_categories
! 			 + _S_num_c_categories; ++__i)
! 		    {
! 		      __env = getenv(_M_impl->_M_c_cats(__i));
! 		      if (__env && strcmp(__env, "") != 0
! 			  && strcmp(__env, __res) != 0) break;
! 		    }
! 	
! 		// If one is found build the complete string of
! 		// the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on...
! 		if (__i < _S_num_categories + _S_num_c_categories)
! 		  {
! 		    string __str;
! 		    for (size_t __j = 0; __j < __i; ++__j)
! 		      {
! 			__str += _M_impl->_M_c_cats(__j);
! 			__str += "=";
! 			__str += __res;
! 			__str += ";";
! 		      }
! 		    __str += _M_impl->_M_c_cats(__i);
! 		    __str += "=";
! 		    __str += __env;
! 		    __str += ";";
! 		    __i++;
! 		    for (; __i < _S_num_categories
! 			   + _S_num_c_categories; ++__i)
! 		      {
! 			__env = getenv(_M_impl->_M_c_cats(__i));
! 			if (!__env || strcmp(__env, "") == 0)
! 			  {
! 			    __str += _M_impl->_M_c_cats(__i);
! 			    __str += '=';
! 			    __str += __res;
! 			    __str += ';';
! 			  }
! 			else if (strcmp(__env, "C") == 0
! 				 || strcmp(__env, "POSIX") == 0)
! 			  {
! 			    __str += _M_impl->_M_c_cats(__i);
! 			    __str += "=C;";
! 			  }
! 			else
! 			  {
! 			    __str += _M_impl->_M_c_cats(__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 (strcmp(__res, "C") == 0)
! 		  (_M_impl = _S_classic)->_M_add_reference();
! 		else
! 		  _M_impl = new _Impl(__res, 1);
! 
! 		free(__res);
! 	      }
  	  }
  	else
  	  _M_impl = new _Impl(__s, 1);
*************** namespace std 
*** 261,282 ****
    string
    locale::name() const
    {
-     // Need some kind of separator character. This one was pretty much
-     // arbitrarily chosen as to not conflict with glibc locales: the
-     // exact formatting is not set in stone.
-     const char __separator = '|';
- 
      string __ret;
      if (_M_impl->_M_check_same_name())
        __ret = _M_impl->_M_names[0];
      else
        {
! 	for (size_t i = 0; i < _S_num_categories; ++i)
  	  {
! 	    __ret += __separator;
! 	    __ret += _M_impl->_M_names[i];
  	  }
        }
      return __ret;
    }
  
--- 350,373 ----
    string
    locale::name() const
    {
      string __ret;
      if (_M_impl->_M_check_same_name())
        __ret = _M_impl->_M_names[0];
      else
        {
! 	__ret += _M_impl->_M_c_cats(0);
! 	__ret += "=";
! 	__ret += _M_impl->_M_names[0]; 
! 	for (size_t __i = 1; __i < _S_num_categories
! 	       + _S_num_c_categories; ++__i)
  	  {
! 	    __ret += ";";
! 	    __ret += _M_impl->_M_c_cats(__i);
! 	    __ret += "=";
! 	    __ret += _M_impl->_M_names[__i];
  	  }
        }
+     
      return __ret;
    }
  
diff -prN libstdc++-v3-orig/src/localename.cc libstdc++-v3/src/localename.cc
*** libstdc++-v3-orig/src/localename.cc	Tue Sep 10 21:35:04 2002
--- libstdc++-v3/src/localename.cc	Wed Oct  2 16:42:33 2002
*************** namespace std
*** 95,102 ****
  	if (_M_facets[__i])
  	  _M_facets[__i]->_M_add_reference();
        }
!     for (size_t __i = 0; __i < _S_num_categories; ++__i)
!       _M_names[__i] = __imp._M_names[__i];
    }
  
    // Construct named _Impl.
--- 95,103 ----
  	if (_M_facets[__i])
  	  _M_facets[__i]->_M_add_reference();
        }
!     for (size_t __i = 0; __i < _S_num_categories
! 	   + _S_num_c_categories; ++__i)
!       strcpy(_M_names[__i], __imp._M_names[__i]);
    }
  
    // Construct named _Impl.
*************** namespace std
*** 121,130 ****
  	__throw_exception_again;
        }
  
!     // Name all the categories.
!     for (size_t i = 0; i < _S_num_categories; ++i)
!       _M_names[i] = __s;
! 
      // Construct all standard facets and add them to _M_facets.
      _M_init_facet(new std::ctype<char>(__cloc));
      _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc));
--- 122,148 ----
  	__throw_exception_again;
        }
  
!     // Name all the categories: C++ + additional C only.
!     if (!strchr(__s, ';'))
!       for (size_t __i = 0; __i < _S_num_categories
! 	     + _S_num_c_categories; ++__i)
! 	strcpy(_M_names[__i], __s);
!     else
!       {
! 	char *__tmp = strdup(__s);
! 	__tmp[strlen(__tmp)] = ';';
! 	strtok(__tmp, "=;");
! 	for (size_t __i = 0; __i < _S_num_categories
! 	       + _S_num_c_categories - 1; ++__i)
! 	  {
! 	    strcpy(_M_names[__i], strtok(NULL, "=;"));
! 	    strtok(NULL, "=;");
! 	  }
! 	strcpy(_M_names[_S_num_categories + _S_num_c_categories - 1],
! 	       strtok(NULL, "=;"));
! 	free(__tmp);
!       }
!       
      // Construct all standard facets and add them to _M_facets.
      _M_init_facet(new std::ctype<char>(__cloc));
      _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc));
*************** namespace std
*** 166,173 ****
    : _M_references(__refs), _M_facets(__f), _M_facets_size(_GLIBCPP_NUM_FACETS)
    {
      // Name all the categories.
!     for (size_t i = 0; i < _S_num_categories; ++i)
!       _M_names[i] = "C";
  
      // This is needed as presently the C++ version of "C" locales
      // != data in the underlying locale model for __timepunct,
--- 184,191 ----
    : _M_references(__refs), _M_facets(__f), _M_facets_size(_GLIBCPP_NUM_FACETS)
    {
      // Name all the categories.
!     for (size_t i = 0; i < _S_num_categories + _S_num_c_categories; ++i)
!       strcpy(_M_names[i], "C");
  
      // This is needed as presently the C++ version of "C" locales
      // != data in the underlying locale model for __timepunct,
*************** namespace std
*** 210,216 ****
    _M_replace_categories(const _Impl* __imp, category __cat)
    {
      category __mask;
!     for (unsigned int __ix = 0; __ix < _S_num_categories; ++__ix)
        {
  	__mask = 1 << __ix;
  	if (__mask & __cat)
--- 228,234 ----
    _M_replace_categories(const _Impl* __imp, category __cat)
    {
      category __mask;
!     for (size_t __ix = 0; __ix < _S_num_categories; ++__ix)
        {
  	__mask = 1 << __ix;
  	if (__mask & __cat)
*************** namespace std
*** 220,226 ****
  	    // If both have names, go ahead and mangle.
  	    if (strcmp(_M_names[__ix], "*") != 0 
  		&& strcmp(__imp->_M_names[__ix], "*") != 0)
! 	      _M_names[__ix] = __imp->_M_names[__ix];
  	  }
        }
    }
--- 238,244 ----
  	    // If both have names, go ahead and mangle.
  	    if (strcmp(_M_names[__ix], "*") != 0 
  		&& strcmp(__imp->_M_names[__ix], "*") != 0)
! 	      strcpy(_M_names[__ix], __imp->_M_names[__ix]);
  	  }
        }
    }
diff -prN libstdc++-v3-orig/testsuite/22_locale/ctor_copy_dtor.cc libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc
*** libstdc++-v3-orig/testsuite/22_locale/ctor_copy_dtor.cc	Thu Sep  5 23:13:06 2002
--- libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc	Wed Oct  2 18:13:49 2002
*************** void test03()
*** 315,330 ****
  {
    bool test = true;
  #ifdef _GLIBCPP_HAVE_SETENV 
!   const char* oldLANG = getenv("LANG");
!   if (!setenv("LANG", "it_IT", 1))
      {
        std::locale loc(""); 
        VERIFY( loc.name() == "it_IT" );
!       setenv("LANG", oldLANG ? oldLANG : "", 1);
      }
  #endif
  }
  
  int main()
  {
    test00();
--- 315,406 ----
  {
    bool test = true;
  #ifdef _GLIBCPP_HAVE_SETENV 
!   const char* oldLC_ALL = getenv("LC_ALL");
!   if (!setenv("LC_ALL", "it_IT", 1))
      {
        std::locale loc(""); 
        VERIFY( loc.name() == "it_IT" );
!       setenv("LC_ALL", oldLC_ALL ? oldLC_ALL : "", 1);
      }
  #endif
  }
  
+ 
+ // More tests for Posix locale::name. 
+ void test04()
+ {
+   bool test = true;
+ #ifdef _GLIBCPP_HAVE_SETENV
+ 
+   const char* oldLC_ALL = getenv("LC_ALL") ? strdup(getenv("LC_ALL")) : "";
+   const char* oldLANG = getenv("LANG") ? strdup(getenv("LANG")) : "";
+ 
+   // Check that a "POSIX" LC_ALL is equivalent to "C".
+   if (!setenv("LC_ALL", "POSIX", 1))
+     {
+       std::locale loc("");
+       assert( loc.name() == "C" );
+     }
+ 
+   // Check the default set by LANG.
+   if (!setenv("LC_ALL", "", 1) && !setenv("LANG", "fr_FR", 1))
+     {
+       std::locale loc("");
+       assert( loc.name() == "fr_FR" );
+     }
+ 
+   // Check that a "POSIX" LANG is equivalent to "C".
+   if (!setenv("LANG", "POSIX", 1))
+     {
+       std::locale loc(""); 
+       assert( loc.name() == "C" );
+     }
+ 
+   // Setting a category in the "C" default.
+   const char* oldLC_COLLATE =
+     getenv("LC_COLLATE") ? strdup(getenv("LC_COLLATE")) : "";
+   if (!setenv("LC_COLLATE", "de_DE", 1))
+     {
+       std::locale loc("");
+       assert( loc.name() == "LC_CTYPE=C;LC_NUMERIC=C;LC_COLLATE=de_DE;"
+ 	      "LC_TIME=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;"
+ 	      "LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;"
+ 	      "LC_IDENTIFICATION=C" );
+     }
+ 
+   // Changing the LANG default while LC_COLLATE is set.
+   if (!setenv("LANG", "fr_FR", 1))
+     {
+       std::locale loc("");
+       assert( loc.name() == "LC_CTYPE=fr_FR;LC_NUMERIC=fr_FR;"
+ 	      "LC_COLLATE=de_DE;LC_TIME=fr_FR;LC_MONETARY=fr_FR;"
+ 	      "LC_MESSAGES=fr_FR;LC_PAPER=fr_FR;LC_NAME=fr_FR;"
+ 	      "LC_ADDRESS=fr_FR;LC_TELEPHONE=fr_FR;LC_MEASUREMENT=fr_FR;"
+ 	      "LC_IDENTIFICATION=fr_FR" );
+     }
+   
+   // Changing another (C only) category.
+   const char* oldLC_IDENTIFICATION =
+     getenv("LC_IDENTIFICATION") ? strdup(getenv("LC_IDENTIFICATION")) : "";
+   if (!setenv("LC_IDENTIFICATION", "it_IT", 1))
+     {
+       std::locale loc("");
+       assert( loc.name() == "LC_CTYPE=fr_FR;LC_NUMERIC=fr_FR;"
+ 	      "LC_COLLATE=de_DE;LC_TIME=fr_FR;LC_MONETARY=fr_FR;"
+ 	      "LC_MESSAGES=fr_FR;LC_PAPER=fr_FR;LC_NAME=fr_FR;"
+ 	      "LC_ADDRESS=fr_FR;LC_TELEPHONE=fr_FR;LC_MEASUREMENT=fr_FR;"
+ 	      "LC_IDENTIFICATION=it_IT" );
+     }
+ 
+   // Restore the environment.
+   setenv("LC_ALL", oldLC_ALL ? oldLC_ALL : "", 1);
+   setenv("LANG", oldLANG ? oldLANG : "", 1);
+   setenv("LC_COLLATE", oldLC_COLLATE ? oldLC_COLLATE : "", 1);
+   setenv("LC_IDENTIFICATION",
+ 	 oldLC_IDENTIFICATION ? oldLC_IDENTIFICATION : "", 1);
+ #endif
+ }
+ 
  int main()
  {
    test00();
*************** int main()
*** 335,340 ****
--- 411,417 ----
  
    test02();
    test03();
+   test04();
  
    return 0;
  }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]