1 // std::messages implementation details, GNU version -*- C++ -*-
3 // Copyright (C) 2001-2015 Free Software Foundation, Inc.
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)
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.
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.
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/>.
26 // ISO C++ 14882: 22.2.7.1.2 messages virtual functions
29 // Written by Benjamin Kosnik <bkoz@redhat.com>
32 #include <bits/c++locale_internal.h>
37 #include <cstdlib> // std::free
38 #include <string.h> // ::strdup
40 #include <backward/auto_ptr.h>
41 #include <ext/concurrence.h>
47 typedef messages_base::catalog catalog
;
51 Catalog_info(catalog __id
, const string
& __domain
, locale __loc
)
52 : _M_id(__id
), _M_domain(__domain
), _M_locale(__loc
)
63 Catalogs() : _M_catalog_counter(0) { }
67 for (vector
<Catalog_info
*>::iterator __it
= _M_infos
.begin();
68 __it
!= _M_infos
.end(); ++__it
)
73 _M_add(const string
& __domain
, locale __l
)
75 __gnu_cxx::__scoped_lock
lock(_M_mutex
);
77 // The counter is not likely to roll unless catalogs keep on being
78 // opened/closed which is consider as an application mistake for the
80 if (_M_catalog_counter
== numeric_limits
<catalog
>::max())
83 std::auto_ptr
<Catalog_info
> info(new Catalog_info(_M_catalog_counter
++,
85 _M_infos
.push_back(info
.get());
86 return info
.release()->_M_id
;
92 __gnu_cxx::__scoped_lock
lock(_M_mutex
);
94 vector
<Catalog_info
*>::iterator __res
=
95 lower_bound(_M_infos
.begin(), _M_infos
.end(), __c
, _Comp());
96 if (__res
== _M_infos
.end() || (*__res
)->_M_id
!= __c
)
100 _M_infos
.erase(__res
);
102 // Just in case closed catalog was the last open.
103 if (__c
== _M_catalog_counter
- 1)
104 --_M_catalog_counter
;
108 _M_get(catalog __c
) const
110 __gnu_cxx::__scoped_lock
lock(_M_mutex
);
112 vector
<Catalog_info
*>::const_iterator __res
=
113 lower_bound(_M_infos
.begin(), _M_infos
.end(), __c
, _Comp());
115 if (__res
!= _M_infos
.end() && (*__res
)->_M_id
== __c
)
124 bool operator()(catalog __cat
, const Catalog_info
* __info
) const
125 { return __cat
< __info
->_M_id
; }
127 bool operator()(const Catalog_info
* __info
, catalog __cat
) const
128 { return __info
->_M_id
< __cat
; }
131 mutable __gnu_cxx::__mutex _M_mutex
;
132 catalog _M_catalog_counter
;
133 std::vector
<Catalog_info
*> _M_infos
;
139 static Catalogs __catalogs
;
144 get_glibc_msg(__c_locale __locale_messages
__attribute__((unused
)),
145 const char* __name_messages
__attribute__((unused
)),
146 const char* __domainname
,
147 const char* __dfault
)
149 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
150 std::__c_locale __old
= __uselocale(__locale_messages
);
151 const char* __msg
= dgettext(__domainname
, __dfault
);
155 if (char* __sav
= strdup(setlocale(LC_ALL
, 0)))
157 setlocale(LC_ALL
, __name_messages
);
158 const char* __msg
= dgettext(__domainname
, __dfault
);
159 setlocale(LC_ALL
, __sav
);
168 namespace std
_GLIBCXX_VISIBILITY(default)
170 _GLIBCXX_BEGIN_NAMESPACE_VERSION
174 typename messages
<char>::catalog
175 messages
<char>::do_open(const basic_string
<char>& __s
,
176 const locale
& __l
) const
178 typedef codecvt
<char, char, mbstate_t> __codecvt_t
;
179 const __codecvt_t
& __codecvt
= use_facet
<__codecvt_t
>(__l
);
181 bind_textdomain_codeset(__s
.c_str(),
182 __nl_langinfo_l(CODESET
, __codecvt
._M_c_locale_codecvt
));
183 return get_catalogs()._M_add(__s
, __l
);
188 messages
<char>::do_close(catalog __c
) const
189 { get_catalogs()._M_erase(__c
); }
193 messages
<char>::do_get(catalog __c
, int, int,
194 const string
& __dfault
) const
196 if (__c
< 0 || __dfault
.empty())
199 const Catalog_info
* __cat_info
= get_catalogs()._M_get(__c
);
204 return get_glibc_msg(_M_c_locale_messages
, _M_name_messages
,
205 __cat_info
->_M_domain
.c_str(),
209 #ifdef _GLIBCXX_USE_WCHAR_T
211 typename messages
<wchar_t>::catalog
212 messages
<wchar_t>::do_open(const basic_string
<char>& __s
,
213 const locale
& __l
) const
215 typedef codecvt
<wchar_t, char, mbstate_t> __codecvt_t
;
216 const __codecvt_t
& __codecvt
= use_facet
<__codecvt_t
>(__l
);
218 bind_textdomain_codeset(__s
.c_str(),
219 __nl_langinfo_l(CODESET
, __codecvt
._M_c_locale_codecvt
));
221 return get_catalogs()._M_add(__s
, __l
);
226 messages
<wchar_t>::do_close(catalog __c
) const
227 { get_catalogs()._M_erase(__c
); }
231 messages
<wchar_t>::do_get(catalog __c
, int, int,
232 const wstring
& __wdfault
) const
234 if (__c
< 0 || __wdfault
.empty())
237 const Catalog_info
* __cat_info
= get_catalogs()._M_get(__c
);
242 typedef codecvt
<wchar_t, char, mbstate_t> __codecvt_t
;
243 const __codecvt_t
& __conv
=
244 use_facet
<__codecvt_t
>(__cat_info
->_M_locale
);
246 const char* __translation
;
248 __builtin_memset(&__state
, 0, sizeof(mbstate_t));
250 const wchar_t* __wdfault_next
;
251 size_t __mb_size
= __wdfault
.size() * __conv
.max_length();;
253 static_cast<char*>(__builtin_alloca(sizeof(char) * (__mb_size
+ 1)));
256 __wdfault
.data(), __wdfault
.data() + __wdfault
.size(),
258 __dfault
, __dfault
+ __mb_size
, __dfault_next
);
260 // Make sure string passed to dgettext is \0 terminated.
261 *__dfault_next
= '\0';
262 __translation
= get_glibc_msg(_M_c_locale_messages
, _M_name_messages
,
263 __cat_info
->_M_domain
.c_str(), __dfault
);
265 // If we end up getting default value back we can simply return original
267 if (__translation
== __dfault
)
271 __builtin_memset(&__state
, 0, sizeof(mbstate_t));
272 size_t __size
= __builtin_strlen(__translation
);
273 const char* __translation_next
;
274 wchar_t* __wtranslation
=
275 static_cast<wchar_t*>(__builtin_alloca(sizeof(wchar_t) * (__size
+ 1)));
276 wchar_t* __wtranslation_next
;
277 __conv
.in(__state
, __translation
, __translation
+ __size
,
279 __wtranslation
, __wtranslation
+ __size
,
280 __wtranslation_next
);
281 return wstring(__wtranslation
, __wtranslation_next
);
285 _GLIBCXX_END_NAMESPACE_VERSION