blob: 147b0547e4599ef1ee6a6b3c8eb556fef66bfbeb [file] [log] [blame]
* 22.locale.ctype.tolower.cpp - Tests exercising the tolower() of ctype facet
* $Id$
* 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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* implied. See the License for the specific language governing
* permissions and limitations under the License.
* Copyright 2001-2006 Rogue Wave Software.
// DESCRIPTION: test iterates over the locales installed on a machine,
// calling the C character classification functions and
// their C++ counterpart(s), comparing the results of
// the calls against one another.
#include <rw/_defs.h>
#if defined __linux__
// on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
# define _XOPEN_SOURCE 500 /* Single Unix conformance */
// bring __int32_t into scope (otherwise <wctype.h> fails to compile)
# include <sys/types.h>
#endif // __linux__
// see Onyx PR #28150
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
# include <wchar.h>
#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
#include <locale>
#include <climits>
#include <clocale>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cwchar> // for WEOF, btowc(), wctob()
#include <cwctype> // for iswxxx()
#if !defined (_MSC_VER)
# if !defined (LC_MESSAGES)
# endif // LC_MESSAGES
# include <langinfo.h>
#endif // _MSC_VER
#include <driver.h>
#include <file.h> // for SLASH
#include <rw_locale.h> // for rw_locales()
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// not set here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root;
#define NLOOPS 25
#define MAX_STR_SIZE 16
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
for (const char* locname = rw_locales (LC_CTYPE, 0); \
locname && *locname; locname += std::strlen (locname) + 1) { \
_TRY { \
const std::locale loc (locname); \
const std::ctype<char> &ctc = \
_STD_USE_FACET (std::ctype<char>, loc); \
_RWSTD_UNUSED (ctc); \
const std::ctype<charT> &ctp = \
_STD_USE_FACET (std::ctype<charT>, loc); \
for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
#define END_LOCALE_LOOP(locname) \
} \
_CATCH (...) { \
rw_assert (0, 0, __LINE__, \
"locale (\"%s\") threw an exception", locname); \
} \
// for notational convenience
typedef unsigned char UChar;
#define ALPHA std::ctype_base::alpha
#define UPPER std::ctype_base::upper
#define LOWER std::ctype_base::lower
#define DIGIT std::ctype_base::digit
#define SPACE std::ctype_base::space
#define CNTRL std::ctype_base::cntrl
#define PUNCT std::ctype_base::punct
#define XDIGIT std::ctype_base::xdigit
#define GRAPH std::ctype_base::graph
#define PRINT std::ctype_base::print
// wrapper functions for the c library char and wchar_t functions
char libc_tolower (char ch)
return std::tolower (UChar (ch));
char libc_toupper (char ch)
return (std::toupper)(UChar (ch));
const char* widen (char *dst, const char *src)
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
char widen (char, char ch, const char*)
return ch;
wchar_t libc_tolower (wchar_t ch)
return (std::towlower)(ch);
wchar_t libc_toupper (wchar_t ch)
return (std::towupper)(ch);
const wchar_t* widen (wchar_t *dst, const char *src)
static wchar_t buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::strlen (src);
_RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
wchar_t widen (wchar_t, char ch, const char *locname)
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
wchar_t result;
result = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBTOWC)
if (1 != std::mbtowc (&result, &ch, 1))
result = wchar_t (WEOF);
result = UChar (ch);
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result;
#endif // _RWSTD_NO_WCHAR_T
template <class charT>
void test_tolower (charT, const char *cname)
rw_info (0, 0, __LINE__, "std::ctype<%s>::tolower(%1$s)", cname);
const charT ch = charT (i);
// set the global C locale to locname for the C library call
std::setlocale (LC_CTYPE, locname);
const charT lch = libc_tolower (ch);
// set the global C locale to default to make sure
// the C++ library does not asume a set value
std::setlocale (LC_CTYPE, "");
// exercise tolower using ctype<>::tolower ()
rw_assert (lch == (ctp.tolower)(ch), 0, __LINE__,
"ctype<%s>::tolower(%{#lc}) == %{#lc}, got %{#lc} "
"in locale(%#s)",
cname, ch, lch, (ctp.tolower)(ch), locname);
// exercise tolower using tolower (char, locale)
rw_assert (lch == (charT)(std::tolower)(ch, loc), 0, __LINE__,
"tolower<%s>(%{#lc}, locale(%#s)) == %{#lc}, got %{#lc}",
cname, ch, locname, lch, (std::tolower)(ch, loc));
} END_LOCALE_LOOP (locname);
template <class charT>
void test_libc (charT, const char *cname)
test_tolower (charT (), cname);
template <class charT>
void test_libstd_tolower (charT, const char *cname,
const std::ctype<charT> &ct,
const char *locname)
rw_info (0, 0, __LINE__,
"std::ctype<%s>::tolower(%1$s) in locale(%#s)",
cname, locname);
int success;
#undef TEST
#define TEST(lower, upper) \
success = ct.widen (lower) == ct.tolower (ct.widen (upper)); \
rw_assert (success, 0, __LINE__, \
"ctype<%s>::tolower(%d) == %d, got %d", \
cname, upper, lower, ct.tolower((charT)upper))
TEST ('a', 'A');
TEST ('b', 'B');
TEST ('c', 'C');
if (sizeof(charT) > 1)
TEST ('\xa0', '\xa1');
#undef TEST
template <class charT>
void test_libstd (charT, const char *cname)
const char cmap_1[] = {
"<code_set_name> \"ANSI_X3.4-1968\"\n"
"<mb_cur_max> 1\n"
"<mb_cur_min> 1\n"
"<U0000> \\x00\n"
"<U0001> \\x01\n"
"<U0002> \\x02\n"
"<U0003> \\x03\n"
"<U0004> \\x04\n"
"<U0005> \\x05\n"
"<U0006> \\x06\n"
"<U0007> \\x07\n"
"<U0008> \\x08\n"
"<U0009> \\x09\n"
"<U000a> \\x0a\n"
"<U000b> \\x0b\n"
"<U000c> \\x0c\n"
"<U000d> \\x0d\n"
"<U000e> \\x0e\n"
"<U000f> \\x0f\n"
"<U0010> \\x10\n"
"<U0011> \\x11\n"
"<U0012> \\x12\n"
"<U0013> \\x13\n"
"<U0014> \\x14\n"
"<U0015> \\x15\n"
"<U0016> \\x16\n"
"<U0017> \\x17\n"
"<U0018> \\x18\n"
"<U0019> \\x19\n"
"<U001a> \\x1a\n"
"<U001b> \\x1b\n"
"<U001c> \\x1c\n"
"<U001d> \\x1d\n"
"<U001e> \\x1e\n"
"<U001f> \\x1f\n"
"<U0020> \\x20\n"
"<U0021> \\x21\n"
"<U0022> \\x22\n"
"<U0023> \\x23\n"
"<U0024> \\x24\n"
"<U0025> \\x25\n"
"<U0026> \\x26\n"
"<U0027> \\x27\n"
"<U0028> \\x28\n"
"<U0029> \\x29\n"
"<U002a> \\x2a\n"
"<U002b> \\x2b\n"
"<U002c> \\x2c\n"
"<U002d> \\x2d\n"
"<U002e> \\x2e\n"
"<U002f> \\x2f\n"
"<U0030> \\x30\n"
"<U0031> \\x31\n"
"<U0032> \\x32\n"
"<U0033> \\x33\n"
"<U0034> \\x34\n"
"<U0035> \\x35\n"
"<U0036> \\x36\n"
"<U0037> \\x37\n"
"<U0038> \\x38\n"
"<U0039> \\x39\n"
"<U003a> \\x3a\n"
"<U003b> \\x3b\n"
"<U003c> \\x3c\n"
"<U003d> \\x3d\n"
"<U003e> \\x3e\n"
"<U003f> \\x3f\n"
"<U0040> \\x40\n"
"<U0041> \\x41\n"
"<U0042> \\x42\n"
"<U0043> \\x43\n"
"<U0044> \\x44\n"
"<U0045> \\x45\n"
"<U0046> \\x46\n"
"<U0047> \\x47\n"
"<U0048> \\x48\n"
"<U0049> \\x49\n"
"<U004a> \\x4a\n"
"<U004b> \\x4b\n"
"<U004c> \\x4c\n"
"<U004d> \\x4d\n"
"<U004e> \\x4e\n"
"<U004f> \\x4f\n"
"<U0050> \\x50\n"
"<U0051> \\x51\n"
"<U0052> \\x52\n"
"<U0053> \\x53\n"
"<U0054> \\x54\n"
"<U0055> \\x55\n"
"<U0056> \\x56\n"
"<U0057> \\x57\n"
"<U0058> \\x58\n"
"<U0059> \\x59\n"
"<U005a> \\x5a\n"
"<U005b> \\x5b\n"
"<U005c> \\x5c\n"
"<U005d> \\x5d\n"
"<U005e> \\x5e\n"
"<U005f> \\x5f\n"
"<U0060> \\x60\n"
"<U0061> \\x61\n"
"<U0062> \\x62\n"
"<U0063> \\x63\n"
"<U0064> \\x64\n"
"<U0065> \\x65\n"
"<U0066> \\x66\n"
"<U0067> \\x67\n"
"<U0068> \\x68\n"
"<U0069> \\x69\n"
"<U006a> \\x6a\n"
"<U006b> \\x6b\n"
"<U006c> \\x6c\n"
"<U006d> \\x6d\n"
"<U006e> \\x6e\n"
"<U006f> \\x6f\n"
"<U0070> \\x70\n"
"<U0071> \\x71\n"
"<U0072> \\x72\n"
"<U0073> \\x73\n"
"<U0074> \\x74\n"
"<U0075> \\x75\n"
"<U0076> \\x76\n"
"<U0077> \\x77\n"
"<U0078> \\x78\n"
"<U0079> \\x79\n"
"<U007a> \\x7a\n"
"<U007b> \\x7b\n"
"<U007c> \\x7c\n"
"<U007d> \\x7d\n"
"<U007e> \\x7e\n"
"<U007f> \\x7f\n"
"<U1000> \\xa0\n"
"<U1001> \\xa1\n"
"<U1002> \\xa2\n"
const char loc_1[] = {
"escape_char /\n"
"toupper (<U0061>,<U0041>);(<U0062>,<U0042>);"
"tolower (<U0041>,<U0061>);(<U0042>,<U0062>);"
//invoke rw_create_locale to build a locale to test with
const char* const locname = rw_create_locale (cmap_1, loc_1);
if (!rw_error (0 != locname, 0, __LINE__,
"failed to create a locale in %s", locale_root))
const std::locale loc (locname);
const std::ctype<charT> &ct =
_STD_USE_FACET (std::ctype<charT>, loc);
ct._C_opts |= ct._C_use_libstd;
ct._C_opts &= ~ct._C_use_libc;
test_libstd_tolower (charT (), cname, ct, locname);
template <class charT>
void run_test (charT, const char *cname)
if (0) {
// do a compile time only test on use_facet and has_facet
_STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
_STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
test_libstd (charT (), cname);
test_libc (charT (), cname);
static int
run_test (int, char**)
run_test (char (), "char");
run_test (wchar_t (), "wchar_t");
return 0;
int main (int argc, char *argv[])
return rw_test (argc, argv, __FILE__,
0 /* no comment */,
(void*)0 /* sentinel */);