monetary_members.cc revision 102782
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
38namespace std
39{
40  // Construct and return valid pattern consisting of some combination of:
41  // space none symbol sign value
42  money_base::pattern
43  money_base::_S_construct_pattern(char __precedes, char __space, char __posn)
44  {
45    pattern __ret;
46
47    // This insanely complicated routine attempts to construct a valid
48    // pattern for use with monyepunct. A couple of invariants:
49
50    // if (__precedes) symbol -> value
51    // else value -> symbol
52
53    // if (__space) space
54    // else none
55
56    // none == never first
57    // space never first or last
58
59    // Any elegant implementations of this are welcome.
60    switch (__posn)
61      {
62      case 0:
63      case 1:
64	// 1 The sign precedes the value and symbol.
65	if (__space)
66	  {
67	    // Pattern starts with sign.
68	    if (__precedes)
69	      {
70		__ret.field[1] = symbol;
71		__ret.field[2] = space;
72		__ret.field[3] = value;
73	      }
74	    else
75	      {
76		__ret.field[1] = value;
77		__ret.field[2] = space;
78		__ret.field[3] = symbol;
79	      }
80	    __ret.field[0] = sign;
81	  }
82	else
83	  {
84	    // Pattern starts with sign and ends with none.
85	    if (__precedes)
86	      {
87		__ret.field[1] = symbol;
88		__ret.field[2] = value;
89	      }
90	    else
91	      {
92		__ret.field[1] = value;
93		__ret.field[2] = symbol;
94	      }
95	    __ret.field[0] = sign;
96	    __ret.field[3] = none;
97	  }
98	break;
99      case 2:
100	// 2 The sign follows the value and symbol.
101	if (__space)
102	  {
103	    // Pattern either ends with sign.
104	    if (__precedes)
105	      {
106		__ret.field[0] = symbol;
107		__ret.field[1] = space;
108		__ret.field[2] = value;
109	      }
110	    else
111	      {
112		__ret.field[0] = value;
113		__ret.field[1] = space;
114		__ret.field[2] = symbol;
115	      }
116	    __ret.field[3] = sign;
117	  }
118	else
119	  {
120	    // Pattern ends with sign then none.
121	    if (__precedes)
122	      {
123		__ret.field[0] = symbol;
124		__ret.field[1] = value;
125	      }
126	    else
127	      {
128		__ret.field[0] = value;
129		__ret.field[1] = symbol;
130	      }
131	    __ret.field[2] = sign;
132	    __ret.field[3] = none;
133	  }
134	break;
135      case 3:
136	// 3 The sign immediately precedes the symbol.
137	if (__space)
138	  {
139	    // Have space.
140	    if (__precedes)
141	      {
142		__ret.field[0] = sign;
143		__ret.field[1] = symbol;
144		__ret.field[2] = space;
145		__ret.field[3] = value;
146	      }
147	    else
148	      {
149		__ret.field[0] = value;
150		__ret.field[1] = space;
151		__ret.field[2] = sign;
152		__ret.field[3] = symbol;
153	      }
154	  }
155	else
156	  {
157	    // Have none.
158	    if (__precedes)
159	      {
160		__ret.field[0] = sign;
161		__ret.field[1] = symbol;
162		__ret.field[2] = value;
163	      }
164	    else
165	      {
166		__ret.field[0] = value;
167		__ret.field[1] = sign;
168		__ret.field[2] = symbol;
169	      }
170	    __ret.field[3] = none;
171	  }
172	break;
173      case 4:
174	// 4 The sign immediately follows the symbol.
175	if (__space)
176	  {
177	    // Have space.
178	    if (__precedes)
179	      {
180		__ret.field[0] = symbol;
181		__ret.field[1] = sign;
182		__ret.field[2] = space;
183		__ret.field[3] = value;
184	      }
185	    else
186	      {
187		__ret.field[0] = value;
188		__ret.field[1] = space;
189		__ret.field[2] = symbol;
190		__ret.field[3] = sign;
191	      }
192	  }
193	else
194	  {
195	    // Have none.
196	    if (__precedes)
197	      {
198		__ret.field[0] = symbol;
199		__ret.field[1] = sign;
200		__ret.field[2] = value;
201	      }
202	    else
203	      {
204		__ret.field[0] = value;
205		__ret.field[1] = symbol;
206		__ret.field[2] = sign;
207	      }
208	    __ret.field[3] = none;
209	  }
210	break;
211      default:
212	;
213      }
214    return __ret;
215  }
216
217  template<>
218    void
219    moneypunct<char, true>::_M_initialize_moneypunct(__c_locale __cloc,
220						     const char*)
221    {
222      if (__cloc == _S_c_locale)
223	{
224	  // "C" locale
225	  _M_decimal_point = '.';
226	  _M_thousands_sep = ',';
227	  _M_grouping = "";
228	  _M_curr_symbol = "";
229	  _M_positive_sign = "";
230	  _M_negative_sign = "";
231	  _M_frac_digits = 0;
232	  _M_pos_format = money_base::_S_default_pattern;
233	  _M_neg_format = money_base::_S_default_pattern;
234	}
235      else
236	{
237	  // Named locale.
238	  _M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT, __cloc));
239	  _M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP, __cloc));
240	  _M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
241	  _M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
242
243	  char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
244	  if (!__nposn)
245	    _M_negative_sign = "()";
246	  else
247	    _M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
248
249	  // _Intl == true
250	  _M_curr_symbol = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc);
251	  _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc));
252	  char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
253	  char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
254	  char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
255	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
256	  char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
257	  char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
258	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
259	}
260    }
261
262  template<>
263    void
264    moneypunct<char, false>::_M_initialize_moneypunct(__c_locale __cloc,
265						      const char*)
266    {
267      if (__cloc == _S_c_locale)
268	{
269	  // "C" locale
270	  _M_decimal_point = '.';
271	  _M_thousands_sep = ',';
272	  _M_grouping = "";
273	  _M_curr_symbol = "";
274	  _M_positive_sign = "";
275	  _M_negative_sign = "";
276	  _M_frac_digits = 0;
277	  _M_pos_format = money_base::_S_default_pattern;
278	  _M_neg_format = money_base::_S_default_pattern;
279	}
280      else
281	{
282	  // Named locale.
283	  _M_decimal_point = *(__nl_langinfo_l(__MON_DECIMAL_POINT, __cloc));
284	  _M_thousands_sep = *(__nl_langinfo_l(__MON_THOUSANDS_SEP, __cloc));
285	  _M_grouping = __nl_langinfo_l(__MON_GROUPING, __cloc);
286	  _M_positive_sign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
287
288	  char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
289	  if (!__nposn)
290	    _M_negative_sign = "()";
291	  else
292	    _M_negative_sign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
293
294	  // _Intl == false
295	  _M_curr_symbol = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
296	  _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc));
297	  char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
298	  char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
299	  char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
300	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
301	  char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
302	  char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
303	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
304	}
305    }
306
307  template<>
308    moneypunct<char, true>::~moneypunct()
309    { }
310
311  template<>
312    moneypunct<char, false>::~moneypunct()
313    { }
314
315#ifdef _GLIBCPP_USE_WCHAR_T
316  template<>
317    void
318    moneypunct<wchar_t, true>::_M_initialize_moneypunct(__c_locale __cloc,
319							const char* __name)
320    {
321      if (__cloc == _S_c_locale)
322	{
323	  // "C" locale
324	  _M_decimal_point = L'.';
325	  _M_thousands_sep = L',';
326	  _M_grouping = "";
327	  _M_curr_symbol = L"";
328	  _M_positive_sign = L"";
329	  _M_negative_sign = L"";
330	  _M_frac_digits = 0;
331	  _M_pos_format = money_base::_S_default_pattern;
332	  _M_neg_format = money_base::_S_default_pattern;
333	}
334      else
335	{
336	  // Named locale.
337	  // XXX Fix me. Switch to named locale so that mbsrtowcs will work.
338	  char* __old = strdup(setlocale(LC_ALL, NULL));
339	  setlocale(LC_ALL, __name);
340
341	  _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);
342
343	  _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);
344	  _M_grouping = __nl_langinfo_l(GROUPING, __cloc);
345
346	  mbstate_t __state;
347	  size_t __len;
348	  const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
349	  const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
350	  const char* __ccurr = __nl_langinfo_l(__INT_CURR_SYMBOL, __cloc);
351
352	  // NB: Should swich to __cloc's ctype info first.
353	  __len = strlen(__cpossign);
354	  if (__len)
355	    {
356	      ++__len;
357	      memset(&__state, 0, sizeof(mbstate_t));
358	      wchar_t* __wcs = new wchar_t[__len];
359	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
360	      _M_positive_sign = __wcs;
361	    }
362	  else
363	    _M_positive_sign = L"";
364
365	  char __nposn = *(__nl_langinfo_l(__INT_N_SIGN_POSN, __cloc));
366	  __len = strlen(__cnegsign);
367	  if (!__nposn)
368	    _M_negative_sign = L"()";
369	  else if (__len)
370	    {
371	      ++__len;
372	      memset(&__state, 0, sizeof(mbstate_t));
373	      wchar_t* __wcs = new wchar_t[__len];
374	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
375	      _M_negative_sign = __wcs;
376	    }
377	  else
378	    _M_negative_sign = L"";
379
380	  // _Intl == true.
381	  __len = strlen(__ccurr);
382	  if (__len)
383	    {
384	      ++__len;
385	      memset(&__state, 0, sizeof(mbstate_t));
386	      wchar_t* __wcs = new wchar_t[__len];
387	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
388	      _M_curr_symbol = __wcs;
389	    }
390	  else
391	    _M_curr_symbol = L"";
392
393	  _M_frac_digits = *(__nl_langinfo_l(__INT_FRAC_DIGITS, __cloc));
394	  char __pprecedes = *(__nl_langinfo_l(__INT_P_CS_PRECEDES, __cloc));
395	  char __pspace = *(__nl_langinfo_l(__INT_P_SEP_BY_SPACE, __cloc));
396	  char __pposn = *(__nl_langinfo_l(__INT_P_SIGN_POSN, __cloc));
397	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
398	  char __nprecedes = *(__nl_langinfo_l(__INT_N_CS_PRECEDES, __cloc));
399	  char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
400	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
401
402	  // XXX
403	  setlocale(LC_ALL, __old);
404	  free(__old);
405	}
406    }
407
408  template<>
409    void
410    moneypunct<wchar_t, false>::_M_initialize_moneypunct(__c_locale __cloc,
411							 const char* __name)
412    {
413      if (__cloc == _S_c_locale)
414	{
415	  // "C" locale
416	  _M_decimal_point = L'.';
417	  _M_thousands_sep = L',';
418	  _M_grouping = "";
419	  _M_curr_symbol = L"";
420	  _M_positive_sign = L"";
421	  _M_negative_sign = L"";
422	  _M_frac_digits = 0;
423	  _M_pos_format = money_base::_S_default_pattern;
424	  _M_neg_format = money_base::_S_default_pattern;
425	}
426      else
427	{
428	  // Named locale.
429	  // XXX Fix me. Switch to named locale so that mbsrtowcs will work.
430	  char* __old = strdup(setlocale(LC_ALL, NULL));
431	  setlocale(LC_ALL, __name);
432
433	  _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);
434	  _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);
435	  _M_grouping = __nl_langinfo_l(GROUPING, __cloc);
436
437	  mbstate_t __state;
438	  size_t __len;
439	  const char* __cpossign = __nl_langinfo_l(__POSITIVE_SIGN, __cloc);
440	  const char* __cnegsign = __nl_langinfo_l(__NEGATIVE_SIGN, __cloc);
441	  const char* __ccurr = __nl_langinfo_l(__CURRENCY_SYMBOL, __cloc);
442
443	  // NB: Should swich to __cloc's ctype info first.
444	  __len = strlen(__cpossign);
445	  if (__len)
446	    {
447	      ++__len;
448	      memset(&__state, 0, sizeof(mbstate_t));
449	      wchar_t* __wcs = new wchar_t[__len];
450	      mbsrtowcs(__wcs, &__cpossign, __len, &__state);
451	      _M_positive_sign = __wcs;
452	    }
453	  else
454	    _M_positive_sign = L"";
455
456	  char __nposn = *(__nl_langinfo_l(__N_SIGN_POSN, __cloc));
457	  __len = strlen(__cnegsign);
458	  if (!__nposn)
459	    _M_negative_sign = L"()";
460	  else if (__len)
461	    {
462	      ++__len;
463	      memset(&__state, 0, sizeof(mbstate_t));
464	      wchar_t* __wcs = new wchar_t[__len];
465	      mbsrtowcs(__wcs, &__cnegsign, __len, &__state);
466	      _M_negative_sign = __wcs;
467	    }
468	  else
469	    _M_negative_sign = L"";
470
471	  // _Intl == true.
472	  __len = strlen(__ccurr);
473	  if (__len)
474	    {
475	      ++__len;
476	      memset(&__state, 0, sizeof(mbstate_t));
477	      wchar_t* __wcs = new wchar_t[__len];
478	      mbsrtowcs(__wcs, &__ccurr, __len, &__state);
479	      _M_curr_symbol = __wcs;
480	    }
481	  else
482	    _M_curr_symbol = L"";
483
484	  _M_frac_digits = *(__nl_langinfo_l(__FRAC_DIGITS, __cloc));
485	  char __pprecedes = *(__nl_langinfo_l(__P_CS_PRECEDES, __cloc));
486	  char __pspace = *(__nl_langinfo_l(__P_SEP_BY_SPACE, __cloc));
487	  char __pposn = *(__nl_langinfo_l(__P_SIGN_POSN, __cloc));
488	  _M_pos_format = _S_construct_pattern(__pprecedes, __pspace, __pposn);
489	  char __nprecedes = *(__nl_langinfo_l(__N_CS_PRECEDES, __cloc));
490	  char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
491	  _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
492
493	  // XXX
494	  setlocale(LC_ALL, __old);
495	  free(__old);
496	}
497    }
498
499  template<>
500    moneypunct<wchar_t, true>::~moneypunct()
501    {
502      if (wcslen(_M_positive_sign))
503	delete [] _M_positive_sign;
504      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
505	delete [] _M_negative_sign;
506      if (wcslen(_M_curr_symbol))
507	delete [] _M_curr_symbol;
508    }
509
510  template<>
511    moneypunct<wchar_t, false>::~moneypunct()
512    {
513      if (wcslen(_M_positive_sign))
514	delete [] _M_positive_sign;
515      if (wcslen(_M_negative_sign) && (wcscmp(_M_negative_sign, L"()") != 0))
516	delete [] _M_negative_sign;
517      if (wcslen(_M_curr_symbol))
518	delete [] _M_curr_symbol;
519    }
520#endif
521}
522