400 lines
13 KiB
C++
400 lines
13 KiB
C++
/************************************************************************
|
|
*
|
|
* 22.locale.numpunct.cpp
|
|
*
|
|
* test exercising the std::numpunct facet
|
|
*
|
|
* $Id: 22.locale.numpunct.cpp 648752 2008-04-16 17:01:56Z faridz $
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
**************************************************************************/
|
|
|
|
#include <rw/_defs.h>
|
|
|
|
#if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION)
|
|
// Disable implicit inclusion to work around
|
|
// a limitation in IBM's VisualAge 5.0.2.0 (see PR#26959)
|
|
|
|
# define _RWSTD_NO_IMPLICIT_INCLUSION
|
|
#endif
|
|
|
|
|
|
#include <clocale> // for struct lconv, setlocale()
|
|
#include <cstdio> // for sprintf()
|
|
#include <cstdlib> // for getenv()
|
|
#include <cstring> // for strcmp()
|
|
#include <locale>
|
|
|
|
#include <driver.h>
|
|
#include <environ.h>
|
|
#include <rw_locale.h>
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void run_test (charT*);
|
|
|
|
template <class charT>
|
|
void check_decimal_point (charT, const char*, const std::locale*);
|
|
|
|
template <class charT>
|
|
void check_thousands_sep (charT, const char*, const std::locale*);
|
|
|
|
template <class charT>
|
|
void check_grouping (charT, const char*, const std::string&, const std::locale*);
|
|
|
|
template <class charT>
|
|
void check_falsename (const std::basic_string<charT>&,
|
|
const char*, const std::locale*);
|
|
|
|
template <class charT>
|
|
void check_truename (const std::basic_string<charT>&,
|
|
const char*, const std::locale*);
|
|
|
|
template <class charT>
|
|
bool check_numpunct (charT, const char*, const char*, const std::locale*);
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void run_test (charT, const char *tname)
|
|
{
|
|
rw_info (0, 0, __LINE__, "classic \"C\" locale");
|
|
|
|
// create a copy of the classic ("C") locale
|
|
std::locale *loc = new std::locale (std::locale::classic ());
|
|
|
|
// verify (at compile time) that _byname facets can be used
|
|
// to specialize use_facet() and has_facet()
|
|
typedef std::numpunct_byname<charT> NumpunctByname;
|
|
|
|
if (_STD_HAS_FACET (NumpunctByname, *loc))
|
|
_STD_USE_FACET (NumpunctByname, *loc);
|
|
|
|
// verify values as per 7.4 of C89, and 7.11, p2 of C99
|
|
check_decimal_point (charT ('.'), tname, loc);
|
|
|
|
// verify 22.2.3.1.2, p2
|
|
check_thousands_sep (charT (','), tname, loc);
|
|
check_grouping (charT (), tname, "", loc);
|
|
|
|
const charT fn[] = { 'f', 'a', 'l', 's', 'e', '\0' };
|
|
const charT tn[] = { 't', 'r', 'u', 'e', '\0' };
|
|
|
|
check_falsename (std::basic_string<charT>(fn), tname, loc);
|
|
check_truename (std::basic_string<charT>(tn), tname, loc);
|
|
|
|
delete loc;
|
|
loc = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// verify that the facet can be safely used on its own, without
|
|
// first having to be installed in a locale and retrieved using
|
|
// use_facet
|
|
|
|
check_decimal_point (charT ('.'), tname, loc);
|
|
check_thousands_sep (charT (','), tname, loc);
|
|
check_grouping (charT (), tname, "", loc);
|
|
|
|
check_falsename (std::basic_string<charT>(fn), tname, loc);
|
|
check_truename (std::basic_string<charT>(tn), tname, loc);
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// exercise the native locale (affected by the environment
|
|
// variables LANG, LC_ALL, LC_NUMERIC, etc.)
|
|
check_numpunct (charT (), tname, "", loc); // 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 += std::strlen (s) + 1) {
|
|
if (check_numpunct (charT (), tname, s, loc))
|
|
if ( !first_non_c
|
|
&& std::strcmp ("C", s)
|
|
&& std::strcmp ("POSIX", s))
|
|
first_non_c = s;
|
|
}
|
|
|
|
// verify that numpunct behaves correctly when LC_ALL is set
|
|
// to the name of the (non-C, non-POSIX) locale
|
|
char envvar [80];
|
|
std::sprintf (envvar, "LC_ALL=%s", first_non_c);
|
|
rw_putenv (envvar);
|
|
check_numpunct (charT (), tname, "", loc);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
char widen (char, const char *s)
|
|
{
|
|
return *s;
|
|
}
|
|
|
|
#ifndef _RWSTD_NO_WCHAR_T
|
|
|
|
wchar_t widen (wchar_t, const char *s)
|
|
{
|
|
wchar_t wc = 0;
|
|
|
|
# ifndef _RWSTD_NO_MBTOWC
|
|
|
|
const int n = s && *s ? std::mbtowc (&wc, s, std::strlen (s)) : 0;
|
|
|
|
# else // if defined (_RWSTD_NO_MBTOWC)
|
|
|
|
const int n = 1;
|
|
|
|
wc = s ? wchar_t (_RWSTD_STATIC_CAST (unsigned char, *s)) : 0;
|
|
|
|
# endif // _RWSTD_NO_MBTOWC
|
|
|
|
return n > 0 ? wc : n ? -1 : 0;
|
|
}
|
|
|
|
#endif // _RWSTD_NO_WCHAR_T
|
|
|
|
|
|
template <class charT>
|
|
bool check_numpunct (charT,
|
|
const char *tname,
|
|
const char *locname,
|
|
const std::locale *loc)
|
|
{
|
|
// (try to) set the global C locale
|
|
const char *tmploc = std::setlocale (LC_ALL, locname);
|
|
if (!tmploc)
|
|
return false;
|
|
|
|
// future setlocale() calls may change tmploc's value, so make a copy
|
|
// (fixed-size char buf is clunky but avoids memory-leak potential)
|
|
char locnamebuf [1024];
|
|
RW_ASSERT ((std::strlen (tmploc) + 1) < sizeof locnamebuf);
|
|
std::strcpy (locnamebuf, tmploc);
|
|
|
|
_TRY {
|
|
|
|
rw_info (0, 0, __LINE__,
|
|
"locale (%s) -> \"%s\"; LANG=%s, "
|
|
"LC_ALL=%s, LC_NUMERIC=%s",
|
|
locname, loc,
|
|
std::getenv ("LANG"),
|
|
std::getenv ("LC_ALL"),
|
|
std::getenv ("LC_NUMERIC"));
|
|
|
|
// get a pointer to lconv
|
|
const std::lconv *plconv = std::localeconv ();
|
|
|
|
if (!plconv)
|
|
return false;
|
|
|
|
// copy important data; the contents of *plconv may
|
|
// be overwritten by the call sto setlocale() below
|
|
// note that decimal_point at al may be multbyte character
|
|
// strings that need to be widened according to the rules
|
|
// of the same locale
|
|
const charT decimal_point = widen (charT (), plconv->decimal_point);
|
|
const charT thousands_sep = widen (charT (), plconv->thousands_sep);
|
|
|
|
const std::string grouping =
|
|
plconv->grouping ? plconv->grouping : "";
|
|
|
|
// reset to default locale given by LC_LANG
|
|
std::setlocale (LC_ALL, "");
|
|
|
|
loc = new std::locale (locname);
|
|
|
|
// check that newly constructed locale matches
|
|
|
|
if ( 'C' == locnamebuf [0] && '\0' == locnamebuf [1]
|
|
|| 'C' == locname [0] && '\0' == locname [1]
|
|
|| *loc == std::locale::classic ()) {
|
|
// follow requirements in 22.2.3.1.2. p1, 2, and 3
|
|
check_decimal_point (charT ('.'), tname, loc);
|
|
check_thousands_sep (charT (','), tname, loc);
|
|
|
|
check_grouping (charT (), tname, "", loc);
|
|
}
|
|
else {
|
|
// cast to prevent sign extension between (signed) char and wchar_t
|
|
// tmp guards against possibly passing along a "(nil)" pointer
|
|
check_decimal_point (decimal_point, tname, loc);
|
|
check_thousands_sep (thousands_sep, tname, loc);
|
|
check_grouping (charT (), tname, grouping.c_str (), loc);
|
|
}
|
|
|
|
// FIXME: exercise falsename() and truename() in named locales
|
|
|
|
delete loc;
|
|
loc = 0;
|
|
}
|
|
_CATCH (...) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void check_decimal_point (charT expect,
|
|
const char *tname,
|
|
const std::locale *loc)
|
|
{
|
|
typedef std::numpunct<charT> Punct;
|
|
typedef std::char_traits<charT> Traits;
|
|
|
|
const charT c = loc ?
|
|
_STD_USE_FACET (Punct, *loc).decimal_point ()
|
|
: Punct ().decimal_point ();
|
|
|
|
|
|
rw_assert (Traits::eq (c, expect), 0, __LINE__,
|
|
"numpunct<%s>::decimal_point() == %{#lc}, got %{#lc}",
|
|
tname, expect, c);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void check_thousands_sep (charT expect,
|
|
const char *tname,
|
|
const std::locale *loc)
|
|
{
|
|
typedef std::numpunct<charT> Punct;
|
|
typedef std::char_traits<charT> Traits;
|
|
|
|
const charT c = loc ?
|
|
_STD_USE_FACET (Punct, *loc).thousands_sep ()
|
|
: Punct ().thousands_sep ();
|
|
|
|
rw_assert (Traits::eq (c, expect), 0, __LINE__,
|
|
"numpunct<%s>::thousands_sep() == %{#lc}, got %{#lc}",
|
|
tname, expect, c);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void check_grouping (charT,
|
|
const char *tname,
|
|
const std::string &expect,
|
|
const std::locale *loc)
|
|
{
|
|
typedef std::numpunct<charT> Punct;
|
|
|
|
const std::string s = loc ?
|
|
_STD_USE_FACET (Punct, *loc).grouping ()
|
|
: Punct ().grouping ();
|
|
|
|
if ( s != expect
|
|
&& s.size () != expect.size () && s.size () && expect.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 () > expect.size () ? &expect : &s;
|
|
const std::string *shrt = s.size () < expect.size () ? &expect : &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>::grouping() equivalent to %{#S}, got %{#S}",
|
|
tname, &expect, &s);
|
|
}
|
|
else
|
|
rw_assert (s == expect, 0, __LINE__,
|
|
"numpunct<%s>::grouping() == %{#S}, got %{#S}",
|
|
tname, &expect, &s);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void check_falsename (const std::basic_string<charT> &expect,
|
|
const char *tname,
|
|
const std::locale *loc)
|
|
{
|
|
typedef std::numpunct<charT> Punct;
|
|
|
|
const std::basic_string<charT> s = loc ?
|
|
_STD_USE_FACET (Punct, *loc).falsename ()
|
|
: Punct ().falsename ();
|
|
|
|
const int char_size = int (sizeof (charT));
|
|
|
|
rw_assert (s == expect, 0, __LINE__,
|
|
"numpunct<%s>::falsename() == %{#*S}, got %{#*S}",
|
|
tname, char_size, &expect, char_size, &s);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
template <class charT>
|
|
void check_truename (const std::basic_string<charT> &expect,
|
|
const char *tname,
|
|
const std::locale *loc)
|
|
{
|
|
typedef std::numpunct<charT> Punct;
|
|
|
|
const std::basic_string<charT> s = loc ?
|
|
_STD_USE_FACET (Punct, *loc).truename ()
|
|
: Punct ().truename ();
|
|
|
|
const int char_size = int (sizeof (charT));
|
|
|
|
rw_assert (s == expect, 0, __LINE__,
|
|
"numpunct<%s>::truename() == %{#*S}, got %{#*S}",
|
|
tname, char_size, &expect, char_size, &s);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static int
|
|
run_test (int, char**)
|
|
{
|
|
run_test (char (), "char");
|
|
|
|
#ifndef _RWSTD_WCHAR_T
|
|
|
|
run_test (wchar_t (), "wchar_t");
|
|
|
|
#endif // _RWSTD_WCHAR_T
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
return rw_test (argc, argv, __FILE__,
|
|
"lib.locale.numpunct",
|
|
"", run_test,
|
|
"",
|
|
(void*)0);
|
|
}
|