1 // std::moneypunct implementation details, GNU version -*- C++ -*-
3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 // Free Software Foundation, Inc.
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
27 // ISO C++ 14882: 22.2.6.3.2 moneypunct virtual functions
30 // Written by Benjamin Kosnik <bkoz@redhat.com>
33 #include <bits/c++locale_internal.h>
35 _GLIBCXX_BEGIN_NAMESPACE(std)
37 // Construct and return valid pattern consisting of some combination of:
38 // space none symbol sign value
40 money_base::_S_construct_pattern(char __precedes, char __space, char __posn)
44 // This insanely complicated routine attempts to construct a valid
45 // pattern for use with monyepunct. A couple of invariants:
47 // if (__precedes) symbol -> value
48 // else value -> symbol
53 // none == never first
54 // space never first or last
56 // Any elegant implementations of this are welcome.
61 // 1 The sign precedes the value and symbol.
62 __ret.field[0] = sign;
65 // Pattern starts with sign.
68 __ret.field[1] = symbol;
69 __ret.field[3] = value;
73 __ret.field[1] = value;
74 __ret.field[3] = symbol;
76 __ret.field[2] = space;
80 // Pattern starts with sign and ends with none.
83 __ret.field[1] = symbol;
84 __ret.field[2] = value;
88 __ret.field[1] = value;
89 __ret.field[2] = symbol;
91 __ret.field[3] = none;
95 // 2 The sign follows the value and symbol.
98 // Pattern either ends with sign.
101 __ret.field[0] = symbol;
102 __ret.field[2] = value;
106 __ret.field[0] = value;
107 __ret.field[2] = symbol;
109 __ret.field[1] = space;
110 __ret.field[3] = sign;
114 // Pattern ends with sign then none.
117 __ret.field[0] = symbol;
118 __ret.field[1] = value;
122 __ret.field[0] = value;
123 __ret.field[1] = symbol;
125 __ret.field[2] = sign;
126 __ret.field[3] = none;
130 // 3 The sign immediately precedes the symbol.
133 __ret.field[0] = sign;
134 __ret.field[1] = symbol;
137 __ret.field[2] = space;
138 __ret.field[3] = value;
142 __ret.field[2] = value;
143 __ret.field[3] = none;
148 __ret.field[0] = value;
151 __ret.field[1] = space;
152 __ret.field[2] = sign;
153 __ret.field[3] = symbol;
157 __ret.field[1] = sign;
158 __ret.field[2] = symbol;
159 __ret.field[3] = none;
164 // 4 The sign immediately follows the symbol.
167 __ret.field[0] = symbol;
168 __ret.field[1] = sign;
171 __ret.field[2] = space;
172 __ret.field[3] = value;
176 __ret.field[2] = value;
177 __ret.field[3] = none;
182 __ret.field[0] = value;
185 __ret.field[1] = space;
186 __ret.field[2] = symbol;
187 __ret.field[3] = sign;
191 __ret.field[1] = symbol;
192 __ret.field[2] = sign;
193 __ret.field[3] = none;
205 moneypunct<char, true>::_M_initialize_moneypunct(__c_locale __cloc,
209 _M_data = new __moneypunct_cache<char, true>;
214 _M_data->_M_decimal_point = '.';
215 _M_data->_M_thousands_sep = ',';
216 _M_data->_M_grouping = "";
217 _M_data->_M_grouping_size = 0;
218 _M_data->_M_use_grouping = false;
219 _M_data->_M_curr_symbol = "";
220 _M_data->_M_curr_symbol_size = 0;
221 _M_data->_M_positive_sign = "";
222 _M_data->_M_positive_sign_size = 0;
223 _M_data->_M_negative_sign = "";
224 _M_data->_M_negative_sign_size = 0;
225 _M_data->_M_frac_digits = 0;
226 _M_data->_M_pos_format = money_base::_S_default_pattern;
227 _M_data->_M_neg_format = money_base::_S_default_pattern;
229 for (size_t __i = 0; __i < money_base::_S_end; ++__i)
230 _M_data->_M_atoms[__i] = money_base::_S_atoms[__i];
235 _M_data->_M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT,
237 _M_data->_M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP,
239 _M_data->_M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
240 _M_data->_M_positive_sign_size = strlen(_M_data->_M_positive_sign);
242 // Check for NULL, which implies no grouping.
243 if (_M_data->_M_thousands_sep == '\0')
245 // Like in "C" locale.
246 _M_data->_M_grouping = "";
247 _M_data->_M_grouping_size = 0;
248 _M_data->_M_use_grouping = false;
249 _M_data->_M_thousands_sep = ',';
253 _M_data->_M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
254 _M_data->_M_grouping_size = strlen(_M_data->_M_grouping);
257 // Check for NULL, which implies no fractional digits.
258 if (_M_data->_M_decimal_point == '\0')
260 // Like in "C" locale.
261 _M_data->_M_frac_digits = 0;
262 _M_data->_M_decimal_point = '.';
265 _M_data->_M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS,
268 char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
270 _M_data->_M_negative_sign = "()";
272 _M_data->_M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN,
274 _M_data->_M_negative_sign_size = strlen(_M_data->_M_negative_sign);
277 _M_data->_M_curr_symbol = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc);
278 _M_data->_M_curr_symbol_size = strlen(_M_data->_M_curr_symbol);
279 char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
280 char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
281 char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
282 _M_data->_M_pos_format = _S_construct_pattern(__pprecedes, __pspace,
284 char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
285 char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
286 _M_data->_M_neg_format = _S_construct_pattern(__nprecedes, __nspace,
293 moneypunct<char, false>::_M_initialize_moneypunct(__c_locale __cloc,
297 _M_data = new __moneypunct_cache<char, false>;
302 _M_data->_M_decimal_point = '.';
303 _M_data->_M_thousands_sep = ',';
304 _M_data->_M_grouping = "";
305 _M_data->_M_grouping_size = 0;
306 _M_data->_M_use_grouping = false;
307 _M_data->_M_curr_symbol = "";
308 _M_data->_M_curr_symbol_size = 0;
309 _M_data->_M_positive_sign = "";
310 _M_data->_M_positive_sign_size = 0;
311 _M_data->_M_negative_sign = "";
312 _M_data->_M_negative_sign_size = 0;
313 _M_data->_M_frac_digits = 0;
314 _M_data->_M_pos_format = money_base::_S_default_pattern;
315 _M_data->_M_neg_format = money_base::_S_default_pattern;
317 for (size_t __i = 0; __i < money_base::_S_end; ++__i)
318 _M_data->_M_atoms[__i] = money_base::_S_atoms[__i];
323 _M_data->_M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT,
325 _M_data->_M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP,
327 _M_data->_M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
328 _M_data->_M_positive_sign_size = strlen(_M_data->_M_positive_sign);
330 // Check for NULL, which implies no grouping.
331 if (_M_data->_M_thousands_sep == '\0')
333 // Like in "C" locale.
334 _M_data->_M_grouping = "";
335 _M_data->_M_grouping_size = 0;
336 _M_data->_M_use_grouping = false;
337 _M_data->_M_thousands_sep = ',';
341 _M_data->_M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
342 _M_data->_M_grouping_size = strlen(_M_data->_M_grouping);
345 // Check for NULL, which implies no fractional digits.
346 if (_M_data->_M_decimal_point == '\0')
348 // Like in "C" locale.
349 _M_data->_M_frac_digits = 0;
350 _M_data->_M_decimal_point = '.';
353 _M_data->_M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS,
356 char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
358 _M_data->_M_negative_sign = "()";
360 _M_data->_M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN,
362 _M_data->_M_negative_sign_size = strlen(_M_data->_M_negative_sign);
365 _M_data->_M_curr_symbol = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
366 _M_data->_M_curr_symbol_size = strlen(_M_data->_M_curr_symbol);
367 char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
368 char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
369 char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
370 _M_data->_M_pos_format = _S_construct_pattern(__pprecedes, __pspace,
372 char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
373 char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
374 _M_data->_M_neg_format = _S_construct_pattern(__nprecedes, __nspace,
380 moneypunct<char, true>::~moneypunct()
384 moneypunct<char, false>::~moneypunct()
387 #ifdef _GLIBCXX_USE_WCHAR_T
390 moneypunct<wchar_t, true>::_M_initialize_moneypunct(__c_locale __cloc,
391 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
398 _M_data = new __moneypunct_cache<wchar_t, true>;
403 _M_data->_M_decimal_point = L'.';
404 _M_data->_M_thousands_sep = L',';
405 _M_data->_M_grouping = "";
406 _M_data->_M_grouping_size = 0;
407 _M_data->_M_use_grouping = false;
408 _M_data->_M_curr_symbol = L"";
409 _M_data->_M_curr_symbol_size = 0;
410 _M_data->_M_positive_sign = L"";
411 _M_data->_M_positive_sign_size = 0;
412 _M_data->_M_negative_sign = L"";
413 _M_data->_M_negative_sign_size = 0;
414 _M_data->_M_frac_digits = 0;
415 _M_data->_M_pos_format = money_base::_S_default_pattern;
416 _M_data->_M_neg_format = money_base::_S_default_pattern;
418 // Use ctype::widen code without the facet...
419 for (size_t __i = 0; __i < money_base::_S_end; ++__i)
420 _M_data->_M_atoms[__i] =
421 static_cast<wchar_t>(money_base::_S_atoms[__i]);
426 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
427 __c_locale __old = __uselocale(__cloc);
429 // Switch to named locale so that mbsrtowcs will work.
430 char* __old = setlocale(LC_ALL, NULL);
431 const size_t __llen = strlen(__old) + 1;
432 char* __sav = new char[__llen];
433 memcpy(__sav, __old, __llen);
434 setlocale(LC_ALL, __name);
437 union { char *__s; wchar_t __w; } __u;
438 __u.__s = __nl_langinfo_l(_NL_MONETARY_DECIMAL_POINT_WC, __cloc);
439 _M_data->_M_decimal_point = __u.__w;
441 __u.__s = __nl_langinfo_l(_NL_MONETARY_THOUSANDS_SEP_WC, __cloc);
442 _M_data->_M_thousands_sep = __u.__w;
444 // Check for NULL, which implies no grouping.
445 if (_M_data->_M_thousands_sep == L'\0')
447 // Like in "C" locale.
448 _M_data->_M_grouping = "";
449 _M_data->_M_grouping_size = 0;
450 _M_data->_M_use_grouping = false;
451 _M_data->_M_thousands_sep = L',';
455 _M_data->_M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
456 _M_data->_M_grouping_size = strlen(_M_data->_M_grouping);
459 // Check for NULL, which implies no fractional digits.
460 if (_M_data->_M_decimal_point == L'\0')
462 // Like in "C" locale.
463 _M_data->_M_frac_digits = 0;
464 _M_data->_M_decimal_point = L'.';
467 _M_data->_M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS,
470 const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
471 const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
472 const char* __ccurr = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc);
474 wchar_t* __wcs_ps = 0;
475 wchar_t* __wcs_ns = 0;
476 const char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
480 size_t __len = strlen(__cpossign);
484 memset(&__state, 0, sizeof(mbstate_t));
485 __wcs_ps = new wchar_t[__len];
486 mbsrtowcs(__wcs_ps, &__cpossign, __len, &__state);
487 _M_data->_M_positive_sign = __wcs_ps;
490 _M_data->_M_positive_sign = L"";
491 _M_data->_M_positive_sign_size = wcslen(_M_data->_M_positive_sign);
493 __len = strlen(__cnegsign);
495 _M_data->_M_negative_sign = L"()";
499 memset(&__state, 0, sizeof(mbstate_t));
500 __wcs_ns = new wchar_t[__len];
501 mbsrtowcs(__wcs_ns, &__cnegsign, __len, &__state);
502 _M_data->_M_negative_sign = __wcs_ns;
505 _M_data->_M_negative_sign = L"";
506 _M_data->_M_negative_sign_size = wcslen(_M_data->_M_negative_sign);
509 __len = strlen(__ccurr);
513 memset(&__state, 0, sizeof(mbstate_t));
514 wchar_t* __wcs = new wchar_t[__len];
515 mbsrtowcs(__wcs, &__ccurr, __len, &__state);
516 _M_data->_M_curr_symbol = __wcs;
519 _M_data->_M_curr_symbol = L"";
520 _M_data->_M_curr_symbol_size = wcslen(_M_data->_M_curr_symbol);
528 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
531 setlocale(LC_ALL, __sav);
534 __throw_exception_again;
537 char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
538 char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
539 char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
540 _M_data->_M_pos_format = _S_construct_pattern(__pprecedes, __pspace,
542 char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
543 char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
544 _M_data->_M_neg_format = _S_construct_pattern(__nprecedes, __nspace,
547 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
550 setlocale(LC_ALL, __sav);
558 moneypunct<wchar_t, false>::_M_initialize_moneypunct(__c_locale __cloc,
559 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
566 _M_data = new __moneypunct_cache<wchar_t, false>;
571 _M_data->_M_decimal_point = L'.';
572 _M_data->_M_thousands_sep = L',';
573 _M_data->_M_grouping = "";
574 _M_data->_M_grouping_size = 0;
575 _M_data->_M_use_grouping = false;
576 _M_data->_M_curr_symbol = L"";
577 _M_data->_M_curr_symbol_size = 0;
578 _M_data->_M_positive_sign = L"";
579 _M_data->_M_positive_sign_size = 0;
580 _M_data->_M_negative_sign = L"";
581 _M_data->_M_negative_sign_size = 0;
582 _M_data->_M_frac_digits = 0;
583 _M_data->_M_pos_format = money_base::_S_default_pattern;
584 _M_data->_M_neg_format = money_base::_S_default_pattern;
586 // Use ctype::widen code without the facet...
587 for (size_t __i = 0; __i < money_base::_S_end; ++__i)
588 _M_data->_M_atoms[__i] =
589 static_cast<wchar_t>(money_base::_S_atoms[__i]);
594 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
595 __c_locale __old = __uselocale(__cloc);
597 // Switch to named locale so that mbsrtowcs will work.
598 char* __old = setlocale(LC_ALL, NULL);
599 const size_t __llen = strlen(__old) + 1;
600 char* __sav = new char[__llen];
601 memcpy(__sav, __old, __llen);
602 setlocale(LC_ALL, __name);
605 union { char *__s; wchar_t __w; } __u;
606 __u.__s = __nl_langinfo_l(_NL_MONETARY_DECIMAL_POINT_WC, __cloc);
607 _M_data->_M_decimal_point = __u.__w;
609 __u.__s = __nl_langinfo_l(_NL_MONETARY_THOUSANDS_SEP_WC, __cloc);
610 _M_data->_M_thousands_sep = __u.__w;
612 // Check for NULL, which implies no grouping.
613 if (_M_data->_M_thousands_sep == L'\0')
615 // Like in "C" locale.
616 _M_data->_M_grouping = "";
617 _M_data->_M_grouping_size = 0;
618 _M_data->_M_use_grouping = false;
619 _M_data->_M_thousands_sep = L',';
623 _M_data->_M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
624 _M_data->_M_grouping_size = strlen(_M_data->_M_grouping);
627 // Check for NULL, which implies no fractional digits.
628 if (_M_data->_M_decimal_point == L'\0')
630 // Like in "C" locale.
631 _M_data->_M_frac_digits = 0;
632 _M_data->_M_decimal_point = L'.';
635 _M_data->_M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS,
638 const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
639 const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
640 const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
642 wchar_t* __wcs_ps = 0;
643 wchar_t* __wcs_ns = 0;
644 const char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
649 __len = strlen(__cpossign);
653 memset(&__state, 0, sizeof(mbstate_t));
654 __wcs_ps = new wchar_t[__len];
655 mbsrtowcs(__wcs_ps, &__cpossign, __len, &__state);
656 _M_data->_M_positive_sign = __wcs_ps;
659 _M_data->_M_positive_sign = L"";
660 _M_data->_M_positive_sign_size = wcslen(_M_data->_M_positive_sign);
662 __len = strlen(__cnegsign);
664 _M_data->_M_negative_sign = L"()";
668 memset(&__state, 0, sizeof(mbstate_t));
669 __wcs_ns = new wchar_t[__len];
670 mbsrtowcs(__wcs_ns, &__cnegsign, __len, &__state);
671 _M_data->_M_negative_sign = __wcs_ns;
674 _M_data->_M_negative_sign = L"";
675 _M_data->_M_negative_sign_size = wcslen(_M_data->_M_negative_sign);
678 __len = strlen(__ccurr);
682 memset(&__state, 0, sizeof(mbstate_t));
683 wchar_t* __wcs = new wchar_t[__len];
684 mbsrtowcs(__wcs, &__ccurr, __len, &__state);
685 _M_data->_M_curr_symbol = __wcs;
688 _M_data->_M_curr_symbol = L"";
689 _M_data->_M_curr_symbol_size = wcslen(_M_data->_M_curr_symbol);
697 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
700 setlocale(LC_ALL, __sav);
703 __throw_exception_again;
706 char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
707 char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
708 char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
709 _M_data->_M_pos_format = _S_construct_pattern(__pprecedes, __pspace,
711 char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
712 char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
713 _M_data->_M_neg_format = _S_construct_pattern(__nprecedes, __nspace,
716 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
719 setlocale(LC_ALL, __sav);
726 moneypunct<wchar_t, true>::~moneypunct()
728 if (_M_data->_M_positive_sign_size)
729 delete [] _M_data->_M_positive_sign;
730 if (_M_data->_M_negative_sign_size
731 && wcscmp(_M_data->_M_negative_sign, L"()") != 0)
732 delete [] _M_data->_M_negative_sign;
733 if (_M_data->_M_curr_symbol_size)
734 delete [] _M_data->_M_curr_symbol;
739 moneypunct<wchar_t, false>::~moneypunct()
741 if (_M_data->_M_positive_sign_size)
742 delete [] _M_data->_M_positive_sign;
743 if (_M_data->_M_negative_sign_size
744 && wcscmp(_M_data->_M_negative_sign, L"()") != 0)
745 delete [] _M_data->_M_negative_sign;
746 if (_M_data->_M_curr_symbol_size)
747 delete [] _M_data->_M_curr_symbol;
752 _GLIBCXX_END_NAMESPACE