1 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 2 // Free Software Foundation, Inc. 3 // 4 // This file is part of the GNU ISO C++ Library. This library is free 5 // software; you can redistribute it and/or modify it under the 6 // terms of the GNU General Public License as published by the 7 // Free Software Foundation; either version 2, or (at your option) 8 // any later version. 9 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 15 // You should have received a copy of the GNU General Public License along 16 // with this library; see the file COPYING. If not, write to the Free 17 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 18 // USA. 19 20 // As a special exception, you may use this file as part of a free software 21 // library without restriction. Specifically, if other files instantiate 22 // templates or use macros or inline functions from this file, or you compile 23 // this file and link it with other files to produce an executable, this 24 // file does not by itself cause the resulting executable to be covered by 25 // the GNU General Public License. This exception does not however 26 // invalidate any other reasons why the executable file might be covered by 27 // the GNU General Public License. 28 29 #include <clocale> 30 #include <cstring> 31 #include <cstdlib> // For getenv 32 #include <cctype> 33 #include <cwctype> // For towupper, etc. 34 #include <locale> 35 #include <ext/concurrence.h> 36 37 namespace 38 { 39 __gnu_cxx::__mutex locale_cache_mutex; 40 } // anonymous namespace 41 42 // XXX GLIBCXX_ABI Deprecated 43 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 44 # define _GLIBCXX_LOC_ID(mangled) extern std::locale::id mangled 45 _GLIBCXX_LOC_ID (_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 46 _GLIBCXX_LOC_ID (_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 47 _GLIBCXX_LOC_ID (_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 48 _GLIBCXX_LOC_ID (_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 49 # ifdef _GLIBCXX_USE_WCHAR_T 50 _GLIBCXX_LOC_ID (_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 51 _GLIBCXX_LOC_ID (_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 52 _GLIBCXX_LOC_ID (_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 53 _GLIBCXX_LOC_ID (_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 54 # endif 55 #endif 56 57 _GLIBCXX_BEGIN_NAMESPACE(std) 58 59 // Definitions for static const data members of locale. 60 const locale::category locale::none; 61 const locale::category locale::ctype; 62 const locale::category locale::numeric; 63 const locale::category locale::collate; 64 const locale::category locale::time; 65 const locale::category locale::monetary; 66 const locale::category locale::messages; 67 const locale::category locale::all; 68 69 // These are no longer exported. 70 locale::_Impl* locale::_S_classic; 71 locale::_Impl* locale::_S_global; 72 73 #ifdef __GTHREADS 74 __gthread_once_t locale::_S_once = __GTHREAD_ONCE_INIT; 75 #endif 76 77 locale::locale(const locale& __other) throw() 78 : _M_impl(__other._M_impl) 79 { _M_impl->_M_add_reference(); } 80 81 // This is used to initialize global and classic locales, and 82 // assumes that the _Impl objects are constructed correctly. 83 // The lack of a reference increment is intentional. 84 locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 85 { } 86 87 locale::~locale() throw() 88 { _M_impl->_M_remove_reference(); } 89 90 bool 91 locale::operator==(const locale& __rhs) const throw() 92 { 93 // Deal first with the common cases, fast to process: refcopies, 94 // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the 95 // categories same name, i.e., _M_names[0]). Otherwise fall back 96 // to the general locale::name(). 97 bool __ret; 98 if (_M_impl == __rhs._M_impl) 99 __ret = true; 100 else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] 101 || std::strcmp(_M_impl->_M_names[0], 102 __rhs._M_impl->_M_names[0]) != 0) 103 __ret = false; 104 else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) 105 __ret = true; 106 else 107 __ret = this->name() == __rhs.name(); 108 return __ret; 109 } 110 111 const locale& 112 locale::operator=(const locale& __other) throw() 113 { 114 __other._M_impl->_M_add_reference(); 115 _M_impl->_M_remove_reference(); 116 _M_impl = __other._M_impl; 117 return *this; 118 } 119 120 string 121 locale::name() const 122 { 123 string __ret; 124 if (!_M_impl->_M_names[0]) 125 __ret = '*'; 126 else if (_M_impl->_M_check_same_name()) 127 __ret = _M_impl->_M_names[0]; 128 else 129 { 130 __ret.reserve(128); 131 __ret += _S_categories[0]; 132 __ret += '='; 133 __ret += _M_impl->_M_names[0]; 134 for (size_t __i = 1; __i < _S_categories_size; ++__i) 135 { 136 __ret += ';'; 137 __ret += _S_categories[__i]; 138 __ret += '='; 139 __ret += _M_impl->_M_names[__i]; 140 } 141 } 142 return __ret; 143 } 144 145 locale::category 146 locale::_S_normalize_category(category __cat) 147 { 148 int __ret = 0; 149 if (__cat == none || (__cat & all) && !(__cat & ~all)) 150 __ret = __cat; 151 else 152 { 153 // NB: May be a C-style "LC_ALL" category; convert. 154 switch (__cat) 155 { 156 case LC_COLLATE: 157 __ret = collate; 158 break; 159 case LC_CTYPE: 160 __ret = ctype; 161 break; 162 case LC_MONETARY: 163 __ret = monetary; 164 break; 165 case LC_NUMERIC: 166 __ret = numeric; 167 break; 168 case LC_TIME: 169 __ret = time; 170 break; 171 #ifdef _GLIBCXX_HAVE_LC_MESSAGES 172 case LC_MESSAGES: 173 __ret = messages; 174 break; 175 #endif 176 case LC_ALL: 177 __ret = all; 178 break; 179 default: 180 __throw_runtime_error(__N("locale::_S_normalize_category " 181 "category not found")); 182 } 183 } 184 return __ret; 185 } 186 187 // locale::facet 188 __c_locale locale::facet::_S_c_locale; 189 190 const char locale::facet::_S_c_name[2] = "C"; 191 192 #ifdef __GTHREADS 193 __gthread_once_t locale::facet::_S_once = __GTHREAD_ONCE_INIT; 194 #endif 195 196 void 197 locale::facet::_S_initialize_once() 198 { 199 // Initialize the underlying locale model. 200 _S_create_c_locale(_S_c_locale, _S_c_name); 201 } 202 203 __c_locale 204 locale::facet::_S_get_c_locale() 205 { 206 #ifdef __GHTREADS 207 if (__gthread_active_p()) 208 __gthread_once(&_S_once, _S_initialize_once); 209 else 210 #endif 211 { 212 if (!_S_c_locale) 213 _S_initialize_once(); 214 } 215 return _S_c_locale; 216 } 217 218 const char* 219 locale::facet::_S_get_c_name() 220 { return _S_c_name; } 221 222 locale::facet:: 223 ~facet() { } 224 225 // locale::_Impl 226 locale::_Impl:: 227 ~_Impl() throw() 228 { 229 if (_M_facets) 230 for (size_t __i = 0; __i < _M_facets_size; ++__i) 231 if (_M_facets[__i]) 232 _M_facets[__i]->_M_remove_reference(); 233 delete [] _M_facets; 234 235 if (_M_caches) 236 for (size_t __i = 0; __i < _M_facets_size; ++__i) 237 if (_M_caches[__i]) 238 _M_caches[__i]->_M_remove_reference(); 239 delete [] _M_caches; 240 241 if (_M_names) 242 for (size_t __i = 0; __i < _S_categories_size; ++__i) 243 delete [] _M_names[__i]; 244 delete [] _M_names; 245 } 246 247 // Clone existing _Impl object. 248 locale::_Impl:: 249 _Impl(const _Impl& __imp, size_t __refs) 250 : _M_refcount(__refs), _M_facets(0), _M_facets_size(__imp._M_facets_size), 251 _M_caches(0), _M_names(0) 252 { 253 try 254 { 255 _M_facets = new const facet*[_M_facets_size]; 256 for (size_t __i = 0; __i < _M_facets_size; ++__i) 257 { 258 _M_facets[__i] = __imp._M_facets[__i]; 259 if (_M_facets[__i]) 260 _M_facets[__i]->_M_add_reference(); 261 } 262 _M_caches = new const facet*[_M_facets_size]; 263 for (size_t __j = 0; __j < _M_facets_size; ++__j) 264 { 265 _M_caches[__j] = __imp._M_caches[__j]; 266 if (_M_caches[__j]) 267 _M_caches[__j]->_M_add_reference(); 268 } 269 _M_names = new char*[_S_categories_size]; 270 for (size_t __k = 0; __k < _S_categories_size; ++__k) 271 _M_names[__k] = 0; 272 273 // Name the categories. 274 for (size_t __l = 0; (__l < _S_categories_size 275 && __imp._M_names[__l]); ++__l) 276 { 277 const size_t __len = std::strlen(__imp._M_names[__l]) + 1; 278 _M_names[__l] = new char[__len]; 279 std::memcpy(_M_names[__l], __imp._M_names[__l], __len); 280 } 281 } 282 catch(...) 283 { 284 this->~_Impl(); 285 __throw_exception_again; 286 } 287 } 288 289 void 290 locale::_Impl:: 291 _M_replace_category(const _Impl* __imp, 292 const locale::id* const* __idpp) 293 { 294 for (; *__idpp; ++__idpp) 295 _M_replace_facet(__imp, *__idpp); 296 } 297 298 void 299 locale::_Impl:: 300 _M_replace_facet(const _Impl* __imp, const locale::id* __idp) 301 { 302 size_t __index = __idp->_M_id(); 303 if ((__index > (__imp->_M_facets_size - 1)) 304 || !__imp->_M_facets[__index]) 305 __throw_runtime_error(__N("locale::_Impl::_M_replace_facet")); 306 _M_install_facet(__idp, __imp->_M_facets[__index]); 307 } 308 309 void 310 locale::_Impl:: 311 _M_install_facet(const locale::id* __idp, const facet* __fp) 312 { 313 if (__fp) 314 { 315 size_t __index = __idp->_M_id(); 316 317 // Check size of facet vector to ensure adequate room. 318 if (__index > _M_facets_size - 1) 319 { 320 const size_t __new_size = __index + 4; 321 322 // New facet array. 323 const facet** __oldf = _M_facets; 324 const facet** __newf; 325 __newf = new const facet*[__new_size]; 326 for (size_t __i = 0; __i < _M_facets_size; ++__i) 327 __newf[__i] = _M_facets[__i]; 328 for (size_t __l = _M_facets_size; __l < __new_size; ++__l) 329 __newf[__l] = 0; 330 331 // New cache array. 332 const facet** __oldc = _M_caches; 333 const facet** __newc; 334 try 335 { 336 __newc = new const facet*[__new_size]; 337 } 338 catch(...) 339 { 340 delete [] __newf; 341 __throw_exception_again; 342 } 343 for (size_t __j = 0; __j < _M_facets_size; ++__j) 344 __newc[__j] = _M_caches[__j]; 345 for (size_t __k = _M_facets_size; __k < __new_size; ++__k) 346 __newc[__k] = 0; 347 348 _M_facets_size = __new_size; 349 _M_facets = __newf; 350 _M_caches = __newc; 351 delete [] __oldf; 352 delete [] __oldc; 353 } 354 355 __fp->_M_add_reference(); 356 const facet*& __fpr = _M_facets[__index]; 357 if (__fpr) 358 { 359 // Replacing an existing facet. Order matters. 360 __fpr->_M_remove_reference(); 361 __fpr = __fp; 362 } 363 else 364 { 365 // Installing a newly created facet into an empty 366 // _M_facets container, say a newly-constructed, 367 // swanky-fresh _Impl. 368 _M_facets[__index] = __fp; 369 } 370 371 // Ideally, it would be nice to only remove the caches that 372 // are now incorrect. However, some of the caches depend on 373 // multiple facets, and we only know about one facet 374 // here. It's no great loss: the first use of the new facet 375 // will create a new, correctly cached facet anyway. 376 for (size_t __i = 0; __i < _M_facets_size; ++__i) 377 { 378 const facet* __cpr = _M_caches[__i]; 379 if (__cpr) 380 { 381 __cpr->_M_remove_reference(); 382 _M_caches[__i] = 0; 383 } 384 } 385 } 386 } 387 388 void 389 locale::_Impl:: 390 _M_install_cache(const facet* __cache, size_t __index) 391 { 392 __gnu_cxx::__scoped_lock sentry(locale_cache_mutex); 393 if (_M_caches[__index] != 0) 394 { 395 // Some other thread got in first. 396 delete __cache; 397 } 398 else 399 { 400 __cache->_M_add_reference(); 401 _M_caches[__index] = __cache; 402 } 403 } 404 405 // locale::id 406 // Definitions for static const data members of locale::id 407 _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker 408 409 size_t 410 locale::id::_M_id() const 411 { 412 if (!_M_index) 413 { 414 // XXX GLIBCXX_ABI Deprecated 415 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT 416 locale::id *f = 0; 417 # define _GLIBCXX_SYNC_ID(facet, mangled) \ 418 if (this == &::mangled) \ 419 f = &facet::id 420 _GLIBCXX_SYNC_ID (num_get<char>, _ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 421 _GLIBCXX_SYNC_ID (num_put<char>, _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 422 _GLIBCXX_SYNC_ID (money_get<char>, _ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE2idE); 423 _GLIBCXX_SYNC_ID (money_put<char>, _ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE); 424 # ifdef _GLIBCXX_USE_WCHAR_T 425 _GLIBCXX_SYNC_ID (num_get<wchar_t>, _ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 426 _GLIBCXX_SYNC_ID (num_put<wchar_t>, _ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 427 _GLIBCXX_SYNC_ID (money_get<wchar_t>, _ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE2idE); 428 _GLIBCXX_SYNC_ID (money_put<wchar_t>, _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE); 429 # endif 430 if (f) 431 _M_index = 1 + f->_M_id(); 432 else 433 #endif 434 _M_index = 1 + __gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 435 1); 436 } 437 return _M_index - 1; 438 } 439 440 _GLIBCXX_END_NAMESPACE 441