blob: dd000b9a013ec69cf311f17cc02c008088ff2e5d [file] [log] [blame]
/***************************************************************************
*
* wctype.cpp - source for the C++ Standard Library ctype<wchar_t> facets
*
* $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-2005 Rogue Wave Software.
*
**************************************************************************/
#define _RWSTD_LIB_SRC
#include <rw/_defs.h>
#ifndef _RWSTD_NO_WCHAR_T
#include <ctype.h>
#include <limits.h>
#include <locale.h>
#ifndef _RWSTD_NO_WCHAR_H
# include <wchar.h> // for wctob()
#endif // _RWSTD_NO_WCHAR_H
#include <stdlib.h> // for wctomb()
#include <string.h> // for memset()
#include <wctype.h> // for iswspace(), ...
#include <loc/_ctype.h>
#include <loc/_locale.h>
#include <loc/_localedef.h>
#include "setlocale.h"
#include "use_facet.h"
#ifdef _RWSTD_NO_EQUAL_CTYPE_MASK
# include "once.h" // for __rw_once()
#endif // _RWSTD_NO_EQUAL_CTYPE_MASK
// utf8 encoding maximum size
#undef _UTF8_MB_CUR_MAX
#define _UTF8_MB_CUR_MAX 6
_RWSTD_NAMESPACE (__rw) {
typedef _STD::ctype_base::mask MaskT;
extern const MaskT __rw_classic_tab [];
extern const unsigned char __rw_upper_tab [];
extern const unsigned char __rw_lower_tab [];
static const wchar_t*
__rw_get_mask (__rw_ctype_t *impl,
const wchar_t *beg,
const wchar_t *end,
MaskT mask,
MaskT *vec,
bool scan_is,
bool use_libstd,
const char *locname)
{
_RWSTD_ASSERT (!end || beg <= end);
if (use_libstd && impl != 0) {
for (; beg != end; ++beg) {
// using binary search look up the character and its mask
_RWSTD_SIZE_T low = 0;
_RWSTD_SIZE_T high = (_RWSTD_SIZE_T)impl->wmask_s;
if (vec)
*vec = MaskT ();
while (low <= high) {
const _RWSTD_SIZE_T cur = (low + high) / 2;
const __rw_mask_elm next_elm = impl->wmask_tab (cur);
if (next_elm.ch == *beg) {
// character found
// if vec is non-0, fill it with the character's mask
// otherwise, if scanning for a match and the char's
// mask matches, or if scanning for a mismatch and
// the char's mask does not match, return the pointer
// to the current character; otherwise continue
if (vec)
*vec = MaskT (next_elm.mask & mask);
else if ( scan_is && next_elm.mask & mask
|| !scan_is && !(next_elm.mask & mask))
return beg;
break;
}
// convert both sides to a sufficiently large type
// with the same signedness
if ( _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, next_elm.ch)
< _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, *beg))
low = cur + 1;
else
high = cur - 1;
}
if (vec)
++vec;
}
return beg;
}
const __rw_setlocale clocale (locname, LC_CTYPE);
for (; beg != end; ++beg) {
int m = 0;
// does the value of *beg fit into the range of an unsigned char?
const bool fits_char =
_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *beg) <= _RWSTD_UCHAR_MAX;
// `fits_char' is not used if all wide character
// classification functions use below are present
_RWSTD_UNUSED (fits_char);
if (mask & __rw_space) {
#ifndef _RWSTD_NO_ISWSPACE
if ((::iswspace)(*beg))
#else
if (fits_char && (::isspace)(*beg))
#endif // _RWSTD_NO_ISWSPACE
m |= __rw_space;
}
if (mask & __rw_print) {
#ifndef _RWSTD_NO_ISWPRINT
if ((::iswprint)(*beg))
#else
if (fits_char && (::isprint)(*beg))
#endif // _RWSTD_NO_ISWPRINT
m |= __rw_print;
}
if (mask & __rw_cntrl) {
#ifndef _RWSTD_NO_ISWCNTRL
if ((::iswcntrl)(*beg))
#else
if (fits_char && (::iscntrl)(*beg))
#endif // _RWSTD_NO_ISWCNTRL
m |= __rw_cntrl;
}
if (mask & __rw_upper) {
#ifndef _RWSTD_NO_ISWUPPER
if ((::iswupper)(*beg))
#else
if (fits_char && (::isupper)(*beg))
#endif // _RWSTD_NO_ISWUPPER
m |= __rw_upper;
}
if (mask & __rw_lower) {
#ifndef _RWSTD_NO_ISWLOWER
if ((::iswlower)(*beg))
#else
if (fits_char && (::islower)(*beg))
#endif // _RWSTD_NO_ISWLOWER
m |= __rw_lower;
}
if (mask & __rw_alpha) {
#ifndef _RWSTD_NO_ISWALPHA
if ((::iswalpha)(*beg))
#else
if (fits_char && (::isalpha)(*beg))
#endif // _RWSTD_NO_ISWALPHA
m |= __rw_alpha;
}
if (mask & __rw_digit) {
#ifndef _RWSTD_NO_ISWDIGIT
if ((::iswdigit)(*beg))
#else
if (fits_char && (::isdigit)(*beg))
#endif
m |= __rw_digit;
}
if (mask & __rw_punct) {
#ifndef _RWSTD_NO_ISWPUNCT
if ((::iswpunct)(*beg))
#else
if (fits_char && (::ispunct)(*beg))
#endif // _RWSTD_NO_ISWPUNCT
m |= __rw_punct;
}
if (mask & __rw_xdigit) {
#ifndef _RWSTD_NO_ISWXDIGIT
if ((::iswxdigit)(*beg))
#else
if (fits_char && (::isxdigit) (*beg))
#endif // _RWSTD_NO_ISWXDIGIT
m |= __rw_xdigit;
}
if (mask & __rw_graph) {
#ifndef _RWSTD_NO_ISWGRAPH
if ((::iswgraph)(*beg))
#else
if (fits_char && (::isgraph)(*beg))
#endif // _RWSTD_NO_ISWGRAPH
m |= __rw_graph;
}
if (vec)
*vec++ = MaskT (m);
else if (scan_is && m & mask || !scan_is && !(m & mask))
break;
}
return beg;
}
static _STD::ctype_byname<wchar_t>::char_type
__rw_toupper (__rw_ctype_t* impl,
wchar_t c, bool use_libstd,
const char* locname)
{
if (use_libstd && impl != 0) {
_RWSTD_SIZE_T low = 0;
_RWSTD_SIZE_T high = (_RWSTD_SIZE_T)impl->wtoupper_s();
_RWSTD_SIZE_T cur;
__rw_upper_elm next_elm;
while (low <= high) {
cur = (low + high) / 2;
next_elm = impl->wtoupper_tab(cur);
if (next_elm.lower == c) {
c = next_elm.upper;
break;
}
// convert both sides to a sufficiently large type
// with the same signedness
if ( _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, next_elm.lower)
< _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, c))
low = cur + 1;
else
high = cur - 1;
}
}
else {
#ifndef _RWSTD_NO_TOWUPPER
const __rw_setlocale clocale (locname, LC_CTYPE);
c = (::towupper)(c);
#else // if defined (_RWSTD_NO_TOWUPPER)
if (_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) <= _RWSTD_UCHAR_MAX) {
const __rw_setlocale clocale (locname, LC_CTYPE);
c = (::toupper)(c);
}
#endif // _RWSTD_NO_TOWUPPER
}
return c;
}
static _STD::ctype_byname<wchar_t>::char_type
__rw_tolower (__rw_ctype_t* impl,
wchar_t c, bool use_libstd,
const char* locname)
{
if (use_libstd && impl != 0) {
_RWSTD_SIZE_T low = 0;
_RWSTD_SIZE_T high = (_RWSTD_SIZE_T)impl->wtolower_s ();
_RWSTD_SIZE_T cur;
__rw_lower_elm next_elm;
while (low <= high) {
cur = (low + high) / 2;
next_elm = impl->wtolower_tab(cur);
if (next_elm.upper == c) {
c = next_elm.lower;
break;
}
// convert both sides to a sufficiently large type
// with the same signedness
if ( _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, next_elm.upper)
< _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, c))
low = cur + 1;
else
high = cur - 1;
}
}
else {
#ifndef _RWSTD_NO_TOWLOWER
const __rw_setlocale clocale (locname, LC_CTYPE);
c = (::towlower)(c);
#else // if defined (_RWSTD_NO_TOWLOWER)
if (_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) <= _RWSTD_UCHAR_MAX) {
const __rw_setlocale clocale (locname, LC_CTYPE);
c = (::tolower)(c);
}
#endif // _RWSTD_NO_TOWLOWER
}
return c;
}
#if 0 // FIXME: implement analogously to the above
static void
__rw_narrow (const __rw_codecvt_t *cvt, bool use_libstd,
const wchar_t *lo, const wchar_t *hi, char dfault, char *dst)
{
}
static void
__rw_widen (const __rw_codecvt_t *cvt, bool use_libstd,
const char *lo, const char *hi, wchar_t *dst)
{
}
#endif // 0/1
#ifdef _RWSTD_NO_EQUAL_CTYPE_MASK
// table of wide character classes
static _STD::ctype_base::mask
__rw_classic_wide_tab [_STD::ctype<char>::table_size];
// init-once flag for the classic wide tab
static __rw_once_t
__rw_classic_wide_tab_once_init = _RWSTD_ONCE_INIT;
extern "C" {
// one-time initializer for the classic wide_tab
static void
__rw_init_classic_wide_tab ()
{
# ifdef _RWSTDDEBUG
static int init;
// paranoid check: verify that one-time initialization works
_RWSTD_ASSERT (0 == init);
++init;
# endif // _RWSTDDEBUG
// init the classic wide tab
wchar_t wc_array [_STD::ctype<char>::table_size];
for (wchar_t wc = 0; wc < _STD::ctype<char>::table_size; ++wc)
wc_array [wc] = wc;
__rw_get_mask (0, wc_array, wc_array + _STD::ctype<char>::table_size,
__rw_all, __rw_classic_wide_tab, false, false, "C");
}
} // extern "C"
#endif // _RWSTD_NO_EQUAL_CTYPE_MASK
} // namespace __rw
_RWSTD_NAMESPACE (std) {
_RW::__rw_facet_id ctype<wchar_t>::id;
ctype<wchar_t>::ctype (_RWSTD_SIZE_T ref)
: _RW::__rw_facet (ref)
{
#ifndef _RWSTD_NO_EQUAL_CTYPE_MASK
_C_mask_tab = _RW::__rw_classic_tab;
#else
// initialize classic wide tab exactly once
_RW::__rw_once (&_RW::__rw_classic_wide_tab_once_init,
_RW::__rw_init_classic_wide_tab);
_C_mask_tab = _RW::__rw_classic_wide_tab;
#endif
_C_upper_tab = _RWSTD_CONST_CAST (_UChar*, _RW::__rw_upper_tab);
_C_lower_tab = _RWSTD_CONST_CAST (_UChar*, _RW::__rw_lower_tab);
_C_delete_it = false;
memset (_C_narrow_tab, 0, sizeof _C_narrow_tab);
memset (_C_wide_tab, 0, sizeof _C_wide_tab);
}
ctype<wchar_t>::~ctype ()
{
if (_C_delete_it) {
delete[] _RWSTD_CONST_CAST (mask*, _C_mask_tab);
if (_C_upper_tab != _RW::__rw_upper_tab) {
// lower_tab is allocated in the same block of memory
// as upper_tab and must not be deleted
delete[] _C_upper_tab;
}
}
}
bool ctype<wchar_t>::
do_is (mask m, char_type c) const
{
return _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) <= _C_tab_size
&& (_C_mask_tab [_UChar (c)] & m);
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_is (const char_type *lo, const char_type *hi, mask *mvec) const
{
_RWSTD_ASSERT (lo <= hi);
for ( ; lo != hi; ++lo, ++mvec) {
*mvec = _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *lo) < _C_tab_size ?
_C_mask_tab [_UChar (*lo)] : mask (0);
}
return hi;
}
ctype<wchar_t>::char_type
ctype<wchar_t>::
do_widen (char c) const
{
// explicitly specifying template argument list to work around
// HP aCC 3 and 5 bug (STDCXX-445)
return _RWSTD_CONST_CAST (ctype<wchar_t>*, this)->
_C_wide_tab [_UChar (c)] = char_type (_UChar (c));
}
const char*
ctype<wchar_t>::
do_widen (const char *lo, const char *hi, char_type *dest) const
{
_RWSTD_ASSERT (lo <= hi);
while (lo < hi) {
// call widen instead of do_widen to take advantage of the
// table optimization
*dest++ = widen (*lo++);
}
return hi;
}
ctype<wchar_t>::char_type
ctype<wchar_t>::
do_toupper (char_type c) const
{
return _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) < _C_tab_size ?
_C_upper_tab [_UChar (c)] : c;
}
ctype<wchar_t>::char_type
ctype<wchar_t>::
do_tolower (char_type c) const
{
return _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) < _C_tab_size ?
_C_lower_tab [_UChar (c)] : c;
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_toupper (char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
for ( ; lo < hi; ++lo)
*lo = _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *lo) < _C_tab_size ?
_C_upper_tab [_UChar (*lo)] : 0;
return lo;
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_tolower (char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
for ( ; lo < hi; ++lo)
*lo = _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *lo) < _C_tab_size ?
_C_lower_tab [_UChar (*lo)] : 0;
return lo;
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_scan_is (mask m, const char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
for ( ; lo != hi; ++lo) {
if ( _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *lo) <= _C_tab_size
&& (_C_mask_tab [_UChar (*lo)] & m))
break;
}
return lo;
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_scan_not (mask m, const char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
for ( ; lo != hi; ++lo) {
if ( _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, *lo) >= _C_tab_size
|| !(_C_mask_tab [_UChar (*lo)] & m))
break;
}
return lo;
}
char
ctype<wchar_t>::
do_narrow (char_type c, char dfault) const
{
return _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, c) <= _RWSTD_SCHAR_MAX ?
_RWSTD_STATIC_CAST (char, c) : dfault;
}
const ctype<wchar_t>::char_type*
ctype<wchar_t>::
do_narrow (const char_type *lo, const char_type *hi,
char dfault, char *dest) const
{
_RWSTD_ASSERT (lo <= hi);
while (lo != hi) {
*dest++ = do_narrow (*lo++, dfault);
}
return hi;
}
ctype_byname<wchar_t>::
ctype_byname (const char *name, _RWSTD_SIZE_T refs)
: ctype<wchar_t> (refs), _C_cvtimpl (0), _C_cvtsize (0)
{
this->_C_set_name (name, _C_namebuf, sizeof _C_namebuf);
if ('C' == name [0] && '\0' == name [1])
return;
// delayed initialization not used for efficiency
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_RW::__rw_get_facet_data (LC_CTYPE, _C_impsize, _C_name)));
_C_impdata = impl;
// Memory map the codecvt database and store it for future use
if (impl)
_C_cvtimpl = _RW::__rw_get_facet_data (LC_CTYPE, _C_cvtsize, 0,
impl->codeset_name ());
if (impl == 0 || (this->_C_opts & this->_C_use_libc)) {
// set locale first to avoid unnecessary allocation
// if `name' doesn't refer to a valid locale (and
// __rw_setlocale throws an exception)
const _RW::__rw_setlocale clocale (name, LC_CTYPE);
_C_delete_it = true;
// casts prevent bogus gcc 2.95.2 warning:
// size in array new must have integral type
_C_mask_tab = new mask [(_RWSTD_SIZE_T)_C_tab_size];
_TRY {
// avoid doing one extra allocation by allocating
// both the upper and lower tables in the same space
_C_upper_tab = new _UChar [(_RWSTD_SIZE_T)_C_tab_size * 2];
_C_lower_tab = _C_upper_tab + _C_tab_size;
}
_CATCH (...) {
delete[] _RWSTD_CONST_CAST (mask*, _C_mask_tab);
_RETHROW;
}
for (char_type i = 0; i <= char_type (_RWSTD_UCHAR_MAX); i++) {
int m = 0;
#ifndef _RWSTD_NO_ISWSPACE
if ((::iswspace)(i))
#else
if ((::isspace)(i))
#endif // _RWSTD_NO_ISWSPACE
m |= _RW::__rw_space;
#ifndef _RWSTD_NO_ISWPRINT
if ((::iswprint)(i))
#else
if ((::isprint)(i))
#endif // _RWSTD_NO_ISWPRINT
m |= _RW::__rw_print;
#ifndef _RWSTD_NO_ISWCNTRL
if ((::iswcntrl)(i))
#else
if ((::iscntrl)(i))
#endif // _RWSTD_NO_ISWCNTRL
m |= _RW::__rw_cntrl;
#ifndef _RWSTD_NO_ISWUPPER
if ((::iswupper)(i))
#else
if ((::isupper)(i))
#endif // _RWSTD_NO_ISWUPPER
m |= _RW::__rw_upper;
#ifndef _RWSTD_NO_ISWLOWER
if ((::iswlower)(i))
#else
if ((::islower)(i))
#endif // _RWSTD_NO_ISWLOWER
m |= _RW::__rw_lower;
#ifndef _RWSTD_NO_ISWALPHA
if ((::iswalpha)(i))
#else
if ((::isalpha)(i))
#endif // _RWSTD_NO_ISWALPHA
m |= _RW::__rw_alpha;
#ifndef _RWSTD_NO_ISWDIGIT
if ((::iswdigit)(i))
#else
if ((::isdigit)(i))
#endif // _RWSTD_NO_ISWDIGIT
m |= _RW::__rw_digit;
#ifndef _RWSTD_NO_ISWPUNCT
if ((::iswpunct)(i))
#else
if ((::ispunct)(i))
#endif // _RWSTD_NO_ISWPUNCT
m |= _RW::__rw_punct;
#ifndef _RWSTD_NO_ISWXDIGIT
if ((::iswxdigit)(i))
#else
if ((::isxdigit)(i))
#endif // _RWSTD_NO_ISWXDIGIT
m |= _RW::__rw_xdigit;
#ifndef _RWSTD_NO_ISWGRAPH
if ((::iswgraph)(i))
#else
if ((::isgraph)(i))
#endif // _RWSTD_NO_ISWGRAPH
m |= _RW::__rw_graph;
_RWSTD_CONST_CAST (mask*, _C_mask_tab) [i] = mask (m);
typedef _RWSTD_SIZE_T SizeT;
#ifndef _RWSTD_NO_TOWUPPER
const SizeT upr = SizeT ((::towupper)(i));
#else // if defined (_RWSTD_NO_TOWUPPER)
const SizeT upr = SizeT ((::toupper)(i));
#endif // _RWSTD_NO_TOWUPPER
#ifndef _RWSTD_NO_TOWLOWER
const SizeT lwr = SizeT ((::towlower)(i));
#else // if defined (_RWSTD_NO_TOWLOWER)
const SizeT lwr = SizeT ((::tolower)(i));
#endif // _RWSTD_NO_TOWLOWER
// optimize (and avoid warnings) when wint_t is unsigned
_C_upper_tab [i] = upr <= SizeT (_RWSTD_UCHAR_MAX) ?
_UChar (upr) : _UChar (0);
_C_lower_tab [i] = lwr <= SizeT (_RWSTD_UCHAR_MAX) ?
_UChar (lwr) : _UChar (0);
}
}
else {
_C_delete_it = false;
_C_mask_tab = (mask*)impl->mask_tab;
_C_upper_tab = impl->toupper_tab;
_C_lower_tab = impl->tolower_tab;
}
}
ctype_byname<wchar_t>::
~ctype_byname ()
{
// Release the codecvt database at this level
if (_C_cvtimpl != 0 && _C_cvtsize != 0)
_RW::__rw_release_facet_data (_C_cvtimpl, _C_cvtsize);
}
bool
ctype_byname<wchar_t>::
do_is (mask m, wchar_t c) const
{
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool libstd = 0 != (this->_C_opts & this->_C_use_libstd);
mask res = mask ();
_RW::__rw_get_mask (impl, &c, &c + 1, m, &res, false, libstd, _C_name);
return res != 0;
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_is (const char_type *lo, const char_type *hi, mask *mvec) const
{
_RWSTD_ASSERT (lo <= hi);
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool libstd = 0 != (this->_C_opts & this->_C_use_libstd);
return _RW::__rw_get_mask (impl, lo, hi, _RW::__rw_all,
mvec, false, libstd, _C_name);
}
ctype_byname<wchar_t>::char_type
ctype_byname<wchar_t>::
do_toupper (char_type c) const
{
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool use_libstd = 0 != (this->_C_opts & this->_C_use_libstd);
return _RW::__rw_toupper (impl, c, use_libstd, _C_name);
}
ctype_byname<wchar_t>::char_type
ctype_byname<wchar_t>::
do_tolower (char_type c) const
{
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool use_libstd = 0 != (this->_C_opts & this->_C_use_libstd);
return _RW::__rw_tolower (impl, c, use_libstd, _C_name);
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_toupper (char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool use_libstd = 0 != (this->_C_opts & this->_C_use_libstd);
// FIXME: implement efficiently (__rw_toupper() may call setlocale())
for ( ; lo < hi; ++lo)
*lo = _RW::__rw_toupper (impl, *lo, use_libstd, _C_name);
return lo;
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_tolower (char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool use_libstd = 0 != (this->_C_opts & this->_C_use_libstd);
// FIXME: implement efficiently (__rw_tolower() may call setlocale())
for ( ; lo < hi; ++lo)
*lo = _RW::__rw_tolower (impl, *lo, use_libstd, _C_name);
return lo;
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_scan_is (mask m, const char_type* lo, const char_type* hi) const
{
_RWSTD_ASSERT (lo <= hi);
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool libstd = 0 != (this->_C_opts & this->_C_use_libstd);
return _RW::__rw_get_mask (impl, lo, hi, m, 0, true, libstd, _C_name);
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_scan_not (mask m, const char_type *lo, const char_type *hi) const
{
_RWSTD_ASSERT (lo <= hi);
_RW::__rw_ctype_t* impl =
_RWSTD_CONST_CAST (_RW::__rw_ctype_t*,
_RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*,
_C_data ()));
const bool libstd = 0 != (this->_C_opts & this->_C_use_libstd);
return _RW::__rw_get_mask (impl, lo, hi, m, 0, false, libstd, _C_name);
}
char
ctype_byname<wchar_t>::
do_narrow (char_type c, char dfault) const
{
#if _RWSTD_WCHAR_MIN < 0
// wchar_t is a signed type
if (c > L'\0' && c < SCHAR_MAX)
return char (c);
#else // if _RWSTD_WCHAR_MIN >= 0
// wchar_t is an unsigned type
if (c < SCHAR_MAX)
return char (c);
#endif // _RWSTD_WCHAR_MIN
const _RW::__rw_codecvt_t* cvt =
_RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, _C_cvtimpl);
char ch = 0;
if (0 == cvt || (this->_C_opts & this->_C_use_libc)) {
#ifndef _RWSTD_NO_WCTOB
const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
const int tmp = wctob (c);
ch = tmp < 0 ? dfault : char (tmp);
#elif !defined (_RWSTD_NO_WCTOMB)
char tmp [_RWSTD_MB_LEN_MAX];
ch = 1 == wctomb (tmp, c) ? *tmp : dfault;
#else // if defined (_RWSTD_NO_WCTOMB)
ch = dfault;
#endif // _RWSTD_NO_WCTOB, _RWSTD_NO_WCTOMB
}
else {
#if _RWSTD_WCHAR_MIN < 0
// For a signed wchar_t test if the character has a negative value
if (c < 0)
return dfault;
#endif // _RWSTD_WCHAR_MIN < 0
// Look up narrow character value in database; be aware that there
// is no way to know what the internal representation is for this
// wide character; we have to assume that the internal representation
// was native and use wide-to-narrow tables for conversion
char_type wc = 0;
unsigned int* tbl = _RWSTD_CONST_CAST(unsigned int*,
cvt->w_to_n_tab ());
unsigned int* ptbl = tbl;
char tmp [_UTF8_MB_CUR_MAX + 1];
char* ptmp = tmp;
_RWSTD_SIZE_T utf8_sz = _RW::__rw_itoutf8 (c, tmp);
#if _RWSTD_WCHAR_MIN < 0
// compute the invalid bit mask (the MSB set)
const wchar_t imask = wchar_t (~(_RWSTD_WCHAR_MAX));
#else
const wchar_t imask = wchar_t (~(_RWSTD_WCHAR_MAX >> 1));
#endif // _RWSTD_WCHAR_MIN < 0
typedef unsigned char UChar;
_RWSTD_SIZE_T i = 0;
wc = ptbl [UChar (*ptmp)];
while (wc & imask) {
// check validity of the value
if (wc == (imask | _RWSTD_WCHAR_MAX))
return dfault;
ptbl = tbl + 256 * (wc & (~imask));
ptmp++;
// check for invalid sequences
if (++i >= utf8_sz)
return dfault;
// fetch next byte
wc = ptbl [UChar (*ptmp)];
}
// the resulting ch value is an index to the storage space of
// the narrow sequence; for our purposes here, that sequence has
// to have length of one
const char* impl_raw =
_RWSTD_REINTERPRET_CAST(const char*, cvt);
_RWSTD_SIZE_T offset = wc + sizeof (_RW::__rw_codecvt_t);
if (impl_raw [offset + 1])
return dfault;
else
ch = impl_raw [offset];
}
return ch;
}
const ctype_byname<wchar_t>::char_type*
ctype_byname<wchar_t>::
do_narrow (const char_type *lo, const char_type *hi,
char dfault, char *dest) const
{
_RWSTD_ASSERT (lo <= hi);
// FIXME: implement w/o relying on another virtual function
while (lo != hi) {
*dest++ = do_narrow (*lo, dfault);
lo++;
}
return hi;
}
ctype_byname<wchar_t>::char_type
ctype_byname<wchar_t>::
do_widen (char c) const
{
const unsigned char u_c = _UChar (c);
if (u_c <= SCHAR_MAX)
return char_type (u_c);
// when using the C++ locale database files then we have to do
// a table lookup to get the wide version of this character
// otherwise we have to call setlocale() and btowc() to get the
// corresponding wchar_t
const _RW::__rw_codecvt_t* cvt =
_RWSTD_STATIC_CAST (const _RW::__rw_codecvt_t*, _C_cvtimpl);
char_type ch;
if (0 == cvt || (this->_C_opts & this->_C_use_libc)) {
#ifndef _RWSTD_NO_BTOWC
const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
// prevent sign extension if `c' is negative
ch = btowc (u_c);
#else // if defined (_RWSTD_NO_BTOWC)
ch = char_type (u_c);
#endif // _RWSTD_NO_BTOWC
}
else {
#if _RWSTD_WCHAR_MIN < 0
// compute the invalid bit mask (the MSB set)
const char_type imask = char_type (~(_RWSTD_WCHAR_MAX));
#else
const char_type imask = char_type (~(_RWSTD_WCHAR_MAX >> 1));
#endif // _RWSTD_WCHAR_MIN < 0
// Lookup the narrow character in the table; be aware that
// the result of the lookup might be the index for another
// table (i.e., the narrow character may be the first byte
// of a multibyte character) in which case return an error.
ch = cvt->n_to_w_tab ()[u_c];
if (ch & imask)
return char_type (_RWSTD_WEOF);
ch = cvt->get_internal_at_offset (ch);
}
return ch;
}
const char*
ctype_byname<wchar_t>::
do_widen (const char *lo, const char *hi, char_type *dest) const
{
_RWSTD_ASSERT (lo <= hi);
// FIXME: implement w/o relying on another virtual function
while (lo < hi) {
*dest++ = widen (*lo++);
}
return hi;
}
} // namespace std
_RWSTD_DEFINE_FACET_FACTORY (static, ctype, <wchar_t>, wctype);
_RWSTD_SPECIALIZE_USE_FACET (wctype);
#endif // _RWSTD_NO_WCHAR_T