From aa53f832ac68acf6b5f8dee96bc1aeb57081fe76 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 9 Oct 2002 01:32:23 +0200 Subject: [PATCH] localefwd.h (class locale): Add static member _S_num_extra_categories... 2002-10-08 Paolo Carlini Benjamin Kosnik * include/bits/localefwd.h (class locale): Add static member _S_num_extra_categories, encoding the number of additional categories. Change _S_num_categories to _S_categories_size. (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_extra_categories_size, 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_categories_size_*, tweak. (locale::_Impl::_Impl(facet**, size_t, bool)): Ditto. (locale::_Impl::_Impl(const char*, size_t)): Name each category individually. (locale::_Impl::_M_replace_categories): Use strcpy. * include/bits/locale_facets.h (numpunct::_M_initialize_numpunct): Change default argument to NULL from _S_c_locale. (timepunct::_M_initialize_timepunct): Same. _S_c_locale cleanups. * src/codecvt.c: _S_c_locale simplification. * src/ctype.c: Same. * src/globals.cc: Add fake_name. * src/locale-inst.cc: Remove extra includes. * src/locale.cc: Remove extra includes. Add _S_extra_categories_size definition. Correct "C" initialization. (locale::facet::facet): Don't initialize _S_c_locale. (locale::facet::_M_remove_reference): Adjust. * src/localename: Use facet_vec, facet_name. (locale::_Impl::_Impl(facet** __f, size_t __refs, bool)): Set facet ref counts to one. Initialize _S_c_locale. (locale::_Impl::_M_install_facet(id*, facet*)): Adjust facet ref counts when installing unilaterally. * config/locale/generic/c_locale.cc: Add _S_categories definition. * config/locale/generic/c_locale.h: Add _GLIBCPP_NUM_CATEGORIES macro. * config/locale/generic/time_members.cc: _S_c_locale cleanup. * config/locale/gnu/c_locale.cc: Add _S_categories definition. (_S_destroy_c_locale): Move checks against _S_c_locale here. * config/locale/gnu/c_locale.h: Add _GLIBCPP_NUM_CATEGORIES macro. * config/locale/gnu/ctype_members.cc: Simplify _S_destroy_c_locale calls, _S_c_locale usage. * config/locale/gnu/monetary_members.cc: Same, tweaks. * config/locale/gnu/monetary_members.cc: Same. * config/locale/gnu/time_members.cc: Same. * config/os/gnu-linux/ctype_noninline.h: Use locale::classic(). * docs/html/22_locale/locale.html: Add bits about global locales and "C" setlocale. * testsuite/22_locale/facet.cc (test02): Add. * testsuite/22_locale/static_members.cc (test02): Add. * testsuite/22_locale/ctor_copy_dtor.cc (test04): Add. Co-Authored-By: Benjamin Kosnik From-SVN: r57964 --- libstdc++-v3/ChangeLog | 64 ++++++++ .../config/locale/generic/c_locale.cc | 11 ++ libstdc++-v3/config/locale/generic/c_locale.h | 2 + .../config/locale/generic/time_members.cc | 10 +- libstdc++-v3/config/locale/gnu/c_locale.cc | 22 ++- libstdc++-v3/config/locale/gnu/c_locale.h | 2 + .../config/locale/gnu/ctype_members.cc | 3 +- .../config/locale/gnu/monetary_members.cc | 19 +-- .../config/locale/gnu/numeric_members.cc | 4 +- .../config/locale/gnu/time_members.cc | 20 +-- .../config/os/gnu-linux/ctype_noninline.h | 5 +- libstdc++-v3/docs/html/22_locale/locale.html | 29 +++- libstdc++-v3/include/bits/locale_facets.h | 22 +-- libstdc++-v3/include/bits/localefwd.h | 45 +++++- libstdc++-v3/src/codecvt.cc | 12 +- libstdc++-v3/src/ctype.cc | 11 +- libstdc++-v3/src/globals.cc | 5 +- libstdc++-v3/src/locale-inst.cc | 4 - libstdc++-v3/src/locale.cc | 151 ++++++++++++++---- libstdc++-v3/src/localename.cc | 148 ++++++++++++----- .../testsuite/22_locale/ctor_copy_dtor.cc | 85 +++++++++- libstdc++-v3/testsuite/22_locale/facet.cc | 63 +++++++- .../testsuite/22_locale/static_members.cc | 50 +++++- 23 files changed, 609 insertions(+), 178 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2f93aa97f31..5bb78b84226 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,67 @@ +2002-10-08 Paolo Carlini + Benjamin Kosnik + + * include/bits/localefwd.h (class locale): Add static member + _S_num_extra_categories, encoding the number of additional + categories. + Change _S_num_categories to _S_categories_size. + (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_extra_categories_size, 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_categories_size_*, tweak. + (locale::_Impl::_Impl(facet**, size_t, bool)): Ditto. + (locale::_Impl::_Impl(const char*, size_t)): Name each category + individually. + (locale::_Impl::_M_replace_categories): Use strcpy. + + * include/bits/locale_facets.h (numpunct::_M_initialize_numpunct): + Change default argument to NULL from _S_c_locale. + (timepunct::_M_initialize_timepunct): Same. + _S_c_locale cleanups. + * src/codecvt.c: _S_c_locale simplification. + * src/ctype.c: Same. + * src/globals.cc: Add fake_name. + * src/locale-inst.cc: Remove extra includes. + * src/locale.cc: Remove extra includes. + Add _S_extra_categories_size definition. + Correct "C" initialization. + (locale::facet::facet): Don't initialize _S_c_locale. + (locale::facet::_M_remove_reference): Adjust. + * src/localename: Use facet_vec, facet_name. + (locale::_Impl::_Impl(facet** __f, size_t __refs, bool)): Set + facet ref counts to one. Initialize _S_c_locale. + (locale::_Impl::_M_install_facet(id*, facet*)): Adjust facet ref + counts when installing unilaterally. + + * config/locale/generic/c_locale.cc: Add _S_categories definition. + * config/locale/generic/c_locale.h: Add _GLIBCPP_NUM_CATEGORIES macro. + * config/locale/generic/time_members.cc: _S_c_locale cleanup. + + * config/locale/gnu/c_locale.cc: Add _S_categories definition. + (_S_destroy_c_locale): Move checks against _S_c_locale here. + * config/locale/gnu/c_locale.h: Add _GLIBCPP_NUM_CATEGORIES macro. + * config/locale/gnu/ctype_members.cc: Simplify _S_destroy_c_locale + calls, _S_c_locale usage. + * config/locale/gnu/monetary_members.cc: Same, tweaks. + * config/locale/gnu/monetary_members.cc: Same. + * config/locale/gnu/time_members.cc: Same. + * config/os/gnu-linux/ctype_noninline.h: Use locale::classic(). + + * docs/html/22_locale/locale.html: Add bits about global locales + and "C" setlocale. + + * testsuite/22_locale/facet.cc (test02): Add. + * testsuite/22_locale/static_members.cc (test02): Add. + * testsuite/22_locale/ctor_copy_dtor.cc (test04): Add. + 2002-10-07 Jonathan Wakely * docs/html/configopts.html, docs/html/documentation.html, diff --git a/libstdc++-v3/config/locale/generic/c_locale.cc b/libstdc++-v3/config/locale/generic/c_locale.cc index e274836fd90..689bbf592b9 100644 --- a/libstdc++-v3/config/locale/generic/c_locale.cc +++ b/libstdc++-v3/config/locale/generic/c_locale.cc @@ -223,4 +223,15 @@ namespace std __c_locale locale::facet::_S_clone_c_locale(__c_locale&) { return __c_locale(); } + + const char* locale::_S_categories[_S_categories_size + + _S_extra_categories_size] = + { + "LC_CTYPE", + "LC_NUMERIC", + "LC_COLLATE", + "LC_TIME", + "LC_MONETARY", + "LC_MESSAGES" + }; } // namespace std diff --git a/libstdc++-v3/config/locale/generic/c_locale.h b/libstdc++-v3/config/locale/generic/c_locale.h index bfd9bf0a0bf..9627d8646af 100644 --- a/libstdc++-v3/config/locale/generic/c_locale.h +++ b/libstdc++-v3/config/locale/generic/c_locale.h @@ -35,6 +35,8 @@ #include +#define _GLIBCPP_NUM_CATEGORIES 0 + namespace std { typedef int* __c_locale; diff --git a/libstdc++-v3/config/locale/generic/time_members.cc b/libstdc++-v3/config/locale/generic/time_members.cc index d02f0c3fa0e..7b5a25c8760 100644 --- a/libstdc++-v3/config/locale/generic/time_members.cc +++ b/libstdc++-v3/config/locale/generic/time_members.cc @@ -40,10 +40,7 @@ namespace std { template<> __timepunct::~__timepunct() - { - if (_M_c_locale_timepunct != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_timepunct); - } + { _S_destroy_c_locale(_M_c_locale_timepunct); } template<> void @@ -123,10 +120,7 @@ namespace std #ifdef _GLIBCPP_USE_WCHAR_T template<> __timepunct::~__timepunct() - { - if (_M_c_locale_timepunct != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_timepunct); - } + { _S_destroy_c_locale(_M_c_locale_timepunct); } template<> void diff --git a/libstdc++-v3/config/locale/gnu/c_locale.cc b/libstdc++-v3/config/locale/gnu/c_locale.cc index 3982a65ceb6..188f3a2f1c1 100644 --- a/libstdc++-v3/config/locale/gnu/c_locale.cc +++ b/libstdc++-v3/config/locale/gnu/c_locale.cc @@ -178,9 +178,29 @@ namespace std void locale::facet::_S_destroy_c_locale(__c_locale& __cloc) - { __freelocale(__cloc); } + { + if (_S_c_locale != __cloc) + __freelocale(__cloc); + } __c_locale locale::facet::_S_clone_c_locale(__c_locale& __cloc) { return __duplocale(__cloc); } + + const char* locale::_S_categories[_S_categories_size + + _S_extra_categories_size] = + { + "LC_CTYPE", + "LC_NUMERIC", + "LC_COLLATE", + "LC_TIME", + "LC_MONETARY", + "LC_MESSAGES", + "LC_PAPER", + "LC_NAME", + "LC_ADDRESS", + "LC_TELEPHONE", + "LC_MEASUREMENT", + "LC_IDENTIFICATION" + }; } // namespace std diff --git a/libstdc++-v3/config/locale/gnu/c_locale.h b/libstdc++-v3/config/locale/gnu/c_locale.h index aabbe6af425..130b843d7f9 100644 --- a/libstdc++-v3/config/locale/gnu/c_locale.h +++ b/libstdc++-v3/config/locale/gnu/c_locale.h @@ -40,6 +40,8 @@ #define _GLIBCPP_C_LOCALE_GNU 1 +#define _GLIBCPP_NUM_CATEGORIES 6 + #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) namespace __gnu_cxx { diff --git a/libstdc++-v3/config/locale/gnu/ctype_members.cc b/libstdc++-v3/config/locale/gnu/ctype_members.cc index db1e356d038..3b78c60405a 100644 --- a/libstdc++-v3/config/locale/gnu/ctype_members.cc +++ b/libstdc++-v3/config/locale/gnu/ctype_members.cc @@ -44,8 +44,7 @@ namespace std ctype_byname::ctype_byname(const char* __s, size_t __refs) : ctype(0, false, __refs) { - if (_M_c_locale_ctype != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_ctype); + _S_destroy_c_locale(_M_c_locale_ctype); _S_create_c_locale(_M_c_locale_ctype, __s); _M_toupper = _M_c_locale_ctype->__ctype_toupper; _M_tolower = _M_c_locale_ctype->__ctype_tolower; diff --git a/libstdc++-v3/config/locale/gnu/monetary_members.cc b/libstdc++-v3/config/locale/gnu/monetary_members.cc index 68b154bdc7c..0386ab6dc54 100644 --- a/libstdc++-v3/config/locale/gnu/monetary_members.cc +++ b/libstdc++-v3/config/locale/gnu/monetary_members.cc @@ -220,7 +220,7 @@ namespace std moneypunct::_M_initialize_moneypunct(__c_locale __cloc, const char*) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = '.'; @@ -265,7 +265,7 @@ namespace std moneypunct::_M_initialize_moneypunct(__c_locale __cloc, const char*) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = '.'; @@ -319,7 +319,7 @@ namespace std moneypunct::_M_initialize_moneypunct(__c_locale __cloc, const char* __name) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = L'.'; @@ -348,14 +348,12 @@ namespace std _M_thousands_sep = static_cast(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc)}).__w); _M_grouping = __nl_langinfo_l(GROUPING, __cloc); - mbstate_t __state; - size_t __len; const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); const char* __ccurr = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc); - // NB: Should swich to __cloc's ctype info first. - __len = strlen(__cpossign); + mbstate_t __state; + size_t __len = strlen(__cpossign); if (__len) { ++__len; @@ -418,7 +416,7 @@ namespace std moneypunct::_M_initialize_moneypunct(__c_locale __cloc, const char* __name) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = L'.'; @@ -446,13 +444,12 @@ namespace std _M_thousands_sep = static_cast(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc)}).__w); _M_grouping = __nl_langinfo_l(GROUPING, __cloc); - mbstate_t __state; - size_t __len; const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc); - // NB: Should swich to __cloc's ctype info first. + mbstate_t __state; + size_t __len; __len = strlen(__cpossign); if (__len) { diff --git a/libstdc++-v3/config/locale/gnu/numeric_members.cc b/libstdc++-v3/config/locale/gnu/numeric_members.cc index b71374c4b8e..a502bfb2150 100644 --- a/libstdc++-v3/config/locale/gnu/numeric_members.cc +++ b/libstdc++-v3/config/locale/gnu/numeric_members.cc @@ -42,7 +42,7 @@ namespace std void numpunct::_M_initialize_numpunct(__c_locale __cloc) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = '.'; @@ -76,7 +76,7 @@ namespace std void numpunct::_M_initialize_numpunct(__c_locale __cloc) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale _M_decimal_point = L'.'; diff --git a/libstdc++-v3/config/locale/gnu/time_members.cc b/libstdc++-v3/config/locale/gnu/time_members.cc index ce3d9bf0106..b2b6f23120f 100644 --- a/libstdc++-v3/config/locale/gnu/time_members.cc +++ b/libstdc++-v3/config/locale/gnu/time_members.cc @@ -41,10 +41,7 @@ namespace std { template<> __timepunct::~__timepunct() - { - if (_M_c_locale_timepunct != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_timepunct); - } + { _S_destroy_c_locale(_M_c_locale_timepunct); } template<> void @@ -67,11 +64,10 @@ namespace std void __timepunct::_M_initialize_timepunct(__c_locale __cloc) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale - - _M_c_locale_timepunct = _S_c_locale; + _M_c_locale_timepunct = _S_c_locale; _M_date_format = "%m/%d/%y"; _M_date_era_format = "%m/%d/%y"; @@ -194,10 +190,7 @@ namespace std #ifdef _GLIBCPP_USE_WCHAR_T template<> __timepunct::~__timepunct() - { - if (_M_c_locale_timepunct != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_timepunct); - } + { _S_destroy_c_locale(_M_c_locale_timepunct); } template<> void @@ -220,11 +213,10 @@ namespace std void __timepunct::_M_initialize_timepunct(__c_locale __cloc) { - if (__cloc == _S_c_locale) + if (!__cloc) { // "C" locale - - _M_c_locale_timepunct = _S_c_locale; + _M_c_locale_timepunct = _S_c_locale; _M_date_format = L"%m/%d/%y"; _M_date_era_format = L"%m/%d/%y"; diff --git a/libstdc++-v3/config/os/gnu-linux/ctype_noninline.h b/libstdc++-v3/config/os/gnu-linux/ctype_noninline.h index 1578828cced..8f06d1397ee 100644 --- a/libstdc++-v3/config/os/gnu-linux/ctype_noninline.h +++ b/libstdc++-v3/config/os/gnu-linux/ctype_noninline.h @@ -38,8 +38,7 @@ const ctype_base::mask* ctype::classic_table() throw() { - if (!_S_c_locale) - _S_create_c_locale(_S_c_locale, "C"); + locale::classic(); return _S_c_locale->__ctype_b; } #else @@ -96,7 +95,7 @@ ctype::ctype(const mask* __table, bool __del, size_t __refs) : __ctype_abstract_base(__refs), _M_del(__table != 0 && __del) { - _M_c_locale_ctype = _S_c_locale; + _M_c_locale_ctype = _S_c_locale; _M_toupper = _M_c_locale_ctype->__ctype_toupper; _M_tolower = _M_c_locale_ctype->__ctype_tolower; _M_table = __table ? __table : _M_c_locale_ctype->__ctype_b; diff --git a/libstdc++-v3/docs/html/22_locale/locale.html b/libstdc++-v3/docs/html/22_locale/locale.html index 437acce0406..d4d74b536c9 100644 --- a/libstdc++-v3/docs/html/22_locale/locale.html +++ b/libstdc++-v3/docs/html/22_locale/locale.html @@ -68,14 +68,36 @@ public: The only other thing of interest in this class is the memory management of facets. Each constructor of a facet class takes a std::size_t __refs argument: if __refs == 0, the facet is deleted when -no longer used. if __refs == 1, the facet is not destroyed, even when -it is no longer reference. +the locale containing it is destroyed. If __refs == 1, the facet is +not destroyed, even when it is no longer referenced. class id Provides an index for looking up specific facets. class _Impl +The internal representation of the std::locale object. + +

