Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.moneypunct.cpp
Go to the documentation of this file.
1
29#include <locale>
30
31#include <cassert>
32#include <clocale> // for LC_ALL, setlocale()
33#include <cstdio> // for fprintf(), stderr
34#include <cstdlib> // for getenv()
35#include <cstring> // for memcmp(), strerror()
36
37#include <rw_driver.h> // for rw_test()
38#include <rw_environ.h> // for rw_putenv()
39#include <rw_locale.h> // for rw_locales()
40#include <rw_printf.h> // for rw_fprintf()
41
42
44typedef unsigned char UChar;
45
46
48// does a deep copy of struct lconv
49std::lconv* lconvdup (const std::lconv *plconv)
50{
51 if (!plconv)
52 return 0;
53
54 const std::size_t
55 decimal_point_sz = std::strlen (plconv->decimal_point) + 1,
56 thousands_sep_sz = std::strlen (plconv->thousands_sep) + 1,
57 grouping_sz = std::strlen (plconv->grouping) + 1,
58 int_curr_symbol_sz = std::strlen (plconv->int_curr_symbol) + 1,
59 currency_symbol_sz = std::strlen (plconv->currency_symbol) + 1,
60 mon_decimal_point_sz = std::strlen (plconv->mon_decimal_point) + 1,
61 mon_thousands_sep_sz = std::strlen (plconv->mon_thousands_sep) + 1,
62 mon_grouping_sz = std::strlen (plconv->mon_grouping) + 1,
63 positive_sign_sz = std::strlen (plconv->positive_sign) + 1,
64 negative_sign_sz = std::strlen (plconv->negative_sign) + 1;
65
66 const std::size_t total_sz =
67 decimal_point_sz
68 + thousands_sep_sz
69 + grouping_sz
70 + int_curr_symbol_sz
71 + currency_symbol_sz
72 + mon_decimal_point_sz
73 + mon_thousands_sep_sz
74 + mon_grouping_sz
75 + positive_sign_sz
76 + negative_sign_sz;
77
78 const std::size_t bufsize = sizeof (std::lconv) + total_sz;
79
80 char *pbuf = _RWSTD_STATIC_CAST (char*, operator new (bufsize));
81
82 std::lconv *plconv2 = _RWSTD_REINTERPRET_CAST (std::lconv*, pbuf);
83
84 plconv2->decimal_point = (pbuf += sizeof (std::lconv));
85 std::memcpy (pbuf, plconv->decimal_point, decimal_point_sz);
86
87 plconv2->thousands_sep = (pbuf += decimal_point_sz);
88 std::memcpy (pbuf, plconv->thousands_sep, thousands_sep_sz);
89
90 plconv2->grouping = (pbuf += thousands_sep_sz);
91 std::memcpy (pbuf, plconv->grouping, grouping_sz);
92
93 plconv2->int_curr_symbol = (pbuf += grouping_sz);
94 std::memcpy (pbuf, plconv->int_curr_symbol, int_curr_symbol_sz);
95
96 plconv2->currency_symbol = (pbuf += int_curr_symbol_sz);
97 std::memcpy (pbuf, plconv->currency_symbol, currency_symbol_sz);
98
99 plconv2->mon_decimal_point = (pbuf += currency_symbol_sz);
100 std::memcpy (pbuf, plconv->mon_decimal_point, mon_decimal_point_sz);
101
102 plconv2->mon_thousands_sep = (pbuf += mon_decimal_point_sz);
103 std::memcpy (pbuf, plconv->mon_thousands_sep, mon_thousands_sep_sz);
104
105 plconv2->mon_grouping = (pbuf += mon_thousands_sep_sz);
106 std::memcpy (pbuf, plconv->mon_grouping, mon_grouping_sz);
107
108 plconv2->positive_sign = (pbuf += mon_grouping_sz);
109 std::memcpy (pbuf, plconv->positive_sign, positive_sign_sz);
110
111 plconv2->negative_sign = (pbuf += positive_sign_sz);
112 std::memcpy (pbuf, plconv->negative_sign, negative_sign_sz);
113
114 plconv2->int_frac_digits = plconv->int_frac_digits;
115 plconv2->frac_digits = plconv->frac_digits;
116 plconv2->p_cs_precedes = plconv->p_cs_precedes;
117 plconv2->p_sep_by_space = plconv->p_sep_by_space;
118 plconv2->n_cs_precedes = plconv->n_cs_precedes;
119 plconv2->n_sep_by_space = plconv->n_sep_by_space;
120 plconv2->p_sign_posn = plconv->p_sign_posn;
121 plconv2->n_sign_posn = plconv->n_sign_posn;
122
123#ifndef _RWSTD_NO_LCONV_INT_FMAT
124
125 plconv2->int_p_cs_precedes = plconv->int_p_cs_precedes;
126 plconv2->int_p_sep_by_space = plconv->int_p_sep_by_space;
127 plconv2->int_n_cs_precedes = plconv->int_n_cs_precedes;
128 plconv2->int_n_sep_by_space = plconv->int_n_sep_by_space;
129 plconv2->int_p_sign_posn = plconv->int_p_sign_posn;
130 plconv2->int_n_sign_posn = plconv->int_n_sign_posn;
131
132#endif // _RWSTD_NO_LCONV_INT_FMAT
133
134 return plconv2;
135}
136
137
139template <class charT>
140class Test
141{
142 std::locale loc_;
143 bool intl_; // international?
144 const char *char_name_; // charT name ("char" or "wchar_t")
145 const char *locname_;
146 const char *lang_;
147 const char *lc_all_;
148 const char *lc_monetary_;
149
150public:
151
152 typedef std::moneypunct<charT, false> Punct;
153 typedef std::moneypunct<charT, true> IntlPunct;
154
155 Test (const char *cname, bool intl)
156 : loc_ (), intl_ (intl),
157 char_name_ (cname),
158 locname_ (0), lang_ (0), lc_all_ (0), lc_monetary_ (0) { }
159
160 void runTest ();
161
164 void check_frac_digits (int);
165 void check_grouping (const std::string&);
166
167 typedef std::char_traits<charT> Traits;
168 typedef std::allocator<charT> Allocator;
169 typedef std::basic_string<charT, Traits, Allocator> String;
170
171 void check_curr_symbol (const String&);
172 void check_positive_sign (const String&);
173 void check_negative_sign (const String&);
174
175 void check_format (const std::lconv&);
176 void check_format (bool, std::money_base::pattern, const UChar [3]);
177
178 bool check_moneypunct (const char*);
179};
180
181
183template <class charT>
185runTest()
186{
187 // create a copy of the classic C locale
188 loc_ = std::locale::classic ();
189
190 // verify (at compile time) that _bynam facets can be used
191 // to specialize use_facet() and has_facet()
192 typedef std::moneypunct_byname<charT, false> MoneyPunctByname;
193 typedef std::moneypunct_byname<charT, true> MoneyPunctIntlByname;
194
195 if (1) {
196 if (_STD_HAS_FACET (MoneyPunctByname, loc_))
197 _RWSTD_USE_FACET (MoneyPunctByname, loc_);
198
199 if (_STD_HAS_FACET (MoneyPunctIntlByname, loc_))
200 _RWSTD_USE_FACET (MoneyPunctIntlByname, loc_);
201 }
202
203 // note that values in 7.4 of C89, and 7.11, p2 of C99, respectively,
204 // or '\0' and '\0' for decimal_point and thousands_sep, are specified
205 // in 22.2.3.1.2, p1 and p2 of C++98 to be '.', and ',' in the C locale
206 //
209 check_frac_digits (0 /* i.e., not available, or same as CHAR_MAX in C */);
210 check_grouping ("");
211
212 const charT empty[] = { '\0' };
213 check_curr_symbol (empty);
214 check_positive_sign (empty);
215 check_negative_sign (empty);
216
217 // verify 22.2.6.3.2, p7:
218 // moneypunct<char>, moneypunct<wchar_t>, moneypunct<char,true>, and
219 // moneypunct<wchar_t,true>, return an object of type pattern initialized
220 // to { symbol, sign, none, value }
221 std::money_base::pattern fmat = {
222 // initializer must be properly bracketed to prevent g++ warnings
223 {
224 std::money_base::symbol,
225 std::money_base::sign,
226 std::money_base::none,
227 std::money_base::value
228 }
229 };
230
231 const UChar cpat [4] = { '?', '?', '?', 0 };
232 check_format (false /* negative */, fmat, cpat);
233 check_format (true /* positive */, fmat, cpat);
234
235 // exercise the native locale (affected by the environment
236 // variables LANG, LC_ALL, LC_MONETARY, etc.)
237 check_moneypunct (""); // native locale
238
239 // the name of the first non-C (and non-POSIX) locale
240 const char *first_non_c = 0;
241
242 // exercise named locales (including "C" and "POSIX")
243 for (const char* s = rw_locales (); s && *s; s += std::strlen (s) + 1) {
244 if (check_moneypunct (s))
245 if ( !first_non_c
246 && std::strcmp ("C", s)
247 && std::strcmp ("POSIX", s)) {
248 first_non_c = s;
249 }
250 }
251
252 if (!first_non_c)
253 return;
254
255 // verify that moneypunct behaves correctly when LC_ALL is set
256 // to the name of the (non-C, non-POSIX) locale
257 char envvar [80];
258
259 // make sure buffer doesn't overflow
260 assert (std::strlen(first_non_c) + sizeof "LC_ALL=" <= sizeof envvar);
261
262 std::sprintf (envvar, "LC_ALL=%s", first_non_c);
263 rw_putenv (envvar);
264 check_moneypunct ("");
265
266 // remove LC_ALL from the environment
267 rw_putenv ("LC_ALL=");
268}
269
270
272std::string convert (const char*, const char *s, const char*)
273{
274 return std::string (s);
275}
276
277
278// convert a multibyte character string in an external representation
279// to wstring object in an internal representation
280std::wstring
281convert (const char *locname, const char *s, const wchar_t*)
282{
283 // save the name of the original locale
284 std::string saved_loc;
285
286 if (const char *savename = std::setlocale (LC_ALL, 0))
287 saved_loc = savename;
288
289 // switch to (named) locale
290 const char *loc = std::setlocale (LC_ALL, locname);
291 if (!loc) {
293 "%s:%d: setlocale (LC_ALL, %s) = 0: %m\n",
294 locname);
295 return std::wstring ();
296 }
297
298 // use an extension: allocate but do not initialize
299 std::wstring res ((wchar_t*)0, 64);
300
301 for ( ; ; ) {
302 // try to convert, resizing buffer if necessary
303 std::size_t n =
304 std::mbstowcs (&res [0], s, res.capacity ());
305
306 if (res.capacity () == n)
307 // increase capacity
308 res.reserve (res.capacity () * 2);
309 else if (std::size_t (-1) == n) {
310
311 // restore the original locale before printing out
312 // the error message (we don't want it localized)
313 std::setlocale (LC_ALL, saved_loc.c_str ());
314
316 "%s:%d: mbstowcs(..., %#s, %zu) "
317 "= -1: %m\n", __FILE__, __LINE__,
318 s, res.capacity ());
319 res = std::wstring (); // mbstowcs() error
320
321 return res;
322 }
323 else {
324 // shrink if necessary
325 res.resize (n);
326 break;
327 }
328 }
329
330 // restore original locale
331 std::setlocale (LC_ALL, saved_loc.c_str ());
332
333 return res;
334}
335
336
338template <class charT>
340check_moneypunct (const char *locname)
341{
342 // (try to) set the global C locale
343 char locnamebuf [256];
344 const char *loc = std::setlocale (LC_ALL, locname);
345 if (!loc)
346 return false;
347
348 loc = std::strcpy (locnamebuf, loc);
349
350 locname_ = loc;
351
352 // the values of the environment variables LANG, LC_ALL,
353 // and LC_MONETARY (and others) affect the native locale
354 lang_ = std::getenv ("LANG");
355 lc_all_ = std::getenv ("LC_ALL");
356 lc_monetary_ = std::getenv ("LC_MONETARY");
357
358 if (!lang_)
359 lang_ = "(null)";
360 if (!lc_all_)
361 lc_all_ = "(null)";
362 if (!lc_monetary_)
363 lc_monetary_ = "(null)";
364
365 _TRY {
366
367 // get a pointer to lconv and copy data to a temporray buffer
368 const std::lconv* const plconv = lconvdup (std::localeconv ());
369
370 if (!plconv)
371 return false;
372
373 // reset to default locale given by LC_LANG
374 std::setlocale (LC_ALL, "");
375
376 // create a new C++ locale object
377 loc_ = std::locale (locname);
378
379 // check that newly constructed locale matches
380
381 // the MBCS mon_decimal_point and mon_thousands_sep must
382 // be properly converted (i.e., *mon_decimal_point may not
383 // the same as s [0] after the conversion)
384 String s;
385
386 // `locname' may be the empty string, in which case `loc'
387 // will be set to the actual name of the locale
388 if ( std::strcmp ("C", locname)
389 && std::strcmp ("C", loc)) {
390
391 // named locale other than "C" or "POISX"
392 s = ::convert (locname, plconv->mon_decimal_point, (charT*)0);
393 check_decimal_point (s.size () ? s [0] : charT ());
394
395 s = ::convert (locname, plconv->mon_thousands_sep, (charT*)0);
396 check_thousands_sep (s.size () ? s [0] : charT ());
397
398 check_frac_digits (plconv->int_frac_digits);
399 }
400 else {
401 // note that values in 7.4 of C89, and 7.11, p2 of C99,
402 // respectively, or '\0' and '\0' for decimal_point and
403 // thousands_sep, are specified in 22.2.3.1.2, p1 and p2
404 // of C++98 to be '.', and ',' in the C locale
407
408 // frac_digits is specified as CHAR_MAX (i.e., not available) by C99
409 // verify that the C++ value is NOT CHAR_MAX, but rather 0 (it could
410 // be negative with the same result)
411 check_frac_digits (0);
412 }
413
414 check_grouping (plconv->mon_grouping);
415
416 // convert a (possibly) multibyte string in external
417 // representation to one in internal representation
418 s = intl_ ? ::convert (locname, plconv->int_curr_symbol, (charT*)0)
419 : ::convert (locname, plconv->currency_symbol, (charT*)0);
420
421 check_curr_symbol (s);
422
423 s = ::convert (locname, plconv->positive_sign, (charT*)0);
424
425 check_positive_sign (s);
426
427 s = ::convert (locname, plconv->negative_sign, (charT*)0);
428
429 check_negative_sign (s);
430
431 check_format (*plconv);
432
433 // cast away constness to work around compiler bugs (e.g., MSVC 6)
434 operator delete (_RWSTD_CONST_CAST (std::lconv*, plconv));
435 }
436 _CATCH (...) {
437 return false;
438 }
439 return true;
440}
441
442
444template <class charT>
447{
448 const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).decimal_point ()
449 : _RWSTD_USE_FACET (Punct, loc_).decimal_point ();
450
451 rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
452 "moneypunct<%s, %b>::decimal_point() == %#lc, got %#lc "
453 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
454 char_name_, intl_, result, c,
455 locname_, lang_, lc_all_, lc_monetary_);
456}
457
458
460template <class charT>
463{
464 const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).thousands_sep ()
465 : _RWSTD_USE_FACET (Punct, loc_).thousands_sep ();
466
467 rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
468 "moneypunct<%s, %b>::thousands_sep() == %#lc, got %#lc "
469 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
470 char_name_, intl_, result, c,
471 locname_, lang_, lc_all_, lc_monetary_);
472}
473
474
476template <class charT>
479{
480 const int i = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).frac_digits ()
481 : _RWSTD_USE_FACET (Punct, loc_).frac_digits ();
482
483 rw_assert (i == result, 0, __LINE__,
484 "moneypunct<%s, %b>::frac_digits() == %d, got %d "
485 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
486 char_name_, intl_, result, i,
487 locname_, lang_, lc_all_, lc_monetary_);
488}
489
490
492template <class charT>
494check_grouping (const std::string &result)
495{
496 const std::string s = intl_ ?
497 _RWSTD_USE_FACET (IntlPunct, loc_).grouping ()
498 : _RWSTD_USE_FACET (Punct, loc_).grouping ();
499
500 if ( s != result
501 && s.size () != result.size () && s.size () && result.size ()) {
502
503 // if the grouping is not exactly the same as the expected result,
504 // verify that the actual grouping is equivalent to the expected
505 // one, e.g., that "\003\003" is equivalent to "\003"
506
507 const std::string *lng = s.size () > result.size () ? &result : &s;
508 const std::string *shrt = s.size () < result.size () ? &result : &s;
509
510 std::size_t i = shrt->size () - 1;
511
512 for ( ; i != lng->size (); ++i)
513 if ((*shrt) [shrt->size () - 1] != (*lng)[i])
514 break;
515
516 rw_assert (i == lng->size (), 0, __LINE__,
517 "numpunct<%s, %b>::grouping() equivalent to %#s, got %#s "
518 "in locale (%#s) with LANG=%s, LC_ALL=%s, "
519 "LC_MONETARY=%s",
520 char_name_, intl_, result.c_str (), s.c_str (),
521 locname_, lang_, lc_all_, lc_monetary_);
522 }
523 else
524 rw_assert (s == result, 0, __LINE__,
525 "moneypunct<%s, %b>::grouping() == %#s, got %#s "
526 "in locale (%#s) with LANG=%s, LC_ALL=%s, "
527 "LC_MONETARY=%s",
528 char_name_, intl_, result.c_str (), s.c_str (),
529 locname_, lang_, lc_all_, lc_monetary_);
530
531#if 0
532
533 // Test disabled: what's meant here is that the pattern, NOT the value,
534 // is defined identically as that of numpunct<charT>::do_grouping().
535 // The values are often going to be different since one uses
536 // lconv::grouping, and the other lconv::mon_grouping.
537
538 // 22.2.6.3.2, p3: do_grouping() returns a pattern defined identically
539 // as the result of numpunct<charT>::do_grouping().
540
541 const std::string grp =
542 _RWSTD_USE_FACET (std::numpunct<charT>, loc_).grouping ();
543
544 rw_assert (s == grp, 0, __LINE__,
545 "moneypunct<%s, %b>::grouping() == numpunct<>::grouping() == "
546 "%{*Ac}, got %{*Ac} in locale (\"%s\") with LANG=%s, LC_ALL=%s, "
547 "LC_MONETARY=%s",
548 char_name_, intl_,
549 int (sizeof (charT)), result.c_str (),
550 int (sizeof (charT)), s.c_str (),
551 locname_, lang_, lc_all_, lc_monetary_);
552
553#endif // 0
554
555}
556
557
559template <class charT>
562{
563 const String s = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).curr_symbol ()
564 : _RWSTD_USE_FACET (Punct, loc_).curr_symbol ();
565
566 rw_assert (s == result, 0, __LINE__,
567 "moneypunct<%s, %b>::curr_symbol() == %{*Ac}, got %{*Ac} "
568 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
569 char_name_, intl_,
570 int (sizeof (charT)), result.c_str (),
571 int (sizeof (charT)), s.c_str (),
572 locname_, lang_, lc_all_, lc_monetary_);
573}
574
575
577template <class charT>
580{
581 const String s = intl_ ?
582 _RWSTD_USE_FACET (IntlPunct, loc_).positive_sign ()
583 : _RWSTD_USE_FACET (Punct, loc_).positive_sign ();
584
585 rw_assert (s == result, 0, __LINE__,
586 "moneypunct<%s, %b>::positive_sign() == %{*Ac}, got %{*Ac} "
587 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
588 char_name_, intl_,
589 int (sizeof (charT)), result.c_str (),
590 int (sizeof (charT)), s.c_str (),
591 locname_, lang_, lc_all_, lc_monetary_);
592}
593
594
596template <class charT>
599{
600 const String s = intl_ ?
601 _RWSTD_USE_FACET (IntlPunct, loc_).negative_sign ()
602 : _RWSTD_USE_FACET (Punct, loc_).negative_sign ();
603
604 rw_assert (s == result, 0, __LINE__,
605 "moneypunct<%s, %b>::negative_sign() == %{*Ac}, got %{*Ac} "
606 "in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
607 char_name_, intl_,
608 int (sizeof (charT)), result.c_str (),
609 int (sizeof (charT)), s.c_str (),
610 locname_, lang_, lc_all_, lc_monetary_);
611}
612
613
615template <class charT>
617check_format (const std::lconv &lc)
618{
619 const UChar cpat [2][2][3] = {
620 // ^ ^ ^
621 // | | |
622 // | | +--- cs_precedes, sep_by_space, sign_posn
623 // | +------ positive, negative
624 // +--------- local, international
625
626 {
627 // C90 positive local format
628 { lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
629
630 // C90 negative local format
631 { lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
632 },
633
634#ifndef _RWSTD_NO_LCONV_INT_FMAT
635
636 { // C99 positive international format
637 { lc.int_p_cs_precedes, lc.int_p_sep_by_space, lc.int_p_sign_posn},
638
639 // C99 negative international format
640 { lc.int_n_cs_precedes, lc.int_n_sep_by_space, lc.int_n_sign_posn }
641 }
642
643#else // if defined (_RWSTD_NO_LCONV_INT_FMAT)
644
645 {
646 { lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
647 { lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
648 }
649
650#endif // _RWSTD_NO_LCONV_INT_FMAT
651 };
652
653 // cs_precedes [0..1]:
654 //
655 // An integer set to 1 if the currency_symbol precedes the value
656 // for a monetary value, and set to 0 if the symbol succeeds
657 // the value.
658
659 // sep_by_space [0..2]:
660 //
661 // 0 No space separates the currency_symbol from the value for
662 // a monetary value.
663 // 1 If the currency symbol and sign string are adjacent, a space
664 // separates them from the value; otherwise, a space separates
665 // the currency symbol from the value.
666 // 2 If the currency symbol and sign string are adjacent, a space
667 // separates them; otherwise, a space separates the sign string
668 // from the value.
669
670 // sign_posn [0..4]:
671 //
672 // An integer set to a value indicating the positioning of the
673 // positive_sign for a monetary value. The following integer
674 // values shall be recognized:
675 //
676 // 0 Parentheses enclose the value and the currency_symbol.
677 // 1 The sign string precedes the value and the currency_symbol.
678 // 2 The sign string succeeds the value and the currency_symbol.
679 // 3 The sign string immediately precedes the currency_symbol.
680 // 4 The sign string immediately succeeds the currency_symbol.
681
682 enum {
683 none = std::money_base::none,
684 space = std::money_base::space,
685 symbol = std::money_base::symbol,
686 sign = std::money_base::sign,
687 value = std::money_base::value
688 };
689
690 static const std::money_base::pattern patterns[] = {
691
692 /* 000: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
693 /* 001: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
694 /* 002: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
695 /* 003: 1-$. */ { { value, sign, symbol, none } }, // "\4\3\2\0"
696 /* 004: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
697
698 /* 010: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
699 /* 011: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
700 /* 012: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
701 /* 013: 1 -$ */ { { value, space, sign, symbol } }, // "\4\3\3\2"
702 /* 014: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
703
704 /* 020: - 1$ */ { { sign, space, value, symbol } }, // "\3\1\4\2"
705 /* 021: - 1$ */ { { sign, space, value, symbol } }, // "\3\\14\2"
706 /* 022: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
707 /* 023: 1- $ */ { { value, sign, space, symbol } }, // "\4\3\1\2"
708 /* 024: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
709
710 /* 100: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
711 /* 101: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
712 /* 102: $1-. */ { { symbol, value, sign, none } }, // "\2\4\3\0"
713 /* 103: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
714 /* 104: $-1. */ { { symbol, sign, value, none } }, // "\2\3\4\0"
715
716 /* 110: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
717 /* 111: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
718 /* 112: $ 1- */ { { symbol, space, value, sign } }, // "\2\1\4\3"
719 /* 113: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
720 /* 114: $- 1 */ { { symbol, sign, space, value } }, // "\2\3\1\4"
721
722 /* 120: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
723 /* 121: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
724 /* 122: $1 - */ { { symbol, value, space, sign } }, // "\2\4\1\3"
725 /* 123: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
726 /* 124: $ -1 */ { { symbol, space, sign, value } } // "\2\1\3\4"
727 };
728
729 for (int neg = 0; neg != 2; ++neg) {
730
731 enum { cs_precedes, sep_by_space, sign_posn };
732
733 // ignore unspecified formats (-1)
734 if ( cpat [intl_][neg][cs_precedes] > 1
735 || cpat [intl_][neg][sep_by_space] > 2
736 || cpat [intl_][neg][sign_posn] > 4)
737 continue;
738
739 const int inx =
740 cpat [intl_][neg][cs_precedes] * 3 * 5
741 + cpat [intl_][neg][sep_by_space] * 5
742 + cpat [intl_][neg][sign_posn];
743
744 check_format (!neg, patterns [inx], cpat [intl_][neg]);
745 }
746}
747
748
750template <class charT>
752check_format (bool pos, std::money_base::pattern result, const UChar cpat [3])
753{
754 const std::money_base::pattern pat =
755 intl_ ? pos ? _RWSTD_USE_FACET (IntlPunct, loc_).pos_format ()
756 : _RWSTD_USE_FACET (IntlPunct, loc_).neg_format ()
757 : pos ? _RWSTD_USE_FACET (Punct, loc_).pos_format ()
758 : _RWSTD_USE_FACET (Punct, loc_).neg_format ();
759
760 // number of times each symbol appears in pattern
761 int counts [5] = { 0 };
762
763 for (unsigned i = 0; i != sizeof pat.field / sizeof *pat.field; i++) {
764
765 if (UChar (pat.field [i] < char (sizeof counts / sizeof *counts)))
766 ++counts [UChar (pat.field [i])];
767
768 // verify 22.2.6.3, p1
769 if (std::money_base::none == pat.field [i] && !i)
770 rw_assert (false, 0, __LINE__,
771 "moneypunct<%s, %b>::%s_format() == %{LM}, "
772 "none must not appear first",
773 char_name_, intl_, pos ? "pos" : "neg",
774 pat.field);
775
776 if ( std::money_base::space == pat.field [i]
777 && !i && i != sizeof pat.field / sizeof *pat.field - 1)
778 rw_assert (false, 0, __LINE__,
779 "moneypunct<%s, %b>::%s_format() == %{LM}, "
780 "space must not appear first or last",
781 char_name_, intl_, pos ? "pos" : "neg",
782 pat.field);
783 }
784
785 // verify that the actual pattern matches the expected one
786 rw_assert (0 == std::memcmp (&pat, &result, sizeof pat), 0, __LINE__,
787 "moneypunct<%s, %b>::%s_format() == %{LM}, got %{LM}; "
788 "(cs_precedes = '\\%o', sep_by_space = '\\%o', "
789 "sign_posn = '\\%o')",
790 char_name_, intl_, pos ? "pos" : "neg",
791 pat.field, result.field, cpat [0], cpat [1], cpat [2]);
792
793 // verify 22.2.6.3, p1
794 rw_assert (1 == counts [std::money_base::symbol], 0, __LINE__,
795 "money_base::symbol must apear exactly once, did %d times",
796 counts [std::money_base::symbol]);
797
798 rw_assert (1 == counts [std::money_base::sign], 0, __LINE__,
799 "money_base::sign must apear exactly once, did %d times",
800 counts [std::money_base::sign]);
801
802 rw_assert (1 == counts [std::money_base::value], 0, __LINE__,
803 "money_base::value must apear exactly once, did %d times",
804 counts [std::money_base::value]);
805
806 rw_assert (1 == counts [std::money_base::space]
807 + counts [std::money_base::none], 0, __LINE__,
808 "money_base::space or money_base::none must appear "
809 "exactly once, did %d times",
810 counts [std::money_base::space]
811 + counts [std::money_base::none]);
812}
813
814
816static int
817run_test (int, char**)
818{
819 {
820 Test<char> t ("char", false);
821 t.runTest ();
822 }
823
824 {
825 Test<char> t ("char", true);
826 t.runTest ();
827 }
828
829#ifndef _RWSTD_NO_WCHAR_T
830
831 {
832 Test<wchar_t> t ("wchar_t", false);
833 t.runTest ();
834 }
835
836 {
837 Test<wchar_t> t ("wchar_t", true);
838 t.runTest ();
839 }
840
841#endif // _RWSTD_NO_WCHAR_T
842
843 return 0;
844}
845
846
847
849int main (int argc, char *argv[])
850{
851 return rw_test (argc, argv, __FILE__,
852 "lib.locale.moneypunct",
853 0 /* no comment */,
854 run_test,
855 "",
856 (void*)0 /* sentinel */);
857}
#define i
Definition 17.names.cpp:126
#define t
Definition 17.names.cpp:136
#define res
Definition 17.names.cpp:531
#define loc
Definition 17.names.cpp:492
#define neg
Definition 17.names.cpp:503
#define c
Definition 17.names.cpp:111
#define charT
Definition 17.names.cpp:456
#define s
#define n
Definition 17.names.cpp:130
#define inx
Definition 17.names.cpp:484
#define pos
Definition 17.names.cpp:518
volatile int result
std::string convert(const char *, const char *s, const char *)
unsigned char UChar
std::lconv * lconvdup(const std::lconv *plconv)
void check_decimal_point(charT, const char *, const std::locale *)
void check_grouping(charT, const char *, const std::string &, const std::locale *)
void check_thousands_sep(charT, const char *, const std::locale *)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
T value(const T &val)
#define main
#define assert(expr)
Definition _cassert.h:40
#define LC_ALL
#define _RWSTD_USE_FACET(type, arg)
Definition _defs.h:949
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _STD_HAS_FACET(type, arg)
Definition _defs.h:917
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _TRY
Definition _defs.h:850
#define _CATCH(ex)
Definition _defs.h:851
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
void check_format(const std::lconv &)
std::moneypunct< charT, true > IntlPunct
std::basic_string< charT, Traits, Allocator > String
void check_positive_sign(const String &)
void check_thousands_sep(charT)
void check_curr_symbol(const String &)
std::allocator< charT > Allocator
void check_negative_sign(const String &)
std::char_traits< charT > Traits
void check_grouping(const std::string &)
std::moneypunct< charT, false > Punct
Test(const char *cname, bool intl)
bool check_moneypunct(const char *)
void check_frac_digits(int)
void check_decimal_point(charT)
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_putenv(const char *, int=-1)
Definition environ.cpp:69
_TEST_EXPORT char * rw_locales(int=_UNUSED_CAT, const char *=0, bool=true)
Definition locale.cpp:368
_TEST_EXPORT rw_file *const rw_stderr
Definition printf.cpp:3348
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
Definition printf.cpp:3397
unsigned char UChar
Definition collate.cpp:122