1 // std::messages implementation details, GNU version -*- C++ -*- 2 3 // Copyright (C) 2001-2019 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