monetary_members.cc revision 107606
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 "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							const char* __name)
321    {
322      if (!__cloc)
323	{
324	  // "C" locale
325	  _M_decimal_point = L'.';
326	  _M_thousands_sep = L',';
327	  _M_grouping = "";
328	  _M_curr_symbol = L"";
329	  _M_positive_sign = L"";
330	  _M_negative_sign = L"";
331	  _M_frac_digits = 0;
332	  _M_pos_format = money_base::_S_default_pattern;
333	  _M_neg_format = money_base::_S_default_pattern;
334	}
335      else
336	{
337	  // Named locale.
338#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
339	  __c_locale __old = __uselocale(__cloc);
340#else
341	  // Switch to named locale so that mbsrtowcs will work.
342	  char* __old = strdup(setlocale(LC_ALL, NULL));
343	  setlocale(LC_ALL, __name);
344#endif
345
346	  _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);
347
348	  _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);
349	  _M_grouping = __nl_langinfo_l(GROUPING, __cloc);
350
351	  const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
352	  const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
353	  const char* __ccurr = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc);
354
355	  mbstate_t __state;
356	  size_t __len = strlen(__cpossign);
357	  if (__len)
358	    {
359	      ++__len;
360	      memset(&__state, 0, sizeof(mbstate_t));
361	      wchar_t* __wcs = new wchar_t[__len];
362	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
363	      _M_positive_sign = __wcs;
364	    }
365	  else
366	    _M_positive_sign = L"";
367
368	  char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
369	  __len = strlen(__cnegsign);
370	  if (!__nposn)
371	    _M_negative_sign = L"()";
372	  else if (__len)
373	    {
374	      ++__len;
375	      memset(&__state, 0, sizeof(mbstate_t));
376	      wchar_t* __wcs = new wchar_t[__len];
377	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
378	      _M_negative_sign = __wcs;
379	    }
380	  else
381	    _M_negative_sign = L"";
382
383	  // _Intl == true.
384	  __len = strlen(__ccurr);
385	  if (__len)
386	    {
387	      ++__len;
388	      memset(&__state, 0, sizeof(mbstate_t));
389	      wchar_t* __wcs = new wchar_t[__len];
390	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
391	      _M_curr_symbol = __wcs;
392	    }
393	  else
394	    _M_curr_symbol = L"";
395
396	  _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc));
397	  char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
398	  char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
399	  char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
400	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
401	  char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
402	  char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
403	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
404
405#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
406	  __uselocale(__old);
407#else
408	  setlocale(LC_ALL, __old);
409	  free(__old);
410#endif
411	}
412    }
413
414  template<>
415    void
416    moneypunct<wchar_t, false>::_M_initialize_moneypunct(__c_locale __cloc,
417							 const char* __name)
418    {
419      if (!__cloc)
420	{
421	  // "C" locale
422	  _M_decimal_point = L'.';
423	  _M_thousands_sep = L',';
424	  _M_grouping = "";
425	  _M_curr_symbol = L"";
426	  _M_positive_sign = L"";
427	  _M_negative_sign = L"";
428	  _M_frac_digits = 0;
429	  _M_pos_format = money_base::_S_default_pattern;
430	  _M_neg_format = money_base::_S_default_pattern;
431	}
432      else
433	{
434	  // Named locale.
435#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
436	  __c_locale __old = __uselocale(__cloc);
437#else
438	  // Switch to named locale so that mbsrtowcs will work.
439	  char* __old = strdup(setlocale(LC_ALL, NULL));
440	  setlocale(LC_ALL, __name);
441#endif
442
443	  _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);
444	  _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);
445	  _M_grouping = __nl_langinfo_l(GROUPING, __cloc);
446
447	  const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
448	  const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
449	  const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
450
451	  mbstate_t __state;
452	  size_t __len;
453	  __len = strlen(__cpossign);
454	  if (__len)
455	    {
456	      ++__len;
457	      memset(&__state, 0, sizeof(mbstate_t));
458	      wchar_t* __wcs = new wchar_t[__len];
459	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
460	      _M_positive_sign = __wcs;
461	    }
462	  else
463	    _M_positive_sign = L"";
464
465	  char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
466	  __len = strlen(__cnegsign);
467	  if (!__nposn)
468	    _M_negative_sign = L"()";
469	  else if (__len)
470	    {
471	      ++__len;
472	      memset(&__state, 0, sizeof(mbstate_t));
473	      wchar_t* __wcs = new wchar_t[__len];
474	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
475	      _M_negative_sign = __wcs;
476	    }
477	  else
478	    _M_negative_sign = L"";
479
480	  // _Intl == true.
481	  __len = strlen(__ccurr);
482	  if (__len)
483	    {
484	      ++__len;
485	      memset(&__state, 0, sizeof(mbstate_t));
486	      wchar_t* __wcs = new wchar_t[__len];
487	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
488	      _M_curr_symbol = __wcs;
489	    }
490	  else
491	    _M_curr_symbol = L"";
492
493	  _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc));
494	  char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
495	  char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
496	  char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
497	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
498	  char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
499	  char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
500	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
501
502#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
503	  __uselocale(__old);
504#else
505	  setlocale(LC_ALL, __old);
506	  free(__old);
507#endif
508	}
509    }
510
511  template<>
512    moneypunct<wchar_t, true>::~moneypunct()
513    {
514      if (wcslen(_M_positive_sign))
515	delete [] _M_positive_sign;
516      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
517	delete [] _M_negative_sign;
518      if (wcslen(_M_curr_symbol))
519	delete [] _M_curr_symbol;
520    }
521
522  template<>
523    moneypunct<wchar_t, false>::~moneypunct()
524    {
525      if (wcslen(_M_positive_sign))
526	delete [] _M_positive_sign;
527      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
528	delete [] _M_negative_sign;
529      if (wcslen(_M_curr_symbol))
530	delete [] _M_curr_symbol;
531    }
532#endif
533}
534