blob: dfb2809885f9d2cbe6ecde047121e6adf82c3331 [file] [log] [blame]
/**************************************************************************
*
* ctype.cpp - definitions of UserCtype facet members
*
* $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.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
#include <rw_ctype.h>
#include <stdarg.h> // for va_arg(), va_list
#include <string.h> // 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, ...)
{
_RWSTD_UNUSED (file);
_RWSTD_UNUSED (line);
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<char>::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<char>::mask Mask;
const size_t size = UserCtype<char>::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<char>::
UserCtype (size_t refs /* = 0 */)
: Base (0, false, refs),
UserCtypeBase ("char")
{
chars_ = 0;
masks_ = _rw_char_masks;
}
UserCtype<char>::
UserCtype (const int *chars, const int *masks, size_t refs /* = 0 */)
: Base (_rw_make_mask_vec (chars, masks), true, refs),
UserCtypeBase ("char")
{
chars_ = chars;
masks_ = masks;
}
UserCtype<char>::char_type
UserCtype<char>::
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>::char_type*
UserCtype<char>::
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>::char_type
UserCtype<char>::
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>::char_type*
UserCtype<char>::
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>::char_type
UserCtype<char>::
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<char>::
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<char>::
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;
}
return ch;
}
const UserCtype<char>::char_type*
UserCtype<char>::
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<wchar_t>::
UserCtype (size_t refs /* = 0 */)
: Base (refs), UserCtypeBase ("wchar_t")
{
chars_ = 0;
masks_ = _rw_char_masks;
}
UserCtype<wchar_t>::
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<wchar_t>::
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<wchar_t>::char_type*
UserCtype<wchar_t>::
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<wchar_t>::char_type*
UserCtype<wchar_t>::
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<wchar_t>::char_type*
UserCtype<wchar_t>::
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<wchar_t>::char_type
UserCtype<wchar_t>::
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<wchar_t>::char_type*
UserCtype<wchar_t>::
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<wchar_t>::char_type
UserCtype<wchar_t>::
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<wchar_t>::char_type*
UserCtype<wchar_t>::
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<wchar_t>::char_type
UserCtype<wchar_t>::
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<wchar_t>::
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<wchar_t>::
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;
}
return char (uch);
}
const UserCtype<wchar_t>::char_type*
UserCtype<wchar_t>::
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
/**************************************************************************/
_RWSTD_NAMESPACE (std) {
std::locale::id
ctype<UserChar>::
id;
ctype<UserChar>::
ctype (size_t refs /* = 0 */)
: Base (refs), UserCtypeBase ("UserChar")
{
masks_ = _rw_char_masks;
chars_ = 0;
}
ctype<UserChar>::
ctype (const int *chars, const int *masks, size_t refs /* = 0 */)
: Base (refs), UserCtypeBase ("UserChar")
{
if (0 == masks) {
// when masks is null so must chars
RW_ASSERT (0 == chars);
masks = _rw_char_masks;
}
chars_ = chars;
masks_ = masks;
}
bool ctype<UserChar>::
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 ctype<UserChar>::char_type*
ctype<UserChar>::
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 ctype<UserChar>::char_type*
ctype<UserChar>::
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 ctype<UserChar>::char_type*
ctype<UserChar>::
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;
}
ctype<UserChar>::char_type
ctype<UserChar>::
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 ctype<UserChar>::char_type*
ctype<UserChar>::
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;
}
ctype<UserChar>::char_type
ctype<UserChar>::
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 ctype<UserChar>::char_type*
ctype<UserChar>::
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;
}
ctype<UserChar>::char_type
ctype<UserChar>::
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*
ctype<UserChar>::
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 ctype<UserChar>::
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;
}
return char (uch);
}
const ctype<UserChar>::char_type*
ctype<UserChar>::
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;
}
} // namespace std
/**************************************************************************/
UserCtype<UserChar>::
UserCtype (size_t refs /* = 0 */)
: Base (refs)
{
chars_ = 0;
masks_ = _rw_char_masks;
}
UserCtype<UserChar>::
UserCtype (const int *chars, const int *masks, size_t refs)
: Base (refs)
{
if (0 == masks) {
// when masks is null so must chars
RW_ASSERT (0 == chars);
masks = _rw_char_masks;
}
chars_ = chars;
masks_ = masks;
}