locale.cc revision 107606
1// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <cassert> 32#include <cctype> 33#include <cwctype> // For towupper, etc. 34#include <locale> 35#include <bits/atomicity.h> 36 37namespace __gnu_cxx 38{ 39 // Defined in globals.cc. 40 extern std::locale c_locale; 41 extern std::locale::_Impl c_locale_impl; 42} // namespace __gnu_cxx 43 44namespace std 45{ 46 using namespace __gnu_cxx; 47 48 // Definitions for static const data members of locale. 49 const locale::category locale::none; 50 const locale::category locale::ctype; 51 const locale::category locale::numeric; 52 const locale::category locale::collate; 53 const locale::category locale::time; 54 const locale::category locale::monetary; 55 const locale::category locale::messages; 56 const locale::category locale::all; 57 58 // In the future, GLIBCXX_ABI > 5 should remove all uses of 59 // _GLIBCPP_ASM_SYMVER in this file, and remove exports of any 60 // static data members of locale. 61 locale::_Impl* locale::_S_classic; 62 locale::_Impl* locale::_S_global; 63 const size_t locale::_S_categories_size; 64 _GLIBCPP_ASM_SYMVER(_ZNSt6locale18_S_categories_sizeE, _ZNSt6locale17_S_num_categoriesE, GLIBCPP_3.2) 65 const size_t locale::_S_extra_categories_size; 66 67 // Definitions for static const data members of locale::id 68 _Atomic_word locale::id::_S_highwater; // init'd to 0 by linker 69 70 // Definitions for static const data members of locale::_Impl 71 const locale::id* const 72 locale::_Impl::_S_id_ctype[] = 73 { 74 &std::ctype<char>::id, 75 &codecvt<char, char, mbstate_t>::id, 76#ifdef _GLIBCPP_USE_WCHAR_T 77 &std::ctype<wchar_t>::id, 78 &codecvt<wchar_t, char, mbstate_t>::id, 79#endif 80 0 81 }; 82 83 const locale::id* const 84 locale::_Impl::_S_id_numeric[] = 85 { 86 &num_get<char>::id, 87 &num_put<char>::id, 88 &numpunct<char>::id, 89#ifdef _GLIBCPP_USE_WCHAR_T 90 &num_get<wchar_t>::id, 91 &num_put<wchar_t>::id, 92 &numpunct<wchar_t>::id, 93#endif 94 0 95 }; 96 97 const locale::id* const 98 locale::_Impl::_S_id_collate[] = 99 { 100 &std::collate<char>::id, 101#ifdef _GLIBCPP_USE_WCHAR_T 102 &std::collate<wchar_t>::id, 103#endif 104 0 105 }; 106 107 const locale::id* const 108 locale::_Impl::_S_id_time[] = 109 { 110 &__timepunct<char>::id, 111 &time_get<char>::id, 112 &time_put<char>::id, 113#ifdef _GLIBCPP_USE_WCHAR_T 114 &__timepunct<wchar_t>::id, 115 &time_get<wchar_t>::id, 116 &time_put<wchar_t>::id, 117#endif 118 0 119 }; 120 121 const locale::id* const 122 locale::_Impl::_S_id_monetary[] = 123 { 124 &money_get<char>::id, 125 &money_put<char>::id, 126 &moneypunct<char, false>::id, 127 &moneypunct<char, true >::id, 128#ifdef _GLIBCPP_USE_WCHAR_T 129 &money_get<wchar_t>::id, 130 &money_put<wchar_t>::id, 131 &moneypunct<wchar_t, false>::id, 132 &moneypunct<wchar_t, true >::id, 133#endif 134 0 135 }; 136 137 const locale::id* const 138 locale::_Impl::_S_id_messages[] = 139 { 140 &std::messages<char>::id, 141#ifdef _GLIBCPP_USE_WCHAR_T 142 &std::messages<wchar_t>::id, 143#endif 144 0 145 }; 146 147 const locale::id* const* const 148 locale::_Impl::_S_facet_categories[] = 149 { 150 // Order must match the decl order in class locale. 151 locale::_Impl::_S_id_ctype, 152 locale::_Impl::_S_id_numeric, 153 locale::_Impl::_S_id_collate, 154 locale::_Impl::_S_id_time, 155 locale::_Impl::_S_id_monetary, 156 locale::_Impl::_S_id_messages, 157 0 158 }; 159 160 locale::locale() throw() 161 { 162 _S_initialize(); 163 (_M_impl = _S_global)->_M_add_reference(); 164 } 165 166 locale::locale(const locale& __other) throw() 167 { (_M_impl = __other._M_impl)->_M_add_reference(); } 168 169 // This is used to initialize global and classic locales, and 170 // assumes that the _Impl objects are constructed correctly. 171 // The lack of a reference increment is intentional. 172 locale::locale(_Impl* __ip) throw() : _M_impl(__ip) 173 { } 174 175 locale::locale(const char* __s) 176 { 177 if (__s) 178 { 179 _S_initialize(); 180 if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0) 181 (_M_impl = _S_classic)->_M_add_reference(); 182 else if (strcmp(__s, "") != 0) 183 _M_impl = new _Impl(__s, 1); 184 else 185 { 186 // Get it from the environment. 187 char* __env = getenv("LC_ALL"); 188 // If LC_ALL is set we are done. 189 if (__env && strcmp(__env, "") != 0) 190 { 191 if (strcmp(__env, "C") == 0 || strcmp(__env, "POSIX") == 0) 192 (_M_impl = _S_classic)->_M_add_reference(); 193 else 194 _M_impl = new _Impl(__env, 1); 195 } 196 else 197 { 198 char* __res; 199 // LANG may set a default different from "C". 200 char* __env = getenv("LANG"); 201 if (!__env || strcmp(__env, "") == 0 || strcmp(__env, "C") == 0 202 || strcmp(__env, "POSIX") == 0) 203 __res = strdup("C"); 204 else 205 __res = strdup(__env); 206 207 // Scan the categories looking for the first one 208 // different from LANG. 209 size_t __i = 0; 210 if (strcmp(__res, "C") == 0) 211 for (__i = 0; 212 __i < _S_categories_size + _S_extra_categories_size; 213 ++__i) 214 { 215 __env = getenv(_S_categories[__i]); 216 if (__env && strcmp(__env, "") != 0 217 && strcmp(__env, "C") != 0 218 && strcmp(__env, "POSIX") != 0) 219 break; 220 } 221 else 222 for (__i = 0; 223 __i < _S_categories_size + _S_extra_categories_size; 224 ++__i) 225 { 226 __env = getenv(_S_categories[__i]); 227 if (__env && strcmp(__env, "") != 0 228 && strcmp(__env, __res) != 0) 229 break; 230 } 231 232 // If one is found, build the complete string of 233 // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on... 234 if (__i < _S_categories_size + _S_extra_categories_size) 235 { 236 string __str; 237 for (size_t __j = 0; __j < __i; ++__j) 238 { 239 __str += _S_categories[__j]; 240 __str += "="; 241 __str += __res; 242 __str += ";"; 243 } 244 __str += _S_categories[__i]; 245 __str += "="; 246 __str += __env; 247 __str += ";"; 248 __i++; 249 for (; __i < _S_categories_size 250 + _S_extra_categories_size; ++__i) 251 { 252 __env = getenv(_S_categories[__i]); 253 if (!__env || strcmp(__env, "") == 0) 254 { 255 __str += _S_categories[__i]; 256 __str += '='; 257 __str += __res; 258 __str += ';'; 259 } 260 else if (strcmp(__env, "C") == 0 261 || strcmp(__env, "POSIX") == 0) 262 { 263 __str += _S_categories[__i]; 264 __str += "=C;"; 265 } 266 else 267 { 268 __str += _S_categories[__i]; 269 __str += "="; 270 __str += __env; 271 __str += ";"; 272 } 273 } 274 __str.erase(__str.end() - 1); 275 _M_impl = new _Impl(__str.c_str(), 1); 276 } 277 // ... otherwise either an additional instance of 278 // the "C" locale or LANG. 279 else if (strcmp(__res, "C") == 0) 280 (_M_impl = _S_classic)->_M_add_reference(); 281 else 282 _M_impl = new _Impl(__res, 1); 283 free(__res); 284 } 285 } 286 } 287 else 288 __throw_runtime_error("attempt to create locale from NULL name"); 289 } 290 291 locale::locale(const locale& __base, const char* __s, category __cat) 292 { 293 // NB: There are complicated, yet more efficient ways to do 294 // this. Building up locales on a per-category way is tedious, so 295 // let's do it this way until people complain. 296 locale __add(__s); 297 _M_coalesce(__base, __add, __cat); 298 } 299 300 locale::locale(const locale& __base, const locale& __add, category __cat) 301 { _M_coalesce(__base, __add, __cat); } 302 303 locale::~locale() throw() 304 { _M_impl->_M_remove_reference(); } 305 306 bool 307 locale::operator==(const locale& __rhs) const throw() 308 { 309 string __name = this->name(); 310 return (_M_impl == __rhs._M_impl 311 || (__name != "*" && __name == __rhs.name())); 312 } 313 314 const locale& 315 locale::operator=(const locale& __other) throw() 316 { 317 __other._M_impl->_M_add_reference(); 318 _M_impl->_M_remove_reference(); 319 _M_impl = __other._M_impl; 320 return *this; 321 } 322 323 locale 324 locale::global(const locale& __other) 325 { 326 // XXX MT 327 _S_initialize(); 328 _Impl* __old = _S_global; 329 __other._M_impl->_M_add_reference(); 330 _S_global = __other._M_impl; 331 if (_S_global->_M_check_same_name() 332 && (strcmp(_S_global->_M_names[0], "*") != 0)) 333 setlocale(LC_ALL, __other.name().c_str()); 334 335 // Reference count sanity check: one reference removed for the 336 // subsition of __other locale, one added by return-by-value. Net 337 // difference: zero. When the returned locale object's destrutor 338 // is called, then the reference count is decremented and possibly 339 // destroyed. 340 return locale(__old); 341 } 342 343 string 344 locale::name() const 345 { 346 string __ret; 347 if (_M_impl->_M_check_same_name()) 348 __ret = _M_impl->_M_names[0]; 349 else 350 { 351 __ret += _S_categories[0]; 352 __ret += "="; 353 __ret += _M_impl->_M_names[0]; 354 for (size_t __i = 1; 355 __i < _S_categories_size + _S_extra_categories_size; 356 ++__i) 357 { 358 __ret += ";"; 359 __ret += _S_categories[__i]; 360 __ret += "="; 361 __ret += _M_impl->_M_names[__i]; 362 } 363 } 364 return __ret; 365 } 366 367 const locale& 368 locale::classic() 369 { 370 static _STL_mutex_lock __lock __STL_MUTEX_INITIALIZER; 371 _STL_auto_lock __auto(__lock); 372 373 if (!_S_classic) 374 { 375 try 376 { 377 // 26 Standard facets, 2 references. 378 // One reference for _S_classic, one for _S_global 379 _S_classic = new (&c_locale_impl) _Impl(0, 2, true); 380 _S_global = _S_classic; 381 new (&c_locale) locale(_S_classic); 382 } 383 catch(...) 384 { 385 // Just call destructor, so that locale_impl_c's memory is 386 // not deallocated via a call to delete. 387 if (_S_classic) 388 _S_classic->~_Impl(); 389 _S_classic = _S_global = 0; 390 __throw_exception_again; 391 } 392 } 393 return c_locale; 394 } 395 396 void 397 locale::_M_coalesce(const locale& __base, const locale& __add, 398 category __cat) 399 { 400 __cat = _S_normalize_category(__cat); 401 _M_impl = new _Impl(*__base._M_impl, 1); 402 403 try 404 { _M_impl->_M_replace_categories(__add._M_impl, __cat); } 405 catch (...) 406 { 407 _M_impl->_M_remove_reference(); 408 __throw_exception_again; 409 } 410 } 411 412 locale::category 413 locale::_S_normalize_category(category __cat) 414 { 415 int __ret = 0; 416 if (__cat == none || (__cat & all) && !(__cat & ~all)) 417 __ret = __cat; 418 else 419 { 420 // NB: May be a C-style "LC_ALL" category; convert. 421 switch (__cat) 422 { 423 case LC_COLLATE: 424 __ret = collate; 425 break; 426 case LC_CTYPE: 427 __ret = ctype; 428 break; 429 case LC_MONETARY: 430 __ret = monetary; 431 break; 432 case LC_NUMERIC: 433 __ret = numeric; 434 break; 435 case LC_TIME: 436 __ret = time; 437 break; 438#ifdef _GLIBCPP_HAVE_LC_MESSAGES 439 case LC_MESSAGES: 440 __ret = messages; 441 break; 442#endif 443 case LC_ALL: 444 __ret = all; 445 break; 446 default: 447 __throw_runtime_error("bad locale category"); 448 } 449 } 450 return __ret; 451 } 452 453 __c_locale 454 locale::facet::_S_c_locale; 455 456 locale::facet:: 457 ~facet() { } 458 459 locale::facet:: 460 facet(size_t __refs) throw() : _M_references(__refs ? 1 : 0) 461 { } 462 463 void 464 locale::facet:: 465 _M_add_reference() throw() 466 { __atomic_add(&_M_references, 1); } 467 468 void 469 locale::facet:: 470 _M_remove_reference() throw() 471 { 472 if (__exchange_and_add(&_M_references, -1) == 1) 473 { 474 try 475 { delete this; } 476 catch (...) 477 { } 478 } 479 } 480 481 locale::id::id() 482 { } 483 484 // Definitions for static const data members of time_base 485 template<> 486 const char* 487 __timepunct<char>::_S_timezones[14] = 488 { 489 "GMT", "HST", "AKST", "PST", "MST", "CST", "EST", "AST", "NST", "CET", 490 "IST", "EET", "CST", "JST" 491 }; 492 493#ifdef _GLIBCPP_USE_WCHAR_T 494 template<> 495 const wchar_t* 496 __timepunct<wchar_t>::_S_timezones[14] = 497 { 498 L"GMT", L"HST", L"AKST", L"PST", L"MST", L"CST", L"EST", L"AST", 499 L"NST", L"CET", L"IST", L"EET", L"CST", L"JST" 500 }; 501#endif 502 503 // Definitions for static const data members of money_base 504 const money_base::pattern 505 money_base::_S_default_pattern = { {symbol, sign, none, value} }; 506 507 const char __num_base::_S_atoms[] = "0123456789eEabcdfABCDF"; 508 509 bool 510 __num_base::_S_format_float(const ios_base& __io, char* __fptr, char __mod, 511 streamsize __prec) 512 { 513 bool __incl_prec = false; 514 ios_base::fmtflags __flags = __io.flags(); 515 *__fptr++ = '%'; 516 // [22.2.2.2.2] Table 60 517 if (__flags & ios_base::showpos) 518 *__fptr++ = '+'; 519 if (__flags & ios_base::showpoint) 520 *__fptr++ = '#'; 521 // As per [22.2.2.2.2.11] 522 if (__flags & ios_base::fixed || __prec > 0) 523 { 524 *__fptr++ = '.'; 525 *__fptr++ = '*'; 526 __incl_prec = true; 527 } 528 if (__mod) 529 *__fptr++ = __mod; 530 ios_base::fmtflags __fltfield = __flags & ios_base::floatfield; 531 // [22.2.2.2.2] Table 58 532 if (__fltfield == ios_base::fixed) 533 *__fptr++ = 'f'; 534 else if (__fltfield == ios_base::scientific) 535 *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e'; 536 else 537 *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g'; 538 *__fptr = '\0'; 539 return __incl_prec; 540 } 541 542 void 543 __num_base::_S_format_int(const ios_base& __io, char* __fptr, char __mod, 544 char __modl) 545 { 546 ios_base::fmtflags __flags = __io.flags(); 547 *__fptr++ = '%'; 548 // [22.2.2.2.2] Table 60 549 if (__flags & ios_base::showpos) 550 *__fptr++ = '+'; 551 if (__flags & ios_base::showbase) 552 *__fptr++ = '#'; 553 *__fptr++ = 'l'; 554 555 // For long long types. 556 if (__modl) 557 *__fptr++ = __modl; 558 559 ios_base::fmtflags __bsefield = __flags & ios_base::basefield; 560 if (__bsefield == ios_base::hex) 561 *__fptr++ = (__flags & ios_base::uppercase) ? 'X' : 'x'; 562 else if (__bsefield == ios_base::oct) 563 *__fptr++ = 'o'; 564 else 565 *__fptr++ = __mod; 566 *__fptr = '\0'; 567 } 568} // namespace std 569 570