aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/config
diff options
context:
space:
mode:
authorFrançois Dumont <fdumont@gcc.gnu.org>2014-12-03 19:47:00 +0000
committerFrançois Dumont <fdumont@gcc.gnu.org>2014-12-03 19:47:00 +0000
commitd31008d7a0d53b431f176aad8dda5498de823122 (patch)
treedc940f51b00c0ea19e058fb1a6003428315b179b /libstdc++-v3/config
parent61a1a73ecbc18c92bda1f240c8cd2ee4f5d2d6fe (diff)
downloadgcc-d31008d7a0d53b431f176aad8dda5498de823122.zip
gcc-d31008d7a0d53b431f176aad8dda5498de823122.tar.gz
gcc-d31008d7a0d53b431f176aad8dda5498de823122.tar.bz2
re PR libstdc++/13631 (Problems in messages)
2014-12-03 François Dumont <fdumont@gcc.gnu.org> PR libstdc++/13631 * include/bits/codecvt.h (codecvt<char, char, mbstate_t>): friend class std::messages<char>. (codecvt<wchar_t, char, mbstate_t>): friend class std::messages<wchar_t>. * config/locale/gnu/messages_member.h (messages<char>::do_open): Specialized. (messages<char>::do_close): Likewise. (messages<wchar_t>::do_open): Likewise. (messages<wchar_t>::do_close): Likewise. * config/locale/gnu/messages_member.cc: (messages<char>::do_open): Implement. Use bind_textdomain_codeset based on codecvt<char, char, mbstate_t>._M_c_locale_codecvt code set. Use internal cache to keep opened domain name with locale information. (messages<wchar_t>::do_open): Likewise with codecvt<wchar_t, char, mbstate_t>. (messages<char>::do_close): Implement. Clean cache information. (messages<wchar_t>::do_close): Likewise. (get_glibc_msg): New. Use dgettext rather than gettext using cached domain name associated to catalog id. (messages<char>::do_get): Use latter. (messages<wchar_t>::do_get): Likewise and use also cached locale codecvt<wchar_t, char, mbstate_t> facet to convert wchar_t default value to char and the result back to wchar_t. * testsuite/22_locale/messages/13631.cc: New. * testsuite/22_locale/messages/members/char/2.cc: Use also fr_FR locale for charset conversion to get the expected accented character. From-SVN: r218329
Diffstat (limited to 'libstdc++-v3/config')
-rw-r--r--libstdc++-v3/config/locale/gnu/messages_members.cc255
-rw-r--r--libstdc++-v3/config/locale/gnu/messages_members.h137
2 files changed, 306 insertions, 86 deletions
diff --git a/libstdc++-v3/config/locale/gnu/messages_members.cc b/libstdc++-v3/config/locale/gnu/messages_members.cc
index b3c2527..0134f0f 100644
--- a/libstdc++-v3/config/locale/gnu/messages_members.cc
+++ b/libstdc++-v3/config/locale/gnu/messages_members.cc
@@ -31,54 +31,253 @@
#include <locale>
#include <bits/c++locale_internal.h>
-namespace std _GLIBCXX_VISIBILITY(default)
+#include <limits>
+#include <algorithm>
+#include <vector>
+
+#include <backward/auto_ptr.h>
+#include <ext/concurrence.h>
+
+namespace
{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ using namespace std;
- // Specializations.
- template<>
- string
- messages<char>::do_get(catalog, int, int, const string& __dfault) const
+ typedef messages_base::catalog catalog;
+
+ struct Catalog_info
+ {
+ Catalog_info(catalog __id, const string& __domain, locale __loc)
+ : _M_id(__id), _M_domain(__domain), _M_locale(__loc)
+ { }
+
+ catalog _M_id;
+ string _M_domain;
+ locale _M_locale;
+ };
+
+ class Catalogs
+ {
+ public:
+ Catalogs() : _M_catalog_counter(0) { }
+
+ ~Catalogs()
+ {
+ for (vector<Catalog_info*>::iterator __it = _M_infos.begin();
+ __it != _M_infos.end(); ++__it)
+ delete *__it;
+ }
+
+ catalog
+ _M_add(const string& __domain, locale __l)
+ {
+ __gnu_cxx::__scoped_lock lock(_M_mutex);
+
+ // The counter is not likely to roll unless catalogs keep on being
+ // opened/closed which is consider as an application mistake for the
+ // moment.
+ if (_M_catalog_counter == numeric_limits<catalog>::max())
+ return -1;
+
+ std::auto_ptr<Catalog_info> info(new Catalog_info(_M_catalog_counter++,
+ __domain, __l));
+ _M_infos.push_back(info.get());
+ return info.release()->_M_id;
+ }
+
+ void
+ _M_erase(catalog __c)
{
+ __gnu_cxx::__scoped_lock lock(_M_mutex);
+
+ vector<Catalog_info*>::iterator __res =
+ lower_bound(_M_infos.begin(), _M_infos.end(), __c, _Comp());
+ if (__res == _M_infos.end() || (*__res)->_M_id != __c)
+ return;
+
+ delete *__res;
+ _M_infos.erase(__res);
+
+ // Just in case closed catalog was the last open.
+ if (__c == _M_catalog_counter - 1)
+ --_M_catalog_counter;
+ }
+
+ const Catalog_info*
+ _M_get(catalog __c) const
+ {
+ __gnu_cxx::__scoped_lock lock(_M_mutex);
+
+ vector<Catalog_info*>::const_iterator __res =
+ lower_bound(_M_infos.begin(), _M_infos.end(), __c, _Comp());
+
+ if (__res != _M_infos.end() && (*__res)->_M_id == __c)
+ return *__res;
+
+ return 0;
+ }
+
+ private:
+ struct _Comp
+ {
+ bool operator()(catalog __cat, const Catalog_info* __info) const
+ { return __cat < __info->_M_id; }
+
+ bool operator()(const Catalog_info* __info, catalog __cat) const
+ { return __info->_M_id < __cat; }
+ };
+
+ mutable __gnu_cxx::__mutex _M_mutex;
+ catalog _M_catalog_counter;
+ std::vector<Catalog_info*> _M_infos;
+ };
+
+ Catalogs&
+ get_catalogs()
+ {
+ static Catalogs __catalogs;
+ return __catalogs;
+ }
+
+ const char*
+ get_glibc_msg(__c_locale __attribute__((unused)) __locale_messages,
+ const char* __domainname,
+ const char* __dfault)
+ {
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
- __c_locale __old = __uselocale(_M_c_locale_messages);
- const char* __msg = const_cast<const char*>(gettext(__dfault.c_str()));
+ std::__c_locale __old = __uselocale(__locale_messages);
+ const char* __msg =
+ const_cast<const char*>(dgettext(__domainname, __dfault));
__uselocale(__old);
- return string(__msg);
#else
char* __old = setlocale(LC_ALL, 0);
const size_t __len = strlen(__old) + 1;
char* __sav = new char[__len];
memcpy(__sav, __old, __len);
setlocale(LC_ALL, _M_name_messages);
- const char* __msg = gettext(__dfault.c_str());
+ const char* __msg = dgettext(__domainname, __dfault);
setlocale(LC_ALL, __sav);
delete [] __sav;
- return string(__msg);
#endif
+
+ return __msg;
+ }
+}
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ // Specializations.
+ template<>
+ typename messages<char>::catalog
+ messages<char>::do_open(const basic_string<char>& __s,
+ const locale& __l) const
+ {
+ typedef codecvt<char, char, mbstate_t> __codecvt_t;
+ const __codecvt_t& __codecvt = use_facet<__codecvt_t>(__l);
+
+ bind_textdomain_codeset(__s.c_str(),
+ __nl_langinfo_l(CODESET, __codecvt._M_c_locale_codecvt));
+ return get_catalogs()._M_add(__s, __l);
+ }
+
+ template<>
+ void
+ messages<char>::do_close(catalog __c) const
+ { get_catalogs()._M_erase(__c); }
+
+ template<>
+ string
+ messages<char>::do_get(catalog __c, int, int,
+ const string& __dfault) const
+ {
+ if (__c < 0 || __dfault.empty())
+ return __dfault;
+
+ const Catalog_info* __cat_info = get_catalogs()._M_get(__c);
+
+ if (!__cat_info)
+ return __dfault;
+
+ return get_glibc_msg(_M_c_locale_messages,
+ __cat_info->_M_domain.c_str(),
+ __dfault.c_str());
}
#ifdef _GLIBCXX_USE_WCHAR_T
template<>
+ typename messages<wchar_t>::catalog
+ messages<wchar_t>::do_open(const basic_string<char>& __s,
+ const locale& __l) const
+ {
+ typedef codecvt<wchar_t, char, mbstate_t> __codecvt_t;
+ const __codecvt_t& __codecvt = use_facet<__codecvt_t>(__l);
+
+ bind_textdomain_codeset(__s.c_str(),
+ __nl_langinfo_l(CODESET, __codecvt._M_c_locale_codecvt));
+
+ return get_catalogs()._M_add(__s, __l);
+ }
+
+ template<>
+ void
+ messages<wchar_t>::do_close(catalog __c) const
+ { get_catalogs()._M_erase(__c); }
+
+ template<>
wstring
- messages<wchar_t>::do_get(catalog, int, int, const wstring& __dfault) const
+ messages<wchar_t>::do_get(catalog __c, int, int,
+ const wstring& __wdfault) const
{
-# if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
- __c_locale __old = __uselocale(_M_c_locale_messages);
- char* __msg = gettext(_M_convert_to_char(__dfault));
- __uselocale(__old);
- return _M_convert_from_char(__msg);
-# else
- char* __old = setlocale(LC_ALL, 0);
- const size_t __len = strlen(__old) + 1;
- char* __sav = new char[__len];
- memcpy(__sav, __old, __len);
- setlocale(LC_ALL, _M_name_messages);
- char* __msg = gettext(_M_convert_to_char(__dfault));
- setlocale(LC_ALL, __sav);
- delete [] __sav;
- return _M_convert_from_char(__msg);
-# endif
+ if (__c < 0 || __wdfault.empty())
+ return __wdfault;
+
+ const Catalog_info* __cat_info = get_catalogs()._M_get(__c);
+
+ if (!__cat_info)
+ return __wdfault;
+
+ typedef codecvt<wchar_t, char, mbstate_t> __codecvt_t;
+ const __codecvt_t& __conv =
+ use_facet<__codecvt_t>(__cat_info->_M_locale);
+
+ const char* __translation;
+ mbstate_t __state;
+ __builtin_memset(&__state, 0, sizeof(mbstate_t));
+ {
+ const wchar_t* __wdfault_next;
+ size_t __mb_size = __wdfault.size() * __conv.max_length();;
+ char* __dfault =
+ static_cast<char*>(__builtin_alloca(sizeof(char) * (__mb_size + 1)));
+ char* __dfault_next;
+ __conv.out(__state,
+ __wdfault.data(), __wdfault.data() + __wdfault.size(),
+ __wdfault_next,
+ __dfault, __dfault + __mb_size, __dfault_next);
+
+ // Make sure string passed to dgettext is \0 terminated.
+ *__dfault_next = '\0';
+ __translation
+ = get_glibc_msg(_M_c_locale_messages,
+ __cat_info->_M_domain.c_str(), __dfault);
+
+ // If we end up getting default value back we can simply return original
+ // default value.
+ if (__translation == __dfault)
+ return __wdfault;
+ }
+
+ __builtin_memset(&__state, 0, sizeof(mbstate_t));
+ size_t __size = __builtin_strlen(__translation);
+ const char* __translation_next;
+ wchar_t* __wtranslation =
+ static_cast<wchar_t*>(__builtin_alloca(sizeof(wchar_t) * (__size + 1)));
+ wchar_t* __wtranslation_next;
+ __conv.in(__state, __translation, __translation + __size,
+ __translation_next,
+ __wtranslation, __wtranslation + __size,
+ __wtranslation_next);
+ return wstring(__wtranslation, __wtranslation_next);
}
#endif
diff --git a/libstdc++-v3/config/locale/gnu/messages_members.h b/libstdc++-v3/config/locale/gnu/messages_members.h
index f90a61e..cb3fd67 100644
--- a/libstdc++-v3/config/locale/gnu/messages_members.h
+++ b/libstdc++-v3/config/locale/gnu/messages_members.h
@@ -41,53 +41,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Non-virtual member functions.
template<typename _CharT>
- messages<_CharT>::messages(size_t __refs)
- : facet(__refs), _M_c_locale_messages(_S_get_c_locale()),
- _M_name_messages(_S_get_c_name())
- { }
+ messages<_CharT>::messages(size_t __refs)
+ : facet(__refs), _M_c_locale_messages(_S_get_c_locale()),
+ _M_name_messages(_S_get_c_name())
+ { }
template<typename _CharT>
- messages<_CharT>::messages(__c_locale __cloc, const char* __s,
- size_t __refs)
- : facet(__refs), _M_c_locale_messages(0), _M_name_messages(0)
- {
- if (__builtin_strcmp(__s, _S_get_c_name()) != 0)
- {
- const size_t __len = __builtin_strlen(__s) + 1;
- char* __tmp = new char[__len];
- __builtin_memcpy(__tmp, __s, __len);
- _M_name_messages = __tmp;
- }
- else
- _M_name_messages = _S_get_c_name();
-
- // Last to avoid leaking memory if new throws.
- _M_c_locale_messages = _S_clone_c_locale(__cloc);
- }
+ messages<_CharT>::messages(__c_locale __cloc, const char* __s,
+ size_t __refs)
+ : facet(__refs), _M_c_locale_messages(0), _M_name_messages(0)
+ {
+ if (__builtin_strcmp(__s, _S_get_c_name()) != 0)
+ {
+ const size_t __len = __builtin_strlen(__s) + 1;
+ char* __tmp = new char[__len];
+ __builtin_memcpy(__tmp, __s, __len);
+ _M_name_messages = __tmp;
+ }
+ else
+ _M_name_messages = _S_get_c_name();
+
+ // Last to avoid leaking memory if new throws.
+ _M_c_locale_messages = _S_clone_c_locale(__cloc);
+ }
template<typename _CharT>
- typename messages<_CharT>::catalog
- messages<_CharT>::open(const basic_string<char>& __s, const locale& __loc,
+ typename messages<_CharT>::catalog
+ messages<_CharT>::open(const basic_string<char>& __s, const locale& __loc,
const char* __dir) const
- {
+ {
bindtextdomain(__s.c_str(), __dir);
- return this->do_open(__s, __loc);
+ return this->do_open(__s, __loc);
}
// Virtual member functions.
template<typename _CharT>
messages<_CharT>::~messages()
- {
+ {
if (_M_name_messages != _S_get_c_name())
delete [] _M_name_messages;
- _S_destroy_c_locale(_M_c_locale_messages);
+ _S_destroy_c_locale(_M_c_locale_messages);
}
template<typename _CharT>
- typename messages<_CharT>::catalog
- messages<_CharT>::do_open(const basic_string<char>& __s,
+ typename messages<_CharT>::catalog
+ messages<_CharT>::do_open(const basic_string<char>& __s,
const locale&) const
- {
+ {
// No error checking is done, assume the catalog exists and can
// be used.
textdomain(__s.c_str());
@@ -95,36 +95,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT>
- void
- messages<_CharT>::do_close(catalog) const
+ void
+ messages<_CharT>::do_close(catalog) const
{ }
- // 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);
- }
- }
+ // 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);
+ }
+ }
+
+ //Specializations.
+ template<>
+ typename messages<char>::catalog
+ messages<char>::do_open(const basic_string<char>&,
+ const locale&) const;
+
+ template<>
+ void
+ messages<char>::do_close(catalog) const;
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template<>
+ typename messages<wchar_t>::catalog
+ messages<wchar_t>::do_open(const basic_string<char>&,
+ const locale&) const;
+
+ template<>
+ void
+ messages<wchar_t>::do_close(catalog) const;
+#endif
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace