1/*
2 * Copyright (c) 1999
3 * Silicon Graphics Computer Systems, Inc.
4 *
5 * Copyright (c) 1999
6 * Boris Fomitchev
7 *
8 * This material is provided "as is", with absolutely no warranty expressed
9 * or implied. Any use is at your own risk.
10 *
11 * Permission to use or copy this software for any purpose is hereby granted
12 * without fee, provided the above notices are retained on all copies.
13 * Permission to modify the code and to distribute modified code is granted,
14 * provided the above notices are retained, and a notice that the code was
15 * modified is included with the above copyright notice.
16 *
17 */
18#include "stlport_prefix.h"
19
20#include <hash_map>
21#include <vector>
22
23#include <locale>
24#include <istream>
25
26#include <algorithm>
27#include <functional>
28
29#include "c_locale.h"
30#include "locale_impl.h"
31#include "acquire_release.h"
32
33_STLP_BEGIN_NAMESPACE
34
35//----------------------------------------------------------------------
36// ctype_byname<char>
37
38#if defined (__DMC__)
39_STLP_DECLSPEC
40#endif
41ctype_byname<char>::ctype_byname(const char* name, size_t refs)
42    : ctype<char>( 0, false, refs) {
43  if (!name)
44    locale::_M_throw_on_null_name();
45
46  int __err_code;
47  char buf[_Locale_MAX_SIMPLE_NAME];
48  _M_ctype = _STLP_PRIV __acquire_ctype(name, buf, 0, &__err_code);
49  if (!_M_ctype)
50    locale::_M_throw_on_creation_failure(__err_code, name, "ctype");
51
52  _M_init();
53}
54
55void ctype_byname<char>::_M_init() {
56  _M_ctype_table = _M_byname_table;
57
58  // We have to do this, instead of just pointer twiddling, because
59  // ctype_base::mask isn't the same type as _Locale_mask_t.
60  const _Locale_mask_t* p = _Locale_ctype_table(_M_ctype);
61  for (size_t i = 0; i != table_size; ++i) {
62    _M_byname_table[i] = ctype_base::mask(p[i]);
63  }
64}
65
66ctype_byname<char>::~ctype_byname()
67{ _STLP_PRIV __release_ctype(_M_ctype); }
68
69char ctype_byname<char>::do_toupper(char c) const
70{ return (char)_Locale_toupper(_M_ctype, c); }
71
72char ctype_byname<char>::do_tolower(char c) const
73{ return (char)_Locale_tolower(_M_ctype, c); }
74
75const char*
76ctype_byname<char>::do_toupper(char* first, const char* last) const {
77  for ( ; first != last ; ++first)
78    *first = (char)_Locale_toupper(_M_ctype, *first);
79  return last;
80}
81
82const char*
83ctype_byname<char>::do_tolower(char* first, const char* last) const {
84  for ( ; first != last ; ++first)
85    *first = (char)_Locale_tolower(_M_ctype, *first);
86  return last;
87}
88
89
90// Some helper functions used in ctype<>::scan_is and scan_is_not.
91#if !defined (_STLP_NO_WCHAR_T)
92
93_STLP_MOVE_TO_PRIV_NAMESPACE
94
95// ctype_byname<wchar_t>
96
97struct _Ctype_byname_w_is_mask : public unary_function<wchar_t, bool> {
98  _Locale_mask_t M;
99  _Locale_ctype* M_ctp;
100
101  _Ctype_byname_w_is_mask(_Locale_mask_t m, _Locale_ctype* c)
102    : M(m), M_ctp(c) {}
103  bool operator()(wchar_t c) const
104  { return _WLocale_ctype(M_ctp, c, M) != 0; }
105};
106
107_STLP_MOVE_TO_STD_NAMESPACE
108
109#if defined (__DMC__)
110_STLP_DECLSPEC
111#endif
112ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
113  : ctype<wchar_t>(refs) {
114  if (!name)
115    locale::_M_throw_on_null_name();
116
117  int __err_code;
118  char buf[_Locale_MAX_SIMPLE_NAME];
119  _M_ctype = _STLP_PRIV __acquire_ctype(name, buf, 0, &__err_code);
120  if (!_M_ctype)
121    locale::_M_throw_on_creation_failure(__err_code, name, "ctype");
122}
123
124ctype_byname<wchar_t>::~ctype_byname()
125{ _STLP_PRIV __release_ctype(_M_ctype); }
126
127bool ctype_byname<wchar_t>::do_is(ctype_base::mask  m, wchar_t c) const
128{ return _WLocale_ctype(_M_ctype, c, (_Locale_mask_t)m) != 0; }
129
130const wchar_t*
131ctype_byname<wchar_t>::do_is(const wchar_t* low, const wchar_t* high,
132                             ctype_base::mask * m) const {
133  _Locale_mask_t all_bits = _Locale_mask_t(ctype_base::space |
134                                           ctype_base::print |
135                                           ctype_base::cntrl |
136                                           ctype_base::upper |
137                                           ctype_base::lower |
138                                           ctype_base::alpha |
139                                           ctype_base::digit |
140                                           ctype_base::punct |
141                                           ctype_base::xdigit);
142
143  for ( ; low < high; ++low, ++m)
144    *m = ctype_base::mask (_WLocale_ctype(_M_ctype, *low, all_bits));
145  return high;
146}
147
148const wchar_t*
149ctype_byname<wchar_t>
150  ::do_scan_is(ctype_base::mask  m, const wchar_t* low, const wchar_t* high) const
151{ return find_if(low, high, _STLP_PRIV _Ctype_byname_w_is_mask(m, _M_ctype)); }
152
153const wchar_t*
154ctype_byname<wchar_t>
155  ::do_scan_not(ctype_base::mask  m, const wchar_t* low, const wchar_t* high) const
156{ return find_if(low, high, not1(_STLP_PRIV _Ctype_byname_w_is_mask(m, _M_ctype))); }
157
158wchar_t ctype_byname<wchar_t>::do_toupper(wchar_t c) const
159{ return _WLocale_toupper(_M_ctype, c); }
160
161const wchar_t*
162ctype_byname<wchar_t>::do_toupper(wchar_t* low, const wchar_t* high) const {
163  for ( ; low < high; ++low)
164    *low = _WLocale_toupper(_M_ctype, *low);
165  return high;
166}
167
168wchar_t ctype_byname<wchar_t>::do_tolower(wchar_t c) const
169{ return _WLocale_tolower(_M_ctype, c); }
170
171const wchar_t*
172ctype_byname<wchar_t>::do_tolower(wchar_t* low, const wchar_t* high) const {
173  for ( ; low < high; ++low)
174    *low = _WLocale_tolower(_M_ctype, *low);
175  return high;
176}
177
178#endif /* WCHAR_T */
179
180// collate_byname<char>
181#if defined (__DMC__)
182_STLP_DECLSPEC
183#endif
184collate_byname<char>::collate_byname(const char* name, size_t refs)
185  : collate<char>(refs) {
186  if (!name)
187    locale::_M_throw_on_null_name();
188
189  int __err_code;
190  char buf[_Locale_MAX_SIMPLE_NAME];
191  _M_collate = _STLP_PRIV __acquire_collate(name, buf, 0, &__err_code);
192  if (!_M_collate)
193    locale::_M_throw_on_creation_failure(__err_code, name, "collate");
194}
195
196collate_byname<char>::~collate_byname()
197{ _STLP_PRIV __release_collate(_M_collate); }
198
199int collate_byname<char>::do_compare(const char* __low1,
200                                     const char* __high1,
201                                     const char* __low2,
202                                     const char* __high2) const {
203  return _Locale_strcmp(_M_collate,
204                        __low1, __high1 - __low1,
205                        __low2, __high2 - __low2);
206}
207
208collate_byname<char>::string_type
209collate_byname<char>::do_transform(const char* low, const char* high) const {
210  if (low == high)
211    return string_type();
212
213  size_t n = _Locale_strxfrm(_M_collate, NULL, 0, low, high - low);
214
215  // NOT PORTABLE.  What we're doing relies on internal details of the
216  // string implementation.  (Contiguity of string elements and presence
217  // of trailing zero.)
218  string_type buf(n, 0);
219  _Locale_strxfrm(_M_collate, &(*buf.begin()), n + 1, low, high - low);
220  return buf;
221}
222
223
224#if !defined (_STLP_NO_WCHAR_T)
225
226// collate_byname<wchar_t>
227
228#if defined (__DMC__)
229_STLP_DECLSPEC
230#endif
231collate_byname<wchar_t>::collate_byname(const char* name, size_t refs)
232  : collate<wchar_t>(refs) {
233  if (!name)
234    locale::_M_throw_on_null_name();
235
236  int __err_code;
237  char buf[_Locale_MAX_SIMPLE_NAME];
238  _M_collate = _STLP_PRIV __acquire_collate(name, buf, 0, &__err_code);
239  if (!_M_collate)
240    locale::_M_throw_on_creation_failure(__err_code, name, "collate");
241}
242
243collate_byname<wchar_t>::~collate_byname()
244{ _STLP_PRIV __release_collate(_M_collate); }
245
246int collate_byname<wchar_t>::do_compare(const wchar_t* low1,
247                                        const wchar_t* high1,
248                                        const wchar_t* low2,
249                                        const wchar_t* high2) const {
250  return _WLocale_strcmp(_M_collate,
251                         low1, high1 - low1,
252                         low2, high2 - low2);
253}
254
255collate_byname<wchar_t>::string_type
256collate_byname<wchar_t>::do_transform(const wchar_t* low,
257                                      const wchar_t* high) const {
258  if (low == high)
259    return string_type();
260
261  size_t n = _WLocale_strxfrm(_M_collate, NULL, 0, low, high - low);
262
263  // NOT PORTABLE.  What we're doing relies on internal details of the
264  // string implementation.  (Contiguity of string elements and presence
265  // of trailing zero.)
266  string_type buf(n, 0);
267  _WLocale_strxfrm(_M_collate, &(*buf.begin()), n + 1, low, high - low);
268  return buf;
269}
270
271#endif /*  _STLP_NO_WCHAR_T */
272
273//----------------------------------------------------------------------
274// codecvt_byname<char>
275
276codecvt_byname<char, char, mbstate_t>
277  ::codecvt_byname(const char* name, size_t refs)
278    : codecvt<char, char, mbstate_t>(refs) {
279  if (!name)
280    locale::_M_throw_on_null_name();
281}
282
283codecvt_byname<char, char, mbstate_t>::~codecvt_byname() {}
284
285
286#if !defined (_STLP_NO_WCHAR_T)
287
288//----------------------------------------------------------------------
289// codecvt_byname<wchar_t>
290codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname(const char* name, size_t refs)
291  : codecvt<wchar_t, char, mbstate_t>(refs) {
292  if (!name)
293    locale::_M_throw_on_null_name();
294
295  int __err_code;
296  char buf[_Locale_MAX_SIMPLE_NAME];
297  _M_codecvt = _STLP_PRIV __acquire_codecvt(name, buf, 0, &__err_code);
298  if (!_M_codecvt)
299    locale::_M_throw_on_creation_failure(__err_code, name, "ctype");
300}
301
302codecvt_byname<wchar_t, char, mbstate_t>::~codecvt_byname()
303{ _STLP_PRIV __release_codecvt(_M_codecvt); }
304
305codecvt<wchar_t, char, mbstate_t>::result
306codecvt_byname<wchar_t, char, mbstate_t>::do_out(state_type&         state,
307                                                 const intern_type*  from,
308                                                 const intern_type*  from_end,
309                                                 const intern_type*& from_next,
310                                                 extern_type*        to,
311                                                 extern_type*        to_limit,
312                                                 extern_type*&       to_next) const {
313  while (from != from_end && to != to_limit) {
314    size_t chars_stored = _WLocale_wctomb(_M_codecvt,
315                                          to, to_limit - to, *from,
316                                          &state);
317    if (chars_stored == (size_t) -1) {
318      from_next = from;
319      to_next   = to;
320      return error;
321    }
322    else if (chars_stored == (size_t) -2) {
323      from_next = from;
324      to_next   = to;
325      return partial;
326    }
327
328    ++from;
329    to += chars_stored;
330  }
331
332  from_next = from;
333  to_next   = to;
334  return ok;
335}
336
337codecvt<wchar_t, char, mbstate_t>::result
338codecvt_byname<wchar_t, char, mbstate_t>::do_in(state_type&         state,
339                                                const extern_type*  from,
340                                                const extern_type*  from_end,
341                                                const extern_type*& from_next,
342                                                intern_type*        to,
343                                                intern_type*        to_end,
344                                                intern_type*&       to_next) const {
345  while (from != from_end && to != to_end) {
346    size_t chars_read = _WLocale_mbtowc(_M_codecvt,
347                                        to, from, from_end - from,
348                                        &state);
349    if (chars_read == (size_t) -1) {
350      from_next = from;
351      to_next   = to;
352      return error;
353    }
354
355    if (chars_read == (size_t) -2) {
356      from_next = from;
357      to_next   = to;
358      return partial;
359    }
360
361    from += chars_read;
362    to++;
363  }
364
365  from_next = from;
366  to_next   = to;
367  return ok;
368}
369
370codecvt<wchar_t, char, mbstate_t>::result
371codecvt_byname<wchar_t, char, mbstate_t>::do_unshift(state_type&   state,
372                                                     extern_type*  to,
373                                                     extern_type*  to_limit,
374                                                     extern_type*& to_next) const {
375  to_next = to;
376  size_t result = _WLocale_unshift(_M_codecvt, &state,
377                                   to, to_limit - to, &to_next);
378  if (result == (size_t) -1)
379    return error;
380  else if (result == (size_t) -2)
381    return partial;
382  else
383#    if defined (__ISCPP__)
384    return /*to_next == to ? noconv :*/ ok;
385#    else
386    return to_next == to ? noconv : ok;
387#    endif
388}
389
390int
391codecvt_byname<wchar_t, char, mbstate_t>::do_encoding() const _STLP_NOTHROW {
392  if (_WLocale_is_stateless(_M_codecvt)) {
393    int max_width = _WLocale_mb_cur_max(_M_codecvt);
394    int min_width = _WLocale_mb_cur_min(_M_codecvt);
395    return min_width == max_width ? min_width : 0;
396  }
397  else
398    return -1;
399}
400
401bool
402codecvt_byname<wchar_t, char, mbstate_t>::do_always_noconv() const _STLP_NOTHROW
403{ return false; }
404
405int
406codecvt_byname<wchar_t, char, mbstate_t>::do_length(state_type&         state,
407                                                    const  extern_type* from,
408                                                    const  extern_type* end,
409                                                    size_t              mx) const {
410  size_t __count = 0;
411  while (from != end && mx--) {
412    intern_type __dummy;
413    size_t chars_read = _WLocale_mbtowc(_M_codecvt,
414                                        &__dummy, from, end - from,
415                                        &state);
416    if ((chars_read == (size_t) -1) || (chars_read == (size_t) -2)) // error or partial
417      break;
418    __count += chars_read;
419    from += chars_read;
420  }
421  return int(__count);
422}
423
424int
425codecvt_byname<wchar_t, char, mbstate_t>::do_max_length() const _STLP_NOTHROW
426{ return _WLocale_mb_cur_max(_M_codecvt); }
427#endif
428
429// numpunct_byname<char>
430numpunct_byname<char>::numpunct_byname(const char* name, size_t refs)
431: numpunct<char>(refs) {
432  if (!name)
433    locale::_M_throw_on_null_name();
434
435  int __err_code;
436  char buf[_Locale_MAX_SIMPLE_NAME];
437  _M_numeric = _STLP_PRIV __acquire_numeric(name, buf, 0, &__err_code);
438  if (!_M_numeric)
439    locale::_M_throw_on_creation_failure(__err_code, name, "numpunct");
440}
441
442numpunct_byname<char>::~numpunct_byname()
443{ _STLP_PRIV __release_numeric(_M_numeric); }
444
445char numpunct_byname<char>::do_decimal_point() const
446{ return _Locale_decimal_point(_M_numeric); }
447
448char numpunct_byname<char>::do_thousands_sep() const
449{ return _Locale_thousands_sep(_M_numeric); }
450
451string numpunct_byname<char>::do_grouping() const {
452  const char * __grouping = _Locale_grouping(_M_numeric);
453  if (__grouping != NULL && __grouping[0] == CHAR_MAX)
454    __grouping = "";
455  return __grouping;
456}
457
458string numpunct_byname<char>::do_truename() const
459{ return _Locale_true(_M_numeric); }
460
461string numpunct_byname<char>::do_falsename() const
462{ return _Locale_false(_M_numeric); }
463
464//----------------------------------------------------------------------
465// numpunct<wchar_t>
466
467#if !defined (_STLP_NO_WCHAR_T)
468
469// numpunct_byname<wchar_t>
470
471numpunct_byname<wchar_t>::numpunct_byname(const char* name, size_t refs)
472: numpunct<wchar_t>(refs) {
473  if (!name)
474    locale::_M_throw_on_null_name();
475
476  int __err_code;
477  char buf[_Locale_MAX_SIMPLE_NAME];
478  _M_numeric = _STLP_PRIV __acquire_numeric(name, buf, 0, &__err_code);
479  if (!_M_numeric)
480    locale::_M_throw_on_creation_failure(__err_code, name, "numpunct");
481}
482
483numpunct_byname<wchar_t>::~numpunct_byname()
484{ _STLP_PRIV __release_numeric(_M_numeric); }
485
486wchar_t numpunct_byname<wchar_t>::do_decimal_point() const
487{ return _WLocale_decimal_point(_M_numeric); }
488
489wchar_t numpunct_byname<wchar_t>::do_thousands_sep() const
490{ return _WLocale_thousands_sep(_M_numeric); }
491
492string numpunct_byname<wchar_t>::do_grouping() const {
493  const char * __grouping = _Locale_grouping(_M_numeric);
494  if (__grouping != NULL && __grouping[0] == CHAR_MAX)
495    __grouping = "";
496  return __grouping;
497}
498
499wstring numpunct_byname<wchar_t>::do_truename() const {
500  wchar_t buf[16];
501  return _WLocale_true(_M_numeric, _STLP_ARRAY_AND_SIZE(buf));
502}
503
504wstring numpunct_byname<wchar_t>::do_falsename() const {
505  wchar_t buf[16];
506  return _WLocale_false(_M_numeric, _STLP_ARRAY_AND_SIZE(buf));
507}
508
509#endif
510
511_STLP_MOVE_TO_PRIV_NAMESPACE
512
513static void _Init_monetary_formats(money_base::pattern& pos_format,
514                                   money_base::pattern& neg_format,
515                                   _Locale_monetary * monetary) {
516  switch (_Locale_p_sign_posn(monetary)) {
517    case 0: // Parentheses surround the quantity and currency symbol
518    case 1: // The sign string precedes the quantity and currency symbol
519      pos_format.field[0] = (char) money_base::sign;
520      if (_Locale_p_cs_precedes(monetary)) {
521        // 1 if currency symbol precedes a positive value
522        pos_format.field[1] = (char) money_base::symbol;
523        if (_Locale_p_sep_by_space(monetary)) {
524          // a space separates currency symbol from a positive value.
525          pos_format.field[2] = (char) money_base::space;
526          pos_format.field[3] = (char) money_base::value;
527        } else {
528          // a space not separates currency symbol from a positive value.
529          pos_format.field[2] = (char) money_base::value;
530          pos_format.field[3] = (char) money_base::none;
531        }
532      } else {
533        // 0 if currency symbol succeeds a positive value
534        pos_format.field[1] = (char) money_base::value;
535        if (_Locale_p_sep_by_space(monetary)) {
536          // a space separates currency symbol from a positive value.
537          pos_format.field[2] = (char) money_base::space;
538          pos_format.field[3] = (char) money_base::symbol;
539        } else {
540          // a space not separates currency symbol from a positive value.
541          pos_format.field[2] = (char) money_base::symbol;
542          pos_format.field[3] = (char) money_base::none;
543        }
544      }
545      break;
546    case 2: // The sign string succeeds the quantity and currency symbol.
547      if (_Locale_p_cs_precedes(monetary)) {
548        // 1 if currency symbol precedes a positive value
549        pos_format.field[0] = (char) money_base::symbol;
550        if (_Locale_p_sep_by_space(monetary)) {
551          // a space separates currency symbol from a positive value.
552          pos_format.field[1] = (char) money_base::space;
553          pos_format.field[2] = (char) money_base::value;
554          pos_format.field[3] = (char) money_base::sign;
555        } else {
556          // a space not separates currency symbol from a positive value.
557          pos_format.field[1] = (char) money_base::value;
558          pos_format.field[2] = (char) money_base::sign;
559          pos_format.field[3] = (char) money_base::none;
560        }
561      } else {
562        // 0 if currency symbol succeeds a positive value
563        pos_format.field[0] = (char) money_base::value;
564        if (_Locale_p_sep_by_space(monetary)) {
565          // a space separates currency symbol from a positive value.
566          pos_format.field[1] = (char) money_base::space;
567          pos_format.field[2] = (char) money_base::symbol;
568          pos_format.field[3] = (char) money_base::sign;
569        } else {
570          // a space not separates currency symbol from a positive value.
571          pos_format.field[1] = (char) money_base::symbol;
572          pos_format.field[2] = (char) money_base::sign;
573          pos_format.field[3] = (char) money_base::none;
574        }
575      }
576      break;
577    case 3: // The sign string immediately precedes the currency symbol.
578      if (_Locale_p_cs_precedes(monetary)) {
579        // 1 if currency symbol precedes a positive value
580        pos_format.field[0] = (char) money_base::sign;
581        pos_format.field[1] = (char) money_base::symbol;
582        if (_Locale_p_sep_by_space(monetary)) {
583          // a space separates currency symbol from a positive value.
584          pos_format.field[2] = (char) money_base::space;
585          pos_format.field[3] = (char) money_base::value;
586        } else {
587          // a space not separates currency symbol from a positive value.
588          pos_format.field[2] = (char) money_base::value;
589          pos_format.field[3] = (char) money_base::none;
590        }
591      } else {
592        // 0 if currency symbol succeeds a positive value
593        pos_format.field[0] = (char) money_base::value;
594        pos_format.field[1] = (char) money_base::sign;
595        pos_format.field[2] = (char) money_base::symbol;
596        pos_format.field[3] = (char) money_base::none;
597      }
598      break;
599    case 4: // The sign string immediately succeeds the currency symbol.
600      if (_Locale_p_cs_precedes(monetary)) {
601        // 1 if currency symbol precedes a positive value
602        pos_format.field[0] = (char) money_base::symbol;
603        pos_format.field[1] = (char) money_base::sign;
604        pos_format.field[2] = (char) money_base::value;
605        pos_format.field[3] = (char) money_base::none;
606      } else {
607        // 0 if currency symbol succeeds a positive value
608        pos_format.field[0] = (char) money_base::value;
609        if (_Locale_p_sep_by_space(monetary)) {
610          // a space separates currency symbol from a positive value.
611          pos_format.field[1] = (char) money_base::space;
612          pos_format.field[2] = (char) money_base::symbol;
613          pos_format.field[3] = (char) money_base::sign;
614        } else {
615          // a space not separates currency symbol from a positive value.
616          pos_format.field[1] = (char) money_base::symbol;
617          pos_format.field[2] = (char) money_base::sign;
618          pos_format.field[3] = (char) money_base::none;
619        }
620      }
621      break;
622    default: // Default C++ Standard format
623      pos_format.field[0] = (char) money_base::symbol;
624      pos_format.field[1] = (char) money_base::sign;
625      pos_format.field[2] = (char) money_base::none;
626      pos_format.field[3] = (char) money_base::value;
627      break;
628  }
629
630  switch (_Locale_n_sign_posn(monetary)) {
631    case 0: // Parentheses surround the quantity and currency symbol
632    case 1: // The sign string precedes the quantity and currency symbol
633      neg_format.field[0] = (char) money_base::sign;
634      if (_Locale_n_cs_precedes(monetary)) {
635        // 1 if currency symbol precedes a negative value
636        neg_format.field[1] = (char) money_base::symbol;
637        if (_Locale_n_sep_by_space(monetary)) {
638          // a space separates currency symbol from a negative value.
639          neg_format.field[2] = (char) money_base::space;
640          neg_format.field[3] = (char) money_base::value;
641        } else {
642          // a space not separates currency symbol from a negative value.
643          neg_format.field[2] = (char) money_base::value;
644          neg_format.field[3] = (char) money_base::none;
645        }
646      } else {
647        // 0 if currency symbol succeeds a negative value
648        neg_format.field[1] = (char) money_base::value;
649        if (_Locale_n_sep_by_space(monetary)) {
650          // a space separates currency symbol from a negative value.
651          neg_format.field[2] = (char) money_base::space;
652          neg_format.field[3] = (char) money_base::symbol;
653        } else {
654          // a space not separates currency symbol from a negative value.
655          neg_format.field[2] = (char) money_base::symbol;
656          neg_format.field[3] = (char) money_base::none;
657        }
658      }
659      break;
660    case 2: // The sign string succeeds the quantity and currency symbol.
661      if (_Locale_n_cs_precedes(monetary)) {
662        // 1 if currency symbol precedes a negative value
663        neg_format.field[0] = (char) money_base::symbol;
664        if (_Locale_n_sep_by_space(monetary)) {
665          // a space separates currency symbol from a negative value.
666          neg_format.field[1] = (char) money_base::space;
667          neg_format.field[2] = (char) money_base::value;
668          neg_format.field[3] = (char) money_base::sign;
669        } else {
670          // a space not separates currency symbol from a negative value.
671          neg_format.field[1] = (char) money_base::value;
672          neg_format.field[2] = (char) money_base::sign;
673          neg_format.field[3] = (char) money_base::none;
674        }
675      } else {
676        // 0 if currency symbol succeeds a negative value
677        neg_format.field[0] = (char) money_base::value;
678        if (_Locale_n_sep_by_space(monetary)) {
679          // a space separates currency symbol from a negative value.
680          neg_format.field[1] = (char) money_base::space;
681          neg_format.field[2] = (char) money_base::symbol;
682          neg_format.field[3] = (char) money_base::sign;
683        } else {
684          // a space not separates currency symbol from a negative value.
685          neg_format.field[1] = (char) money_base::symbol;
686          neg_format.field[2] = (char) money_base::sign;
687          neg_format.field[3] = (char) money_base::none;
688        }
689      }
690      break;
691    case 3: // The sign string immediately precedes the currency symbol.
692      if (_Locale_n_cs_precedes(monetary)) {
693        // 1 if currency symbol precedes a negative value
694        neg_format.field[0] = (char) money_base::sign;
695        neg_format.field[1] = (char) money_base::symbol;
696        if (_Locale_n_sep_by_space(monetary)) {
697          // a space separates currency symbol from a negative value.
698          neg_format.field[2] = (char) money_base::space;
699          neg_format.field[3] = (char) money_base::value;
700        } else {
701          // a space not separates currency symbol from a negative value.
702          neg_format.field[2] = (char) money_base::value;
703          neg_format.field[3] = (char) money_base::none;
704        }
705      } else {
706        // 0 if currency symbol succeeds a negative value
707        neg_format.field[0] = (char) money_base::value;
708        neg_format.field[1] = (char) money_base::sign;
709        neg_format.field[2] = (char) money_base::symbol;
710        neg_format.field[3] = (char) money_base::none;
711      }
712      break;
713    case 4: // The sign string immediately succeeds the currency symbol.
714      if (_Locale_n_cs_precedes(monetary)) {
715        // 1 if currency symbol precedes a negative value
716        neg_format.field[0] = (char) money_base::symbol;
717        neg_format.field[1] = (char) money_base::sign;
718        neg_format.field[2] = (char) money_base::none;
719        neg_format.field[3] = (char) money_base::value;
720      } else {
721        // 0 if currency symbol succeeds a negative value
722        neg_format.field[0] = (char) money_base::value;
723        if (_Locale_n_sep_by_space(monetary)) {
724          // a space separates currency symbol from a negative value.
725          neg_format.field[1] = (char) money_base::space;
726          neg_format.field[2] = (char) money_base::symbol;
727          neg_format.field[3] = (char) money_base::sign;
728        } else {
729          // a space not separates currency symbol from a negative value.
730          neg_format.field[1] = (char) money_base::symbol;
731          neg_format.field[2] = (char) money_base::sign;
732          neg_format.field[3] = (char) money_base::none;
733        }
734      }
735      break;
736    default: // Default C++ Standard format
737      neg_format.field[0] = (char) money_base::symbol;
738      neg_format.field[1] = (char) money_base::sign;
739      neg_format.field[2] = (char) money_base::none;
740      neg_format.field[3] = (char) money_base::value;
741      break;
742  }
743}
744
745// international variant of monetary
746
747/*
748 * int_curr_symbol
749 *
750 *   The international currency symbol. The operand is a four-character
751 *   string, with the first three characters containing the alphabetic
752 *   international currency symbol in accordance with those specified
753 *   in the ISO 4217 specification. The fourth character is the character used
754 *   to separate the international currency symbol from the monetary quantity.
755 *
756 * (http://www.opengroup.org/onlinepubs/7990989775/xbd/locale.html)
757 */
758
759/*
760 * Standards are unclear in the usage of international currency
761 * and monetary formats.
762 * But I am expect that international currency symbol should be the first
763 * (not depends upon where currency symbol situated in the national
764 * format).
765 *
766 * If this isn't so, let's see:
767 *       1 234.56 RUR
768 *       GBP 1,234.56
769 *       USD 1,234.56
770 * The situation really is worse than you see above:
771 * RUR typed wrong here---it prints '1 234.56 RUR ' (see space after RUR).
772 * This is due to intl_fmp.curr_symbol() == "RUR ". (see reference in comments
773 * above).
774 *
775 */
776
777static void _Init_monetary_formats_int(money_base::pattern& pos_format,
778                                       money_base::pattern& neg_format,
779                                       _Locale_monetary * monetary)
780{
781
782  switch (_Locale_p_sign_posn(monetary)) {
783    case 0: // Parentheses surround the quantity and currency symbol
784    case 1: // The sign string precedes the quantity and currency symbol
785      pos_format.field[0] = (char) money_base::symbol;
786      pos_format.field[1] = (char) money_base::sign;
787      pos_format.field[2] = (char) money_base::value;
788      pos_format.field[3] = (char) money_base::none;
789      break;
790    case 2: // The sign string succeeds the quantity and currency symbol.
791      pos_format.field[0] = (char) money_base::symbol;
792      pos_format.field[1] = (char) money_base::value;
793      pos_format.field[2] = (char) money_base::sign;
794      pos_format.field[3] = (char) money_base::none;
795      break;
796    case 3: // The sign string immediately precedes the currency symbol.
797    case 4: // The sign string immediately succeeds the currency symbol.
798      pos_format.field[0] = (char) money_base::symbol;
799      if (_Locale_p_cs_precedes(monetary)) {
800        // 1 if currency symbol precedes a positive value
801        pos_format.field[1] = (char) money_base::sign;
802        pos_format.field[2] = (char) money_base::value;
803      } else {
804        // 0 if currency symbol succeeds a positive value
805        pos_format.field[1] = (char) money_base::value;
806        pos_format.field[2] = (char) money_base::sign;
807      }
808      pos_format.field[3] = (char) money_base::none;
809      break;
810    default: // Default C++ Standard format
811      pos_format.field[0] = (char) money_base::symbol;
812      pos_format.field[1] = (char) money_base::sign;
813      pos_format.field[2] = (char) money_base::none;
814      pos_format.field[3] = (char) money_base::value;
815      break;
816  }
817
818
819  switch (_Locale_n_sign_posn(monetary)) {
820    case 0: // Parentheses surround the quantity and currency symbol
821    case 1: // The sign string precedes the quantity and currency symbol
822      neg_format.field[0] = (char) money_base::symbol;
823      neg_format.field[1] = (char) money_base::sign;
824      neg_format.field[2] = (char) money_base::value;
825      neg_format.field[3] = (char) money_base::none;
826      break;
827    case 2: // The sign string succeeds the quantity and currency symbol.
828      neg_format.field[0] = (char) money_base::symbol;
829      neg_format.field[1] = (char) money_base::value;
830      neg_format.field[2] = (char) money_base::sign;
831      neg_format.field[3] = (char) money_base::none;
832      break;
833    case 3: // The sign string immediately precedes the currency symbol.
834    case 4: // The sign string immediately succeeds the currency symbol.
835      neg_format.field[0] = (char) money_base::symbol;
836      if (_Locale_n_cs_precedes(monetary)) {
837        // 1 if currency symbol precedes a negative value
838        neg_format.field[1] = (char) money_base::sign;
839        neg_format.field[2] = (char) money_base::value;
840      } else {
841        // 0 if currency symbol succeeds a negative value
842        neg_format.field[1] = (char) money_base::value;
843        neg_format.field[2] = (char) money_base::sign;
844      }
845      neg_format.field[3] = (char) money_base::none;
846      break;
847    default: // Default C++ Standard format
848      neg_format.field[0] = (char) money_base::symbol;
849      neg_format.field[1] = (char) money_base::sign;
850      neg_format.field[2] = (char) money_base::none;
851      neg_format.field[3] = (char) money_base::value;
852      break;
853  }
854}
855
856_STLP_MOVE_TO_STD_NAMESPACE
857
858//
859// moneypunct_byname<>
860//
861moneypunct_byname<char, true>::moneypunct_byname(const char * name,
862                                                 size_t refs)
863    : moneypunct<char, true>(refs) {
864  if (!name)
865    locale::_M_throw_on_null_name();
866
867  int __err_code;
868  char buf[_Locale_MAX_SIMPLE_NAME];
869  _M_monetary = _STLP_PRIV __acquire_monetary(name, buf, 0, &__err_code);
870  if (!_M_monetary)
871    locale::_M_throw_on_creation_failure(__err_code, name, "moneypunct");
872
873  _STLP_PRIV _Init_monetary_formats_int(_M_pos_format, _M_neg_format, _M_monetary);
874}
875
876moneypunct_byname<char, true>::moneypunct_byname(_Locale_monetary *__mon)
877  : _M_monetary(__mon) {
878  _STLP_PRIV _Init_monetary_formats_int(_M_pos_format, _M_neg_format, _M_monetary);
879}
880
881moneypunct_byname<char, true>::~moneypunct_byname()
882{ _STLP_PRIV __release_monetary(_M_monetary); }
883
884char moneypunct_byname<char, true>::do_decimal_point() const
885{ return _Locale_mon_decimal_point(_M_monetary); }
886
887char moneypunct_byname<char, true>::do_thousands_sep() const
888{ return _Locale_mon_thousands_sep(_M_monetary); }
889
890string moneypunct_byname<char, true>::do_grouping() const
891{ return _Locale_mon_grouping(_M_monetary); }
892
893string moneypunct_byname<char, true>::do_curr_symbol() const
894{ return _Locale_int_curr_symbol(_M_monetary); }
895
896string moneypunct_byname<char, true>::do_positive_sign() const
897{ return _Locale_positive_sign(_M_monetary); }
898
899string moneypunct_byname<char, true>::do_negative_sign() const
900{ return _Locale_negative_sign(_M_monetary); }
901
902int moneypunct_byname<char, true>::do_frac_digits() const
903{ return _Locale_int_frac_digits(_M_monetary); }
904
905moneypunct_byname<char, false>::moneypunct_byname(const char * name,
906                                                  size_t refs)
907    : moneypunct<char, false>(refs) {
908  if (!name)
909    locale::_M_throw_on_null_name();
910
911  int __err_code;
912  char buf[_Locale_MAX_SIMPLE_NAME];
913  _M_monetary = _STLP_PRIV __acquire_monetary(name, buf, 0, &__err_code);
914  if (!_M_monetary)
915    locale::_M_throw_on_creation_failure(__err_code, name, "moneypunct");
916
917  _STLP_PRIV _Init_monetary_formats(_M_pos_format, _M_neg_format, _M_monetary);
918}
919
920moneypunct_byname<char, false>::moneypunct_byname(_Locale_monetary *__mon)
921  : _M_monetary(__mon) {
922  _STLP_PRIV _Init_monetary_formats(_M_pos_format, _M_neg_format, _M_monetary);
923}
924
925moneypunct_byname<char, false>::~moneypunct_byname()
926{ _STLP_PRIV __release_monetary(_M_monetary); }
927
928char moneypunct_byname<char, false>::do_decimal_point() const
929{ return _Locale_mon_decimal_point(_M_monetary); }
930
931char moneypunct_byname<char, false>::do_thousands_sep() const
932{ return _Locale_mon_thousands_sep(_M_monetary); }
933
934string moneypunct_byname<char, false>::do_grouping() const
935{ return _Locale_mon_grouping(_M_monetary); }
936
937string moneypunct_byname<char, false>::do_curr_symbol() const
938{ return _Locale_currency_symbol(_M_monetary); }
939
940string moneypunct_byname<char, false>::do_positive_sign() const
941{ return _Locale_positive_sign(_M_monetary); }
942
943string moneypunct_byname<char, false>::do_negative_sign() const
944{ return _Locale_negative_sign(_M_monetary); }
945
946int moneypunct_byname<char, false>::do_frac_digits() const
947{ return _Locale_frac_digits(_M_monetary); }
948
949//
950// moneypunct_byname<wchar_t>
951//
952#if !defined (_STLP_NO_WCHAR_T)
953
954moneypunct_byname<wchar_t, true>::moneypunct_byname(const char * name,
955                                                    size_t refs)
956    : moneypunct<wchar_t, true>(refs) {
957  if (!name)
958    locale::_M_throw_on_null_name();
959
960  int __err_code;
961  char buf[_Locale_MAX_SIMPLE_NAME];
962  _M_monetary = _STLP_PRIV __acquire_monetary(name, buf, 0, &__err_code);
963  if (!_M_monetary)
964    locale::_M_throw_on_creation_failure(__err_code, name, "moneypunct");
965
966  _STLP_PRIV _Init_monetary_formats_int(_M_pos_format, _M_neg_format, _M_monetary);
967}
968
969moneypunct_byname<wchar_t, true>::moneypunct_byname(_Locale_monetary *__mon)
970  : _M_monetary(__mon) {
971  _STLP_PRIV _Init_monetary_formats_int(_M_pos_format, _M_neg_format, _M_monetary);
972}
973
974moneypunct_byname<wchar_t, true>::~moneypunct_byname()
975{ _STLP_PRIV __release_monetary(_M_monetary); }
976
977wchar_t moneypunct_byname<wchar_t, true>::do_decimal_point() const
978{ return _Locale_mon_decimal_point(_M_monetary); }
979
980wchar_t moneypunct_byname<wchar_t, true>::do_thousands_sep() const
981{ return _Locale_mon_thousands_sep(_M_monetary); }
982
983string moneypunct_byname<wchar_t, true>::do_grouping() const
984{ return _Locale_mon_grouping(_M_monetary); }
985
986inline wstring __do_widen (string const& str) {
987#if defined (_STLP_NO_MEMBER_TEMPLATES) || defined (_STLP_MSVC)
988  wstring::_Reserve_t __Reserve;
989  size_t __size = str.size();
990  wstring result(__Reserve, __size);
991  copy(str.begin(), str.end(), result.begin());
992#else
993  wstring result(str.begin(), str.end());
994#endif
995  return result;
996}
997
998wstring moneypunct_byname<wchar_t, true>::do_curr_symbol() const
999{ wchar_t buf[16]; return _WLocale_int_curr_symbol(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1000
1001wstring moneypunct_byname<wchar_t, true>::do_positive_sign() const
1002{ wchar_t buf[16]; return _WLocale_positive_sign(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1003
1004wstring moneypunct_byname<wchar_t, true>::do_negative_sign() const
1005{ wchar_t buf[16]; return _WLocale_negative_sign(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1006
1007int moneypunct_byname<wchar_t, true>::do_frac_digits() const
1008{ return _Locale_int_frac_digits(_M_monetary); }
1009
1010moneypunct_byname<wchar_t, false>::moneypunct_byname(const char * name,
1011                                                     size_t refs)
1012    : moneypunct<wchar_t, false>(refs) {
1013  if (!name)
1014    locale::_M_throw_on_null_name() ;
1015
1016  int __err_code;
1017  char buf[_Locale_MAX_SIMPLE_NAME];
1018  _M_monetary = _STLP_PRIV __acquire_monetary(name, buf, 0, &__err_code);
1019  if (!_M_monetary)
1020    locale::_M_throw_on_creation_failure(__err_code, name, "moneypunct");
1021
1022  _STLP_PRIV _Init_monetary_formats(_M_pos_format, _M_neg_format, _M_monetary);
1023}
1024
1025moneypunct_byname<wchar_t, false>::moneypunct_byname(_Locale_monetary *__mon)
1026  : _M_monetary(__mon) {
1027  _STLP_PRIV _Init_monetary_formats(_M_pos_format, _M_neg_format, _M_monetary);
1028}
1029
1030moneypunct_byname<wchar_t, false>::~moneypunct_byname()
1031{ _STLP_PRIV __release_monetary(_M_monetary); }
1032
1033wchar_t moneypunct_byname<wchar_t, false>::do_decimal_point() const
1034{ return _Locale_mon_decimal_point(_M_monetary); }
1035
1036wchar_t moneypunct_byname<wchar_t, false>::do_thousands_sep() const
1037{ return _Locale_mon_thousands_sep(_M_monetary); }
1038
1039string moneypunct_byname<wchar_t, false>::do_grouping() const
1040{ return _Locale_mon_grouping(_M_monetary); }
1041
1042wstring moneypunct_byname<wchar_t, false>::do_curr_symbol() const
1043{ wchar_t buf[16]; return _WLocale_currency_symbol(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1044
1045wstring moneypunct_byname<wchar_t, false>::do_positive_sign() const
1046{ wchar_t buf[16]; return _WLocale_positive_sign(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1047
1048wstring moneypunct_byname<wchar_t, false>::do_negative_sign() const
1049{ wchar_t buf[16]; return _WLocale_negative_sign(_M_monetary, _STLP_ARRAY_AND_SIZE(buf)); }
1050
1051int moneypunct_byname<wchar_t, false>::do_frac_digits() const
1052{ return _Locale_frac_digits(_M_monetary); }
1053
1054#endif
1055
1056_STLP_END_NAMESPACE
1057
1058