1 // std::messages implementation details, GNU version -*- C++ -*-
2 
3 // Copyright (C) 2001-2020 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 //
26 // ISO C++ 14882: 22.2.7.1.2  messages virtual functions
27 //
28 
29 // Written by Benjamin Kosnik <bkoz@redhat.com>
30 
31 #include <locale>
32 #include <bits/c++locale_internal.h>
33 
34 #include <cstdlib>	// std::free
35 #include <string.h>	// ::strdup
36 
37 namespace
38 {
39   using namespace std;
40 
41   const char*
get_glibc_msg(__c_locale __locale_messages,const char * __name_messages,const char * __domainname,const char * __dfault)42   get_glibc_msg(__c_locale __locale_messages __attribute__((unused)),
43 		const char* __name_messages __attribute__((unused)),
44 		const char* __domainname,
45 		const char* __dfault)
46   {
47 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
48     std::__c_locale __old = __uselocale(__locale_messages);
49     const char* __msg = dgettext(__domainname, __dfault);
50     __uselocale(__old);
51     return __msg;
52 #else
53     if (char* __sav = strdup(setlocale(LC_ALL, 0)))
54       {
55 	setlocale(LC_ALL, __name_messages);
56 	const char* __msg = dgettext(__domainname, __dfault);
57 	setlocale(LC_ALL, __sav);
58 	free(__sav);
59 	return __msg;
60       }
61     return __dfault;
62 #endif
63   }
64 }
65 
66 namespace std _GLIBCXX_VISIBILITY(default)
67 {
68 _GLIBCXX_BEGIN_NAMESPACE_VERSION
69 
70   // Specializations.
71   template<>
72     typename messages<char>::catalog
do_open(const basic_string<char> & __s,const locale & __l) const73     messages<char>::do_open(const basic_string<char>& __s,
74 			    const locale& __l) const
75     {
76       typedef codecvt<char, char, mbstate_t> __codecvt_t;
77       const __codecvt_t& __codecvt = use_facet<__codecvt_t>(__l);
78 
79       bind_textdomain_codeset(__s.c_str(),
80 	  __nl_langinfo_l(CODESET, __codecvt._M_c_locale_codecvt));
81       return get_catalogs()._M_add(__s.c_str(), __l);
82     }
83 
84   template<>
85     void
do_close(catalog __c) const86     messages<char>::do_close(catalog __c) const
87     { get_catalogs()._M_erase(__c); }
88 
89   template<>
90     string
do_get(catalog __c,int,int,const string & __dfault) const91     messages<char>::do_get(catalog __c, int, int,
92 			   const string& __dfault) const
93     {
94       if (__c < 0 || __dfault.empty())
95 	return __dfault;
96 
97       const Catalog_info* __cat_info = get_catalogs()._M_get(__c);
98 
99       if (!__cat_info)
100 	return __dfault;
101 
102       return get_glibc_msg(_M_c_locale_messages, _M_name_messages,
103 			   __cat_info->_M_domain,
104 			   __dfault.c_str());
105     }
106 
107 #ifdef _GLIBCXX_USE_WCHAR_T
108   template<>
109     typename messages<wchar_t>::catalog
do_open(const basic_string<char> & __s,const locale & __l) const110     messages<wchar_t>::do_open(const basic_string<char>& __s,
111 			       const locale& __l) const
112     {
113       typedef codecvt<wchar_t, char, mbstate_t> __codecvt_t;
114       const __codecvt_t& __codecvt = use_facet<__codecvt_t>(__l);
115 
116       bind_textdomain_codeset(__s.c_str(),
117 	  __nl_langinfo_l(CODESET, __codecvt._M_c_locale_codecvt));
118 
119       return get_catalogs()._M_add(__s.c_str(), __l);
120     }
121 
122   template<>
123     void
do_close(catalog __c) const124     messages<wchar_t>::do_close(catalog __c) const
125     { get_catalogs()._M_erase(__c); }
126 
127   template<>
128     wstring
do_get(catalog __c,int,int,const wstring & __wdfault) const129     messages<wchar_t>::do_get(catalog __c, int, int,
130 			      const wstring& __wdfault) const
131     {
132       if (__c < 0 || __wdfault.empty())
133 	return __wdfault;
134 
135       const Catalog_info* __cat_info = get_catalogs()._M_get(__c);
136 
137       if (!__cat_info)
138 	return __wdfault;
139 
140       typedef codecvt<wchar_t, char, mbstate_t> __codecvt_t;
141       const __codecvt_t& __conv =
142 	use_facet<__codecvt_t>(__cat_info->_M_locale);
143 
144       const char* __translation;
145       mbstate_t __state;
146       __builtin_memset(&__state, 0, sizeof(mbstate_t));
147       {
148 	const wchar_t* __wdfault_next;
149 	size_t __mb_size = __wdfault.size() * __conv.max_length();
150 	char* __dfault =
151 	  static_cast<char*>(__builtin_alloca(sizeof(char) * (__mb_size + 1)));
152 	char* __dfault_next;
153 	__conv.out(__state,
154 		   __wdfault.data(), __wdfault.data() + __wdfault.size(),
155 		   __wdfault_next,
156 		   __dfault, __dfault + __mb_size, __dfault_next);
157 
158 	// Make sure string passed to dgettext is \0 terminated.
159 	*__dfault_next = '\0';
160 	__translation = get_glibc_msg(_M_c_locale_messages, _M_name_messages,
161 				      __cat_info->_M_domain, __dfault);
162 
163 	// If we end up getting default value back we can simply return original
164 	// default value.
165 	if (__translation == __dfault)
166 	  return __wdfault;
167       }
168 
169       __builtin_memset(&__state, 0, sizeof(mbstate_t));
170       size_t __size = __builtin_strlen(__translation);
171       const char* __translation_next;
172       wchar_t* __wtranslation =
173 	static_cast<wchar_t*>(__builtin_alloca(sizeof(wchar_t) * (__size + 1)));
174       wchar_t* __wtranslation_next;
175       __conv.in(__state, __translation, __translation + __size,
176 		__translation_next,
177 		__wtranslation, __wtranslation + __size,
178 		__wtranslation_next);
179       return wstring(__wtranslation, __wtranslation_next);
180     }
181 #endif
182 
183 _GLIBCXX_END_NAMESPACE_VERSION
184 } // namespace
185