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