first commit
This commit is contained in:
857
extern/stdcxx/4.2.1/tests/localization/22.locale.moneypunct.cpp
vendored
Normal file
857
extern/stdcxx/4.2.1/tests/localization/22.locale.moneypunct.cpp
vendored
Normal file
@@ -0,0 +1,857 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* 22.locale.moneypunct.cpp - tests for the moneypunct facet
|
||||
*
|
||||
* $Id: 22.locale.moneypunct.cpp 651095 2008-04-23 22:50:27Z sebor $
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed
|
||||
* with this work for additional information regarding copyright
|
||||
* ownership. The ASF licenses this file to you under the Apache
|
||||
* License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
* Copyright 1998-2008 Rogue Wave Software, Inc.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <locale>
|
||||
|
||||
#include <cassert>
|
||||
#include <clocale> // for LC_ALL, setlocale()
|
||||
#include <cstdio> // for fprintf(), stderr
|
||||
#include <cstdlib> // for getenv()
|
||||
#include <cstring> // for memcmp(), strerror()
|
||||
|
||||
#include <driver.h> // for rw_test()
|
||||
#include <environ.h> // for rw_putenv()
|
||||
#include <rw_locale.h> // for rw_locales()
|
||||
#include <rw_printf.h> // for rw_fprintf()
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
typedef unsigned char UChar;
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
// does a deep copy of struct lconv
|
||||
std::lconv* lconvdup (const std::lconv *plconv)
|
||||
{
|
||||
if (!plconv)
|
||||
return 0;
|
||||
|
||||
const std::size_t
|
||||
decimal_point_sz = std::strlen (plconv->decimal_point) + 1,
|
||||
thousands_sep_sz = std::strlen (plconv->thousands_sep) + 1,
|
||||
grouping_sz = std::strlen (plconv->grouping) + 1,
|
||||
int_curr_symbol_sz = std::strlen (plconv->int_curr_symbol) + 1,
|
||||
currency_symbol_sz = std::strlen (plconv->currency_symbol) + 1,
|
||||
mon_decimal_point_sz = std::strlen (plconv->mon_decimal_point) + 1,
|
||||
mon_thousands_sep_sz = std::strlen (plconv->mon_thousands_sep) + 1,
|
||||
mon_grouping_sz = std::strlen (plconv->mon_grouping) + 1,
|
||||
positive_sign_sz = std::strlen (plconv->positive_sign) + 1,
|
||||
negative_sign_sz = std::strlen (plconv->negative_sign) + 1;
|
||||
|
||||
const std::size_t total_sz =
|
||||
decimal_point_sz
|
||||
+ thousands_sep_sz
|
||||
+ grouping_sz
|
||||
+ int_curr_symbol_sz
|
||||
+ currency_symbol_sz
|
||||
+ mon_decimal_point_sz
|
||||
+ mon_thousands_sep_sz
|
||||
+ mon_grouping_sz
|
||||
+ positive_sign_sz
|
||||
+ negative_sign_sz;
|
||||
|
||||
const std::size_t bufsize = sizeof (std::lconv) + total_sz;
|
||||
|
||||
char *pbuf = _RWSTD_STATIC_CAST (char*, operator new (bufsize));
|
||||
|
||||
std::lconv *plconv2 = _RWSTD_REINTERPRET_CAST (std::lconv*, pbuf);
|
||||
|
||||
plconv2->decimal_point = (pbuf += sizeof (std::lconv));
|
||||
std::memcpy (pbuf, plconv->decimal_point, decimal_point_sz);
|
||||
|
||||
plconv2->thousands_sep = (pbuf += decimal_point_sz);
|
||||
std::memcpy (pbuf, plconv->thousands_sep, thousands_sep_sz);
|
||||
|
||||
plconv2->grouping = (pbuf += thousands_sep_sz);
|
||||
std::memcpy (pbuf, plconv->grouping, grouping_sz);
|
||||
|
||||
plconv2->int_curr_symbol = (pbuf += grouping_sz);
|
||||
std::memcpy (pbuf, plconv->int_curr_symbol, int_curr_symbol_sz);
|
||||
|
||||
plconv2->currency_symbol = (pbuf += int_curr_symbol_sz);
|
||||
std::memcpy (pbuf, plconv->currency_symbol, currency_symbol_sz);
|
||||
|
||||
plconv2->mon_decimal_point = (pbuf += currency_symbol_sz);
|
||||
std::memcpy (pbuf, plconv->mon_decimal_point, mon_decimal_point_sz);
|
||||
|
||||
plconv2->mon_thousands_sep = (pbuf += mon_decimal_point_sz);
|
||||
std::memcpy (pbuf, plconv->mon_thousands_sep, mon_thousands_sep_sz);
|
||||
|
||||
plconv2->mon_grouping = (pbuf += mon_thousands_sep_sz);
|
||||
std::memcpy (pbuf, plconv->mon_grouping, mon_grouping_sz);
|
||||
|
||||
plconv2->positive_sign = (pbuf += mon_grouping_sz);
|
||||
std::memcpy (pbuf, plconv->positive_sign, positive_sign_sz);
|
||||
|
||||
plconv2->negative_sign = (pbuf += positive_sign_sz);
|
||||
std::memcpy (pbuf, plconv->negative_sign, negative_sign_sz);
|
||||
|
||||
plconv2->int_frac_digits = plconv->int_frac_digits;
|
||||
plconv2->frac_digits = plconv->frac_digits;
|
||||
plconv2->p_cs_precedes = plconv->p_cs_precedes;
|
||||
plconv2->p_sep_by_space = plconv->p_sep_by_space;
|
||||
plconv2->n_cs_precedes = plconv->n_cs_precedes;
|
||||
plconv2->n_sep_by_space = plconv->n_sep_by_space;
|
||||
plconv2->p_sign_posn = plconv->p_sign_posn;
|
||||
plconv2->n_sign_posn = plconv->n_sign_posn;
|
||||
|
||||
#ifndef _RWSTD_NO_LCONV_INT_FMAT
|
||||
|
||||
plconv2->int_p_cs_precedes = plconv->int_p_cs_precedes;
|
||||
plconv2->int_p_sep_by_space = plconv->int_p_sep_by_space;
|
||||
plconv2->int_n_cs_precedes = plconv->int_n_cs_precedes;
|
||||
plconv2->int_n_sep_by_space = plconv->int_n_sep_by_space;
|
||||
plconv2->int_p_sign_posn = plconv->int_p_sign_posn;
|
||||
plconv2->int_n_sign_posn = plconv->int_n_sign_posn;
|
||||
|
||||
#endif // _RWSTD_NO_LCONV_INT_FMAT
|
||||
|
||||
return plconv2;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
class Test
|
||||
{
|
||||
std::locale loc_;
|
||||
bool intl_; // international?
|
||||
const char *char_name_; // charT name ("char" or "wchar_t")
|
||||
const char *locname_;
|
||||
const char *lang_;
|
||||
const char *lc_all_;
|
||||
const char *lc_monetary_;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::moneypunct<charT, false> Punct;
|
||||
typedef std::moneypunct<charT, true> IntlPunct;
|
||||
|
||||
Test (const char *cname, bool intl)
|
||||
: loc_ (), intl_ (intl),
|
||||
char_name_ (cname),
|
||||
locname_ (0), lang_ (0), lc_all_ (0), lc_monetary_ (0) { }
|
||||
|
||||
void runTest ();
|
||||
|
||||
void check_decimal_point (charT);
|
||||
void check_thousands_sep (charT);
|
||||
void check_frac_digits (int);
|
||||
void check_grouping (const std::string&);
|
||||
|
||||
typedef std::char_traits<charT> Traits;
|
||||
typedef std::allocator<charT> Allocator;
|
||||
typedef std::basic_string<charT, Traits, Allocator> String;
|
||||
|
||||
void check_curr_symbol (const String&);
|
||||
void check_positive_sign (const String&);
|
||||
void check_negative_sign (const String&);
|
||||
|
||||
void check_format (const std::lconv&);
|
||||
void check_format (bool, std::money_base::pattern, const UChar [3]);
|
||||
|
||||
bool check_moneypunct (const char*);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
runTest()
|
||||
{
|
||||
// create a copy of the classic C locale
|
||||
loc_ = std::locale::classic ();
|
||||
|
||||
// verify (at compile time) that _bynam facets can be used
|
||||
// to specialize use_facet() and has_facet()
|
||||
typedef std::moneypunct_byname<charT, false> MoneyPunctByname;
|
||||
typedef std::moneypunct_byname<charT, true> MoneyPunctIntlByname;
|
||||
|
||||
if (1) {
|
||||
if (_STD_HAS_FACET (MoneyPunctByname, loc_))
|
||||
_RWSTD_USE_FACET (MoneyPunctByname, loc_);
|
||||
|
||||
if (_STD_HAS_FACET (MoneyPunctIntlByname, loc_))
|
||||
_RWSTD_USE_FACET (MoneyPunctIntlByname, loc_);
|
||||
}
|
||||
|
||||
// note that values in 7.4 of C89, and 7.11, p2 of C99, respectively,
|
||||
// or '\0' and '\0' for decimal_point and thousands_sep, are specified
|
||||
// in 22.2.3.1.2, p1 and p2 of C++98 to be '.', and ',' in the C locale
|
||||
//
|
||||
check_decimal_point (charT ('.'));
|
||||
check_thousands_sep (charT (','));
|
||||
check_frac_digits (0 /* i.e., not available, or same as CHAR_MAX in C */);
|
||||
check_grouping ("");
|
||||
|
||||
const charT empty[] = { '\0' };
|
||||
check_curr_symbol (empty);
|
||||
check_positive_sign (empty);
|
||||
check_negative_sign (empty);
|
||||
|
||||
// verify 22.2.6.3.2, p7:
|
||||
// moneypunct<char>, moneypunct<wchar_t>, moneypunct<char,true>, and
|
||||
// moneypunct<wchar_t,true>, return an object of type pattern initialized
|
||||
// to { symbol, sign, none, value }
|
||||
std::money_base::pattern fmat = {
|
||||
// initializer must be properly bracketed to prevent g++ warnings
|
||||
{
|
||||
std::money_base::symbol,
|
||||
std::money_base::sign,
|
||||
std::money_base::none,
|
||||
std::money_base::value
|
||||
}
|
||||
};
|
||||
|
||||
const UChar cpat [4] = { '?', '?', '?', 0 };
|
||||
check_format (false /* negative */, fmat, cpat);
|
||||
check_format (true /* positive */, fmat, cpat);
|
||||
|
||||
// exercise the native locale (affected by the environment
|
||||
// variables LANG, LC_ALL, LC_MONETARY, etc.)
|
||||
check_moneypunct (""); // native locale
|
||||
|
||||
// the name of the first non-C (and non-POSIX) locale
|
||||
const char *first_non_c = 0;
|
||||
|
||||
// exercise named locales (including "C" and "POSIX")
|
||||
for (const char* s = rw_locales (); s && *s; s += std::strlen (s) + 1) {
|
||||
if (check_moneypunct (s))
|
||||
if ( !first_non_c
|
||||
&& std::strcmp ("C", s)
|
||||
&& std::strcmp ("POSIX", s)) {
|
||||
first_non_c = s;
|
||||
}
|
||||
}
|
||||
|
||||
if (!first_non_c)
|
||||
return;
|
||||
|
||||
// verify that moneypunct behaves correctly when LC_ALL is set
|
||||
// to the name of the (non-C, non-POSIX) locale
|
||||
char envvar [80];
|
||||
|
||||
// make sure buffer doesn't overflow
|
||||
assert (std::strlen(first_non_c) + sizeof "LC_ALL=" <= sizeof envvar);
|
||||
|
||||
std::sprintf (envvar, "LC_ALL=%s", first_non_c);
|
||||
rw_putenv (envvar);
|
||||
check_moneypunct ("");
|
||||
|
||||
// remove LC_ALL from the environment
|
||||
rw_putenv ("LC_ALL=");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
std::string convert (const char*, const char *s, const char*)
|
||||
{
|
||||
return std::string (s);
|
||||
}
|
||||
|
||||
|
||||
// convert a multibyte character string in an external representation
|
||||
// to wstring object in an internal representation
|
||||
std::wstring
|
||||
convert (const char *locname, const char *s, const wchar_t*)
|
||||
{
|
||||
// save the name of the original locale
|
||||
std::string saved_loc;
|
||||
|
||||
if (const char *savename = std::setlocale (LC_ALL, 0))
|
||||
saved_loc = savename;
|
||||
|
||||
// switch to (named) locale
|
||||
const char *loc = std::setlocale (LC_ALL, locname);
|
||||
if (!loc) {
|
||||
rw_fprintf (rw_stderr,
|
||||
"%s:%d: setlocale (LC_ALL, %s) = 0: %m\n",
|
||||
locname);
|
||||
return std::wstring ();
|
||||
}
|
||||
|
||||
// use an extension: allocate but do not initialize
|
||||
std::wstring res ((wchar_t*)0, 64);
|
||||
|
||||
for ( ; ; ) {
|
||||
// try to convert, resizing buffer if necessary
|
||||
std::size_t n =
|
||||
std::mbstowcs (&res [0], s, res.capacity ());
|
||||
|
||||
if (res.capacity () == n)
|
||||
// increase capacity
|
||||
res.reserve (res.capacity () * 2);
|
||||
else if (std::size_t (-1) == n) {
|
||||
|
||||
// restore the original locale before printing out
|
||||
// the error message (we don't want it localized)
|
||||
std::setlocale (LC_ALL, saved_loc.c_str ());
|
||||
|
||||
rw_fprintf (rw_stderr,
|
||||
"%s:%d: mbstowcs(..., %#s, %zu) "
|
||||
"= -1: %m\n", __FILE__, __LINE__,
|
||||
s, res.capacity ());
|
||||
res = std::wstring (); // mbstowcs() error
|
||||
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
// shrink if necessary
|
||||
res.resize (n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// restore original locale
|
||||
std::setlocale (LC_ALL, saved_loc.c_str ());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
bool Test<charT>::
|
||||
check_moneypunct (const char *locname)
|
||||
{
|
||||
// (try to) set the global C locale
|
||||
char locnamebuf [256];
|
||||
const char *loc = std::setlocale (LC_ALL, locname);
|
||||
if (!loc)
|
||||
return false;
|
||||
|
||||
loc = std::strcpy (locnamebuf, loc);
|
||||
|
||||
locname_ = loc;
|
||||
|
||||
// the values of the environment variables LANG, LC_ALL,
|
||||
// and LC_MONETARY (and others) affect the native locale
|
||||
lang_ = std::getenv ("LANG");
|
||||
lc_all_ = std::getenv ("LC_ALL");
|
||||
lc_monetary_ = std::getenv ("LC_MONETARY");
|
||||
|
||||
if (!lang_)
|
||||
lang_ = "(null)";
|
||||
if (!lc_all_)
|
||||
lc_all_ = "(null)";
|
||||
if (!lc_monetary_)
|
||||
lc_monetary_ = "(null)";
|
||||
|
||||
_TRY {
|
||||
|
||||
// get a pointer to lconv and copy data to a temporray buffer
|
||||
const std::lconv* const plconv = lconvdup (std::localeconv ());
|
||||
|
||||
if (!plconv)
|
||||
return false;
|
||||
|
||||
// reset to default locale given by LC_LANG
|
||||
std::setlocale (LC_ALL, "");
|
||||
|
||||
// create a new C++ locale object
|
||||
loc_ = std::locale (locname);
|
||||
|
||||
// check that newly constructed locale matches
|
||||
|
||||
// the MBCS mon_decimal_point and mon_thousands_sep must
|
||||
// be properly converted (i.e., *mon_decimal_point may not
|
||||
// the same as s [0] after the conversion)
|
||||
String s;
|
||||
|
||||
// `locname' may be the empty string, in which case `loc'
|
||||
// will be set to the actual name of the locale
|
||||
if ( std::strcmp ("C", locname)
|
||||
&& std::strcmp ("C", loc)) {
|
||||
|
||||
// named locale other than "C" or "POISX"
|
||||
s = ::convert (locname, plconv->mon_decimal_point, (charT*)0);
|
||||
check_decimal_point (s.size () ? s [0] : charT ());
|
||||
|
||||
s = ::convert (locname, plconv->mon_thousands_sep, (charT*)0);
|
||||
check_thousands_sep (s.size () ? s [0] : charT ());
|
||||
|
||||
check_frac_digits (plconv->int_frac_digits);
|
||||
}
|
||||
else {
|
||||
// note that values in 7.4 of C89, and 7.11, p2 of C99,
|
||||
// respectively, or '\0' and '\0' for decimal_point and
|
||||
// thousands_sep, are specified in 22.2.3.1.2, p1 and p2
|
||||
// of C++98 to be '.', and ',' in the C locale
|
||||
check_decimal_point (charT ('.'));
|
||||
check_thousands_sep (charT (','));
|
||||
|
||||
// frac_digits is specified as CHAR_MAX (i.e., not available) by C99
|
||||
// verify that the C++ value is NOT CHAR_MAX, but rather 0 (it could
|
||||
// be negative with the same result)
|
||||
check_frac_digits (0);
|
||||
}
|
||||
|
||||
check_grouping (plconv->mon_grouping);
|
||||
|
||||
// convert a (possibly) multibyte string in external
|
||||
// representation to one in internal representation
|
||||
s = intl_ ? ::convert (locname, plconv->int_curr_symbol, (charT*)0)
|
||||
: ::convert (locname, plconv->currency_symbol, (charT*)0);
|
||||
|
||||
check_curr_symbol (s);
|
||||
|
||||
s = ::convert (locname, plconv->positive_sign, (charT*)0);
|
||||
|
||||
check_positive_sign (s);
|
||||
|
||||
s = ::convert (locname, plconv->negative_sign, (charT*)0);
|
||||
|
||||
check_negative_sign (s);
|
||||
|
||||
check_format (*plconv);
|
||||
|
||||
// cast away constness to work around compiler bugs (e.g., MSVC 6)
|
||||
operator delete (_RWSTD_CONST_CAST (std::lconv*, plconv));
|
||||
}
|
||||
_CATCH (...) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_decimal_point (charT result)
|
||||
{
|
||||
const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).decimal_point ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).decimal_point ();
|
||||
|
||||
rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
|
||||
"moneypunct<%s, %b>::decimal_point() == %#lc, got %#lc "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_, result, c,
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_thousands_sep (charT result)
|
||||
{
|
||||
const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).thousands_sep ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).thousands_sep ();
|
||||
|
||||
rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
|
||||
"moneypunct<%s, %b>::thousands_sep() == %#lc, got %#lc "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_, result, c,
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_frac_digits (int result)
|
||||
{
|
||||
const int i = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).frac_digits ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).frac_digits ();
|
||||
|
||||
rw_assert (i == result, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::frac_digits() == %d, got %d "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_, result, i,
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_grouping (const std::string &result)
|
||||
{
|
||||
const std::string s = intl_ ?
|
||||
_RWSTD_USE_FACET (IntlPunct, loc_).grouping ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).grouping ();
|
||||
|
||||
if ( s != result
|
||||
&& s.size () != result.size () && s.size () && result.size ()) {
|
||||
|
||||
// if the grouping is not exactly the same as the expected result,
|
||||
// verify that the actual grouping is equivalent to the expected
|
||||
// one, e.g., that "\003\003" is equivalent to "\003"
|
||||
|
||||
const std::string *lng = s.size () > result.size () ? &result : &s;
|
||||
const std::string *shrt = s.size () < result.size () ? &result : &s;
|
||||
|
||||
std::size_t i = shrt->size () - 1;
|
||||
|
||||
for ( ; i != lng->size (); ++i)
|
||||
if ((*shrt) [shrt->size () - 1] != (*lng)[i])
|
||||
break;
|
||||
|
||||
rw_assert (i == lng->size (), 0, __LINE__,
|
||||
"numpunct<%s, %b>::grouping() equivalent to %#s, got %#s "
|
||||
"in locale (%#s) with LANG=%s, LC_ALL=%s, "
|
||||
"LC_MONETARY=%s",
|
||||
char_name_, intl_, result.c_str (), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
else
|
||||
rw_assert (s == result, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::grouping() == %#s, got %#s "
|
||||
"in locale (%#s) with LANG=%s, LC_ALL=%s, "
|
||||
"LC_MONETARY=%s",
|
||||
char_name_, intl_, result.c_str (), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
|
||||
#if 0
|
||||
|
||||
// Test disabled: what's meant here is that the pattern, NOT the value,
|
||||
// is defined identically as that of numpunct<charT>::do_grouping().
|
||||
// The values are often going to be different since one uses
|
||||
// lconv::grouping, and the other lconv::mon_grouping.
|
||||
|
||||
// 22.2.6.3.2, p3: do_grouping() returns a pattern defined identically
|
||||
// as the result of numpunct<charT>::do_grouping().
|
||||
|
||||
const std::string grp =
|
||||
_RWSTD_USE_FACET (std::numpunct<charT>, loc_).grouping ();
|
||||
|
||||
rw_assert (s == grp, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::grouping() == numpunct<>::grouping() == "
|
||||
"%{*Ac}, got %{*Ac} in locale (\"%s\") with LANG=%s, LC_ALL=%s, "
|
||||
"LC_MONETARY=%s",
|
||||
char_name_, intl_,
|
||||
int (sizeof (charT)), result.c_str (),
|
||||
int (sizeof (charT)), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
|
||||
#endif // 0
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_curr_symbol (const String &result)
|
||||
{
|
||||
const String s = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).curr_symbol ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).curr_symbol ();
|
||||
|
||||
rw_assert (s == result, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::curr_symbol() == %{*Ac}, got %{*Ac} "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_,
|
||||
int (sizeof (charT)), result.c_str (),
|
||||
int (sizeof (charT)), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_positive_sign (const String &result)
|
||||
{
|
||||
const String s = intl_ ?
|
||||
_RWSTD_USE_FACET (IntlPunct, loc_).positive_sign ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).positive_sign ();
|
||||
|
||||
rw_assert (s == result, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::positive_sign() == %{*Ac}, got %{*Ac} "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_,
|
||||
int (sizeof (charT)), result.c_str (),
|
||||
int (sizeof (charT)), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_negative_sign (const String &result)
|
||||
{
|
||||
const String s = intl_ ?
|
||||
_RWSTD_USE_FACET (IntlPunct, loc_).negative_sign ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).negative_sign ();
|
||||
|
||||
rw_assert (s == result, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::negative_sign() == %{*Ac}, got %{*Ac} "
|
||||
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
|
||||
char_name_, intl_,
|
||||
int (sizeof (charT)), result.c_str (),
|
||||
int (sizeof (charT)), s.c_str (),
|
||||
locname_, lang_, lc_all_, lc_monetary_);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_format (const std::lconv &lc)
|
||||
{
|
||||
const UChar cpat [2][2][3] = {
|
||||
// ^ ^ ^
|
||||
// | | |
|
||||
// | | +--- cs_precedes, sep_by_space, sign_posn
|
||||
// | +------ positive, negative
|
||||
// +--------- local, international
|
||||
|
||||
{
|
||||
// C90 positive local format
|
||||
{ lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
|
||||
|
||||
// C90 negative local format
|
||||
{ lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
|
||||
},
|
||||
|
||||
#ifndef _RWSTD_NO_LCONV_INT_FMAT
|
||||
|
||||
{ // C99 positive international format
|
||||
{ lc.int_p_cs_precedes, lc.int_p_sep_by_space, lc.int_p_sign_posn},
|
||||
|
||||
// C99 negative international format
|
||||
{ lc.int_n_cs_precedes, lc.int_n_sep_by_space, lc.int_n_sign_posn }
|
||||
}
|
||||
|
||||
#else // if defined (_RWSTD_NO_LCONV_INT_FMAT)
|
||||
|
||||
{
|
||||
{ lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
|
||||
{ lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
|
||||
}
|
||||
|
||||
#endif // _RWSTD_NO_LCONV_INT_FMAT
|
||||
};
|
||||
|
||||
// cs_precedes [0..1]:
|
||||
//
|
||||
// An integer set to 1 if the currency_symbol precedes the value
|
||||
// for a monetary value, and set to 0 if the symbol succeeds
|
||||
// the value.
|
||||
|
||||
// sep_by_space [0..2]:
|
||||
//
|
||||
// 0 No space separates the currency_symbol from the value for
|
||||
// a monetary value.
|
||||
// 1 If the currency symbol and sign string are adjacent, a space
|
||||
// separates them from the value; otherwise, a space separates
|
||||
// the currency symbol from the value.
|
||||
// 2 If the currency symbol and sign string are adjacent, a space
|
||||
// separates them; otherwise, a space separates the sign string
|
||||
// from the value.
|
||||
|
||||
// sign_posn [0..4]:
|
||||
//
|
||||
// An integer set to a value indicating the positioning of the
|
||||
// positive_sign for a monetary value. The following integer
|
||||
// values shall be recognized:
|
||||
//
|
||||
// 0 Parentheses enclose the value and the currency_symbol.
|
||||
// 1 The sign string precedes the value and the currency_symbol.
|
||||
// 2 The sign string succeeds the value and the currency_symbol.
|
||||
// 3 The sign string immediately precedes the currency_symbol.
|
||||
// 4 The sign string immediately succeeds the currency_symbol.
|
||||
|
||||
enum {
|
||||
none = std::money_base::none,
|
||||
space = std::money_base::space,
|
||||
symbol = std::money_base::symbol,
|
||||
sign = std::money_base::sign,
|
||||
value = std::money_base::value
|
||||
};
|
||||
|
||||
static const std::money_base::pattern patterns[] = {
|
||||
|
||||
/* 000: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
|
||||
/* 001: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
|
||||
/* 002: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
|
||||
/* 003: 1-$. */ { { value, sign, symbol, none } }, // "\4\3\2\0"
|
||||
/* 004: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
|
||||
|
||||
/* 010: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
|
||||
/* 011: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
|
||||
/* 012: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
|
||||
/* 013: 1 -$ */ { { value, space, sign, symbol } }, // "\4\3\3\2"
|
||||
/* 014: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
|
||||
|
||||
/* 020: - 1$ */ { { sign, space, value, symbol } }, // "\3\1\4\2"
|
||||
/* 021: - 1$ */ { { sign, space, value, symbol } }, // "\3\\14\2"
|
||||
/* 022: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
|
||||
/* 023: 1- $ */ { { value, sign, space, symbol } }, // "\4\3\1\2"
|
||||
/* 024: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
|
||||
|
||||
/* 100: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
|
||||
/* 101: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
|
||||
/* 102: $1-. */ { { symbol, value, sign, none } }, // "\2\4\3\0"
|
||||
/* 103: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
|
||||
/* 104: $-1. */ { { symbol, sign, value, none } }, // "\2\3\4\0"
|
||||
|
||||
/* 110: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
|
||||
/* 111: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
|
||||
/* 112: $ 1- */ { { symbol, space, value, sign } }, // "\2\1\4\3"
|
||||
/* 113: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
|
||||
/* 114: $- 1 */ { { symbol, sign, space, value } }, // "\2\3\1\4"
|
||||
|
||||
/* 120: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
|
||||
/* 121: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
|
||||
/* 122: $1 - */ { { symbol, value, space, sign } }, // "\2\4\1\3"
|
||||
/* 123: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
|
||||
/* 124: $ -1 */ { { symbol, space, sign, value } } // "\2\1\3\4"
|
||||
};
|
||||
|
||||
for (int neg = 0; neg != 2; ++neg) {
|
||||
|
||||
enum { cs_precedes, sep_by_space, sign_posn };
|
||||
|
||||
// ignore unspecified formats (-1)
|
||||
if ( cpat [intl_][neg][cs_precedes] > 1
|
||||
|| cpat [intl_][neg][sep_by_space] > 2
|
||||
|| cpat [intl_][neg][sign_posn] > 4)
|
||||
continue;
|
||||
|
||||
const int inx =
|
||||
cpat [intl_][neg][cs_precedes] * 3 * 5
|
||||
+ cpat [intl_][neg][sep_by_space] * 5
|
||||
+ cpat [intl_][neg][sign_posn];
|
||||
|
||||
check_format (!neg, patterns [inx], cpat [intl_][neg]);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class charT>
|
||||
void Test<charT>::
|
||||
check_format (bool pos, std::money_base::pattern result, const UChar cpat [3])
|
||||
{
|
||||
const std::money_base::pattern pat =
|
||||
intl_ ? pos ? _RWSTD_USE_FACET (IntlPunct, loc_).pos_format ()
|
||||
: _RWSTD_USE_FACET (IntlPunct, loc_).neg_format ()
|
||||
: pos ? _RWSTD_USE_FACET (Punct, loc_).pos_format ()
|
||||
: _RWSTD_USE_FACET (Punct, loc_).neg_format ();
|
||||
|
||||
// number of times each symbol appears in pattern
|
||||
int counts [5] = { 0 };
|
||||
|
||||
for (unsigned i = 0; i != sizeof pat.field / sizeof *pat.field; i++) {
|
||||
|
||||
if (UChar (pat.field [i] < char (sizeof counts / sizeof *counts)))
|
||||
++counts [UChar (pat.field [i])];
|
||||
|
||||
// verify 22.2.6.3, p1
|
||||
if (std::money_base::none == pat.field [i] && !i)
|
||||
rw_assert (false, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::%s_format() == %{LM}, "
|
||||
"none must not appear first",
|
||||
char_name_, intl_, pos ? "pos" : "neg",
|
||||
pat.field);
|
||||
|
||||
if ( std::money_base::space == pat.field [i]
|
||||
&& !i && i != sizeof pat.field / sizeof *pat.field - 1)
|
||||
rw_assert (false, 0, __LINE__,
|
||||
"moneypunct<%s, %b>::%s_format() == %{LM}, "
|
||||
"space must not appear first or last",
|
||||
char_name_, intl_, pos ? "pos" : "neg",
|
||||
pat.field);
|
||||
}
|
||||
|
||||
// verify that the actual pattern matches the expected one
|
||||
rw_assert (0 == std::memcmp (&pat, &result, sizeof pat), 0, __LINE__,
|
||||
"moneypunct<%s, %b>::%s_format() == %{LM}, got %{LM}; "
|
||||
"(cs_precedes = '\\%o', sep_by_space = '\\%o', "
|
||||
"sign_posn = '\\%o')",
|
||||
char_name_, intl_, pos ? "pos" : "neg",
|
||||
pat.field, result.field, cpat [0], cpat [1], cpat [2]);
|
||||
|
||||
// verify 22.2.6.3, p1
|
||||
rw_assert (1 == counts [std::money_base::symbol], 0, __LINE__,
|
||||
"money_base::symbol must apear exactly once, did %d times",
|
||||
counts [std::money_base::symbol]);
|
||||
|
||||
rw_assert (1 == counts [std::money_base::sign], 0, __LINE__,
|
||||
"money_base::sign must apear exactly once, did %d times",
|
||||
counts [std::money_base::sign]);
|
||||
|
||||
rw_assert (1 == counts [std::money_base::value], 0, __LINE__,
|
||||
"money_base::value must apear exactly once, did %d times",
|
||||
counts [std::money_base::value]);
|
||||
|
||||
rw_assert (1 == counts [std::money_base::space]
|
||||
+ counts [std::money_base::none], 0, __LINE__,
|
||||
"money_base::space or money_base::none must appear "
|
||||
"exactly once, did %d times",
|
||||
counts [std::money_base::space]
|
||||
+ counts [std::money_base::none]);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static int
|
||||
run_test (int, char**)
|
||||
{
|
||||
{
|
||||
Test<char> t ("char", false);
|
||||
t.runTest ();
|
||||
}
|
||||
|
||||
{
|
||||
Test<char> t ("char", true);
|
||||
t.runTest ();
|
||||
}
|
||||
|
||||
#ifndef _RWSTD_NO_WCHAR_T
|
||||
|
||||
{
|
||||
Test<wchar_t> t ("wchar_t", false);
|
||||
t.runTest ();
|
||||
}
|
||||
|
||||
{
|
||||
Test<wchar_t> t ("wchar_t", true);
|
||||
t.runTest ();
|
||||
}
|
||||
|
||||
#endif // _RWSTD_NO_WCHAR_T
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
return rw_test (argc, argv, __FILE__,
|
||||
"lib.locale.moneypunct",
|
||||
0 /* no comment */,
|
||||
run_test,
|
||||
"",
|
||||
(void*)0 /* sentinel */);
|
||||
}
|
||||
Reference in New Issue
Block a user