1 // std::moneypunct implementation details, GNU version -*- C++ -*- 2 3 // Copyright (C) 2001, 2002, 2004 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 2, 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 // You should have received a copy of the GNU General Public License along 17 // with this library; see the file COPYING. If not, write to the Free 18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 // USA. 20 21 // As a special exception, you may use this file as part of a free software 22 // library without restriction. Specifically, if other files instantiate 23 // templates or use macros or inline functions from this file, or you compile 24 // this file and link it with other files to produce an executable, this 25 // file does not by itself cause the resulting executable to be covered by 26 // the GNU General Public License. This exception does not however 27 // invalidate any other reasons why the executable file might be covered by 28 // the GNU General Public License. 29 30 // 31 // ISO C++ 14882: 22.2.6.3.2 moneypunct virtual functions 32 // 33 34 // Written by Benjamin Kosnik <bkoz@redhat.com> 35 36 #include <locale> 37 #include <bits/c++locale_internal.h> 38 39 namespace std 40 { 41 // Construct and return valid pattern consisting of some combination of: 42 // space none symbol sign value 43 money_base::pattern _S_construct_pattern(char __precedes,char __space,char __posn)44 money_base::_S_construct_pattern(char __precedes, char __space, char __posn) 45 { 46 pattern __ret; 47 48 // This insanely complicated routine attempts to construct a valid 49 // pattern for use with monyepunct. A couple of invariants: 50 51 // if (__precedes) symbol -> value 52 // else value -> symbol 53 54 // if (__space) space 55 // else none 56 57 // none == never first 58 // space never first or last 59 60 // Any elegant implementations of this are welcome. 61 switch (__posn) 62 { 63 case 0: 64 case 1: 65 // 1 The sign precedes the value and symbol. 66 if (__space) 67 { 68 // Pattern starts with sign. 69 if (__precedes) 70 { 71 __ret.field[1] = symbol; 72 __ret.field[2] = space; 73 __ret.field[3] = value; 74 } 75 else 76 { 77 __ret.field[1] = value; 78 __ret.field[2] = space; 79 __ret.field[3] = symbol; 80 } 81 __ret.field[0] = sign; 82 } 83 else 84 { 85 // Pattern starts with sign and ends with none. 86 if (__precedes) 87 { 88 __ret.field[1] = symbol; 89 __ret.field[2] = value; 90 } 91 else 92 { 93 __ret.field[1] = value; 94 __ret.field[2] = symbol; 95 } 96 __ret.field[0] = sign; 97 __ret.field[3] = none; 98 } 99 break; 100 case 2: 101 // 2 The sign follows the value and symbol. 102 if (__space) 103 { 104 // Pattern either ends with sign. 105 if (__precedes) 106 { 107 __ret.field[0] = symbol; 108 __ret.field[1] = space; 109 __ret.field[2] = value; 110 } 111 else 112 { 113 __ret.field[0] = value; 114 __ret.field[1] = space; 115 __ret.field[2] = symbol; 116 } 117 __ret.field[3] = sign; 118 } 119 else 120 { 121 // Pattern ends with sign then none. 122 if (__precedes) 123 { 124 __ret.field[0] = symbol; 125 __ret.field[1] = value; 126 } 127 else 128 { 129 __ret.field[0] = value; 130 __ret.field[1] = symbol; 131 } 132 __ret.field[2] = sign; 133 __ret.field[3] = none; 134 } 135 break; 136 case 3: 137 // 3 The sign immediately precedes the symbol. 138 if (__space) 139 { 140 // Have space. 141 if (__precedes) 142 { 143 __ret.field[0] = sign; 144 __ret.field[1] = symbol; 145 __ret.field[2] = space; 146 __ret.field[3] = value; 147 } 148 else 149 { 150 __ret.field[0] = value; 151 __ret.field[1] = space; 152 __ret.field[2] = sign; 153 __ret.field[3] = symbol; 154 } 155 } 156 else 157 { 158 // Have none. 159 if (__precedes) 160 { 161 __ret.field[0] = sign; 162 __ret.field[1] = symbol; 163 __ret.field[2] = value; 164 } 165 else 166 { 167 __ret.field[0] = value; 168 __ret.field[1] = sign; 169 __ret.field[2] = symbol; 170 } 171 __ret.field[3] = none; 172 } 173 break; 174 case 4: 175 // 4 The sign immediately follows the symbol. 176 if (__space) 177 { 178 // Have space. 179 if (__precedes) 180 { 181 __ret.field[0] = symbol; 182 __ret.field[1] = sign; 183 __ret.field[2] = space; 184 __ret.field[3] = value; 185 } 186 else 187 { 188 __ret.field[0] = value; 189 __ret.field[1] = space; 190 __ret.field[2] = symbol; 191 __ret.field[3] = sign; 192 } 193 } 194 else 195 { 196 // Have none. 197 if (__precedes) 198 { 199 __ret.field[0] = symbol; 200 __ret.field[1] = sign; 201 __ret.field[2] = value; 202 } 203 else 204 { 205 __ret.field[0] = value; 206 __ret.field[1] = symbol; 207 __ret.field[2] = sign; 208 } 209 __ret.field[3] = none; 210 } 211 break; 212 default: 213 ; 214 } 215 return __ret; 216 } 217 218 template<> 219 void _M_initialize_moneypunct(__c_locale __cloc,const char *)220 moneypunct<char, true>::_M_initialize_moneypunct(__c_locale __cloc, 221 const char*) 222 { 223 if (!__cloc) 224 { 225 // "C" locale 226 _M_decimal_point = '.'; 227 _M_thousands_sep = ','; 228 _M_grouping = ""; 229 _M_curr_symbol = ""; 230 _M_positive_sign = ""; 231 _M_negative_sign = ""; 232 _M_frac_digits = 0; 233 _M_pos_format = money_base::_S_default_pattern; 234 _M_neg_format = money_base::_S_default_pattern; 235 } 236 else 237 { 238 // Named locale. 239 _M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT, __cloc)); 240 _M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP, __cloc)); 241 _M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc); 242 _M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); 243 244 char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc)); 245 if (!__nposn) 246 _M_negative_sign = "()"; 247 else 248 _M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); 249 250 // _Intl == true 251 _M_curr_symbol = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc); 252 _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc)); 253 char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc)); 254 char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc)); 255 char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc)); 256 _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn); 257 char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc)); 258 char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc)); 259 _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn); 260 } 261 } 262 263 template<> 264 void _M_initialize_moneypunct(__c_locale __cloc,const char *)265 moneypunct<char, false>::_M_initialize_moneypunct(__c_locale __cloc, 266 const char*) 267 { 268 if (!__cloc) 269 { 270 // "C" locale 271 _M_decimal_point = '.'; 272 _M_thousands_sep = ','; 273 _M_grouping = ""; 274 _M_curr_symbol = ""; 275 _M_positive_sign = ""; 276 _M_negative_sign = ""; 277 _M_frac_digits = 0; 278 _M_pos_format = money_base::_S_default_pattern; 279 _M_neg_format = money_base::_S_default_pattern; 280 } 281 else 282 { 283 // Named locale. 284 _M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT, __cloc)); 285 _M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP, __cloc)); 286 _M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc); 287 _M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); 288 289 char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc)); 290 if (!__nposn) 291 _M_negative_sign = "()"; 292 else 293 _M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); 294 295 // _Intl == false 296 _M_curr_symbol = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc); 297 _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc)); 298 char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc)); 299 char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc)); 300 char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc)); 301 _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn); 302 char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc)); 303 char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc)); 304 _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn); 305 } 306 } 307 308 template<> ~moneypunct()309 moneypunct<char, true>::~moneypunct() 310 { } 311 312 template<> ~moneypunct()313 moneypunct<char, false>::~moneypunct() 314 { } 315 316 #ifdef _GLIBCPP_USE_WCHAR_T 317 template<> 318 void _M_initialize_moneypunct(__c_locale __cloc,const char *)319 moneypunct<wchar_t, true>::_M_initialize_moneypunct(__c_locale __cloc, 320 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 321 const char*) 322 #else 323 const char* __name) 324 #endif 325 { 326 if (!__cloc) 327 { 328 // "C" locale 329 _M_decimal_point = L'.'; 330 _M_thousands_sep = L','; 331 _M_grouping = ""; 332 _M_curr_symbol = L""; 333 _M_positive_sign = L""; 334 _M_negative_sign = L""; 335 _M_frac_digits = 0; 336 _M_pos_format = money_base::_S_default_pattern; 337 _M_neg_format = money_base::_S_default_pattern; 338 } 339 else 340 { 341 // Named locale. 342 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 343 __c_locale __old = __uselocale(__cloc); 344 #else 345 // Switch to named locale so that mbsrtowcs will work. 346 char* __old = strdup(setlocale(LC_ALL, NULL)); 347 setlocale(LC_ALL, __name); 348 #endif 349 350 _M_decimal_point = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc)}).__w); 351 352 _M_thousands_sep = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc)}).__w); 353 _M_grouping = __nl_langinfo_l(GROUPING, __cloc); 354 355 const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); 356 const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); 357 const char* __ccurr = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc); 358 359 wchar_t* __wcs_ps = 0; 360 wchar_t* __wcs_ns = 0; 361 char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc)); 362 try 363 { 364 mbstate_t __state; 365 size_t __len = strlen(__cpossign); 366 if (__len) 367 { 368 ++__len; 369 memset(&__state, 0, sizeof(mbstate_t)); 370 __wcs_ps = new wchar_t[__len]; 371 mbsrtowcs(__wcs_ps, &__cpossign, __len, &__state); 372 _M_positive_sign = __wcs_ps; 373 } 374 else 375 _M_positive_sign = L""; 376 377 __len = strlen(__cnegsign); 378 if (!__nposn) 379 _M_negative_sign = L"()"; 380 else if (__len) 381 { 382 ++__len; 383 memset(&__state, 0, sizeof(mbstate_t)); 384 __wcs_ns = new wchar_t[__len]; 385 mbsrtowcs(__wcs_ns, &__cnegsign, __len, &__state); 386 _M_negative_sign = __wcs_ns; 387 } 388 else 389 _M_negative_sign = L""; 390 391 // _Intl == true. 392 __len = strlen(__ccurr); 393 if (__len) 394 { 395 ++__len; 396 memset(&__state, 0, sizeof(mbstate_t)); 397 wchar_t* __wcs = new wchar_t[__len]; 398 mbsrtowcs(__wcs, &__ccurr, __len, &__state); 399 _M_curr_symbol = __wcs; 400 } 401 else 402 _M_curr_symbol = L""; 403 } 404 catch (...) 405 { 406 delete __wcs_ps; 407 delete __wcs_ns; 408 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 409 __uselocale(__old); 410 #else 411 setlocale(LC_ALL, __old); 412 free(__old); 413 #endif 414 __throw_exception_again; 415 } 416 417 _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc)); 418 char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc)); 419 char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc)); 420 char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc)); 421 _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn); 422 char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc)); 423 char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc)); 424 _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn); 425 426 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 427 __uselocale(__old); 428 #else 429 setlocale(LC_ALL, __old); 430 free(__old); 431 #endif 432 } 433 } 434 435 template<> 436 void _M_initialize_moneypunct(__c_locale __cloc,const char *)437 moneypunct<wchar_t, false>::_M_initialize_moneypunct(__c_locale __cloc, 438 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 439 const char*) 440 #else 441 const char* __name) 442 #endif 443 { 444 if (!__cloc) 445 { 446 // "C" locale 447 _M_decimal_point = L'.'; 448 _M_thousands_sep = L','; 449 _M_grouping = ""; 450 _M_curr_symbol = L""; 451 _M_positive_sign = L""; 452 _M_negative_sign = L""; 453 _M_frac_digits = 0; 454 _M_pos_format = money_base::_S_default_pattern; 455 _M_neg_format = money_base::_S_default_pattern; 456 } 457 else 458 { 459 // Named locale. 460 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 461 __c_locale __old = __uselocale(__cloc); 462 #else 463 // Switch to named locale so that mbsrtowcs will work. 464 char* __old = strdup(setlocale(LC_ALL, NULL)); 465 setlocale(LC_ALL, __name); 466 #endif 467 _M_decimal_point = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc)}).__w); 468 _M_thousands_sep = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc)}).__w); 469 _M_grouping = __nl_langinfo_l(GROUPING, __cloc); 470 471 const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc); 472 const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc); 473 const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc); 474 475 wchar_t* __wcs_ps = 0; 476 wchar_t* __wcs_ns = 0; 477 char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc)); 478 try 479 { 480 mbstate_t __state; 481 size_t __len; 482 __len = strlen(__cpossign); 483 if (__len) 484 { 485 ++__len; 486 memset(&__state, 0, sizeof(mbstate_t)); 487 __wcs_ps = new wchar_t[__len]; 488 mbsrtowcs(__wcs_ps, &__cpossign, __len, &__state); 489 _M_positive_sign = __wcs_ps; 490 } 491 else 492 _M_positive_sign = L""; 493 494 __len = strlen(__cnegsign); 495 if (!__nposn) 496 _M_negative_sign = L"()"; 497 else if (__len) 498 { 499 ++__len; 500 memset(&__state, 0, sizeof(mbstate_t)); 501 __wcs_ns = new wchar_t[__len]; 502 mbsrtowcs(__wcs_ns, &__cnegsign, __len, &__state); 503 _M_negative_sign = __wcs_ns; 504 } 505 else 506 _M_negative_sign = L""; 507 508 // _Intl == true. 509 __len = strlen(__ccurr); 510 if (__len) 511 { 512 ++__len; 513 memset(&__state, 0, sizeof(mbstate_t)); 514 wchar_t* __wcs = new wchar_t[__len]; 515 mbsrtowcs(__wcs, &__ccurr, __len, &__state); 516 _M_curr_symbol = __wcs; 517 } 518 else 519 _M_curr_symbol = L""; 520 } 521 catch (...) 522 { 523 delete __wcs_ps; 524 delete __wcs_ns; 525 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 526 __uselocale(__old); 527 #else 528 setlocale(LC_ALL, __old); 529 free(__old); 530 #endif 531 __throw_exception_again; 532 } 533 534 _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc)); 535 char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc)); 536 char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc)); 537 char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc)); 538 _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn); 539 char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc)); 540 char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc)); 541 _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn); 542 543 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) 544 __uselocale(__old); 545 #else 546 setlocale(LC_ALL, __old); 547 free(__old); 548 #endif 549 } 550 } 551 552 template<> ~moneypunct()553 moneypunct<wchar_t, true>::~moneypunct() 554 { 555 if (wcslen(_M_positive_sign)) 556 delete [] _M_positive_sign; 557 if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0)) 558 delete [] _M_negative_sign; 559 if (wcslen(_M_curr_symbol)) 560 delete [] _M_curr_symbol; 561 } 562 563 template<> ~moneypunct()564 moneypunct<wchar_t, false>::~moneypunct() 565 { 566 if (wcslen(_M_positive_sign)) 567 delete [] _M_positive_sign; 568 if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0)) 569 delete [] _M_negative_sign; 570 if (wcslen(_M_curr_symbol)) 571 delete [] _M_curr_symbol; 572 } 573 #endif 574 } 575