1 // Copyright (C) 1997-2014 Free Software Foundation, Inc. 2 // 3 // This file is part of the GNU ISO C++ Library. This library is free 4 // software; you can redistribute it and/or modify it under the 5 // terms of the GNU General Public License as published by the 6 // Free Software Foundation; either version 3, or (at your option) 7 // any later version. 8 9 // This library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // Under Section 7 of GPL version 3, you are granted additional 15 // permissions described in the GCC Runtime Library Exception, version 16 // 3.1, as published by the Free Software Foundation. 17 18 // You should have received a copy of the GNU General Public License and 19 // a copy of the GCC Runtime Library Exception along with this program; 20 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21 // <http://www.gnu.org/licenses/>. 22 23 #include <clocale> 24 #include <cstring> 25 #include <cstdlib> 26 #include <locale> 27 28 namespace std _GLIBCXX_VISIBILITY(default) 29 { 30 _GLIBCXX_BEGIN_NAMESPACE_VERSION 31 32 using namespace __gnu_cxx; 33 locale(const char * __s)34 locale::locale(const char* __s) : _M_impl(0) 35 { 36 if (__s) 37 { 38 _S_initialize(); 39 if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0) 40 (_M_impl = _S_classic)->_M_add_reference(); 41 else if (std::strcmp(__s, "") != 0) 42 _M_impl = new _Impl(__s, 1); 43 else 44 { 45 // Get it from the environment. 46 char* __env = std::getenv("LC_ALL"); 47 // If LC_ALL is set we are done. 48 if (__env && std::strcmp(__env, "") != 0) 49 { 50 if (std::strcmp(__env, "C") == 0 51 || std::strcmp(__env, "POSIX") == 0) 52 (_M_impl = _S_classic)->_M_add_reference(); 53 else 54 _M_impl = new _Impl(__env, 1); 55 } 56 else 57 { 58 // LANG may set a default different from "C". 59 string __lang; 60 __env = std::getenv("LANG"); 61 if (!__env || std::strcmp(__env, "") == 0 62 || std::strcmp(__env, "C") == 0 63 || std::strcmp(__env, "POSIX") == 0) 64 __lang = "C"; 65 else 66 __lang = __env; 67 68 // Scan the categories looking for the first one 69 // different from LANG. 70 size_t __i = 0; 71 if (__lang == "C") 72 for (; __i < _S_categories_size; ++__i) 73 { 74 __env = std::getenv(_S_categories[__i]); 75 if (__env && std::strcmp(__env, "") != 0 76 && std::strcmp(__env, "C") != 0 77 && std::strcmp(__env, "POSIX") != 0) 78 break; 79 } 80 else 81 for (; __i < _S_categories_size; ++__i) 82 { 83 __env = std::getenv(_S_categories[__i]); 84 if (__env && std::strcmp(__env, "") != 0 85 && __lang != __env) 86 break; 87 } 88 89 // If one is found, build the complete string of 90 // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on... 91 if (__i < _S_categories_size) 92 { 93 string __str; 94 __str.reserve(128); 95 for (size_t __j = 0; __j < __i; ++__j) 96 { 97 __str += _S_categories[__j]; 98 __str += '='; 99 __str += __lang; 100 __str += ';'; 101 } 102 __str += _S_categories[__i]; 103 __str += '='; 104 __str += __env; 105 __str += ';'; 106 ++__i; 107 for (; __i < _S_categories_size; ++__i) 108 { 109 __env = std::getenv(_S_categories[__i]); 110 __str += _S_categories[__i]; 111 if (!__env || std::strcmp(__env, "") == 0) 112 { 113 __str += '='; 114 __str += __lang; 115 __str += ';'; 116 } 117 else if (std::strcmp(__env, "C") == 0 118 || std::strcmp(__env, "POSIX") == 0) 119 __str += "=C;"; 120 else 121 { 122 __str += '='; 123 __str += __env; 124 __str += ';'; 125 } 126 } 127 __str.erase(__str.end() - 1); 128 _M_impl = new _Impl(__str.c_str(), 1); 129 } 130 // ... otherwise either an additional instance of 131 // the "C" locale or LANG. 132 else if (__lang == "C") 133 (_M_impl = _S_classic)->_M_add_reference(); 134 else 135 _M_impl = new _Impl(__lang.c_str(), 1); 136 } 137 } 138 } 139 else 140 __throw_runtime_error(__N("locale::locale null not valid")); 141 } 142 locale(const locale & __base,const char * __s,category __cat)143 locale::locale(const locale& __base, const char* __s, category __cat) 144 : _M_impl(0) 145 { 146 // NB: There are complicated, yet more efficient ways to do 147 // this. Building up locales on a per-category way is tedious, so 148 // let's do it this way until people complain. 149 locale __add(__s); 150 _M_coalesce(__base, __add, __cat); 151 } 152 locale(const locale & __base,const locale & __add,category __cat)153 locale::locale(const locale& __base, const locale& __add, category __cat) 154 : _M_impl(0) 155 { _M_coalesce(__base, __add, __cat); } 156 157 void _M_coalesce(const locale & __base,const locale & __add,category __cat)158 locale::_M_coalesce(const locale& __base, const locale& __add, 159 category __cat) 160 { 161 __cat = _S_normalize_category(__cat); 162 _M_impl = new _Impl(*__base._M_impl, 1); 163 164 __try 165 { _M_impl->_M_replace_categories(__add._M_impl, __cat); } 166 __catch(...) 167 { 168 _M_impl->_M_remove_reference(); 169 __throw_exception_again; 170 } 171 } 172 173 // Construct named _Impl. 174 locale::_Impl:: _Impl(const char * __s,size_t __refs)175 _Impl(const char* __s, size_t __refs) 176 : _M_refcount(__refs), _M_facets(0), _M_facets_size(_GLIBCXX_NUM_FACETS), 177 _M_caches(0), _M_names(0) 178 { 179 // Initialize the underlying locale model, which also checks to 180 // see if the given name is valid. 181 __c_locale __cloc; 182 locale::facet::_S_create_c_locale(__cloc, __s); 183 __c_locale __clocm = __cloc; 184 185 __try 186 { 187 _M_facets = new const facet*[_M_facets_size]; 188 for (size_t __i = 0; __i < _M_facets_size; ++__i) 189 _M_facets[__i] = 0; 190 _M_caches = new const facet*[_M_facets_size]; 191 for (size_t __j = 0; __j < _M_facets_size; ++__j) 192 _M_caches[__j] = 0; 193 _M_names = new char*[_S_categories_size]; 194 for (size_t __k = 0; __k < _S_categories_size; ++__k) 195 _M_names[__k] = 0; 196 197 // Name the categories. 198 const char* __smon = __s; 199 const size_t __len = std::strlen(__s); 200 if (!std::memchr(__s, ';', __len)) 201 { 202 _M_names[0] = new char[__len + 1]; 203 std::memcpy(_M_names[0], __s, __len + 1); 204 } 205 else 206 { 207 const char* __end = __s; 208 bool __found_ctype = false; 209 bool __found_monetary = false; 210 size_t __ci = 0, __mi = 0; 211 for (size_t __i = 0; __i < _S_categories_size; ++__i) 212 { 213 const char* __beg = std::strchr(__end + 1, '=') + 1; 214 __end = std::strchr(__beg, ';'); 215 if (!__end) 216 __end = __s + __len; 217 _M_names[__i] = new char[__end - __beg + 1]; 218 std::memcpy(_M_names[__i], __beg, __end - __beg); 219 _M_names[__i][__end - __beg] = '\0'; 220 if (!__found_ctype 221 && *(__beg - 2) == 'E' && *(__beg - 3) == 'P') 222 { 223 __found_ctype = true; 224 __ci = __i; 225 } 226 else if (!__found_monetary && *(__beg - 2) == 'Y') 227 { 228 __found_monetary = true; 229 __mi = __i; 230 } 231 } 232 233 if (std::strcmp(_M_names[__ci], _M_names[__mi])) 234 { 235 __smon = _M_names[__mi]; 236 __clocm = locale::facet::_S_lc_ctype_c_locale(__cloc, 237 __smon); 238 } 239 } 240 241 // Construct all standard facets and add them to _M_facets. 242 _M_init_facet(new std::ctype<char>(__cloc, 0, false)); 243 _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc)); 244 _M_init_facet(new numpunct<char>(__cloc)); 245 _M_init_facet(new num_get<char>); 246 _M_init_facet(new num_put<char>); 247 _M_init_facet(new std::collate<char>(__cloc)); 248 _M_init_facet(new moneypunct<char, false>(__cloc, 0)); 249 _M_init_facet(new moneypunct<char, true>(__cloc, 0)); 250 _M_init_facet(new money_get<char>); 251 _M_init_facet(new money_put<char>); 252 _M_init_facet(new __timepunct<char>(__cloc, __s)); 253 _M_init_facet(new time_get<char>); 254 _M_init_facet(new time_put<char>); 255 _M_init_facet(new std::messages<char>(__cloc, __s)); 256 257 #ifdef _GLIBCXX_USE_WCHAR_T 258 _M_init_facet(new std::ctype<wchar_t>(__cloc)); 259 _M_init_facet(new codecvt<wchar_t, char, mbstate_t>(__cloc)); 260 _M_init_facet(new numpunct<wchar_t>(__cloc)); 261 _M_init_facet(new num_get<wchar_t>); 262 _M_init_facet(new num_put<wchar_t>); 263 _M_init_facet(new std::collate<wchar_t>(__cloc)); 264 _M_init_facet(new moneypunct<wchar_t, false>(__clocm, __smon)); 265 _M_init_facet(new moneypunct<wchar_t, true>(__clocm, __smon)); 266 _M_init_facet(new money_get<wchar_t>); 267 _M_init_facet(new money_put<wchar_t>); 268 _M_init_facet(new __timepunct<wchar_t>(__cloc, __s)); 269 _M_init_facet(new time_get<wchar_t>); 270 _M_init_facet(new time_put<wchar_t>); 271 _M_init_facet(new std::messages<wchar_t>(__cloc, __s)); 272 #endif 273 locale::facet::_S_destroy_c_locale(__cloc); 274 if (__clocm != __cloc) 275 locale::facet::_S_destroy_c_locale(__clocm); 276 } 277 __catch(...) 278 { 279 locale::facet::_S_destroy_c_locale(__cloc); 280 if (__clocm != __cloc) 281 locale::facet::_S_destroy_c_locale(__clocm); 282 this->~_Impl(); 283 __throw_exception_again; 284 } 285 } 286 287 void 288 locale::_Impl:: _M_replace_categories(const _Impl * __imp,category __cat)289 _M_replace_categories(const _Impl* __imp, category __cat) 290 { 291 category __mask = 1; 292 if (!_M_names[0] || !__imp->_M_names[0]) 293 { 294 if (_M_names[0]) 295 { 296 delete [] _M_names[0]; 297 _M_names[0] = 0; // Unnamed. 298 } 299 300 for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1) 301 { 302 if (__mask & __cat) 303 // Need to replace entry in _M_facets with other locale's info. 304 _M_replace_category(__imp, _S_facet_categories[__ix]); 305 } 306 } 307 else 308 { 309 if (!_M_names[1]) 310 { 311 // A full set of _M_names must be prepared, all identical 312 // to _M_names[0] to begin with. Then, below, a few will 313 // be replaced by the corresponding __imp->_M_names. I.e., 314 // not a "simple" locale anymore (see locale::operator==). 315 const size_t __len = std::strlen(_M_names[0]) + 1; 316 for (size_t __i = 1; __i < _S_categories_size; ++__i) 317 { 318 _M_names[__i] = new char[__len]; 319 std::memcpy(_M_names[__i], _M_names[0], __len); 320 } 321 } 322 323 for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1) 324 { 325 if (__mask & __cat) 326 { 327 // Need to replace entry in _M_facets with other locale's info. 328 _M_replace_category(__imp, _S_facet_categories[__ix]); 329 330 // FIXME: Hack for libstdc++/29217: the numerical encodings 331 // of the time and collate categories are swapped vs the 332 // order of the names in locale::_S_categories. We'd like to 333 // adjust the former (the latter is dictated by compatibility 334 // with glibc) but we can't for binary compatibility. 335 size_t __ix_name = __ix; 336 if (__ix == 2 || __ix == 3) 337 __ix_name = 5 - __ix; 338 339 char* __src = __imp->_M_names[__ix_name] ? 340 __imp->_M_names[__ix_name] : __imp->_M_names[0]; 341 const size_t __len = std::strlen(__src) + 1; 342 char* __new = new char[__len]; 343 std::memcpy(__new, __src, __len); 344 delete [] _M_names[__ix_name]; 345 _M_names[__ix_name] = __new; 346 } 347 } 348 } 349 } 350 351 _GLIBCXX_END_NAMESPACE_VERSION 352 } // namespace 353