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
ctype_byname(const char * name,size_t refs)41 ctype_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 
_M_init()55 void 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 
~ctype_byname()66 ctype_byname<char>::~ctype_byname()
67 { _STLP_PRIV __release_ctype(_M_ctype); }
68 
do_toupper(char c) const69 char ctype_byname<char>::do_toupper(char c) const
70 { return (char)_Locale_toupper(_M_ctype, c); }
71 
do_tolower(char c) const72 char ctype_byname<char>::do_tolower(char c) const
73 { return (char)_Locale_tolower(_M_ctype, c); }
74 
75 const char*
do_toupper(char * first,const char * last) const76 ctype_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 
82 const char*
do_tolower(char * first,const char * last) const83 ctype_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 
97 struct _Ctype_byname_w_is_mask : public unary_function<wchar_t, bool> {
98   _Locale_mask_t M;
99   _Locale_ctype* M_ctp;
100 
_Ctype_byname_w_is_mask_Ctype_byname_w_is_mask101   _Ctype_byname_w_is_mask(_Locale_mask_t m, _Locale_ctype* c)
102     : M(m), M_ctp(c) {}
operator ()_Ctype_byname_w_is_mask103   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
ctype_byname(const char * name,size_t refs)112 ctype_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 
~ctype_byname()124 ctype_byname<wchar_t>::~ctype_byname()
125 { _STLP_PRIV __release_ctype(_M_ctype); }
126 
do_is(ctype_base::mask m,wchar_t c) const127 bool 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 
130 const wchar_t*
do_is(const wchar_t * low,const wchar_t * high,ctype_base::mask * m) const131 ctype_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 
148 const wchar_t*
149 ctype_byname<wchar_t>
do_scan_is(ctype_base::mask m,const wchar_t * low,const wchar_t * high) const150   ::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 
153 const wchar_t*
154 ctype_byname<wchar_t>
do_scan_not(ctype_base::mask m,const wchar_t * low,const wchar_t * high) const155   ::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 
do_toupper(wchar_t c) const158 wchar_t ctype_byname<wchar_t>::do_toupper(wchar_t c) const
159 { return _WLocale_toupper(_M_ctype, c); }
160 
161 const wchar_t*
do_toupper(wchar_t * low,const wchar_t * high) const162 ctype_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 
do_tolower(wchar_t c) const168 wchar_t ctype_byname<wchar_t>::do_tolower(wchar_t c) const
169 { return _WLocale_tolower(_M_ctype, c); }
170 
171 const wchar_t*
do_tolower(wchar_t * low,const wchar_t * high) const172 ctype_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
collate_byname(const char * name,size_t refs)184 collate_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 
~collate_byname()196 collate_byname<char>::~collate_byname()
197 { _STLP_PRIV __release_collate(_M_collate); }
198 
do_compare(const char * __low1,const char * __high1,const char * __low2,const char * __high2) const199 int 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 
208 collate_byname<char>::string_type
do_transform(const char * low,const char * high) const209 collate_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
collate_byname(const char * name,size_t refs)231 collate_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 
~collate_byname()243 collate_byname<wchar_t>::~collate_byname()
244 { _STLP_PRIV __release_collate(_M_collate); }
245 
do_compare(const wchar_t * low1,const wchar_t * high1,const wchar_t * low2,const wchar_t * high2) const246 int 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 
255 collate_byname<wchar_t>::string_type
do_transform(const wchar_t * low,const wchar_t * high) const256 collate_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 
276 codecvt_byname<char, char, mbstate_t>
codecvt_byname(const char * name,size_t refs)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 
~codecvt_byname()283 codecvt_byname<char, char, mbstate_t>::~codecvt_byname() {}
284 
285 
286 #if !defined (_STLP_NO_WCHAR_T)
287 
288 //----------------------------------------------------------------------
289 // codecvt_byname<wchar_t>
codecvt_byname(const char * name,size_t refs)290 codecvt_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 
~codecvt_byname()302 codecvt_byname<wchar_t, char, mbstate_t>::~codecvt_byname()
303 { _STLP_PRIV __release_codecvt(_M_codecvt); }
304 
305 codecvt<wchar_t, char, mbstate_t>::result
do_out(state_type & state,const intern_type * from,const intern_type * from_end,const intern_type * & from_next,extern_type * to,extern_type * to_limit,extern_type * & to_next) const306 codecvt_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 
337 codecvt<wchar_t, char, mbstate_t>::result
do_in(state_type & state,const extern_type * from,const extern_type * from_end,const extern_type * & from_next,intern_type * to,intern_type * to_end,intern_type * & to_next) const338 codecvt_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 
370 codecvt<wchar_t, char, mbstate_t>::result
do_unshift(state_type & state,extern_type * to,extern_type * to_limit,extern_type * & to_next) const371 codecvt_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 
390 int
do_encoding() const391 codecvt_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 
401 bool
do_always_noconv() const402 codecvt_byname<wchar_t, char, mbstate_t>::do_always_noconv() const _STLP_NOTHROW
403 { return false; }
404 
405 int
do_length(state_type & state,const extern_type * from,const extern_type * end,size_t mx) const406 codecvt_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 
424 int
do_max_length() const425 codecvt_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>
numpunct_byname(const char * name,size_t refs)430 numpunct_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 
~numpunct_byname()442 numpunct_byname<char>::~numpunct_byname()
443 { _STLP_PRIV __release_numeric(_M_numeric); }
444 
do_decimal_point() const445 char numpunct_byname<char>::do_decimal_point() const
446 { return _Locale_decimal_point(_M_numeric); }
447 
do_thousands_sep() const448 char numpunct_byname<char>::do_thousands_sep() const
449 { return _Locale_thousands_sep(_M_numeric); }
450 
do_grouping() const451 string 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 
do_truename() const458 string numpunct_byname<char>::do_truename() const
459 { return _Locale_true(_M_numeric); }
460 
do_falsename() const461 string 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 
numpunct_byname(const char * name,size_t refs)471 numpunct_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 
~numpunct_byname()483 numpunct_byname<wchar_t>::~numpunct_byname()
484 { _STLP_PRIV __release_numeric(_M_numeric); }
485 
do_decimal_point() const486 wchar_t numpunct_byname<wchar_t>::do_decimal_point() const
487 { return _WLocale_decimal_point(_M_numeric); }
488 
do_thousands_sep() const489 wchar_t numpunct_byname<wchar_t>::do_thousands_sep() const
490 { return _WLocale_thousands_sep(_M_numeric); }
491 
do_grouping() const492 string 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 
do_truename() const499 wstring 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 
do_falsename() const504 wstring 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 
_Init_monetary_formats(money_base::pattern & pos_format,money_base::pattern & neg_format,_Locale_monetary * monetary)513 static 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 
_Init_monetary_formats_int(money_base::pattern & pos_format,money_base::pattern & neg_format,_Locale_monetary * monetary)777 static 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 //
moneypunct_byname(const char * name,size_t refs)861 moneypunct_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 
moneypunct_byname(_Locale_monetary * __mon)876 moneypunct_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 
~moneypunct_byname()881 moneypunct_byname<char, true>::~moneypunct_byname()
882 { _STLP_PRIV __release_monetary(_M_monetary); }
883 
do_decimal_point() const884 char moneypunct_byname<char, true>::do_decimal_point() const
885 { return _Locale_mon_decimal_point(_M_monetary); }
886 
do_thousands_sep() const887 char moneypunct_byname<char, true>::do_thousands_sep() const
888 { return _Locale_mon_thousands_sep(_M_monetary); }
889 
do_grouping() const890 string moneypunct_byname<char, true>::do_grouping() const
891 { return _Locale_mon_grouping(_M_monetary); }
892 
do_curr_symbol() const893 string moneypunct_byname<char, true>::do_curr_symbol() const
894 { return _Locale_int_curr_symbol(_M_monetary); }
895 
do_positive_sign() const896 string moneypunct_byname<char, true>::do_positive_sign() const
897 { return _Locale_positive_sign(_M_monetary); }
898 
do_negative_sign() const899 string moneypunct_byname<char, true>::do_negative_sign() const
900 { return _Locale_negative_sign(_M_monetary); }
901 
do_frac_digits() const902 int moneypunct_byname<char, true>::do_frac_digits() const
903 { return _Locale_int_frac_digits(_M_monetary); }
904 
moneypunct_byname(const char * name,size_t refs)905 moneypunct_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 
moneypunct_byname(_Locale_monetary * __mon)920 moneypunct_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 
~moneypunct_byname()925 moneypunct_byname<char, false>::~moneypunct_byname()
926 { _STLP_PRIV __release_monetary(_M_monetary); }
927 
do_decimal_point() const928 char moneypunct_byname<char, false>::do_decimal_point() const
929 { return _Locale_mon_decimal_point(_M_monetary); }
930 
do_thousands_sep() const931 char moneypunct_byname<char, false>::do_thousands_sep() const
932 { return _Locale_mon_thousands_sep(_M_monetary); }
933 
do_grouping() const934 string moneypunct_byname<char, false>::do_grouping() const
935 { return _Locale_mon_grouping(_M_monetary); }
936 
do_curr_symbol() const937 string moneypunct_byname<char, false>::do_curr_symbol() const
938 { return _Locale_currency_symbol(_M_monetary); }
939 
do_positive_sign() const940 string moneypunct_byname<char, false>::do_positive_sign() const
941 { return _Locale_positive_sign(_M_monetary); }
942 
do_negative_sign() const943 string moneypunct_byname<char, false>::do_negative_sign() const
944 { return _Locale_negative_sign(_M_monetary); }
945 
do_frac_digits() const946 int 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 
moneypunct_byname(const char * name,size_t refs)954 moneypunct_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 
moneypunct_byname(_Locale_monetary * __mon)969 moneypunct_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 
~moneypunct_byname()974 moneypunct_byname<wchar_t, true>::~moneypunct_byname()
975 { _STLP_PRIV __release_monetary(_M_monetary); }
976 
do_decimal_point() const977 wchar_t moneypunct_byname<wchar_t, true>::do_decimal_point() const
978 { return _Locale_mon_decimal_point(_M_monetary); }
979 
do_thousands_sep() const980 wchar_t moneypunct_byname<wchar_t, true>::do_thousands_sep() const
981 { return _Locale_mon_thousands_sep(_M_monetary); }
982 
do_grouping() const983 string moneypunct_byname<wchar_t, true>::do_grouping() const
984 { return _Locale_mon_grouping(_M_monetary); }
985 
__do_widen(string const & str)986 inline 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 
do_curr_symbol() const998 wstring 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 
do_positive_sign() const1001 wstring 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 
do_negative_sign() const1004 wstring 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 
do_frac_digits() const1007 int moneypunct_byname<wchar_t, true>::do_frac_digits() const
1008 { return _Locale_int_frac_digits(_M_monetary); }
1009 
moneypunct_byname(const char * name,size_t refs)1010 moneypunct_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 
moneypunct_byname(_Locale_monetary * __mon)1025 moneypunct_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 
~moneypunct_byname()1030 moneypunct_byname<wchar_t, false>::~moneypunct_byname()
1031 { _STLP_PRIV __release_monetary(_M_monetary); }
1032 
do_decimal_point() const1033 wchar_t moneypunct_byname<wchar_t, false>::do_decimal_point() const
1034 { return _Locale_mon_decimal_point(_M_monetary); }
1035 
do_thousands_sep() const1036 wchar_t moneypunct_byname<wchar_t, false>::do_thousands_sep() const
1037 { return _Locale_mon_thousands_sep(_M_monetary); }
1038 
do_grouping() const1039 string moneypunct_byname<wchar_t, false>::do_grouping() const
1040 { return _Locale_mon_grouping(_M_monetary); }
1041 
do_curr_symbol() const1042 wstring 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 
do_positive_sign() const1045 wstring 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 
do_negative_sign() const1048 wstring 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 
do_frac_digits() const1051 int 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