This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [RFC] First draft of the POSIX locale::name patch
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: Paolo Carlini <pcarlini at unitus dot it>
- Cc: libstdc++ at gcc dot gnu dot org, bkoz <bkoz at redhat dot com>, Roland McGrath <roland at redhat dot com>
- Date: Wed, 02 Oct 2002 18:46:34 +0200
- Subject: Re: [RFC] First draft of the POSIX locale::name patch
- References: <3D9B1714.2070606@unitus.it>
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;
}