monetary_members.cc revision 117397
1// std::moneypunct implementation details, GNU version -*- C++ -*-
2
3// Copyright (C) 2001, 2002 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
39namespace std
40{
41  // Construct and return valid pattern consisting of some combination of:
42  // space none symbol sign value
43  money_base::pattern
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
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
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<>
309    moneypunct<char, true>::~moneypunct()
310    { }
311
312  template<>
313    moneypunct<char, false>::~moneypunct()
314    { }
315
316#ifdef _GLIBCPP_USE_WCHAR_T
317  template<>
318    void
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	  mbstate_t __state;
360	  size_t __len = strlen(__cpossign);
361	  if (__len)
362	    {
363	      ++__len;
364	      memset(&__state, 0, sizeof(mbstate_t));
365	      wchar_t* __wcs = new wchar_t[__len];
366	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
367	      _M_positive_sign = __wcs;
368	    }
369	  else
370	    _M_positive_sign = L"";
371
372	  char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
373	  __len = strlen(__cnegsign);
374	  if (!__nposn)
375	    _M_negative_sign = L"()";
376	  else if (__len)
377	    {
378	      ++__len;
379	      memset(&__state, 0, sizeof(mbstate_t));
380	      wchar_t* __wcs = new wchar_t[__len];
381	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
382	      _M_negative_sign = __wcs;
383	    }
384	  else
385	    _M_negative_sign = L"";
386
387	  // _Intl == true.
388	  __len = strlen(__ccurr);
389	  if (__len)
390	    {
391	      ++__len;
392	      memset(&__state, 0, sizeof(mbstate_t));
393	      wchar_t* __wcs = new wchar_t[__len];
394	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
395	      _M_curr_symbol = __wcs;
396	    }
397	  else
398	    _M_curr_symbol = L"";
399
400	  _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc));
401	  char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
402	  char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
403	  char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
404	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
405	  char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
406	  char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
407	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
408
409#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
410	  __uselocale(__old);
411#else
412	  setlocale(LC_ALL, __old);
413	  free(__old);
414#endif
415	}
416    }
417
418  template<>
419    void
420    moneypunct<wchar_t, false>::_M_initialize_moneypunct(__c_locale __cloc,
421#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
422							 const char*)
423#else
424							 const char* __name)
425#endif
426    {
427      if (!__cloc)
428	{
429	  // "C" locale
430	  _M_decimal_point = L'.';
431	  _M_thousands_sep = L',';
432	  _M_grouping = "";
433	  _M_curr_symbol = L"";
434	  _M_positive_sign = L"";
435	  _M_negative_sign = L"";
436	  _M_frac_digits = 0;
437	  _M_pos_format = money_base::_S_default_pattern;
438	  _M_neg_format = money_base::_S_default_pattern;
439	}
440      else
441	{
442	  // Named locale.
443#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
444	  __c_locale __old = __uselocale(__cloc);
445#else
446	  // Switch to named locale so that mbsrtowcs will work.
447	  char* __old = strdup(setlocale(LC_ALL, NULL));
448	  setlocale(LC_ALL, __name);
449#endif
450
451	  _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);
452	  _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);
453	  _M_grouping = __nl_langinfo_l(GROUPING, __cloc);
454
455	  const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
456	  const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
457	  const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
458
459	  mbstate_t __state;
460	  size_t __len;
461	  __len = strlen(__cpossign);
462	  if (__len)
463	    {
464	      ++__len;
465	      memset(&__state, 0, sizeof(mbstate_t));
466	      wchar_t* __wcs = new wchar_t[__len];
467	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
468	      _M_positive_sign = __wcs;
469	    }
470	  else
471	    _M_positive_sign = L"";
472
473	  char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
474	  __len = strlen(__cnegsign);
475	  if (!__nposn)
476	    _M_negative_sign = L"()";
477	  else if (__len)
478	    {
479	      ++__len;
480	      memset(&__state, 0, sizeof(mbstate_t));
481	      wchar_t* __wcs = new wchar_t[__len];
482	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
483	      _M_negative_sign = __wcs;
484	    }
485	  else
486	    _M_negative_sign = L"";
487
488	  // _Intl == true.
489	  __len = strlen(__ccurr);
490	  if (__len)
491	    {
492	      ++__len;
493	      memset(&__state, 0, sizeof(mbstate_t));
494	      wchar_t* __wcs = new wchar_t[__len];
495	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
496	      _M_curr_symbol = __wcs;
497	    }
498	  else
499	    _M_curr_symbol = L"";
500
501	  _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc));
502	  char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
503	  char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
504	  char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
505	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
506	  char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
507	  char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
508	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
509
510#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
511	  __uselocale(__old);
512#else
513	  setlocale(LC_ALL, __old);
514	  free(__old);
515#endif
516	}
517    }
518
519  template<>
520    moneypunct<wchar_t, true>::~moneypunct()
521    {
522      if (wcslen(_M_positive_sign))
523	delete [] _M_positive_sign;
524      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
525	delete [] _M_negative_sign;
526      if (wcslen(_M_curr_symbol))
527	delete [] _M_curr_symbol;
528    }
529
530  template<>
531    moneypunct<wchar_t, false>::~moneypunct()
532    {
533      if (wcslen(_M_positive_sign))
534	delete [] _M_positive_sign;
535      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
536	delete [] _M_negative_sign;
537      if (wcslen(_M_curr_symbol))
538	delete [] _M_curr_symbol;
539    }
540#endif
541}
542