Author: sebor Date: Sat Jul 8 17:47:25 2006 New Revision: 420234 URL: http://svn.apache.org/viewvc?rev=420234&view=rev Log: 2006-07-08 Martin Sebor STDCXX-3 * rw_ctype.h: New header with the definitions of the UserCtype primary template and explicit specializations for char, wchar_t, and UserChar. * ctype.cpp: Definitions of members of UserCtype specializations. * test/ctype.cpp: New test (partially) exercising UserCtype::is(). Added: incubator/stdcxx/trunk/tests/include/rw_ctype.h (with props) incubator/stdcxx/trunk/tests/self/0.ctype.cpp (with props) incubator/stdcxx/trunk/tests/src/ctype.cpp (with props) Added: incubator/stdcxx/trunk/tests/include/rw_ctype.h URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/include/rw_ctype.h?rev=420234&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/rw_ctype.h (added) +++ incubator/stdcxx/trunk/tests/include/rw_ctype.h Sat Jul 8 17:47:25 2006 @@ -0,0 +1,323 @@ +/************************************************************************** + * + * rw_ctype.h - defines a User Defined ctype facet + * + * $Id$ + * + *************************************************************************** + * + * Copyright 2006 The Apache Software Foundation or its licensors, + * as applicable. + * + * Licensed 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. + * + **************************************************************************/ + +#ifndef RW_CTYPE_H_INCLUDED +#define RW_CTYPE_H_INCLUDED + + +#include // for ctype, locale +#include // for UserChar +#include + + +struct _TEST_EXPORT UserCtypeBase: std::ctype_base +{ + enum MemFunc { + mf_is, + mf_is_range, + mf_scan_is, + mf_scan_not, + mf_toupper, + mf_toupper_range, + mf_tolower, + mf_tolower_range, + mf_widen, + mf_widen_range, + mf_narrow, + mf_narrow_range, + n_funs + }; + + struct Exception { + virtual ~Exception (); + virtual const char* what () const = 0; + }; + + // name of the character type ("char", "wchar_t", "UserChar") + const char* const cname_; + + // array of masks corresponding to each of the characters in chars + // the first negative element in chars denotes the last element + const int* masks_; + const int* chars_; + + // arrays of correspondning uppercase and lowercase characters + const int* upper_; + const int* lower_; + + // arrays of corresponding narrow and wide characters + const int* narrow_; + const int* wide_; + + // counter of the number of calls to all member functions + // made throughout the lifetime of this object + _RWSTD_SIZE_T n_all_calls_; + + // counter of the number of calls to each member function + // made throughout the lifetime of this object + _RWSTD_SIZE_T n_calls_ [n_funs]; + + // counter of the number of exceptions thrown by each member + // function throughout the lifetime of this object + _RWSTD_SIZE_T n_throws_ [n_funs]; + + // member function counter value that, when reached, will + // cause an exception to be thrown + _RWSTD_SIZE_T throw_at_calls_ [n_funs]; + + // value of a character that, when encountered, will cause + // an exception to be thrown + int throw_char_; + + // when true the facet throws an exception when it encounters + // an invalid character (unless otherwise specified) + bool throw_on_invalid_; + +protected: + + UserCtypeBase (const char*); + +private: + + UserCtypeBase (const UserCtypeBase&); // not CopyConstructible + void operator= (const UserCtypeBase&); // not Assignable +}; + + +template +class UserCtype; + + +_RWSTD_SPECIALIZED_CLASS +class _TEST_EXPORT UserCtype + : public std::ctype, public UserCtypeBase +{ + typedef std::ctype Base; + +public: + + explicit + UserCtype (const int* = 0, const int* = 0, _RWSTD_SIZE_T = 0); + +protected: + + virtual char_type + do_toupper (char_type) const; + + virtual const char_type* + do_toupper (char_type*, const char_type*) const; + + virtual char_type + do_tolower (char_type) const; + + virtual const char_type* + do_tolower (char_type*, const char_type*) const; + + virtual char_type + do_widen (char) const; + + virtual const char* + do_widen (const char*, const char*, char_type*) const; + + virtual char + do_narrow (char_type, char) const; + + virtual const char_type* + do_narrow (const char_type*, const char_type*, char, char*) const; +}; + + +#ifndef _RWSTD_NO_WCHAR_T + +_RWSTD_SPECIALIZED_CLASS +class _TEST_EXPORT UserCtype + : public std::ctype, public UserCtypeBase +{ + typedef std::ctype Base; + +public: + + explicit + UserCtype (const int* = 0, const int* = 0, _RWSTD_SIZE_T = 0); + +protected: + + virtual bool + do_is (mask, char_type) const; + + virtual const char_type* + do_is (const char_type*, const char_type*, mask*) const; + + virtual const char_type* + do_scan_is (mask, const char_type*, const char_type*) const; + + virtual const char_type* + do_scan_not (mask, const char_type*, const char_type*) const; + + virtual char_type + do_toupper (char_type) const; + + virtual const char_type* + do_toupper (char_type*, const char_type*) const; + + virtual char_type + do_tolower (char_type) const; + + virtual const char_type* + do_tolower (char_type*, const char_type*) const; + + virtual char_type + do_widen (char) const; + + virtual const char* + do_widen (const char*, const char*, char_type*) const; + + virtual char + do_narrow (char_type, char) const; + + virtual const char_type* + do_narrow (const char_type*, const char_type*, char, char*) const; +}; + + +#endif // _RWSTD_NO_WCHAR_T + + +_RWSTD_SPECIALIZED_CLASS +class _TEST_EXPORT UserCtype + : public std::locale::facet, public UserCtypeBase +{ + typedef std::locale::facet Base; +public: + + typedef UserChar char_type; + + explicit + UserCtype (const int* = 0, const int* = 0, _RWSTD_SIZE_T = 0); + + bool + is (mask m, char_type c) const { + return do_is (m, c); + } + + const char_type* + is (const char_type* lo, const char_type *hi, mask *vec) const { + return do_is (lo, hi, vec); + } + + const char_type* + scan_is (mask m, const char_type *lo, const char_type *hi) const { + return do_scan_is ( m, lo, hi); + } + + const char_type* + scan_not (mask m, const char_type *lo, const char_type *hi) const { + return do_scan_not (m, lo, hi); + } + + char_type + (toupper)(char_type c) const { + return do_toupper (c); + } + + const char_type* + (toupper)(char_type *lo, const char_type *hi) const { + return do_toupper (lo, hi); + } + + char_type + (tolower)(char_type c) const { + return do_tolower (c); + } + + const char_type* + (tolower)(char_type *lo, const char_type *hi) const { + return do_tolower (lo, hi); + } + + char_type + widen (char c) const { + return do_widen (c); + } + + const char* + widen (const char *lo, const char *hi, char_type *to) const { + return do_widen (lo, hi, to); + } + + char + narrow (char_type c, char dfault) const { + return do_narrow (c, dfault); + } + + const char_type* + narrow (const char_type *lo, const char_type *hi, + char dfault, char *to) const { + return do_narrow (lo, hi, dfault, to); + } + + static std::locale::id id; + +protected: + + virtual bool + do_is (mask, char_type) const; + + virtual const char_type* + do_is (const char_type*, const char_type*, mask*) const; + + virtual const char_type* + do_scan_is (mask, const char_type*, const char_type*) const; + + virtual const char_type* + do_scan_not (mask, const char_type*, const char_type*) const; + + virtual char_type + do_toupper (char_type) const; + + virtual const char_type* + do_toupper (char_type*, const char_type*) const; + + virtual char_type + do_tolower (char_type c) const; + + virtual const char_type* + do_tolower (char_type*, const char_type*) const; + + virtual char_type + do_widen (char) const; + + virtual const char* + do_widen (const char*, const char*, char_type*) const; + + virtual char + do_narrow (char_type, char dfault) const; + + virtual const char_type* + do_narrow (const char_type*, const char_type*, char, char*) const; +}; + + +#endif // RW_CTYPE_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/rw_ctype.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/rw_ctype.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/self/0.ctype.cpp URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/self/0.ctype.cpp?rev=420234&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/self/0.ctype.cpp (added) +++ incubator/stdcxx/trunk/tests/self/0.ctype.cpp Sat Jul 8 17:47:25 2006 @@ -0,0 +1,473 @@ +/************************************************************************ + * + * 0.ctype.cpp - test exercising the UserCtype helper class template + * + * $Id$ + * + ************************************************************************ + * + * Copyright 2006 The Apache Software Foundation or its licensors, + * as applicable. + * + * Copyright 2006 Rogue Wave Software. + * + * Licensed 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 // for UserChar +#include // for UserCtype +#include // for rw_printf +#include + +#include // for free() +#include // for memset(), size_t, strlen() + +/***********************************************************************/ + +extern const char +cntrl[] = { + +#if 'A' == 0x41 // ASCII + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" +#elif 'A' == 0xc1 // EBCDIC + "" +#endif + +}; + +extern const std::size_t +n_cntrl = sizeof cntrl - 1; + +extern const char +digits[] = "0123456789"; + +extern const std::size_t +n_digits = sizeof digits - 1; + +extern const char +graph[] = "!\"#$%&\\()*+,-./0123456789:;<=>?@[]^_`{|}~"; + +extern const std::size_t +n_graph = sizeof graph - 1; + +extern const char +lower[] = "abcdefghijklmnopqrstuvwxyz"; + +extern const std::size_t +n_lower = sizeof lower - 1; + +extern const char +punct[] = "!#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~"; + +extern const std::size_t +n_punct = sizeof punct - 1; + +extern const char +print[] = { + "!\"#$%&\\()*+,-./0123456789:;<=>?@[]^_`{|}~" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" +}; + +extern const std::size_t +n_print = sizeof print - 1; + +extern const char +spaces[] = " \t\v\f\r\n"; + +extern const std::size_t +n_spaces = sizeof spaces - 1; + +extern const char +upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +extern const std::size_t +n_upper = sizeof upper - 1; + +extern const char +xdigits[] = "0123456789ABCDEFabcdef"; + +extern const std::size_t +n_xdigits = sizeof xdigits - 1; + +/***********************************************************************/ + +template +void +test_is (charT*, const char *cname, + std::ctype_base::mask m, + const char *chars, std::size_t n_chars) +{ + UserCtype ctp; + + std::size_t n_calls = ctp.n_calls_ [ctp.mf_is]; + std::size_t n_throws = ctp.n_throws_ [ctp.mf_is]; + + std::size_t expect_calls = 0; + std::size_t expect_throws = 0; + + for (std::size_t i = 0; i != n_chars; ++i) { + const charT ch = make_char (chars [i], (charT*)0); + + int result = -1; + +#ifndef _RWSTD_NO_EXCEPTIONS + + // let the first call call succeed and trigger an exception + // on the second call to UserCtype::is() + ctp.throw_at_calls_ [ctp.mf_is] = + ctp.n_calls_ [ctp.mf_is] + 2; + + for (int j = 0; j != 2; ++j) { + + if (1 < sizeof (charT)) { + // can only count UserCtype::is() calls when + // charT != char since there is no virtual do_is() + // in the char explicit specialization + ++expect_calls; + } + else if (j) { + // cannot induce an exception out of UserCtype::is() + // since there is no virtual do_is() in the specialization + break; + } + + if (j) + ++expect_throws; + + int threw = 0; + + try { + result = ctp.is (m, ch); + } + catch (...) { + threw = 1; + } + + rw_assert (j == threw, 0, __LINE__, + "UserCtype<%s>::is(%{LC}, %{#c}) " + "%{?}unexpectedly threw%{:}failed to throw%{;}", + cname, m, ch, j == threw); + } + +#else // if defined (_RWSTD_NO_EXCEPTIONS) + + ++expect_calls; + result = ctp.is (m, ch); + +#endif // _RWSTD_NO_EXCEPTIONS + + rw_assert (result, 0, __LINE__, + "UserCtype<%s>::is(%{LC}, %{#c}) == true", + cname, m, chars [i]); + } + + n_calls = ctp.n_calls_ [ctp.mf_is] - n_calls; + + rw_assert (expect_calls == n_calls, 0, __LINE__, + "expected %zu calls to UserCtype<%s>::is(%{LC}, char_type), " + "got %zu", expect_calls, cname, m, n_calls); + + n_throws = ctp.n_throws_ [ctp.mf_is] - n_throws; + + rw_assert (expect_throws == n_throws, 0, __LINE__, + "expected %zu exceptions thrown by UserCtype<%s>::is(%{LC}, " + "char_type), got %zu", expect_throws, cname, m, n_throws); +} + +template +void +test_is (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::is" + "(mask, char_type) const", cname); + + ////////////////////////////////////////////////////////////////// + // exercise default behavior + + test_is ((charT*)0, cname, std::ctype_base::alnum, lower, n_lower); + test_is ((charT*)0, cname, std::ctype_base::alnum, upper, n_upper); + test_is ((charT*)0, cname, std::ctype_base::alnum, digits, n_digits); + test_is ((charT*)0, cname, std::ctype_base::alnum, xdigits, n_xdigits); + test_is ((charT*)0, cname, std::ctype_base::alpha, lower, n_lower); + test_is ((charT*)0, cname, std::ctype_base::alpha, upper, n_upper); + test_is ((charT*)0, cname, std::ctype_base::cntrl, cntrl, n_cntrl); + test_is ((charT*)0, cname, std::ctype_base::digit, digits, n_digits); + test_is ((charT*)0, cname, std::ctype_base::graph, graph, n_graph); + test_is ((charT*)0, cname, std::ctype_base::lower, lower, n_lower); + test_is ((charT*)0, cname, std::ctype_base::print, print, n_print); + test_is ((charT*)0, cname, std::ctype_base::punct, punct, n_punct); + test_is ((charT*)0, cname, std::ctype_base::space, spaces, n_spaces); + test_is ((charT*)0, cname, std::ctype_base::xdigit, xdigits, n_xdigits); + + ////////////////////////////////////////////////////////////////// + // exercise custom behavior + + static const int chars[] = { + '0', '1', '2', '3', 'a', 'b', 'c', + 0x100, 0x7fff, 0x8000, 0xffff, +#if 2 < _RWSTD_INT_SIZE + 0x10000, 0x7fffffff, 0x80000000, 0xffffffff, +#else + 0x1ff, 0x700, 0x8fff, 0xf000, +#endif + -1 // end of chars + }; + + static const int masks[] = { + /* '0' */ std::ctype_base::alpha, + /* '1' */ std::ctype_base::cntrl, + /* '2' */ std::ctype_base::digit, + /* '3' */ std::ctype_base::lower, + /* 'a' */ std::ctype_base::print, + /* 'b' */ std::ctype_base::punct, + /* 'c' */ std::ctype_base::space, + /* 0x100 */ std::ctype_base::upper, + /* 0x7fff */ std::ctype_base::xdigit, + /* 0x8000 */ std::ctype_base::alpha | std::ctype_base::cntrl, + /* 0xffff */ std::ctype_base::cntrl | std::ctype_base::digit, + /* 0x10000 */ std::ctype_base::digit | std::ctype_base::lower, + /* 0x7fffffff */ std::ctype_base::lower | std::ctype_base::print, + /* 0x80000000 */ std::ctype_base::print | std::ctype_base::punct, + /* 0xffffffff */ std::ctype_base::punct | std::ctype_base::space, + -1 // end of masks + }; + + static const int mask_all = + std::ctype_base::alpha + | std::ctype_base::cntrl + | std::ctype_base::digit + | std::ctype_base::lower + | std::ctype_base::print + | std::ctype_base::punct + | std::ctype_base::space + | std::ctype_base::upper + | std::ctype_base::xdigit; + + const UserCtype cust (chars, masks); + + for (std::size_t i = 0; 0 <= chars [i]; ++i) { + + // FIXME: enable tests of characters greater than CHAR_MAX + if ( _RWSTD_UCHAR_MAX < std::size_t (chars [i]) + /* && sizeof (char) == sizeof (charT) */) { + // when charT == char break out when the character + // value is greater than CHAR_MAX + break; + } + + const charT ch = make_char (chars [i], (charT*)0); + + const std::ctype_base::mask m_is = + std::ctype_base::mask (masks [i]); + + rw_assert (cust.is (m_is, ch), + 0, __LINE__, + "UserCtype<%s>::is(%{LC}, %{#lc}) == true", + cname, m_is, chars [i]); + + const std::ctype_base::mask m_not = + std::ctype_base::mask (~m_is & mask_all); + + rw_assert (!cust.is (m_not, ch), 0, __LINE__, + "UserCtype<%s>::is(%{LC}, %{#lc}) == false", + cname, m_not, chars [i]); + } +} + +/***********************************************************************/ + +template +void +test_scan_is (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::scan_is" + "(mask, const char_type*, const char_type*) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::scan_is" + "(mask, const char_type*, const char_type*) const" + " not exercised", cname); +} + +/***********************************************************************/ + +template +void +test_scan_not (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::scan_not" + "(mask, const char_type*, const char_type*) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::scan_not" + "(mask, const char_type*, const char_type*) const " + "not exercised", cname); +} + +/***********************************************************************/ + +template +void +test_toupper (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::toupper" + "(char_type) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::toupper" + "(char_type) const not exercised", cname); + + rw_info (0, 0, __LINE__, "UserCtype<%s>::toupper" + "(char_type*, const char_type) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::toupper" + "(char_type*, const char_type) const not exercised", cname); +} + +/***********************************************************************/ + +template +void +test_tolower (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::tolower" + "(char_type) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::tolower" + "(char_type) const not exercised", cname); + + rw_info (0, 0, __LINE__, "UserCtype<%s>::tolower" + "(char_type*, const char_type) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::tolower" + "(char_type*, const char_type) const not exercised", cname); +} + +/***********************************************************************/ + +template +void +test_widen (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::widen" + "(char) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::widen" + "(char) const not exercised", cname); + + rw_info (0, 0, __LINE__, "UserCtype<%s>::widen" + "(const char*, const char*, char_type*) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::widen" + "(const char*, const char*, char_type*) const not exercised", + cname); +} + +/***********************************************************************/ + +template +void +test_narrow (charT*, const char *cname) +{ + rw_info (0, 0, __LINE__, "UserCtype<%s>::narrow" + "(char_type, char) const", cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::narrow" + "(char_type, char) const not exercised", cname); + + rw_info (0, 0, __LINE__, "UserCtype<%s>::narrow" + "(const char_type*, const char_type*, char, char*) const", + cname); + + rw_warn (0, 0, __LINE__, "UserCtype<%s>::narrow" + "(const char_type*, const char_type*, char, char*) const" + " not exercised", + cname); +} + +/***********************************************************************/ + +/* extern */ int opt_is; +/* extern */ int opt_scan_is; +/* extern */ int opt_scan_not; + +/* extern */ int opt_toupper; +/* extern */ int opt_tolower; + +/* extern */ int opt_widen; +/* extern */ int opt_narrow; + + +template +void +test (charT*, const char *cname) +{ +#define TEST(func) \ + if (0 <= opt_ ## func) \ + test_ ## func ((charT*)0, cname); \ + else \ + rw_note (0, 0, __LINE__, \ + "UserCtype<%s>::%s() tests disabled", \ + cname, # func) + + TEST (is); + TEST (scan_is); + TEST (scan_not); + + TEST (toupper); + TEST (tolower); + + TEST (widen); + TEST (narrow); +} + +/***********************************************************************/ + +static int +run_test (int, char**) +{ + test ((char*)0, "char"); + +#ifndef _RWSTD_NO_WCHAR_T + test ((wchar_t*)0, "wchar_t"); +#endif // _RWSTD_NO_WCHAR_T + + test ((UserChar*)0, "UserChar"); + + return 0; +} + +/***********************************************************************/ + +int main (int argc, char *argv[]) +{ + return rw_test (argc, argv, __FILE__, + "", + 0, + run_test, + "|-is~ " + "|-scan_is~ " + "|-scan_not~ " + "|-toupper~ " + "|-tolower~ " + "|-widen~ " + "|-narrow~ ", + &opt_is, + &opt_scan_is, + &opt_scan_not, + &opt_toupper, + &opt_tolower, + &opt_widen, + &opt_narrow, + (void*)0 /* sentinel */); +} Propchange: incubator/stdcxx/trunk/tests/self/0.ctype.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/self/0.ctype.cpp ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/src/ctype.cpp URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/src/ctype.cpp?rev=420234&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/src/ctype.cpp (added) +++ incubator/stdcxx/trunk/tests/src/ctype.cpp Sat Jul 8 17:47:25 2006 @@ -0,0 +1,1652 @@ +/************************************************************************** + * + * ctype.cpp - definitions of UserCtype facet members + * + * $Id$ + * + *************************************************************************** + * + * Copyright 2006 The Apache Software Foundation or its licensors, + * as applicable. + * + * Licensed 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. + * + **************************************************************************/ + +// expand _TEST_EXPORT macros +#define _RWSTD_TEST_SRC +#include + +#include // for va_arg(), va_list +#include // for memset() + +/**************************************************************************/ + +typedef unsigned char UChar; + + +_TEST_EXPORT int +rw_vasnprintf (char**, size_t*, const char*, va_list); + + +static void +_rw_throw (const char *file, int line, const char *fmt, ...) +{ + struct Exception: UserCtypeBase::Exception { + char what_ [256]; + + /* virtual */ const char* what () const { + return what_; + } + }; + + Exception ex; + + va_list va; + va_start (va, fmt); + + char *buf = ex.what_; + size_t bufsize = sizeof ex.what_; + rw_vasnprintf (&buf, &bufsize, fmt, va); + + va_end (va); + + throw ex; +} + +/**************************************************************************/ + +static const char* const +_rw_func_names[] = { + "is(mask, char_type)", + "is(const char_type*, const char_type*, mask*)", + "scan_is(mask, const char_type*, const char_type*)", + "scan_not(mask, const char_type*, const char_type*)", + "to_upper(char_type)", + "to_upper(char_type*, const char_type*)", + "to_lower(char_type)", + "to_lower(char_type*, const char_type*)", + "widen(char)", + "widen(const char*, const char*, char_type*)", + "narrow(char_type, char)", + "narrow(const char_type*, const char_type*, char, char*)" +}; + +/**************************************************************************/ + +UserCtypeBase::Exception:: +~Exception () +{ + // no-op +} + +/**************************************************************************/ + +static const int +_rw_char_masks [256] = { + +#define ALPHA std::ctype_base::alpha +#define ALNUM std::ctype_base::alnum +#define CNTRL std::ctype_base::cntrl +#define DIGIT std::ctype_base::digit +#define GRAPH std::ctype_base::graph +#define LOWER std::ctype_base::lower +#define PRINT std::ctype_base::print +#define PUNCT std::ctype_base::punct +#define SPACE std::ctype_base::space +#define UPPER std::ctype_base::upper +#define XDIGIT std::ctype_base::xdigit + + +#undef LETTER +#define LETTER(m) (PRINT | ALPHA | GRAPH | m) + +#if 'A' == 0x41 // ASCII + + /* 0x00 NUL */ CNTRL, + /* 0x01 SOH */ CNTRL, + /* 0x02 STX */ CNTRL, + /* 0x03 ETX */ CNTRL, + /* 0x04 EOT */ CNTRL, + /* 0x05 ENQ */ CNTRL, + /* 0x06 ACK */ CNTRL, + /* '\a' BEL */ CNTRL, + /* 0x08 BS */ CNTRL, + /* '\t' TAB */ SPACE | CNTRL, + /* '\n' LF */ SPACE | CNTRL, + /* 0x0b VT */ SPACE | CNTRL, + /* '\f' FF */ SPACE | CNTRL, + /* '\r' CR */ SPACE | CNTRL, + /* 0x0e SO */ CNTRL, + /* 0x0f SI */ CNTRL, + /* 0x10 DLE */ CNTRL, + /* 0x11 DC1 */ CNTRL, + /* 0x12 DC2 */ CNTRL, + /* 0x13 DC3 */ CNTRL, + /* 0x14 DC4 */ CNTRL, + /* 0x15 NAK */ CNTRL, + /* 0x16 SYN */ CNTRL, + /* 0x17 ETB */ CNTRL, + /* 0x18 CAN */ CNTRL, + /* 0x19 EM */ CNTRL, + /* 0x1a SUB */ CNTRL, + /* 0x1b ESC */ CNTRL, + /* 0x1c FS */ CNTRL, + /* 0x1d GS */ CNTRL, + /* 0x1e RS */ CNTRL, + /* 0x1f US */ CNTRL, + /* ' ' */ SPACE | PRINT, + /* '!' */ PRINT | PUNCT | GRAPH, + /* '"' */ PRINT | PUNCT | GRAPH, + /* '#' */ PRINT | PUNCT | GRAPH, + /* '$' */ PRINT | PUNCT | GRAPH, + /* '%' */ PRINT | PUNCT | GRAPH, + /* '&' */ PRINT | PUNCT | GRAPH, + /* '\'' */ PRINT | PUNCT | GRAPH, + /* '(' */ PRINT | PUNCT | GRAPH, + /* ')' */ PRINT | PUNCT | GRAPH, + /* '*' */ PRINT | PUNCT | GRAPH, + /* '+' */ PRINT | PUNCT | GRAPH, + /* ',' */ PRINT | PUNCT | GRAPH, + /* '-' */ PRINT | PUNCT | GRAPH, + /* '.' */ PRINT | PUNCT | GRAPH, + /* '/' */ PRINT | PUNCT | GRAPH, + /* '0' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '1' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '2' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '3' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '4' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '5' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '6' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '7' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '8' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '9' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* ':' */ PRINT | PUNCT | GRAPH, + /* ';' */ PRINT | PUNCT | GRAPH, + /* '<' */ PRINT | PUNCT | GRAPH, + /* '=' */ PRINT | PUNCT | GRAPH, + /* '>' */ PRINT | PUNCT | GRAPH, + /* '?' */ PRINT | PUNCT | GRAPH, + /* '@' */ PRINT | PUNCT | GRAPH, + + /* 'A' */ LETTER (UPPER | XDIGIT), + /* 'B' */ LETTER (UPPER | XDIGIT), + /* 'C' */ LETTER (UPPER | XDIGIT), + /* 'D' */ LETTER (UPPER | XDIGIT), + /* 'E' */ LETTER (UPPER | XDIGIT), + /* 'F' */ LETTER (UPPER | XDIGIT), + /* 'G' */ LETTER (UPPER), + /* 'H' */ LETTER (UPPER), + /* 'I' */ LETTER (UPPER), + /* 'J' */ LETTER (UPPER), + /* 'K' */ LETTER (UPPER), + /* 'L' */ LETTER (UPPER), + /* 'M' */ LETTER (UPPER), + /* 'N' */ LETTER (UPPER), + /* 'O' */ LETTER (UPPER), + /* 'P' */ LETTER (UPPER), + /* 'Q' */ LETTER (UPPER), + /* 'R' */ LETTER (UPPER), + /* 'S' */ LETTER (UPPER), + /* 'T' */ LETTER (UPPER), + /* 'U' */ LETTER (UPPER), + /* 'V' */ LETTER (UPPER), + /* 'W' */ LETTER (UPPER), + /* 'X' */ LETTER (UPPER), + /* 'Y' */ LETTER (UPPER), + /* 'Z' */ LETTER (UPPER), + + /* '[' */ PRINT | PUNCT | GRAPH, + /* '\\' */ PRINT | PUNCT | GRAPH, + /* ']' */ PRINT | PUNCT | GRAPH, + /* '^' */ PRINT | PUNCT | GRAPH, + /* '_' */ PRINT | PUNCT | GRAPH, + /* '`' */ PRINT | PUNCT | GRAPH, + + /* 'a' */ LETTER (LOWER | XDIGIT), + /* 'b' */ LETTER (LOWER | XDIGIT), + /* 'c' */ LETTER (LOWER | XDIGIT), + /* 'd' */ LETTER (LOWER | XDIGIT), + /* 'e' */ LETTER (LOWER | XDIGIT), + /* 'f' */ LETTER (LOWER | XDIGIT), + /* 'g' */ LETTER (LOWER), + /* 'h' */ LETTER (LOWER), + /* 'i' */ LETTER (LOWER), + /* 'j' */ LETTER (LOWER), + /* 'k' */ LETTER (LOWER), + /* 'l' */ LETTER (LOWER), + /* 'm' */ LETTER (LOWER), + /* 'n' */ LETTER (LOWER), + /* 'o' */ LETTER (LOWER), + /* 'p' */ LETTER (LOWER), + /* 'q' */ LETTER (LOWER), + /* 'r' */ LETTER (LOWER), + /* 's' */ LETTER (LOWER), + /* 't' */ LETTER (LOWER), + /* 'u' */ LETTER (LOWER), + /* 'v' */ LETTER (LOWER), + /* 'w' */ LETTER (LOWER), + /* 'x' */ LETTER (LOWER), + /* 'y' */ LETTER (LOWER), + /* 'z' */ LETTER (LOWER), + + /* '{' */ PRINT | PUNCT | GRAPH, + /* '|' */ PRINT | PUNCT | GRAPH, + /* '}' */ PRINT | PUNCT | GRAPH, + /* '~' */ PRINT | PUNCT | GRAPH, + /* 0x7f DEL */ CNTRL + +#elif 'A' == 0xc1 // EBCDIC + + /* NUL */ CNTRL, + /* SOH */ CNTRL, + /* STX */ CNTRL, + /* ETX */ CNTRL, + /* PF */ CNTRL, + /* HT */ CNTRL, + /* LC */ CNTRL, + /* DEL */ CNTRL, + /* */ 0, + /* */ 0, + /* SMM */ CNTRL, + /* VT */ SPACE | CNTRL, + /* FF */ SPACE | CNTRL, + /* CR */ SPACE | CNTRL, + /* SO */ CNTRL, + /* SI */ CNTRL, + /* DLE */ CNTRL, + /* DC1 */ CNTRL, + /* DC2 */ CNTRL, + /* TM */ CNTRL, + /* RES */ CNTRL, + /* NL */ CNTRL, + /* BS */ CNTRL, + /* IL */ CNTRL, + /* CAN */ CNTRL, + /* EM */ CNTRL, + /* CC */ CNTRL, + /* CU1 */ CNTRL, + /* IFS */ CNTRL, + /* IGS */ CNTRL, + /* IRS */ CNTRL, + /* IUS */ CNTRL, + /* DS */ CNTRL, + /* SOS */ CNTRL, + /* FS */ CNTRL, + /* */ 0, + /* BYP */ CNTRL, + /* LF */ SPACE | CNTRL, + /* ETB */ CNTRL, + /* ESC */ CNTRL, + /* */ 0, + /* */ 0, + /* SM */ CNTRL, + /* CU2 */ CNTRL, + /* */ 0, + /* ENQ */ CNTRL, + /* ACK */ CNTRL, + /* BEL */ CNTRL, + /* */ 0, + /* */ 0, + /* SYN */ CNTRL, + /* */ 0, + /* PN */ CNTRL, + /* RS */ CNTRL, + /* UC */ CNTRL, + /* EOT */ CNTRL, + /* */ 0, + /* */ 0, + /* */ 0, + /* CU3 */ CNTRL, + /* DC4 */ CNTRL, + /* NAK */ CNTRL, + /* */ 0, + /* SUB */ CNTRL, + /* ' ' */ SPACE | PRINT, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* ct. */ PRINT | PUNCT | GRAPH, + /* '.' */ PRINT | PUNCT | GRAPH, + /* '<' */ PRINT | PUNCT | GRAPH, + /* '(' */ PRINT | PUNCT | GRAPH, + /* '+' */ PRINT | PUNCT | GRAPH, + /* '|' */ PRINT | PUNCT | GRAPH, + /* '&' */ PRINT | PUNCT | GRAPH, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* '!' */ PRINT | PUNCT | GRAPH, + /* '$' */ PRINT | PUNCT | GRAPH, + /* '*' */ PRINT | PUNCT | GRAPH, + /* ')' */ PRINT | PUNCT | GRAPH, + /* ';' */ PRINT | PUNCT | GRAPH, + /* '~' */ PRINT | PUNCT | GRAPH, + /* '-' */ PRINT | PUNCT | GRAPH, + /* '/' */ PRINT | PUNCT | GRAPH, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* ',' */ PRINT | PUNCT | GRAPH, + /* '%' */ PRINT | PUNCT | GRAPH, + /* '_' */ PRINT | PUNCT | GRAPH, + /* '>' */ PRINT | PUNCT | GRAPH, + /* '?' */ PRINT | PUNCT | GRAPH, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* ':' */ PRINT | PUNCT | GRAPH, + /* '#' */ PRINT | PUNCT | GRAPH, + /* '@' */ PRINT | PUNCT | GRAPH, + /* ''' */ PRINT | PUNCT | GRAPH, + /* '=' */ PRINT | PUNCT | GRAPH, + /* '"' */ PRINT | PUNCT | GRAPH, + /* */ 0, + /* 'a' */ LETTER (LOWER | XDIGIT), + /* 'b' */ LETTER (LOWER | XDIGIT), + /* 'c' */ LETTER (LOWER | XDIGIT), + /* 'd' */ LETTER (LOWER | XDIGIT), + /* 'e' */ LETTER (LOWER | XDIGIT), + /* 'f' */ LETTER (LOWER | XDIGIT), + /* 'g' */ LETTER (LOWER), + /* 'h' */ LETTER (LOWER), + /* 'i' */ LETTER (LOWER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* 'j' */ LETTER (LOWER), + /* 'k' */ LETTER (LOWER), + /* 'l' */ LETTER (LOWER), + /* 'm' */ LETTER (LOWER), + /* 'n' */ LETTER (LOWER), + /* 'o' */ LETTER (LOWER), + /* 'p' */ LETTER (LOWER), + /* 'q' */ LETTER (LOWER), + /* 'r' */ LETTER (LOWER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* 's' */ LETTER (LOWER), + /* 't' */ LETTER (LOWER), + /* 'u' */ LETTER (LOWER), + /* 'v' */ LETTER (LOWER), + /* 'w' */ LETTER (LOWER), + /* 'x' */ LETTER (LOWER), + /* 'y' */ LETTER (LOWER), + /* 'z' */ LETTER (LOWER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* '`' */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* 'A' */ LETTER (UPPER | XDIGIT), + /* 'B' */ LETTER (UPPER | XDIGIT), + /* 'C' */ LETTER (UPPER | XDIGIT), + /* 'D' */ LETTER (UPPER | XDIGIT), + /* 'E' */ LETTER (UPPER | XDIGIT), + /* 'F' */ LETTER (UPPER | XDIGIT), + /* 'G' */ LETTER (UPPER), + /* 'H' */ LETTER (UPPER), + /* 'I' */ LETTER (UPPER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* 'J' */ LETTER (UPPER), + /* 'K' */ LETTER (UPPER), + /* 'L' */ LETTER (UPPER), + /* 'M' */ LETTER (UPPER), + /* 'N' */ LETTER (UPPER), + /* 'O' */ LETTER (UPPER), + /* 'P' */ LETTER (UPPER), + /* 'Q' */ LETTER (UPPER), + /* 'R' */ LETTER (UPPER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* 'S' */ LETTER (UPPER), + /* 'T' */ LETTER (UPPER), + /* 'U' */ LETTER (UPPER), + /* 'V' */ LETTER (UPPER), + /* 'W' */ LETTER (UPPER), + /* 'X' */ LETTER (UPPER), + /* 'Y' */ LETTER (UPPER), + /* 'Z' */ LETTER (UPPER), + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* '0' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '1' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '2' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '3' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '4' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '5' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '6' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '7' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '8' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* '9' */ PRINT | DIGIT | GRAPH | XDIGIT, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0, + /* */ 0 + +#else // 'A' != 0x41 && 'A' != 0xc1 +# error unknown character set (neither ASCII nor EBCDIC) +#endif // ASCII or EBCDIC + +}; + + +UserCtypeBase:: +UserCtypeBase (const char *cname) + : cname_ (cname), masks_ (_rw_char_masks), chars_ (0), + upper_ (0), lower_ (0), narrow_ (0), wide_ (0), + n_all_calls_ (0), + throw_char_ (-1), throw_on_invalid_ (false) +{ + memset (n_calls_, 0, sizeof n_calls_); + memset (n_throws_, 0, sizeof n_throws_); + memset (throw_at_calls_, 0, sizeof throw_at_calls_); +} + +/**************************************************************************/ + +// records a call to the object's member function fun and +// throws an exception if the number of calls to the member +// function reaches the limit specified by throw_at_calls_ +static void +_rw_funcall (const UserCtypeBase &ctp, + UserCtypeBase::MemFunc mf) +{ + UserCtypeBase* const pctp = _RWSTD_CONST_CAST (UserCtypeBase*, &ctp); + + // increment the number of calls regardless of success + ++pctp->n_all_calls_; + ++pctp->n_calls_ [mf]; + + // check the number of calls and throw an exception + // if the specified limit has been reached + if (ctp.n_calls_ [mf] == ctp.throw_at_calls_ [mf]) { + // increment the exception counter for this function + ++pctp->n_throws_ [mf]; + + _rw_throw (__FILE__, __LINE__, + "UserCtype<%s>::%s: reached call limit of %zu", + ctp.cname_, _rw_func_names [mf], ctp.throw_at_calls_); + + RW_ASSERT (!"logic error: should not reach"); + } +} + +/**************************************************************************/ + +static void +_rw_check_char (const UserCtypeBase &ctp, + UserCtypeBase::MemFunc mf, + size_t uch) +{ + if (0 <= ctp.throw_char_ && size_t (ctp.throw_char_) == uch) { + + UserCtypeBase* const pctp = _RWSTD_CONST_CAST (UserCtypeBase*, &ctp); + ++pctp->n_throws_ [mf]; + + _rw_throw (__FILE__, __LINE__, + "UserCtype<%s>::%s: invalid character: %{#lc}", + ctp.cname_, _rw_func_names [mf], int (uch)); + + RW_ASSERT (!"logic error: should not reach"); + } +} + +/**************************************************************************/ + +static UserCtype::mask* +_rw_make_mask_vec (const int *chars, const int *masks) +{ + if (0 == chars) { + RW_ASSERT (0 == masks); + return 0; + } + + RW_ASSERT (0 != masks); + + typedef UserCtype::mask Mask; + + const size_t size = UserCtype::table_size; + Mask* const vec = new Mask [size]; + + memset (vec, 0, size * sizeof *vec); + + for (size_t i = 0; 0 <= chars [i]; ++i) + vec [UChar (chars [i])] = Mask (masks [i]); + + return vec; +} + + +UserCtype:: +UserCtype (const int *chars, const int *masks, size_t refs) + : Base (_rw_make_mask_vec (chars, masks), true, refs), + UserCtypeBase ("char") +{ + chars_ = chars; + masks_ = masks; +} + + +UserCtype::char_type +UserCtype:: +do_toupper (char_type ch) const +{ + _rw_funcall (*this, mf_toupper); + + const UChar uch = UChar (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (0 == upper_) { + if (masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + return char_type (uch - 32); +#else // EBCDIC + return char_type (uch + 64); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_toupper (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_toupper_range); + + if (0 == upper_) { + for ( ; lo < hi; ++lo) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + *lo = char_type (uch - 32); +#else // EBCDIC + *lo = char_type (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_tolower (char_type ch) const +{ + _rw_funcall (*this, mf_tolower); + + _rw_check_char (*this, mf_toupper, UChar (ch)); + + if (0 == chars_) { + if (masks_ [UChar (ch)] & UPPER) { +#if 'A' == 0x41 // ASCII + return char_type (UChar (ch + 32)); +#else // EBCDIC + return char_type (UChar (ch - 64)); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_tolower (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_tolower_range); + + if (0 == chars_) { + for ( ; lo < hi; ++lo) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ [uch] & UPPER) { +#if 'A' == 0x41 // ASCII + *lo = char_type (uch - 32); +#else // EBCDIC + *lo = char_type (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_widen (char ch) const +{ + _rw_funcall (*this, mf_widen); + + const UChar uch = UChar (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (uch == UChar (narrow_ [i])) { + if (0 <= wide_ [i]) + return UChar (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return ch; +} + + +const char* +UserCtype:: +do_widen (const char *lo, const char *hi, char_type *dst) const +{ + _rw_funcall (*this, mf_widen_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const UChar uch = *lo; + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (uch == UChar (narrow_ [i])) { + if (0 <= wide_ [i]) + *dst = UChar (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + } + else if (throw_char_ < 0 || int (_RWSTD_UCHAR_MAX) < throw_char_) { + const size_t nelems = size_t (hi - lo); + memcpy (dst, lo, nelems); + lo += nelems; + } + else { + for (; lo < hi; ++lo, ++dst) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = char_type (uch); + } + } + + return lo; +} + + +char UserCtype:: +do_narrow (char_type ch, char dfault) const +{ + _rw_funcall (*this, mf_narrow); + + const UChar uch = UChar (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (uch == UChar (wide_ [i])) { + if (0 <= wide_ [i]) + return UChar (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return dfault; +} + + +const UserCtype::char_type* +UserCtype:: +do_narrow (const char_type *lo, const char_type *hi, char dflt, char *dst) const +{ + _rw_funcall (*this, mf_narrow_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (uch == UChar (wide_ [i])) { + *dst = 0 <= narrow_ [i] ? UChar (wide_ [i]) : UChar (dflt); + break; + } + } + } + } + else if (throw_char_ < 0 || int (_RWSTD_UCHAR_MAX) < throw_char_) { + const size_t nelems = size_t (hi - lo); + memcpy (dst, lo, nelems); + lo += nelems; + } + else { + for (; lo < hi; ++lo, ++dst) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = char_type (uch); + } + } + + return lo; +} + +/**************************************************************************/ + +#ifndef _RWSTD_NO_WCHAR_T + +UserCtype:: +UserCtype (const int *chars, const int *masks, size_t refs) + : Base (refs), UserCtypeBase ("wchar_t") +{ + if (0 == masks) { + // when masks is null so must chars + RW_ASSERT (0 == chars); + masks = _rw_char_masks; + } + + chars_ = chars; + masks_ = masks; +} + + +bool UserCtype:: +do_is (mask m, char_type ch) const +{ + _rw_funcall (*this, mf_is); + + const size_t uch = size_t (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ == _rw_char_masks) { + return uch < 256 ? 0 != (masks_ [uch] & m) : false; + } + + for (size_t i = 0; 0 <= chars_ [i]; ++i) + if (chars_ [i] == int (ch)) + return 0 != (masks_ [i] & m); + + return false; +} + + +const UserCtype::char_type* +UserCtype:: +do_is (const char_type *lo, const char_type *hi, mask *vec) const +{ + _rw_funcall (*this, mf_is_range); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo, ++vec) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *vec = mask (uch < 256 ? masks_ [uch] : 0); + } + } + else { + for ( ; lo < hi; ++lo, ++vec) { + + _rw_check_char (*this, mf_toupper, size_t (*lo)); + + bool found = false; + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (*lo)) { + *vec = mask (masks_ [i]); + found = true; + break; + } + } + + if (!found && throw_on_invalid_) + throw; + } + } + + return lo; +} + + +const UserCtype::char_type* +UserCtype:: +do_scan_is (mask m, const char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_scan_is); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && masks_ [uch] & m) + break; + } + } + else { + for ( ; lo < hi; ++lo) { + + _rw_check_char (*this, mf_toupper, size_t (*lo)); + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (*lo) && masks_ [i] & m) + return lo; + } + } + } + + return lo; +} + + +const UserCtype::char_type* +UserCtype:: +do_scan_not (mask m, const char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_scan_not); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && 0 == (masks_ [uch] & m)) + break; + } + } + else { + for ( ; lo < hi; ++lo) { + + _rw_check_char (*this, mf_toupper, size_t (*lo)); + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (*lo) && 0 == (masks_ [i] & m)) + return lo; + } + } + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_toupper (char_type ch) const +{ + _rw_funcall (*this, mf_toupper); + + const size_t uch = size_t (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (0 == upper_) { + + if (uch < 256 && masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + return char_type (uch - 32); +#else // EBCDIC + return char_type (uch + 64); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_toupper (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_toupper_range); + + if (0 == upper_) { + for ( ; lo < hi; ++lo) { + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + *lo = char_type (uch - 32); +#else // EBCDIC + *lo = char_type (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_tolower (char_type ch) const +{ + _rw_funcall (*this, mf_tolower); + + const size_t uch = size_t (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ == _rw_char_masks) { + if (uch < 256 && masks_ [uch] & UPPER) { +#if 'A' == 0x41 // ASCII + return char_type (uch + 32); +#else // EBCDIC + return char_type (uch - 64); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_tolower (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_tolower_range); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + + const size_t uch = size_t (*lo); + + if (uch < 256 && masks_ [uch] & UPPER) { +#if 'A' == 0x41 // ASCII + *lo = char_type (uch - 32); +#else // EBCDIC + *lo = char_type (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_widen (char ch) const +{ + _rw_funcall (*this, mf_widen); + + const UChar uch = UChar (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (int (uch) == narrow_ [i]) { + if (0 <= wide_ [i]) + return char_type (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return ch; +} + + +const char* +UserCtype:: +do_widen (const char *lo, const char *hi, char_type *dst) const +{ + _rw_funcall (*this, mf_widen_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (int (uch) == narrow_ [i]) { + if (0 <= wide_ [i]) + *dst = char_type (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + } + else { + for (; lo < hi; ++lo, ++dst) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = char_type (uch); + } + } + + return lo; +} + + +char UserCtype:: +do_narrow (char_type ch, char dfault) const +{ + _rw_funcall (*this, mf_narrow); + + const size_t uch = size_t (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (int (uch) == wide_ [i]) { + if (0 <= wide_ [i]) + return char (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return dfault; +} + + +const UserCtype::char_type* +UserCtype:: +do_narrow (const char_type *lo, const char_type *hi, char dflt, char *dst) const +{ + _rw_funcall (*this, mf_narrow_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (int (uch) == wide_ [i]) { + *dst = 0 <= narrow_ [i] ? char (wide_ [i]) : dflt; + break; + } + } + } + } + else { + for (; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = char (uch); + } + } + + return lo; +} + +#endif // _RWSTD_NO_WCHAR_T + +/**************************************************************************/ + +UserCtype:: +UserCtype (const int *chars, const int *masks, size_t refs) + : Base (refs), UserCtypeBase ("wchar_t") +{ + if (0 == masks) { + // when masks is null so must chars + RW_ASSERT (0 == chars); + masks = _rw_char_masks; + } + + chars_ = chars; + masks_ = masks; +} + + +bool UserCtype:: +do_is (mask m, char_type ch) const +{ + _rw_funcall (*this, mf_is); + + const size_t uch = size_t (ch.c); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ == _rw_char_masks) { + return uch < 256 ? 0 != (masks_ [uch] & m) : false; + } + + for (size_t i = 0; 0 <= chars_ [i]; ++i) + if (chars_ [i] == int (uch)) + return 0 != (masks_ [i] & m); + + return false; +} + + +const UserCtype::char_type* +UserCtype:: +do_is (const char_type *lo, const char_type *hi, mask *vec) const +{ + _rw_funcall (*this, mf_is_range); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo, ++vec) { + + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + *vec = mask (uch < 256 ? masks_ [uch] : 0); + } + } + else { + for ( ; lo < hi; ++lo, ++vec) { + + _rw_check_char (*this, mf_toupper, size_t (lo->c)); + + bool found = false; + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (UChar (lo->c))) { + *vec = mask (masks_ [i]); + found = true; + break; + } + } + + if (!found && throw_on_invalid_) + throw; + } + } + + return lo; +} + + +const UserCtype::char_type* +UserCtype:: +do_scan_is (mask m, const char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_scan_is); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && masks_ [uch] & m) + break; + } + } + else { + for ( ; lo < hi; ++lo) { + + _rw_check_char (*this, mf_toupper, size_t (lo->c)); + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (UChar (lo->c)) && masks_ [i] & m) + return lo; + } + } + } + + return lo; +} + + +const UserCtype::char_type* +UserCtype:: +do_scan_not (mask m, const char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_scan_not); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && 0 == (masks_ [uch] & m)) + break; + } + } + else { + for ( ; lo < hi; ++lo) { + + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= chars_ [i]; ++i) { + if (chars_ [i] == int (uch) && 0 == (masks_ [i] & m)) + return lo; + } + } + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_toupper (char_type ch) const +{ + _rw_funcall (*this, mf_toupper); + + const size_t uch = size_t (ch.c); + + _rw_check_char (*this, mf_toupper, uch); + + if (0 == upper_) { + + if (uch < 256 && masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + ch.c = UChar (uch - 32); +#else // EBCDIC + ch.c = UChar (uch + 64); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_toupper (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_toupper_range); + + if (0 == upper_) { + for ( ; lo < hi; ++lo) { + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + if (uch < 256 && masks_ [uch] & LOWER) { +#if 'A' == 0x41 // ASCII + lo->c = UChar (uch - 32); +#else // EBCDIC + lo->c = UChar (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_tolower (char_type ch) const +{ + _rw_funcall (*this, mf_tolower); + + const size_t uch = size_t (ch.c); + + _rw_check_char (*this, mf_toupper, uch); + + if (masks_ == _rw_char_masks) { + if (uch < 256 && masks_ [uch] & UPPER) { +#if 'A' == 0x41 // ASCII + ch.c = UChar (uch + 32); +#else // EBCDIC + ch.c = UChar (uch - 64); +#endif + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return ch; +} + + +const UserCtype::char_type* +UserCtype:: +do_tolower (char_type *lo, const char_type *hi) const +{ + _rw_funcall (*this, mf_tolower_range); + + if (masks_ == _rw_char_masks) { + for ( ; lo < hi; ++lo) { + + const size_t uch = size_t (lo->c); + + if (uch < 256 && masks_ [uch] & UPPER) { +#if 'A' == 0x41 // ASCII + lo->c = UChar (uch - 32); +#else // EBCDIC + lo->c = UChar (uch + 64); +#endif + } + } + } + else { + // FIXME: implement this + RW_ASSERT (!"do_toupper() not implemented"); + } + + return lo; +} + + +UserCtype::char_type +UserCtype:: +do_widen (char ch) const +{ + _rw_funcall (*this, mf_widen); + + const UChar uch = UChar (ch); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (int (uch) == narrow_ [i]) { + if (0 <= wide_ [i]) + return make_char (char (wide_ [i]), (UserChar*)0); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return make_char (ch, (UserChar*)0); +} + + +const char* +UserCtype:: +do_widen (const char *lo, const char *hi, char_type *dst) const +{ + _rw_funcall (*this, mf_widen_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= narrow_ [i]; ++i) { + if (int (uch) == narrow_ [i]) { + if (0 <= wide_ [i]) + *dst = make_char (char (wide_ [i]), (UserChar*)0); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + } + else { + for (; lo < hi; ++lo, ++dst) { + + const UChar uch = UChar (*lo); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = make_char (*lo, (UserChar*)0); + } + } + + return lo; +} + + +char UserCtype:: +do_narrow (char_type ch, char dfault) const +{ + _rw_funcall (*this, mf_narrow); + + const size_t uch = size_t (ch.c); + + _rw_check_char (*this, mf_toupper, uch); + + if (narrow_ && wide_) { + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (int (uch) == wide_ [i]) { + if (0 <= wide_ [i]) + return char (wide_ [i]); + + if (throw_on_invalid_) + throw; + + break; + } + } + } + + return dfault; +} + + +const UserCtype::char_type* +UserCtype:: +do_narrow (const char_type *lo, const char_type *hi, char dflt, char *dst) const +{ + _rw_funcall (*this, mf_narrow_range); + + if (narrow_ && wide_) { + for ( ; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + for (size_t i = 0; 0 <= wide_ [i]; ++i) { + if (int (uch) == wide_ [i]) { + *dst = 0 <= narrow_ [i] ? char (wide_ [i]) : dflt; + break; + } + } + } + } + else { + for (; lo < hi; ++lo, ++dst) { + + const size_t uch = size_t (lo->c); + + _rw_check_char (*this, mf_toupper, uch); + + *dst = char (uch); + } + } + + return lo; +} Propchange: incubator/stdcxx/trunk/tests/src/ctype.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/src/ctype.cpp ------------------------------------------------------------------------------ svn:keywords = Id