+5. Relationship to traditional "C" locales. +

+ +From Josuttis, p. 697-698, which says, that "there is only *one* +relation (of the C++ locale mechanism) to the C locale mechanism: the +global C locale is modified if a named C++ locale object is set as the +global locale" (emphasis Paolo), that is: + + std::locale::global(std::locale("")); + +affects the C functions as if the following call was made: + + std::setlocale(LC_ALL, ""); + +On the other hand, there is *no* viceversa, that is, calling setlocale +has *no* whatsoever on the C++ locale mechanism, in particular on the +working of locale(""), which constructs the locale object from the +environment of the running program, that is, in practice, the set of +LC_ALL, LANG, etc. variable of the shell.

5. Examples @@ -87,8 +109,7 @@ class _Impl More information can be found in the following testcases:
    -
  • testsuite/22_locale/ctype_char_members.cc
  • -
  • testsuite/22_locale/ctype_wchar_t_members.cc
  • +
  • testsuite/22_locale/all

diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h index f99562fac49..55953c0d5b1 100644 --- a/libstdc++-v3/include/bits/locale_facets.h +++ b/libstdc++-v3/include/bits/locale_facets.h @@ -525,7 +525,7 @@ namespace std // For use at construction time only. void - _M_initialize_numpunct(__c_locale __cloc = _S_c_locale); + _M_initialize_numpunct(__c_locale __cloc = NULL); }; template @@ -875,10 +875,7 @@ namespace std protected: virtual ~collate() - { - if (_M_c_locale_collate != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_collate); - } + { _S_destroy_c_locale(_M_c_locale_collate); } virtual int do_compare(const _CharT* __lo1, const _CharT* __hi1, @@ -924,8 +921,7 @@ namespace std collate_byname(const char* __s, size_t __refs = 0) : collate<_CharT>(__refs) { - if (_M_c_locale_collate != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_collate); + _S_destroy_c_locale(_M_c_locale_collate); _S_create_c_locale(_M_c_locale_collate, __s); } @@ -1123,7 +1119,7 @@ namespace std // For use at construction time only. void - _M_initialize_timepunct(__c_locale __cloc = _S_c_locale); + _M_initialize_timepunct(__c_locale __cloc = NULL); }; template @@ -1459,7 +1455,7 @@ namespace std // For use at construction time only. void - _M_initialize_moneypunct(__c_locale __cloc = _S_c_locale, + _M_initialize_moneypunct(__c_locale __cloc = NULL, const char* __name = NULL); }; @@ -1667,10 +1663,7 @@ namespace std protected: virtual ~messages() - { - if (_M_c_locale_messages != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_messages); - } + { _S_destroy_c_locale(_M_c_locale_messages); } virtual catalog do_open(const basic_string&, const locale&) const; @@ -1759,8 +1752,7 @@ namespace std : messages<_CharT>(__refs) { _M_name_messages = __s; - if (_M_c_locale_messages != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_messages); + _S_destroy_c_locale(_M_c_locale_messages); _S_create_c_locale(_M_c_locale_messages, __s); } diff --git a/libstdc++-v3/include/bits/localefwd.h b/libstdc++-v3/include/bits/localefwd.h index b92560f0b52..76279609921 100644 --- a/libstdc++-v3/include/bits/localefwd.h +++ b/libstdc++-v3/include/bits/localefwd.h @@ -207,8 +207,8 @@ namespace std static const category time = 1L << 3; static const category monetary = 1L << 4; static const category messages = 1L << 5; - static const category all = (collate | ctype | monetary | - numeric | time | messages); + static const category all = (ctype | numeric | collate | + time | monetary | messages); // Construct/copy/destroy: locale() throw(); @@ -267,7 +267,26 @@ namespace std // Current global reference locale static _Impl* _S_global; - static const size_t _S_num_categories = 6; + // Number of standard categories. For C++, these categories are + // collate, ctype, monetary, numeric, time, and messages. These + // directly correspond to ISO C99 macros LC_COLLATE, LC_CTYPE, + // LC_MONETARY, LC_NUMERIC, and LC_TIME. In addition, POSIX (IEEE + // 1003.1-2001) specifies LC_MESSAGES. + static const size_t _S_categories_size = 6; + + // In addition to the standard categories, the underlying + // operating system is allowed to define extra LC_* + // macros. For GNU systems, the following are also valid: + // LC_PAPER, LC_NAME, LC_ADDRESS, LC_TELEPHONE, LC_MEASUREMENT, + // and LC_IDENTIFICATION. + static const size_t _S_extra_categories_size = _GLIBCPP_NUM_CATEGORIES; + + // Names of underlying locale categories. + // NB: locale::global() has to know how to modify all the + // underlying categories, not just the ones required by the C++ + // standard. + static const char* _S_categories[_S_categories_size + + _S_extra_categories_size]; explicit locale(_Impl*) throw(); @@ -308,7 +327,9 @@ namespace std _Atomic_word _M_references; facet** _M_facets; size_t _M_facets_size; - const char* _M_names[_S_num_categories]; + + char* _M_names[_S_categories_size + + _S_extra_categories_size]; static const locale::id* const _S_id_ctype[]; static const locale::id* const _S_id_numeric[]; static const locale::id* const _S_id_collate[]; @@ -348,8 +369,10 @@ namespace std _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); + for (size_t __i = 0; + __ret && __i < _S_categories_size + _S_extra_categories_size - 1; + ++__i) + __ret &= (strcmp(_M_names[__i], _M_names[__i + 1]) == 0); return __ret; } @@ -376,8 +399,14 @@ namespace std { _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] = "*"; + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size; ++__i) + { + delete [] _M_impl->_M_names[__i]; + char* __new = new char[2]; + strcpy(__new, "*"); + _M_impl->_M_names[__i] = __new; + } } // 22.1.1.1.2 Class locale::facet diff --git a/libstdc++-v3/src/codecvt.cc b/libstdc++-v3/src/codecvt.cc index 8d4c1b40c7e..b9575cf70bc 100644 --- a/libstdc++-v3/src/codecvt.cc +++ b/libstdc++-v3/src/codecvt.cc @@ -55,10 +55,7 @@ namespace std codecvt:: ~codecvt() - { - if (_M_c_locale_codecvt != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_codecvt); - } + { _S_destroy_c_locale(_M_c_locale_codecvt); } codecvt_base::result codecvt:: @@ -123,7 +120,7 @@ namespace std codecvt:: codecvt(size_t __refs) : __codecvt_abstract_base(__refs) - { _M_c_locale_codecvt = _S_c_locale; } + { _M_c_locale_codecvt = _S_c_locale; } codecvt:: codecvt(__c_locale __cloc, size_t __refs) @@ -132,10 +129,7 @@ namespace std codecvt:: ~codecvt() - { - if (_M_c_locale_codecvt != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_codecvt); - } + { _S_destroy_c_locale(_M_c_locale_codecvt); } codecvt_base::result codecvt:: diff --git a/libstdc++-v3/src/ctype.cc b/libstdc++-v3/src/ctype.cc index 7ca934eb379..3d5ee618c53 100644 --- a/libstdc++-v3/src/ctype.cc +++ b/libstdc++-v3/src/ctype.cc @@ -79,8 +79,7 @@ namespace std ctype::~ctype() { - if (_M_c_locale_ctype != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_ctype); + _S_destroy_c_locale(_M_c_locale_ctype); if (_M_del) delete[] this->table(); } @@ -135,17 +134,13 @@ namespace std { _M_c_locale_ctype = _S_clone_c_locale(__cloc); } ctype::~ctype() - { - if (_M_c_locale_ctype != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_ctype); - } + { _S_destroy_c_locale(_M_c_locale_ctype); } template<> ctype_byname::ctype_byname(const char* __s, size_t __refs) : ctype(__refs) { - if (_M_c_locale_ctype != _S_c_locale) - _S_destroy_c_locale(_M_c_locale_ctype); + _S_destroy_c_locale(_M_c_locale_ctype); _S_create_c_locale(_M_c_locale_ctype, __s); } #endif diff --git a/libstdc++-v3/src/globals.cc b/libstdc++-v3/src/globals.cc index 36d193fb406..079fff8fdab 100644 --- a/libstdc++-v3/src/globals.cc +++ b/libstdc++-v3/src/globals.cc @@ -59,6 +59,10 @@ namespace std __attribute__ ((aligned(__alignof__(locale::facet*)))); fake_facet_vec facet_vec[_GLIBCPP_NUM_FACETS]; + typedef char fake_facet_name[sizeof(char*)] + __attribute__ ((aligned(__alignof__(char*)))); + fake_facet_name facet_name[6 + _GLIBCPP_NUM_CATEGORIES]; + typedef char fake_ctype_c[sizeof(std::ctype)] __attribute__ ((aligned(__alignof__(std::ctype)))); fake_ctype_c ctype_c; @@ -200,7 +204,6 @@ namespace std fake_wfilebuf buf_wcerr; #endif - // Globals for once-only runtime initialization of mutex objects. This // allows static initialization of these objects on systems that need a // function call to initialize a mutex. For example, see stl_threads.h. diff --git a/libstdc++-v3/src/locale-inst.cc b/libstdc++-v3/src/locale-inst.cc index 5e6c6751bc4..8f2c8638177 100644 --- a/libstdc++-v3/src/locale-inst.cc +++ b/libstdc++-v3/src/locale-inst.cc @@ -35,11 +35,7 @@ #include #include #include -#include -#include #include -#include -#include namespace std { diff --git a/libstdc++-v3/src/locale.cc b/libstdc++-v3/src/locale.cc index 6314ba6a7a5..641bee21baa 100644 --- a/libstdc++-v3/src/locale.cc +++ b/libstdc++-v3/src/locale.cc @@ -31,11 +31,7 @@ #include #include #include // For towupper, etc. -#include -#include #include -#include -#include #include namespace std @@ -43,7 +39,6 @@ namespace std // Defined in globals.cc. extern locale c_locale; extern locale::_Impl c_locale_impl; - extern locale::facet** facet_vec; // Definitions for static const data members of locale. const locale::category locale::none; @@ -57,7 +52,8 @@ namespace std locale::_Impl* locale::_S_classic; locale::_Impl* locale::_S_global; - const size_t locale::_S_num_categories; + const size_t locale::_S_categories_size; + const size_t locale::_S_extra_categories_size; // Definitions for static const data members of locale::id _Atomic_word locale::id::_S_highwater; // init'd to 0 by linker @@ -146,8 +142,8 @@ namespace std locale::_Impl::_S_id_ctype, locale::_Impl::_S_id_numeric, locale::_Impl::_S_id_collate, - locale::_Impl::_S_id_monetary, locale::_Impl::_S_id_time, + locale::_Impl::_S_id_monetary, locale::_Impl::_S_id_messages, 0 }; @@ -192,18 +188,110 @@ namespace std _S_initialize(); if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0) (_M_impl = _S_classic)->_M_add_reference(); - else if (strcmp(__s, "") == 0) + else if (strcmp(__s, "") != 0) + _M_impl = new _Impl(__s, 1); + else { + // Get it from the environment. char* __env = getenv("LC_ALL"); - if (__env) - _M_impl = new _Impl(__env, 1); - else if ((__env = getenv("LANG"))) - _M_impl = new _Impl(__env, 1); + // 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 - (_M_impl = _S_classic)->_M_add_reference(); + { + 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_categories_size + _S_extra_categories_size; + ++__i) + { + __env = getenv(_S_categories[__i]); + if (__env && strcmp(__env, "") != 0 + && strcmp(__env, "C") != 0 + && strcmp(__env, "POSIX") != 0) + break; + } + else + for (__i = 0; + __i < _S_categories_size + _S_extra_categories_size; + ++__i) + { + __env = getenv(_S_categories[__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_categories_size + _S_extra_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 + + _S_extra_categories_size; ++__i) + { + __env = getenv(_S_categories[__i]); + if (!__env || strcmp(__env, "") == 0) + { + __str += _S_categories[__i]; + __str += '='; + __str += __res; + __str += ';'; + } + else if (strcmp(__env, "C") == 0 + || 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 (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); } else __throw_runtime_error("attempt to create locale from NULL name"); @@ -261,20 +349,22 @@ namespace std 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 += _S_categories[0]; + __ret += "="; + __ret += _M_impl->_M_names[0]; + for (size_t __i = 1; + __i < _S_categories_size + _S_extra_categories_size; + ++__i) { - __ret += __separator; - __ret += _M_impl->_M_names[i]; + __ret += ";"; + __ret += _S_categories[__i]; + __ret += "="; + __ret += _M_impl->_M_names[__i]; } } return __ret; @@ -292,11 +382,7 @@ namespace std { // 26 Standard facets, 2 references. // One reference for _M_classic, one for _M_global - facet** f = new(&facet_vec) facet*[_GLIBCPP_NUM_FACETS]; - for (size_t __i = 0; __i < _GLIBCPP_NUM_FACETS; ++__i) - f[__i] = 0; - - _S_classic = new (&c_locale_impl) _Impl(f, 2, true); + _S_classic = new (&c_locale_impl) _Impl(0, 2, true); _S_global = _S_classic; new (&c_locale) locale(_S_classic); } @@ -361,11 +447,8 @@ namespace std ~facet() { } locale::facet:: - facet(size_t __refs) throw() : _M_references(__refs) - { - if (!_S_c_locale) - _S_create_c_locale(_S_c_locale, "C"); - } + facet(size_t __refs) throw() : _M_references(__refs ? 1 : 0) + { } void locale::facet:: @@ -376,7 +459,7 @@ namespace std locale::facet:: _M_remove_reference() throw() { - if (__exchange_and_add(&_M_references, -1) == 0) + if (__exchange_and_add(&_M_references, -1) == 1) { try { delete this; } diff --git a/libstdc++-v3/src/localename.cc b/libstdc++-v3/src/localename.cc index a0c9e75ee80..a233eb3ec9d 100644 --- a/libstdc++-v3/src/localename.cc +++ b/libstdc++-v3/src/localename.cc @@ -33,6 +33,9 @@ namespace std { // Defined in globals.cc. + extern locale::facet** facet_vec; + extern char* facet_name[6 + _GLIBCPP_NUM_CATEGORIES]; + extern std::ctype ctype_c; extern std::collate collate_c; extern numpunct numpunct_c; @@ -71,6 +74,10 @@ namespace std if (_M_facets[__i]) _M_facets[__i]->_M_remove_reference(); delete [] _M_facets; + + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size; ++__i) + delete [] _M_names[__i]; } // Clone existing _Impl object. @@ -95,14 +102,19 @@ namespace std 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]; + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size; ++__i) + { + char* __new = new char[strlen(__imp._M_names[__i]) + 1]; + strcpy(__new, __imp._M_names[__i]); + _M_names[__i] = __new; + } } // Construct named _Impl. locale::_Impl:: _Impl(const char* __s, size_t __refs) - : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS) // XXX + : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS) { // Initialize the underlying locale model, which also checks // to see if the given name is valid. @@ -122,11 +134,40 @@ namespace std } // Name all the categories. - for (size_t i = 0; i < _S_num_categories; ++i) - _M_names[i] = __s; + if (!strchr(__s, ';')) + { + size_t __len = strlen(__s) + 1; + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size; ++__i) + { + _M_names[__i] = new char[__len]; + strcpy(_M_names[__i], __s); + } + } + else + { + char* __tmp = strdup(__s); + __tmp[strlen(__tmp)] = ';'; + strtok(__tmp, "=;"); + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size - 1; ++__i) + { + char* __src = strtok(NULL, "=;"); + char* __new = new char[strlen(__src) + 1]; + strcpy(__new, __src); + _M_names[__i] = __new; + strtok(NULL, "=;"); + } + char* __src = strtok(NULL, "=;"); + char* __new = new char[strlen(__src) + 1]; + strcpy(__new, __src); + _M_names[_S_categories_size + _S_extra_categories_size - 1] = __new; - // Construct all standard facets and add them to _M_facets. - _M_init_facet(new std::ctype(__cloc)); + free(__tmp); + } + + // Construct all standard facets and add them to _M_facets. + _M_init_facet(new std::ctype(__cloc, 0, false)); _M_init_facet(new codecvt(__cloc)); _M_init_facet(new numpunct(__cloc)); _M_init_facet(new num_get); @@ -162,47 +203,61 @@ namespace std // Construct "C" _Impl. locale::_Impl:: - _Impl(facet** __f, size_t __refs, bool) - : _M_references(__refs), _M_facets(__f), _M_facets_size(_GLIBCPP_NUM_FACETS) + _Impl(facet**, size_t __refs, bool) + : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS) { + // Initialize the underlying locale model. + locale::facet::_S_create_c_locale(locale::facet::_S_c_locale, "C"); + + _M_facets = new(&facet_vec) facet*[_M_facets_size]; + for (size_t __i = 0; __i < _M_facets_size; ++__i) + _M_facets[__i] = 0; + // Name all the categories. - for (size_t i = 0; i < _S_num_categories; ++i) - _M_names[i] = "C"; + for (size_t __i = 0; + __i < _S_categories_size + _S_extra_categories_size; ++__i) + { + _M_names[__i] = new (&facet_name[__i]) char[2]; + strcpy(_M_names[__i], "C"); + } // This is needed as presently the C++ version of "C" locales // != data in the underlying locale model for __timepunct, // numpunct, and moneypunct. Also, the "C" locales must be // constructed in a way such that they are pre-allocated. - _M_init_facet(new (&ctype_c) std::ctype); - _M_init_facet(new (&codecvt_c) codecvt); - _M_init_facet(new (&numpunct_c) numpunct); - _M_init_facet(new (&num_get_c) num_get); - _M_init_facet(new (&num_put_c) num_put); - _M_init_facet(new (&collate_c) std::collate); - _M_init_facet(new (&moneypunct_fc) moneypunct); - _M_init_facet(new (&moneypunct_tc) moneypunct); - _M_init_facet(new (&money_get_c) money_get); - _M_init_facet(new (&money_put_c) money_put); - _M_init_facet(new (&timepunct_c) __timepunct); - _M_init_facet(new (&time_get_c) time_get); - _M_init_facet(new (&time_put_c) time_put); - _M_init_facet(new (&messages_c) std::messages); + // NB: Set locale::facets(ref) count to one so that each individual + // facet is not destroyed when the locale (and thus locale::_Impl) is + // destroyed. + _M_init_facet(new (&ctype_c) std::ctype(0, false, 1)); + _M_init_facet(new (&codecvt_c) codecvt(1)); + _M_init_facet(new (&numpunct_c) numpunct(1)); + _M_init_facet(new (&num_get_c) num_get(1)); + _M_init_facet(new (&num_put_c) num_put(1)); + _M_init_facet(new (&collate_c) std::collate(1)); + _M_init_facet(new (&moneypunct_fc) moneypunct(1)); + _M_init_facet(new (&moneypunct_tc) moneypunct(1)); + _M_init_facet(new (&money_get_c) money_get(1)); + _M_init_facet(new (&money_put_c) money_put(1)); + _M_init_facet(new (&timepunct_c) __timepunct(1)); + _M_init_facet(new (&time_get_c) time_get(1)); + _M_init_facet(new (&time_put_c) time_put(1)); + _M_init_facet(new (&messages_c) std::messages(1)); #ifdef _GLIBCPP_USE_WCHAR_T - _M_init_facet(new (&ctype_w) std::ctype); - _M_init_facet(new (&codecvt_w) codecvt); - _M_init_facet(new (&numpunct_w) numpunct); - _M_init_facet(new (&num_get_w) num_get); - _M_init_facet(new (&num_put_w) num_put); - _M_init_facet(new (&collate_w) std::collate); - _M_init_facet(new (&moneypunct_fw) moneypunct); - _M_init_facet(new (&moneypunct_tw) moneypunct); - _M_init_facet(new (&money_get_w) money_get); - _M_init_facet(new (&money_put_w) money_put); - _M_init_facet(new (&timepunct_w) __timepunct); - _M_init_facet(new (&time_get_w) time_get); - _M_init_facet(new (&time_put_w) time_put); - _M_init_facet(new (&messages_w) std::messages); -#endif + _M_init_facet(new (&ctype_w) std::ctype(1)); + _M_init_facet(new (&codecvt_w) codecvt(1)); + _M_init_facet(new (&numpunct_w) numpunct(1)); + _M_init_facet(new (&num_get_w) num_get(1)); + _M_init_facet(new (&num_put_w) num_put(1)); + _M_init_facet(new (&collate_w) std::collate(1)); + _M_init_facet(new (&moneypunct_fw) moneypunct(1)); + _M_init_facet(new (&moneypunct_tw) moneypunct(1)); + _M_init_facet(new (&money_get_w) money_get(1)); + _M_init_facet(new (&money_put_w) money_put(1)); + _M_init_facet(new (&timepunct_w) __timepunct(1)); + _M_init_facet(new (&time_get_w) time_get(1)); + _M_init_facet(new (&time_put_w) time_put(1)); + _M_init_facet(new (&messages_w) std::messages(1)); +#endif } void @@ -210,7 +265,7 @@ namespace std _M_replace_categories(const _Impl* __imp, category __cat) { 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; if (__mask & __cat) @@ -220,7 +275,12 @@ namespace std // 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]; + { + delete [] _M_names[__ix]; + char* __new = new char[strlen(__imp->_M_names[__ix]) + 1]; + strcpy(__new, __imp->_M_names[__ix]); + _M_names[__ix] = __new; + } } } } @@ -250,6 +310,8 @@ namespace std if (__fp) { size_t __index = __idp->_M_id(); + + // Check size of facet vector to ensure adequate room. if (__index > _M_facets_size - 1) { facet** __old = _M_facets; @@ -266,11 +328,11 @@ namespace std delete [] __old; } + __fp->_M_add_reference(); facet*& __fpr = _M_facets[__index]; if (__fpr) { // Replacing an existing facet. Order matters. - __fp->_M_add_reference(); __fpr->_M_remove_reference(); __fpr = __fp; } diff --git a/libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc b/libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc index a27b2457e87..6f4b1bf5cff 100644 --- a/libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc +++ b/libstdc++-v3/testsuite/22_locale/ctor_copy_dtor.cc @@ -121,7 +121,7 @@ void test01() string str1, str2; // construct a locale object with the C facet - const locale& loc01 = locale::classic(); + const locale loc01 = locale::classic(); // 1 // template locale(const locale& other, Facet* f) @@ -315,16 +315,92 @@ void test03() { bool test = true; #ifdef _GLIBCPP_HAVE_SETENV - const char* oldLANG = getenv("LANG"); - if (!setenv("LANG", "it_IT", 1)) + const char* oldLC_ALL = getenv("LC_ALL"); + if (!setenv("LC_ALL", "it_IT", 1)) { std::locale loc(""); VERIFY( loc.name() == "it_IT" ); - setenv("LANG", oldLANG ? oldLANG : "", 1); + 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(""); + VERIFY( loc.name() == "C" ); + } + + // Check the default set by LANG. + if (!setenv("LC_ALL", "", 1) && !setenv("LANG", "fr_FR", 1)) + { + std::locale loc(""); + VERIFY( loc.name() == "fr_FR" ); + } + + // Check that a "POSIX" LANG is equivalent to "C". + if (!setenv("LANG", "POSIX", 1)) + { + std::locale loc(""); + VERIFY( 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(""); + VERIFY( 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(""); + VERIFY( 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(""); + VERIFY( 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(); @@ -335,6 +411,7 @@ int main() test02(); test03(); + test04(); return 0; } diff --git a/libstdc++-v3/testsuite/22_locale/facet.cc b/libstdc++-v3/testsuite/22_locale/facet.cc index 431718e7834..9c613b4c203 100644 --- a/libstdc++-v3/testsuite/22_locale/facet.cc +++ b/libstdc++-v3/testsuite/22_locale/facet.cc @@ -1,6 +1,6 @@ // 2000-08-31 Benjamin Kosnik -// Copyright (C) 2000 Free Software Foundation +// Copyright (C) 2000, 2002 Free Software Foundation // // 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 @@ -25,6 +25,7 @@ #include #include #include +#include #include // 1 a class if a facet if it is publicly derived from another facet @@ -233,9 +234,69 @@ void test01() } } +// Static counter for use in checking ctors/dtors. +static std::size_t counter; + +class surf : public std::locale::facet +{ +public: + static std::locale::id id; + surf(size_t refs = 0): std::locale::facet(refs) { ++counter; } + ~surf() { --counter; } +}; + +std::locale::id surf::id; + +typedef surf facet_type; + +void test02() +{ + using namespace std; + bool test = true; + + // 1: Destroyed when out of scope. + VERIFY( counter == 0 ); + { + locale loc01(locale::classic(), new facet_type); + VERIFY( counter == 1 ); + } + VERIFY( counter == 0 ); + + // 2: Not destroyed when out of scope, deliberately leaked. + VERIFY( counter == 0 ); + { + // Default refs argument is zero. + locale loc02(locale::classic(), new facet_type(1)); + VERIFY( counter == 1 ); + } + VERIFY( counter == 1 ); + + // 3: Pathological. + counter = 0; + { + // Test bounds. + facet_type* f = new facet_type(numeric_limits::max()); + VERIFY( counter == 1 ); + // Add a reference. + locale loc01(locale::classic(), f); + { + // Add another reference... + locale loc02(locale::classic(), f); + } + VERIFY( counter == 1 ); + } + + // 4: Named locale should destroy facets when it goes out of scope. + // Not quite sure how to test for this w/o valgrind at the moment. + { + locale loc03("es_MX"); + } +} + int main () { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/22_locale/static_members.cc b/libstdc++-v3/testsuite/22_locale/static_members.cc index 16e856a2ee4..06b125852c2 100644 --- a/libstdc++-v3/testsuite/22_locale/static_members.cc +++ b/libstdc++-v3/testsuite/22_locale/static_members.cc @@ -1,6 +1,6 @@ // 2000-09-13 Benjamin Kosnik -// Copyright (C) 2000 Free Software Foundation +// Copyright (C) 2000, 2002 Free Software Foundation // // 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 @@ -22,7 +22,9 @@ #include // for mbstate_t #include -#include +#include +//#include +#define VERIFY(x) test &= x typedef std::codecvt ccodecvt; class gnu_codecvt: public ccodecvt { }; @@ -34,10 +36,12 @@ void test01() bool test = true; string str1, str2; - // construct a locale object with the C facet - const locale& loc01 = locale::classic(); - // construct a locale object with the specialized facet. - locale loc02(locale::classic(), new gnu_codecvt); + // Construct a locale object with the C facet. + const locale loc_env(""); + const locale loc01 = locale::classic(); + + // Construct a locale object with the specialized facet. + locale loc02(locale::classic(), new gnu_codecvt); VERIFY ( loc01 != loc02 ); VERIFY ( !(loc01 == loc02) ); @@ -54,11 +58,45 @@ void test01() locale loc05; VERIFY (loc05 != loc03); VERIFY (loc05 == loc02); + + // Reset global locale. + locale::global(loc_env); +} + +// Sanity check locale::global(loc) and setlocale. +void test02() +{ + using namespace std; + bool test = true; + + const string ph("en_PH"); + const string mx("es_MX"); + + const locale loc_ph(ph.c_str()); + const locale loc_mx(mx.c_str()); + + // Get underlying current locale and environment settings. + const string lc_all_orig = std::setlocale(LC_ALL, NULL); + const locale loc_orig(""); + + // setlocale to en_PH + string lc_all_ph = std::setlocale(LC_ALL, ph.c_str()); + + const locale loc_env(""); + VERIFY( loc_env == loc_orig ); + + locale::global(loc_mx); + string lc_all_mx = std::setlocale(LC_ALL, NULL); + VERIFY( lc_all_mx == mx.c_str() ); + + // Restore global info. + locale::global(loc_orig); } int main () { test01(); + test02(); return 0; } -- 2.30.2