blob: 37bf5b39691decac22a673101af0ade4bd6b0a26 [file] [log] [blame]
/***************************************************************************
*
* codecvt.cpp - definition of codecvt<char, char, mbstate_t> 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.
*
* Copyright 1994-2007 Rogue Wave Software, Inc.
*
**************************************************************************/
#define _RWSTD_LIB_SRC
#include <rw/_defs.h>
// working around a Compaq C++ bug (see PR #26778)
#if __DECCXX_VER >= 60300000 && __DECCXX_VER < 60400000
# include <stdarg.h>
_USING (std::va_list);
// override autoconfigured macro whose value is incorrect
// if <unistd.h> is #included before <iconv.h>
# include <unistd.h>
# define _RWSTD_NO_ICONV_CONST_CHAR
#endif // Compaq C++ 6.3
#include <limits.h>
#include <locale.h>
#include <string.h> // for memcmp()
#include <errno.h>
#include <wchar.h> // for mbsinit()
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540 \
&& (defined (__SunOS_5_8) || defined (__SunOS_5_9))
// working around SunOS/SunPro header dependencies (see PR #26255)
# undef _TIME_T
#endif // SunPro <= 5.4 && SunOS 5.{8,9}
#include <loc/_codecvt.h>
#include <loc/_locale.h>
#include <loc/_localedef.h>
#include "setlocale.h"
#include "use_facet.h"
// _RWSTD_MBSTATE_T macro might expand to char* (on AIX)
typedef _RWSTD_MBSTATE_T StateT;
_RWSTD_NAMESPACE (__rw) {
static inline int
__rw_mbsinit (const StateT *ps)
{
#ifndef _RWSTD_NO_MBSINIT
return ::mbsinit (ps);
#else // if defined (_RWSTD_NO_MBSINIT)
// commented out to work around an HP aCC 1.21 bug
/* static */ const StateT state = StateT ();
return !ps || 0 == memcmp (ps, &state, sizeof state);
#endif // _RWSTD_NO_MBSINIT
}
} // namespace __rw
_RWSTD_NAMESPACE (std) {
_RW::__rw_facet_id codecvt<char, char, _RWSTD_MBSTATE_T>::id;
codecvt<char, char, _RWSTD_MBSTATE_T>::
codecvt (size_t refs /* = 0 */) _THROWS (())
: _RW::__rw_facet (refs), _C_always_noconv (-1)
{
// empty
}
// outlined to avoid generating a vtable in each translation unit
// that uses the class
/* virtual */ codecvt<char, char, _RWSTD_MBSTATE_T>::
~codecvt () // nothrow
{
// no-op
}
/* virtual */ codecvt_base::result
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_out (state_type &state,
const intern_type *from,
const intern_type *from_end,
const intern_type *&from_next,
extern_type *to,
extern_type *to_end,
extern_type *&to_next) const
{
// verify that both ranges are valid
_RWSTD_ASSERT (from <= from_end);
_RWSTD_ASSERT (to <= to_end);
_RWSTD_ASSERT ((from && from_end) || (!from && !from_end));
_RWSTD_ASSERT ((to && to_end) || (!to && !to_end));
// next pointers must always be set before returning, even on error
from_next = from;
to_next = to;
#ifdef _RWSTDDEBUG
// verify that the conversion state is valid
const int mbstate_valid = _RW::__rw_mbsinit (&state);
_RWSTD_ASSERT (0 != mbstate_valid);
#else // if !defined (_RWSTDDEBUG)
_RWSTD_UNUSED (state);
#endif // _RWSTDDEBUG
// be prepared to handle an overridden do_always_noconv()
// that returns false (highly unlikely but possible)
if (always_noconv ())
return noconv;
const size_t nfrom = from_end - from;
const size_t nto = to_end - to;
const size_t nconv = nfrom < nto ? nfrom : nto;
// use memmove() in case ranges overlap
memmove (to, from, nconv);
from_next += nconv;
to_next += nconv;
// Table 53, and lwg issue 382: do_out() returns partial
// if not all source characters could be converted (e.g.,
// because the destination range is full)
return nto < nfrom ? partial : ok;
}
/* virtual */ codecvt_base::result
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_in (state_type &state,
const extern_type *from,
const extern_type *from_end,
const extern_type *&from_next,
intern_type *to,
intern_type *to_end,
intern_type *&to_next) const
{
// verify that both ranges are valid
_RWSTD_ASSERT (from <= from_end);
_RWSTD_ASSERT (to <= to_end);
_RWSTD_ASSERT ((from && from_end) || (!from && !from_end));
_RWSTD_ASSERT ((to && to_end) || (!to && !to_end));
typedef codecvt<char, char, _RWSTD_MBSTATE_T> This;
// call do_out() above (avoid calling overridden do_out(), if any)
return This::do_out (state,
from, from_end, from_next,
to, to_end, to_next);
}
/* virtual */ codecvt_base::result
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_unshift (state_type &state,
extern_type *to,
extern_type *to_end,
extern_type *&to_next) const
{
// verify that the range is valid
_RWSTD_ASSERT (to <= to_end);
_RWSTD_ASSERT ((to && to_end) || (!to && !to_end));
_RWSTD_UNUSED (to_end);
// next pointer must always be set before returning, even on error
to_next = to;
const int mbstate_valid = _RW::__rw_mbsinit (&state);
_RWSTD_ASSERT (mbstate_valid);
return mbstate_valid ? noconv : error;
}
/* virtual */ int
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_encoding () const _THROWS (())
{
return 1; // 1 external char converts to a single internal char
}
/* virtual */ bool
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_always_noconv () const _THROWS (())
{
return true; // conversion never necessary
}
// signature follows lwg issue 75
/* virtual */ int
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_length (state_type &state,
const extern_type *from,
const extern_type *from_end,
size_t imax) const
{
// 22.2.1.5.2, p9 - preconditions
_RWSTD_ASSERT (from <= from_end);
// verify that the range is valid
_RWSTD_ASSERT ((from && from_end) || (!from && !from_end));
const int mbstate_valid = _RW::__rw_mbsinit (&state);
_RWSTD_ASSERT (mbstate_valid);
if (!mbstate_valid)
return 0;
// 22.2.1.5.2, p10
const size_t len = from_end - from;
return int (len < imax ? len : imax);
}
/* virtual */ int
codecvt<char, char, _RWSTD_MBSTATE_T>::
do_max_length () const _THROWS (())
{
return 1; // 22.2.1.5.2, p11
}
codecvt_byname<char, char, _RWSTD_MBSTATE_T>::
codecvt_byname (const char *name, size_t ref)
: codecvt <intern_type, extern_type, state_type> (ref)
{
_C_set_name (name, _C_namebuf, sizeof _C_namebuf);
}
// outlined to avoid generating a vtable in each translation unit
// that uses the class
/* virtual */ codecvt_byname<char, char, _RWSTD_MBSTATE_T>::
~codecvt_byname () // nothrow
{
// no-op
}
} // namespace std
#define TARGS_C <char, char, _RWSTD_MBSTATE_T>
_RWSTD_DEFINE_FACET_FACTORY (static, codecvt, TARGS_C, codecvt);
_RWSTD_SPECIALIZE_USE_FACET (codecvt);