| /*************************************************************************** |
| * |
| * 22.locale.ctype.is.cpp - Tests exercising the is() 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 |
| * |
| * 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 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) |
| # define LC_MESSAGES _RWSTD_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 |
| int libc_isalpha (char ch) |
| { |
| return (std::isalpha)(UChar (ch)); |
| } |
| |
| int libc_isspace (char ch) |
| { |
| return (std::isspace)(UChar (ch)); |
| } |
| |
| int libc_isprint (char ch) |
| { |
| return (std::isprint)(UChar (ch)); |
| } |
| |
| int libc_iscntrl (char ch) |
| { |
| return (std::iscntrl)(UChar (ch)); |
| } |
| |
| int libc_isupper (char ch) |
| { |
| return (std::isupper)(UChar (ch)); |
| } |
| |
| int libc_islower (char ch) |
| { |
| return (std::islower)(UChar (ch)); |
| } |
| |
| int libc_isdigit (char ch) |
| { |
| return (std::isdigit)(UChar (ch)); |
| } |
| |
| int libc_ispunct (char ch) |
| { |
| return (std::ispunct)(UChar (ch)); |
| } |
| |
| int libc_isxdigit (char ch) |
| { |
| return (std::isxdigit)(UChar (ch)); |
| } |
| |
| int libc_isalnum (char ch) |
| { |
| return (std::isalnum)(UChar (ch)); |
| } |
| |
| int libc_isgraph (char ch) |
| { |
| return (std::isgraph)(UChar (ch)); |
| } |
| |
| char libc_tolower (char ch) |
| { |
| return std::tolower (UChar (ch)); |
| } |
| |
| char libc_toupper (char ch) |
| { |
| return (std::toupper)(UChar (ch)); |
| } |
| |
| std::ctype_base::mask libc_mask (int mask, char ch, const char *locname) |
| { |
| char curlocname [256]; |
| |
| if (locname) { |
| std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0)); |
| |
| if (0 == std::setlocale (LC_CTYPE, locname)) |
| return std::ctype_base::mask (); |
| } |
| |
| const int c = UChar (ch); |
| |
| int result = 0; |
| |
| if (mask & ALPHA && (std::isalpha)(c)) |
| result |= ALPHA; |
| if (mask & CNTRL && (std::iscntrl)(c)) |
| result |= CNTRL; |
| if (mask & DIGIT && (std::isdigit)(c)) |
| result |= DIGIT; |
| if (mask & GRAPH && (std::isgraph)(c)) |
| result |= GRAPH; |
| if (mask & LOWER && (std::islower)(c)) |
| result |= LOWER; |
| if (mask & PRINT && (std::isprint)(c)) |
| result |= PRINT; |
| if (mask & PUNCT && (std::ispunct)(c)) |
| result |= PUNCT; |
| if (mask & SPACE && (std::isspace)(c)) |
| result |= SPACE; |
| if (mask & UPPER && (std::isupper)(c)) |
| result |= UPPER; |
| if (mask & XDIGIT && (std::isxdigit)(c)) |
| result |= XDIGIT; |
| |
| if (locname) |
| std::setlocale (LC_CTYPE, curlocname); |
| |
| return std::ctype_base::mask (result); |
| } |
| |
| inline bool libc_is (std::ctype_base::mask mask, char ch, const char *locname) |
| { |
| const std::ctype_base::mask m = libc_mask (mask, ch, locname); |
| |
| return 0 != (m & mask); |
| } |
| |
| std::size_t c_strlen (const char *s1) |
| { |
| return std::strlen (s1); |
| } |
| |
| int c_strcmp (const char *s1, const char *s2) |
| { |
| int ret = std::strcoll (s1, s2); |
| return ret ? ret > 0 ? 1 : -1 : 0; |
| } |
| |
| 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; |
| } |
| |
| |
| #ifndef _RWSTD_NO_WCHAR_T |
| |
| int libc_isalpha (wchar_t ch) |
| { |
| return (std::iswalpha)(ch); |
| } |
| |
| int libc_isspace (wchar_t ch) |
| { |
| return (std::iswspace)(ch); |
| } |
| |
| int libc_isprint (wchar_t ch) |
| { |
| return (std::iswprint)(ch); |
| } |
| |
| int libc_iscntrl (wchar_t ch) |
| { |
| return (std::iswcntrl)(ch); |
| } |
| |
| int libc_isupper (wchar_t ch) |
| { |
| return (std::iswupper)(ch); |
| } |
| |
| int libc_islower (wchar_t ch) |
| { |
| return (std::iswlower)(ch); |
| } |
| |
| int libc_isdigit (wchar_t ch) |
| { |
| return (std::iswdigit)(ch); |
| } |
| |
| int libc_ispunct (wchar_t ch) |
| { |
| return (std::iswpunct)(ch); |
| } |
| |
| int libc_isxdigit (wchar_t ch) |
| { |
| return (std::iswxdigit)(ch); |
| } |
| |
| int libc_isalnum (wchar_t ch) |
| { |
| return (std::iswalnum)(ch); |
| } |
| |
| int libc_isgraph (wchar_t ch) |
| { |
| return (std::iswgraph)(ch); |
| } |
| |
| wchar_t libc_tolower (wchar_t ch) |
| { |
| return (std::towlower)(ch); |
| } |
| |
| wchar_t libc_toupper (wchar_t ch) |
| { |
| return (std::towupper)(ch); |
| } |
| |
| std::size_t c_strlen (const wchar_t *s1) |
| { |
| return std::wcslen (s1); |
| } |
| |
| int c_strcmp (const wchar_t *s1, const wchar_t *s2) |
| { |
| int ret = std::wcscmp (s1, s2); |
| return ret ? ret > 0 ? 1 : -1 : 0; |
| } |
| |
| |
| 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; |
| } |
| |
| std::ctype_base::mask libc_mask (int mask, wchar_t ch, const char *locname) |
| { |
| char curlocname [256]; |
| |
| if (locname) { |
| std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0)); |
| |
| if (0 == std::setlocale (LC_CTYPE, locname)) |
| return std::ctype_base::mask (); |
| } |
| |
| int result = 0; |
| |
| if (mask & ALPHA && (std::iswalpha)(ch)) |
| result |= ALPHA; |
| if (mask & CNTRL && (std::iswcntrl)(ch)) |
| result |= CNTRL; |
| if (mask & DIGIT && (std::iswdigit)(ch)) |
| result |= DIGIT; |
| if (mask & GRAPH && (std::iswgraph)(ch)) |
| result |= GRAPH; |
| if (mask & LOWER && (std::iswlower)(ch)) |
| result |= LOWER; |
| if (mask & PRINT && (std::iswprint)(ch)) |
| result |= PRINT; |
| if (mask & PUNCT && (std::iswpunct)(ch)) |
| result |= PUNCT; |
| if (mask & SPACE && (std::iswspace)(ch)) |
| result |= SPACE; |
| if (mask & UPPER && (std::iswupper)(ch)) |
| result |= UPPER; |
| if (mask & XDIGIT && (std::iswxdigit)(ch)) |
| result |= XDIGIT; |
| |
| if (locname) |
| std::setlocale (LC_CTYPE, curlocname); |
| |
| return std::ctype_base::mask (result); |
| } |
| |
| bool libc_is (std::ctype_base::mask mask, wchar_t ch, const char *locname) |
| { |
| const std::ctype_base::mask m = libc_mask (mask, ch, locname); |
| |
| return 0 != (m & mask); |
| } |
| |
| 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; |
| |
| #ifndef _RWSTD_NO_BTOWC |
| |
| result = std::btowc (UChar (ch)); |
| |
| #elif !defined (_RWSTD_NO_MBTOWC) |
| |
| if (1 != std::mbtowc (&result, &ch, 1)) |
| result = wchar_t (WEOF); |
| |
| #else |
| |
| result = UChar (ch); |
| |
| #endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC |
| |
| if (locname) |
| std::setlocale (LC_CTYPE, curlocname); |
| |
| return result; |
| } |
| |
| #endif // _RWSTD_NO_WCHAR_T |
| |
| |
| template <class charT> |
| void gen_str (charT *str, std::size_t size) |
| { |
| // generate a random string with the given size |
| // we do not attempt to check that the size is within the |
| // valid range for the string. |
| |
| for (std::size_t i = 0; i < size; i++){ |
| str [i] = UChar (std::rand () % UCHAR_MAX); |
| // only increment if we are not going to roll over |
| if (str [i] != charT (UCHAR_MAX - 1U)) |
| ++str [i]; |
| } |
| |
| str [size] = charT (); |
| |
| _RWSTD_ASSERT (c_strlen (str) == size); |
| } |
| |
| /**************************************************************************/ |
| |
| template <class charT> |
| void test_is (charT, const char *cname) |
| { |
| charT str [MAX_STR_SIZE + 1]; |
| |
| BEGIN_LOCALE_LOOP (NLOOPS, locname, j) { |
| |
| std::size_t size = std::size_t (j % MAX_STR_SIZE); |
| |
| gen_str (str, size); |
| |
| // create a mask for each character in the string using the c library |
| // to make sure that it is the same as the mask returned by is |
| std::ctype_base::mask vec [MAX_STR_SIZE + 1]; |
| |
| // set the global C locale to default to make sure |
| // the C++ library does not asume a set value |
| std::setlocale (LC_CTYPE, ""); |
| |
| ctp.is (str, str + size, vec); |
| |
| // set the global C locale to the current locale for calls to the |
| // C library |
| std::setlocale (LC_CTYPE, locname); |
| |
| for (std::size_t i = 0; i < size ; i++) { |
| |
| int libc_result = 0; |
| |
| if (libc_isalpha (str [i])) |
| libc_result |= ALPHA; |
| if (libc_isprint (str [i])) |
| libc_result |= PRINT; |
| if (libc_isspace (str [i])) |
| libc_result |= SPACE; |
| if (libc_iscntrl (str [i])) |
| libc_result |= CNTRL; |
| if (libc_isupper (str [i])) |
| libc_result |= UPPER; |
| if (libc_islower (str [i])) |
| libc_result |= LOWER; |
| if (libc_isdigit (str [i])) |
| libc_result |= DIGIT; |
| if (libc_ispunct (str [i])) |
| libc_result |= PUNCT; |
| if (libc_isxdigit (str [i])) |
| libc_result |= XDIGIT; |
| if (libc_isgraph (str [i])) |
| libc_result |= GRAPH; |
| |
| rw_assert (vec [i] == libc_result, 0, __LINE__, |
| "ctype<%s>::is(%{*Ac}, ..., v) in locale(%#s) " |
| "at offset %zu; got %{LC} expected %{LC}\n", |
| cname, int (sizeof *str), str, |
| locname, i, vec [i], libc_result); |
| } |
| } END_LOCALE_LOOP (locname); |
| } |
| |
| /**************************************************************************/ |
| |
| template <class charT> |
| void test_is_ch (charT, const char *cname) |
| { |
| // buffers to hold the character classification |
| // e.g., for `a' in the "C" locale the string will be |
| // "print lower alpha xdigit alnum graph " |
| |
| static char is_C [80]; // C character classification |
| static char is_CXX [80]; // C++ classification using ctype<char> facet |
| static char is_CXX2 [80]; // C++ classification using convenience funcs |
| |
| rw_info (0, 0, __LINE__, "std::ctype<%s>::is(mask, %1$s)", cname); |
| |
| BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) { |
| |
| const charT ch = charT (i); |
| const UChar uch = ch; |
| |
| *is_C = |
| *is_CXX = |
| *is_CXX2 = '\0'; |
| |
| // set the global C locale to locname for the C library calls |
| std::setlocale (LC_CTYPE, locname); |
| |
| #define IS(what) \ |
| libc_is##what (ch) \ |
| ? (void)std::strcat (is_C, #what" ") : (void)0; |
| |
| // test all classes of characters |
| IS (space); IS (print); IS (cntrl); IS (upper); IS (lower); |
| IS (alpha); IS (digit); IS (punct); IS (xdigit); IS (alnum); |
| IS (graph); |
| |
| // set the global C locale to default to make sure |
| // the C++ library does not asume a set value |
| std::setlocale (LC_CTYPE, ""); |
| |
| #undef IS |
| // convenience macro |
| #define IS(what) \ |
| ctp.is (std::ctype_base::what, ch) \ |
| ? (void)std::strcat (is_CXX, #what" ") : (void)0; \ |
| (std::is##what)(ch, loc) \ |
| ? (void)std::strcat (is_CXX2, #what" ") : (void)0; |
| |
| // test all classes of characters |
| // (must be in the same order as the IS() calls above) |
| IS (space); IS (print); IS (cntrl); IS (upper); IS (lower); |
| IS (alpha); IS (digit); IS (punct); IS (xdigit); IS (alnum); |
| IS (graph); |
| |
| // compare the two strings (should match) |
| |
| rw_assert (0 == std::strcmp (is_C, is_CXX), 0, __LINE__, |
| "ctype<%s>::is(..., %{#lc}) in locale(%#s) " |
| "expected to hold for { %s}, got { %s}", |
| cname, uch, locname, is_C, is_CXX); |
| |
| // convenience functions must produce the same results |
| rw_assert (0 == std::strcmp (is_C, is_CXX2), 0, __LINE__, |
| "is* (%{#lc}, locale (%#s)) expected to hold for " |
| "{ %s}, got { %s}", |
| uch, locname, is_C, is_CXX2); |
| |
| #if !defined (_WIN32) && !defined (_WIN64) |
| |
| // exercise POSIX requirements only on POSIX platforms |
| |
| static const std::ctype_base::mask masks[] = { |
| ALPHA, std::ctype_base::mask (), CNTRL, DIGIT, |
| GRAPH, LOWER, PRINT, PUNCT, |
| SPACE, UPPER, XDIGIT |
| }; |
| |
| // see the POSIX description of LC_CTYPE in Locale for a table |
| // of required and allowed combinations of character classes |
| |
| // a character in a given /* class */ below is also required |
| // to be included in the following set of classes |
| static const int required [sizeof masks / sizeof *masks] = { |
| /* alpha */ ALPHA | GRAPH | PRINT, |
| /* blank */ SPACE, |
| /* cntrl */ CNTRL, |
| /* digit */ DIGIT | GRAPH | PRINT | XDIGIT, |
| /* graph */ GRAPH | PRINT, |
| /* lower */ ALPHA | GRAPH | LOWER | PRINT, |
| /* print */ PRINT, |
| /* punct */ GRAPH | PRINT | PUNCT, |
| /* space */ SPACE, |
| /* upper */ ALPHA | GRAPH | PRINT | UPPER, |
| /* xdigit */ GRAPH | PRINT | XDIGIT |
| }; |
| |
| // a character in a given /* class */ below may also |
| // be included in the following set of classes |
| static const int allowed [sizeof masks / sizeof *masks] = { |
| /* alpha */ UPPER | LOWER | XDIGIT, |
| /* blank */ CNTRL, |
| /* cntrl */ SPACE, |
| /* digit */ 0, |
| /* graph */ UPPER | LOWER | ALPHA | DIGIT | SPACE | PUNCT |XDIGIT, |
| /* lower */ UPPER | XDIGIT, |
| /* print */ UPPER | LOWER | ALPHA | DIGIT | SPACE | PUNCT |XDIGIT, |
| /* punct */ SPACE, |
| /* space */ CNTRL, |
| /* upper */ LOWER | XDIGIT, |
| /* xdigit */ UPPER | LOWER | ALPHA | DIGIT |
| }; |
| |
| // a character in a given /* class */ below is explicitly |
| // disallowed to be included in the following set of classes |
| static const int disallowed [sizeof masks / sizeof *masks] = { |
| /* alpha */ DIGIT | SPACE | CNTRL | PUNCT, |
| /* blank */ UPPER | LOWER | ALPHA | DIGIT, |
| /* cntrl */ UPPER | LOWER | ALPHA | DIGIT | PUNCT | GRAPH | PRINT, |
| /* digit */ UPPER | LOWER | ALPHA | SPACE | SPACE | CNTRL, |
| /* graph */ CNTRL, |
| /* lower */ DIGIT | SPACE | CNTRL | PUNCT, |
| /* print */ CNTRL, |
| /* punct */ UPPER | LOWER | ALPHA | DIGIT | CNTRL | XDIGIT, |
| /* space */ UPPER | LOWER | ALPHA | DIGIT | XDIGIT, |
| /* upper */ DIGIT | SPACE | CNTRL | PUNCT, |
| /* xdigit */ SPACE | CNTRL | PUNCT |
| }; |
| |
| // obtain the mask of a single character |
| std::ctype_base::mask m; |
| ctp.is (&ch, &ch + 1, &m); |
| |
| int missing = 0; // required bits missing in ch's mask |
| int all_allowed = 0; // all bits allowed to be set in ch's mask |
| int all_disallowed = 0; // all bits disallowed to be set in the mask |
| |
| for (std::size_t k = 0; k != sizeof masks / sizeof *masks; ++k) { |
| |
| // assumes masks [k] has a single bit set |
| const int bit = m & masks [k]; |
| if (!bit) |
| continue; |
| |
| if ((bit & required [k]) && (m & required [k]) != required [k]) { |
| // character in a class given by masks[k] is required |
| // to also belong to all classes in required[k] |
| |
| missing |= ~(m & required [k]) & required [k]; |
| } |
| |
| // character in a class given by masks[k] is only allowed |
| // to belong to classes in (allowed[k] | required[k]) and |
| // is not allowed to belong to those in disallowed[k] |
| all_allowed |= required [k] | allowed [k]; |
| all_disallowed |= disallowed [k]; |
| } |
| |
| // the space character automatically belongs to the print class |
| // but cannot belong to the punct or graph classes; other characters |
| // that belong to the space class can belong to the punct and graph |
| // classes |
| if (' ' == ch) { |
| all_disallowed |= PUNCT | GRAPH; |
| if (!(m & PRINT)) |
| missing |= PRINT; |
| } |
| |
| int cmask = -1; |
| |
| if (missing) { |
| |
| if (-1 == cmask) |
| cmask = libc_mask (-1, ch, locname); |
| |
| rw_assert (m == cmask, 0, __LINE__, |
| "mask of %{#lc} in locale(%#s) " |
| "is missing bits %{LC}: %{LC}", |
| ch, locname, missing, m); |
| } |
| |
| if (m & ~all_allowed) { |
| |
| if (-1 == cmask) |
| cmask = libc_mask (-1, ch, locname); |
| |
| rw_assert (m == cmask, 0, __LINE__, |
| "mask of %{#lc} in locale (%#s) " |
| "contains extra bits %{LC}: %{LC}", |
| ch, locname, m & ~all_allowed, m); |
| } |
| |
| if (m & all_disallowed) { |
| |
| if (-1 == cmask) |
| cmask = libc_mask (-1, ch, locname); |
| |
| rw_assert (m == cmask, 0, __LINE__, |
| "mask of %{#lc} in locale (%s#) " |
| "contains disallowed bits { %s }: { %s }", |
| ch, locname, m & all_disallowed, m); |
| } |
| |
| #endif // !WIN32 && !WIN64 |
| |
| } END_LOCALE_LOOP (locname); |
| } |
| |
| /**************************************************************************/ |
| |
| template <class charT> |
| void test_libc (charT, const char *cname) |
| { |
| test_is_ch (charT (), cname); |
| test_is (charT (), cname); |
| } |
| |
| /**************************************************************************/ |
| |
| template <class charT> |
| void test_libstd_mask (charT, const char *cname, |
| const std::ctype<charT> &ct, const char *locname) |
| { |
| |
| rw_info (0, 0, __LINE__, "std::ctype<%s>::is(mask, %1$s) in locale(%#s)", |
| cname, locname); |
| |
| #undef TEST |
| #define TEST(ch, m) \ |
| rw_assert (ct.is (m, ch), 0, __LINE__, \ |
| "ctype<%s>::is(%d, %d) failed", cname, m, ch) |
| |
| // make sure the characters have the correct masks |
| TEST (charT ('a'), ALPHA); |
| TEST (charT ('a'), LOWER); |
| TEST (charT ('a'), XDIGIT); |
| TEST (charT ('a'), GRAPH); |
| TEST (charT ('a'), PRINT); |
| TEST (charT ('a'), ALPHA | LOWER | XDIGIT | PRINT); |
| |
| TEST (charT ('b'), ALPHA); |
| TEST (charT ('b'), LOWER); |
| TEST (charT ('b'), XDIGIT); |
| TEST (charT ('b'), GRAPH); |
| TEST (charT ('b'), PRINT); |
| TEST (charT ('b'), ALPHA | LOWER | XDIGIT | PRINT); |
| |
| TEST (charT ('c'), ALPHA); |
| TEST (charT ('c'), LOWER); |
| TEST (charT ('c'), XDIGIT); |
| TEST (charT ('c'), GRAPH); |
| TEST (charT ('c'), PRINT); |
| TEST (charT ('c'), ALPHA | LOWER | XDIGIT | PRINT); |
| |
| TEST (charT ('A'), ALPHA); |
| TEST (charT ('A'), UPPER); |
| TEST (charT ('A'), XDIGIT); |
| TEST (charT ('A'), GRAPH); |
| TEST (charT ('A'), PRINT); |
| TEST (charT ('A'), ALPHA | UPPER | XDIGIT | PRINT); |
| |
| TEST (charT ('B'), ALPHA); |
| TEST (charT ('B'), UPPER); |
| TEST (charT ('B'), XDIGIT); |
| TEST (charT ('B'), GRAPH); |
| TEST (charT ('B'), PRINT); |
| TEST (charT ('B'), ALPHA | UPPER | XDIGIT | PRINT); |
| |
| TEST (charT ('C'), ALPHA); |
| TEST (charT ('C'), UPPER); |
| TEST (charT ('C'), XDIGIT); |
| TEST (charT ('C'), GRAPH); |
| TEST (charT ('C'), PRINT); |
| TEST (charT ('C'), ALPHA | UPPER | XDIGIT | PRINT); |
| |
| TEST (charT ('1'), DIGIT); |
| TEST (charT ('1'), XDIGIT); |
| TEST (charT ('1'), GRAPH); |
| TEST (charT ('1'), PRINT); |
| TEST (charT ('1'), DIGIT | XDIGIT | GRAPH | PRINT); |
| |
| TEST (charT ('2'), DIGIT); |
| TEST (charT ('2'), XDIGIT); |
| TEST (charT ('2'), GRAPH); |
| TEST (charT ('2'), PRINT); |
| TEST (charT ('2'), DIGIT | XDIGIT | GRAPH | PRINT); |
| |
| TEST (charT ('3'), DIGIT); |
| TEST (charT ('3'), XDIGIT); |
| TEST (charT ('3'), GRAPH); |
| TEST (charT ('3'), PRINT); |
| TEST (charT ('3'), DIGIT | XDIGIT | GRAPH | PRINT); |
| |
| TEST (charT (' '), SPACE); |
| TEST (charT (' '), GRAPH); |
| TEST (charT (' '), PRINT); |
| TEST (charT (' '), SPACE | GRAPH | PRINT); |
| |
| if (sizeof (charT) > 1) { |
| TEST (ct.widen ('\xa0'), ALPHA); |
| TEST (ct.widen ('\xa0'), LOWER); |
| TEST (ct.widen ('\xa0'), GRAPH); |
| TEST (ct.widen ('\xa0'), PRINT); |
| TEST (ct.widen ('\xa0'), ALPHA | LOWER | GRAPH | PRINT); |
| |
| TEST (ct.widen ('\xa1'), ALPHA); |
| TEST (ct.widen ('\xa1'), UPPER); |
| TEST (ct.widen ('\xa1'), GRAPH); |
| TEST (ct.widen ('\xa1'), PRINT); |
| TEST (ct.widen ('\xa1'), ALPHA | UPPER | GRAPH | PRINT); |
| |
| TEST (ct.widen ('\xa2'), DIGIT); |
| TEST (ct.widen ('\xa2'), GRAPH); |
| TEST (ct.widen ('\xa2'), PRINT); |
| TEST (ct.widen ('\xa0'), DIGIT | GRAPH | PRINT); |
| } |
| } |
| |
| /**************************************************************************/ |
| |
| 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" |
| "CHARMAP\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" |
| "END CHARMAP\n" |
| }; |
| |
| const char loc_1[] = { |
| "escape_char /\n" |
| "LC_CTYPE\n" |
| "# <A> <B> <C> MYANMAR LETTER KHA\n" |
| "upper <U0041>;<U0042>;<U0043>;<U1001>\n" |
| " <a> <b> <c> MYANMAR LETTER KA\n" |
| "lower <U0061>;<U0062>;<U0063>;<U1000>\n" |
| "alpha <U0061>;<U0062>;<U0063>;<U0041>;" |
| "<U0042>;<U0043>;<U1000>;<U1001>\n" |
| "digit <U0031>;<U0032>;<U0033>;<U1002>\n" |
| "space <U0020>\n" |
| "cntrl <U0000>\n" |
| " <!> <\">\n" |
| "punct <U0021>; <U0022>\n" |
| "graph <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;<U0063>;" |
| "<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;" |
| "<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n" |
| "print <U0041>;<U0042>;<U0043>;" |
| "<U0061>;<U0062>;<U0063>;" |
| "<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;" |
| "<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n" |
| "xdigit <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;" |
| "<U0063>;<U0031>;<U0032>;<U0033>\n" |
| "END LC_CTYPE\n" |
| }; |
| |
| //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)) |
| return; |
| |
| 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_mask (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__, |
| "lib.category.ctype", |
| 0 /* no comment */, |
| run_test, |
| "", |
| (void*)0 /* sentinel */); |
| } |