blob: bad3e3beaf95427c809fb50020a7a3d2efd4d02f [file] [log] [blame]
/***************************************************************************
*
* exception.cpp - Source for the Standard Library exception classes
*
* $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-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#define _RWSTD_LIB_SRC
#if 3 == __GNUG__ && 3 > __GNUC_MINOR__ \
|| 3 == __GNUC_MINOR__ && 1 >__GNUC_PATCHLEVEL__
// working around a gcc bug (PR #29570)
# include <rw/_config.h>
# ifndef _RWSTD_NO_EXTERN_TEMPLATE
# define _RWSTD_NO_EXTERN_TEMPLATE
# endif
#endif // gcc >= 3.0 && gcc < 3.3.1
#include <rw/_defs.h>
#ifndef _RWSTD_EDG_ECCP
# include <stdarg.h>
#else
// use "special" magic for the EDG eccp demo
# include <ansi/_cstdarg.h>
_USING (_STD::va_list);
#endif // EDG eccp demo
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <loc/_locale.h>
#include <loc/_messages.h>
#include <new>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <rw/_error.h>
#include <rw/_iosfailure.h>
#include <rw/_mutex.h>
#include "podarray.h" // for __rw_aligned_buffer
#ifdef _MSC_VER
// MSVC's libc prepends an underscore
# define vsnprintf _vsnprintf
# undef _RWSTD_NO_VSNPRINTF
#endif
#if defined (_RWSTD_NO_VSNPRINTF) && !defined (_RWSTD_NO_VSNPRINTF_IN_LIBC)
// vsnprintf() not declared, but it is defined in libc
extern "C" _RWSTD_DLLIMPORT int
vsnprintf (char*, _RWSTD_SIZE_T, const char*, va_list) _LIBC_THROWS();
// use vsnprintf()
# undef _RWSTD_NO_VSNPRINTF
#endif // _NO_VSNPRINTF && !_NO_VSNPRINTF_IN_LIBC || !_RWSTD_NO_PURE_C_HEADERS
#ifndef _RWSTD_NO_VSNPRINTF
# define _RWSTD_VSNPRINTF(buf, size, fmat, va) vsnprintf (buf, size, fmat, va)
#else
// unsafely work around the lack of vsnprintf by using vsprintf()
# define _RWSTD_VSNPRINTF(buf, ignore, fmat, va) vsprintf (buf, fmat, va)
#endif // _RWSTD_NO_VSNPRINTF
// declare global versions of exception handlers; will be
// used only if the functions aren't defined in namespace std
// in the compiler support library
void terminate () _RWSTD_GNUC_ATTRIBUTE ((__noreturn__));
_STD::terminate_handler
set_terminate (_STD::terminate_handler) _THROWS (());
_STD::unexpected_handler
set_unexpected (_STD::unexpected_handler) _THROWS (());
void unexpected () _RWSTD_GNUC_ATTRIBUTE ((__noreturn__));
#ifdef _MSC_VER
// MSVC 7 and 8 reliably define __uncaught_exception
// uncaught_exception() only seems to be defined by some compiler
// magic that requires the compiler's native C++ Standard library
// headers
# undef _RWSTD_NO_GLOBAL_UNCAUGHT_EXCEPTION
# define UNCAUGHT_EXCEPTION __uncaught_exception
#endif // MSVC
#ifndef UNCAUGHT_EXCEPTION
# define UNCAUGHT_EXCEPTION uncaught_exception
#endif // UNCAUGHT_EXCEPTION
_RWSTD_DLLIMPORT bool UNCAUGHT_EXCEPTION () _THROWS (());
_RWSTD_NAMESPACE (std) {
// define functions in namespace std to wrap any globals defined
// defined in the compiler support library
// functions are outlined to prevent linker errors in optimized shared builds
// guard definitions when compiling with gcc with -fno-honor-std
#ifndef _RWSTD_NO_HONOR_STD
# if defined (_RWSTD_NO_STD_TERMINATE)
// 18.6.3.3
_RWSTD_EXPORT void terminate ()
{
# ifndef _RWSTD_NO_GLOBAL_TERMINATE
::terminate ();
# else // if defined (_RWSTD_NO_GLOBAL_TERMINATE)
abort ();
# endif // _RWSTD_NO_GLOBAL_TERMINATE
}
# endif // _RWSTD_NO_STD_TERMINATE
# if defined (_RWSTD_NO_STD_SET_TERMINATE)
// 18.6.3.2
_RWSTD_EXPORT terminate_handler
set_terminate (terminate_handler handler) _THROWS (())
{
# ifndef _RWSTD_NO_GLOBAL_SET_TERMINATE
return ::set_terminate (handler);
# else // if defined (_RWSTD_NO_GLOBAL_SET_TERMINATE)
static terminate_handler current;
_RWSTD_MT_STATIC_GUARD (terminate_handler);
terminate_handler save = current;
current = handler;
return save;
# endif // _RWSTD_NO_GLOBAL_SET_TERMINATE
}
# endif // _RWSTD_NO_STD_SET_TERMINATE
# if defined (_RWSTD_NO_STD_SET_UNEXPECTED)
// 18.6.2.3
_RWSTD_EXPORT unexpected_handler
set_unexpected (unexpected_handler handler) _THROWS (())
{
# ifndef _RWSTD_NO_GLOBAL_SET_UNEXPECTED
return ::set_unexpected (handler);
# else // if defined (_RWSTD_NO_GLOBAL_SET_UNEXPECTED)
static unexpected_handler current;
_RWSTD_MT_STATIC_GUARD (unexpected_handler);
unexpected_handler save = current;
current = handler;
return save;
# endif // _RWSTD_NO_GLOBAL_SET_UNEXPECTED
}
# endif // _RWSTD_NO_STD_SET_UNEXPECTED
# if defined (_RWSTD_NO_STD_UNEXPECTED)
// 18.6.2.4
_RWSTD_EXPORT void unexpected ()
{
# ifndef _RWSTD_NO_GLOBAL_UNEXPECTED
::unexpected ();
# else // if defined (_RWSTD_NO_GLOBAL_UNEXPECTED)
abort ();
# endif // _RWSTD_NO_GLOBAL_UNEXPECTED
}
# endif // _RWSTD_NO_STD_UNEXPECTED
# if defined (_RWSTD_NO_STD_UNCAUGHT_EXCEPTION)
// 18.6.4
_RWSTD_EXPORT bool uncaught_exception () _THROWS (())
{
# ifndef _RWSTD_NO_GLOBAL_UNCAUGHT_EXCEPTION
return ::UNCAUGHT_EXCEPTION ();
# else // if defined (_RWSTD_NO_GLOBAL_UNCAUGHT_EXCEPTION)
# ifndef _RWSTD_NO_EXCEPTIONS
return true;
# else // if defined (_RWSTD_NO_EXCEPTIONS)
return false;
# endif // _RWSTD_NO_EXCEPTIONS
# endif // _RWSTD_NO_GLOBAL_UNCAUGHT_EXCEPTION
}
# endif // _RWSTD_NO_STD_UNCAUGHT_EXCEPTION
#endif // _RWSTD_NO_HONOR_STD
} // namespace std
#if defined _RWSTD_EXCEPTION_INCLUDED
// define exception and bad_exception members only if our own
// implementation's <exception> header (as opposed to the compiler's
// native C++ Standard library) has been included; SunPro always
// #includes its own, regardless of compiler options
//**************************************************************************
// class exception members
# if !defined (_RWSTD_NO_STD_EXCEPTION) \
|| !defined (_RWSTD_NO_RUNTIME_IN_STD) \
|| 2 == __GNUG__ && !defined (_RWSTD_NO_HONOR_STD)
_RWSTD_NAMESPACE (std) {
# endif // !_RWSTD_NO_STD_EXCEPTION || !_RWSTD_NO_RUNTIME_IN_STD ...
#ifdef _RWSTD_NO_EXCEPTION_DEFAULT_CTOR
exception::exception () _THROWS (())
{
#if defined (_MSC_VER)
_C_name = 0;
_C_flag = 0;
#elif defined (__INTEL_COMPILER)
_C_name = "";
#endif // _MSC_VER
}
#endif // _RWSTD_NO_EXCEPTION_DEFAULT_CTOR
#ifdef _RWSTD_NO_EXCEPTION_COPY_CTOR
exception::exception (const exception&) _THROWS (())
{
#if defined (_MSC_VER)
_C_name = 0;
_C_flag = 0;
#elif defined (__INTEL_COMPILER)
_C_name = "";
#endif // _MSC_VER
}
#endif // _RWSTD_NO_EXCEPTION_COPY_CTOR
#ifdef _RWSTD_NO_EXCEPTION_DTOR
exception::~exception () _THROWS (())
{
// empty
}
#endif // _RWSTD_NO_EXCEPTION_DTOR
#ifdef _RWSTD_NO_EXCEPTION_ASSIGNMENT
exception&
exception::operator= (const exception&) _THROWS (())
{
return *this;
}
#endif // _RWSTD_NO_EXCEPTION_ASSIGNMENT
#ifdef _RWSTD_NO_EXCEPTION_WHAT
const char* exception::what () const _THROWS (())
{
return _RWSTD_ERROR_EXCEPTION;
}
#endif // _RWSTD_NO_EXCEPTION_WHAT
# if !defined (_RWSTD_NO_STD_EXCEPTION) \
|| !defined (_RWSTD_NO_RUNTIME_IN_STD) \
|| 2 == __GNUG__ && !defined (_RWSTD_NO_HONOR_STD)
} // namespace std
# endif // !_RWSTD_NO_STD_EXCEPTION || !_RWSTD_NO_RUNTIME_IN_STD ...
//**************************************************************************
// class bad_exception members
# if !defined (_RWSTD_NO_STD_BAD_EXCEPTION) \
|| !defined (_RWSTD_NO_RUNTIME_IN_STD) \
|| 2 == __GNUG__ && !defined (_RWSTD_NO_HONOR_STD)
_RWSTD_NAMESPACE (std) {
# endif // !_RWSTD_NO_STD_BAD_EXCEPTION || !_RWSTD_NO_RUNTIME_IN_STD ...
#ifdef _RWSTD_NO_BAD_EXCEPTION_DEFAULT_CTOR
bad_exception::bad_exception () _THROWS (())
: exception ()
{
}
#endif // _RWSTD_NO_BAD_EXCEPTION_DEFAULT_CTOR
#ifdef _RWSTD_NO_BAD_EXCEPTION_COPY_CTOR
bad_exception::bad_exception (const bad_exception &rhs) _THROWS (())
: exception (rhs)
{
}
#endif // _RWSTD_NO_BAD_EXCEPTION_COPY_CTOR
#ifdef _RWSTD_NO_BAD_EXCEPTION_DTOR
bad_exception::~bad_exception () _THROWS (())
{
// empty
}
#endif // _RWSTD_NO_BAD_EXCEPTION_DTOR
#ifdef _RWSTD_NO_BAD_EXCEPTION_ASSIGNMENT
bad_exception&
bad_exception::operator= (const bad_exception &rhs) _THROWS (())
{
exception::operator= (rhs);
return *this;
}
#endif // _RWSTD_NO_BAD_EXCEPTION_ASSIGNMENT
#ifdef _RWSTD_NO_BAD_EXCEPTION_WHAT
const char* bad_exception::what () const _THROWS (())
{
return _RWSTD_ERROR_BAD_EXCEPTION;
}
#endif // _RWSTD_NO_BAD_EXCEPTION_WHAT
# if !defined (_RWSTD_NO_STD_BAD_EXCEPTION) \
|| !defined (_RWSTD_NO_RUNTIME_IN_STD) \
|| 2 == __GNUG__ && !defined (_RWSTD_NO_HONOR_STD)
} // namespace std
# endif // !_RWSTD_NO_STD_BAD_EXCEPTION || !_RWSTD_NO_RUNTIME_IN_STD ...
#endif // _RWSTD_EXCEPTION_INCLUDED
/**************************************************************************/
_RWSTD_NAMESPACE (__rw) {
static _RWSTD_THREAD char
__rw_what_buf [256];
static _RWSTD_THREAD int
__rw_what_refcnt;
// free memory buffer allocated in __rw_vfmtwhat()
_RWSTD_EXPORT void __rw_free_what_buf (char* buf)
{
if (__rw_what_buf == buf) {
_RWSTD_ASSERT (0 < __rw_what_refcnt);
_RWSTD_THREAD_PREDECREMENT (__rw_what_refcnt, false);
}
else
delete[] buf;
}
// allocate a char array and format it sprintf-style
// caller responsible for calling delete[] on returned pointer
// unless a non-zero buffer of non-zero size is passed in
static char*
__rw_vfmtwhat (char *buf, // (allocate if 0)
_RWSTD_SIZE_T bufsize, // buffer size (0 if none)
const char *fmat, // printf-style fmat string
va_list va) // variable arguments
{
_RWSTD_ASSERT (0 != fmat);
_RWSTD_ASSERT (0 == buf || bufsize);
#ifndef _RWSTD_NO_VSNPRINTF
// initial size of buffer, may be increased as needed
_RWSTD_SIZE_T size = bufsize ? bufsize : 256;
#else
// unsafely work around the lack of vsnprintf by using vsprintf()
_RWSTD_SIZE_T size = bufsize ? bufsize : strlen (fmat);
size = size < 1024 ? 1024 : size * 2;
#endif // _RWSTD_NO_VSNPRINTF
if (!buf) {
if (1 == _RWSTD_THREAD_PREINCREMENT (__rw_what_refcnt, false)) {
buf = __rw_what_buf;
}
else {
buf = new char [size];
_RWSTD_THREAD_PREDECREMENT (__rw_what_refcnt, false);
}
}
for ( ; ; ) {
// vsnprintf() return value
//
// 7.19.6.12, p3 of C99:
//
// The vsnprintf function returns the number of characters that
// would have been written had n been sufficiently large, not
// counting the terminating null character, or a neg ative value
// if an encoding error occurred. Thus, the null-terminated output
// has been completely written if and only if the returned value
// is nonnegative and less than n.
//
// HP-UX and Windows are known to return a negative value for
// buffer overflow.
// On IRIX and Tru64 UNIX on overflow the function returns
// the number of bytes actually written to the buffer which
// makes it indistinguishable from a successful return value
// for a completely full buffer.
// Others (AIX, Linux, and Solaris) follow the C99 requirement.
int nwrote;
// copy va to a temporary and use it in each iteration
// of the loop since it may be modified by the call to
// vsnprintf() (e.g., on PowerPC/Linux)
va_list tmp_va;
_RWSTD_VA_COPY (tmp_va, va);
nwrote = _RWSTD_VSNPRINTF (buf, size, fmat, tmp_va);
va_end (tmp_va);
if (0 > nwrote) {
#ifdef _RWSTD_NO_VSNPRINTF_VFLOW_VALID
// set the number of bytes written to 0 to indicate
// that the buffer isn't big enough without actually
// telling how big it needs to be
nwrote = 0;
#else // if !defined (_RWSTD_NO_VSNPRINTF_VFLOW_VALID)
// conversion error
*buf = '\0';
break;
#endif // _RWSTD_NO_VSNPRINTF_VFLOW_VALID
}
#ifdef _RWSTD_NO_VSNPRINTF_VFLOW_VALID
if (nwrote >= int (size) - 1) {
// indicate insufficient buffer size
nwrote = 0;
}
#endif // _RWSTD_NO_VSNPRINTF_VFLOW_VALID
if (0 == nwrote)
size *= 2;
else if (int (size) <= nwrote)
size = nwrote + 1U;
else
break;
// fail if a buffer of insufficient size was passed in
if (bufsize)
return 0;
__rw_free_what_buf (buf);
buf = new char [size];
}
return buf;
}
static
char* __rw_vfmtwhat (char *buf, // buffer (allocate if 0)
_RWSTD_SIZE_T bufsize, // size of buffer or 0
int id, // catalog id of fmt string
va_list va) // variable arguments
{
typedef _STD::messages<char> _Msgs;
static const char *__fname = 0; // catalog file
static int __catset = 1; // catalog set
static _Msgs::catalog __cat = -1; // catalog id
// facet must never be destroyed
static __rw_aligned_buffer<_Msgs> msgs;
// try to open catalog if first time through only
if (!__fname) {
_RWSTD_MT_STATIC_GUARD (void);
// double-check to prevent a race opening a catalog more than once
if (!__fname) {
// get catalog name (absolute or relative) from the environment
char *__fn = getenv (_RWSTD_ERROR_ENVVAR);
// use default hardcoded name if variable doesn't exist
if (!__fn) {
// copy literal into static buffer (will be modified)
static char buffer[] = _RWSTD_ERROR_CATALOG;
__fn = buffer;
}
// catalog name may optionally be followed by a `:' and a set number
char *__set = strrchr (__fn, ':');
if (__set) {
*__set++ = '\0';
if ( 1 != sscanf (__set, "%d", &__catset)
|| __catset <= 0)
__catset = 1;
}
new (msgs._C_store ()) _Msgs;
// assign `fname' _after_ opening catalog to prevent a race
// between calling messages<>::open() and messages<>::get()
// always use the classic locale, not the current snapshot
__cat = msgs._C_data ()->open (__fn, _STD::locale::classic ());
__fname = __fn;
}
}
if (-1 == __cat)
return 0; // indicate a falure to open catalog
_RWSTD_MT_STATIC_GUARD (void);
// retrieve error message from catalog and use it to format args
_STD::string fmat = msgs._C_data ()->get (__cat, __catset, id, "");
if (fmat.empty ())
return 0; // failure to retrieve message
return __rw_vfmtwhat (buf, bufsize, fmat.data (), va);
}
#ifdef _RWSTD_REENTRANT
extern const char* const __rw_mutex_exception =
"Thread synchronization exception.";
#else // if !defined (_RWSTD_REENTRANT)
// dummy empty object (not an actual mutex) - allows lib to "look"
// the same in single-threaded mode as in multi-threaded mode
__rw_mutex _RWSTD_EXPORT __rw_synchronized::_C_mutex;
#endif // _RWSTD_REENTRANT
static void __rw_throw_exception (int id, char *what)
{
#ifndef _RWSTD_NO_EXCEPTIONS
// exception, bad_exception, bad_cast, and bad_alloc
// each or may not be defined in namespace std; avoid
// complicated preprocessor logic by introducing the
// whole namespace into scope
_USING (namespace std);
switch (id) {
case _RWSTD_ERROR_FIRST + 1:
throw exception ();
case _RWSTD_ERROR_FIRST + 2:
throw bad_exception ();
case _RWSTD_ERROR_FIRST + 3:
#ifndef _RWSTD_BAD_ALLOC
# ifndef _RWSTD_NO_RUNTIME_IN_STD
throw std::bad_alloc ();
# else
throw bad_alloc ();
# endif // _RWSTD_NO_RUNTIME_IN_STD
#else // if defined (_RWSTD_BAD_ALLOC)
throw _RWSTD_BAD_ALLOC ();
#endif // _RWSTD_BAD_ALLOC
case _RWSTD_ERROR_BAD_CAST:
throw bad_cast ();
case _RWSTD_ERROR_LOGIC_ERROR:
throw (_STD::logic_error&)_STD::logic_error ()._C_assign (what, 0);
case _RWSTD_ERROR_DOMAIN_ERROR:
throw (_STD::domain_error&)_STD::domain_error ()._C_assign (what, 0);
case _RWSTD_ERROR_INVALID_ARGUMENT:
throw (_STD::invalid_argument&)
_STD::invalid_argument ()._C_assign (what, 0);
case _RWSTD_ERROR_LENGTH_ERROR:
throw (_STD::length_error&)_STD::length_error ()._C_assign (what, 0);
case _RWSTD_ERROR_OUT_OF_RANGE:
throw (_STD::out_of_range&)_STD::out_of_range ()._C_assign (what, 0);
case _RWSTD_ERROR_RUNTIME_ERROR:
throw (_STD::runtime_error&)
_STD::runtime_error ()._C_assign (what, 0);
case _RWSTD_ERROR_RANGE_ERROR:
throw (_STD::range_error&)_STD::range_error ()._C_assign (what, 0);
case _RWSTD_ERROR_OVERFLOW_ERROR:
throw (_STD::overflow_error&)
_STD::overflow_error ()._C_assign (what, 0);
case _RWSTD_ERROR_UNDERFLOW_ERROR:
throw (_STD::underflow_error&)
_STD::underflow_error ()._C_assign (what, 0);
#ifndef _RWSTD_NO_EXT_FAILURE
case _RWSTD_ERROR_FAILBIT_SET:
throw (__rw_failbit_set&)
__rw_failbit_set ()._C_assign (what, 0);
case _RWSTD_ERROR_BADBIT_SET:
throw (__rw_badbit_set&)
__rw_badbit_set ()._C_assign (what, 0);
case _RWSTD_ERROR_EOFBIT_SET:
throw (__rw_eofbit_set&)
__rw_eofbit_set ()._C_assign (what, 0);
#else // if defined (_RWSTD_NO_EXT_FAILURE)
case _RWSTD_ERROR_FAILBIT_SET:
case _RWSTD_ERROR_BADBIT_SET:
case _RWSTD_ERROR_EOFBIT_SET:
// fall through...
#endif // _RWSTD_NO_EXT_FAILURE
case _RWSTD_ERROR_IOSTATE_BIT_SET:
throw (__rw_failure&)
__rw_failure ()._C_assign (what, 0);
case _RWSTD_ERROR_FACET_NOT_FOUND:
case _RWSTD_ERROR_LOCALE_BAD_CAT:
case _RWSTD_ERROR_LOCALE_BAD_NAME:
case _RWSTD_ERROR_LOCALE_ERROR_NAME:
case _RWSTD_ERROR_CODECVT:
case _RWSTD_ERROR_BAD_POINTER:
throw (_STD::runtime_error&)
_STD::runtime_error ()._C_assign (what, 0);
}
__rw_free_what_buf (what);
#else // if defined (_RWSTD_NO_EXCEPTIONS)
if (what) {
fprintf (stderr,"Exception: %s.\n", what);
__rw_free_what_buf (what);
}
else {
const char *__str;
switch (id) {
case _RWSTD_ERROR_FIRST + 0: __str = _RWSTD_ERROR_EXCEPTION; break;
case _RWSTD_ERROR_FIRST + 1: __str = _RWSTD_ERROR_BAD_EXCEPTION; break;
case _RWSTD_ERROR_FIRST + 2: __str = _RWSTD_ERROR_BAD_ALLOC; break;
default: __str = "unknown exception";
}
fprintf (stderr, "Exception: %s.\n", __str);
}
abort ();
#endif // _RWSTD_NO_EXCEPTIONS
}
// may be assigned to a user-defined handler (e.g., to prevent
// the library from throwing exceptions or to implement logging)
_RWSTD_EXPORT void (*__rw_throw_proc)(int, char*) = __rw_throw_exception;
_RWSTD_EXPORT void __rw_throw (int id, ...)
{
if (!__rw_throw_proc)
return;
// do not allocate or format string for exception,
// bad_alloc, bad_cast, bad_exception, or bad_cast
if (id <= _RWSTD_ERROR_BAD_CAST) {
__rw_throw_proc (id, 0);
}
else {
va_list va;
va_start (va, id);
#ifdef va_copy
// copy va to a temporary and use it in the first call
// to __rw_vfmtwhat() since it may be modified by the
// call and rendered invalid for subsequent use (e.g.,
// on PowerPC/Linux)
va_list tmp_va;
va_copy (tmp_va, va);
// try to format a string (look up format in a catalog)...
char *what = _RW::__rw_vfmtwhat (0, 0, id, tmp_va);
va_end (tmp_va);
#else // if !defined (va_copy)
char *what = _RW::__rw_vfmtwhat (0, 0, id, va);
#endif // va_copy
if (!what) {
// obtain an index into table of error strings
id -= _RWSTD_ERROR_FIRST;
static const char* const errors[] = { _RWSTD_ERROR_STRINGS };
// make sure index is valid
if (id < 0 || id >= int (sizeof errors / sizeof *errors))
id = 0;
// use error string to format
what = _RW::__rw_vfmtwhat (0, 0, errors [id], va);
}
// end va list before throwing
va_end (va);
// throw_proc takes ownership of allocated string
__rw_throw_proc (id, what);
}
}
__rw_exception::__rw_exception () _THROWS (())
: _STD::exception (), _C_what (0) { }
__rw_exception::__rw_exception (const __rw_exception &rhs)
: _STD::exception (rhs), _C_what (0)
{
_C_assign (rhs.what ());
}
/* explicit */ __rw_exception::__rw_exception (const char *str)
: _STD::exception (), _C_what (0)
{
_C_assign (str);
}
// outlined to avoid circular dependency on <string>
__rw_exception::__rw_exception (const _STD::string &whatstr)
: _C_what (0)
{
_C_assign (whatstr.c_str (), whatstr.length ());
}
// outlined to avoid functional compatibility issues
/* virtual */ __rw_exception::~__rw_exception () _THROWS (())
{
__rw_free_what_buf (_C_what);
#ifdef _C_dummy_what
// zero out dummy member of the base exception class
// to prevent the base dtor from trying to do the same
// (MSVC 6.0 only)
_C_dummy_what = 0;
#endif // _C_dummy_what
}
// empty exception specification necessary in order to preserve
// the no-exception guarantee provided by std::exception to
// derived classes (e.g., logic_error)
__rw_exception& __rw_exception::
operator= (const __rw_exception &__rhs) _THROWS (())
{
_C_assign (__rhs.what ());
return *this;
}
/* virtual */ const char* __rw_exception::
what () const _THROWS (())
{
// `what' may be 0 indicating the empty string as an optimization
return _C_what ? _C_what : "";
}
// assigns the argument to our string by allocating sufficient space
// and copying the string; if `what' is null or `what' points to the
// empty string (""), deletes buffer and assigns 0
// if `what' is non-null and non-empty but `len' is 0, simply assigns
// `what' to the internal pointer and takes ownership of it
__rw_exception& __rw_exception::
_C_assign (const char *whatstr, size_t len /* = ~0 */)
{
if (whatstr != _C_what) {
char *tmp = 0;
if (whatstr && *whatstr) {
if (whatstr == __rw_what_buf) {
if (len)
_RWSTD_THREAD_PREINCREMENT (__rw_what_refcnt, false);
tmp = __rw_what_buf;
}
else {
if (_RWSTD_SIZE_MAX == len)
len = strlen (whatstr);
if (len) {
// allocate own buffer and copy string
tmp = new char [len + 1];
memcpy (tmp, whatstr, len + 1);
}
else {
// special case: do not allocate, just use passed in pointer
tmp = _RWSTD_CONST_CAST (char*, whatstr);
}
}
}
__rw_free_what_buf (_C_what);
_C_what = tmp;
}
return *this;
}
// trivial dtors outlined to reduce code bloat caused by compilers that
// emit the vtbl in every translation unit containing the definition of
// the class
// virtual dtor
/* virtual */ __rw_failure::~__rw_failure () _THROWS (())
{
// no-op
}
/* virtual */ __rw_badbit_set::~__rw_badbit_set () _THROWS (())
{
// no-op
}
/* virtual */ __rw_eofbit_set::~__rw_eofbit_set () _THROWS (())
{
// no-op
}
/* virtual */ __rw_failbit_set::~__rw_failbit_set () _THROWS (())
{
// no-op
}
} // namespace __rw