| /************************************************************************ |
| * |
| * exception.cpp - exceptions testsuite helpers |
| * |
| * $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_exception.h> |
| #include <rw_driver.h> |
| #include <rw_printf.h> |
| |
| #include <string.h> // for size_t, strcpy() |
| #include <stdlib.h> // for free() |
| #include <stdarg.h> // for va_arg(), va_list |
| #include <new> // for std::bad_alloc |
| |
| /**************************************************************************/ |
| |
| _TEST_EXPORT int |
| rw_vasnprintf (char**, size_t*, const char*, va_list); |
| |
| static int |
| _rw_format (char** pbuf, size_t* pbufsize, const char* file, int line, |
| const char* function, const char* fmt, va_list va); |
| |
| /**************************************************************************/ |
| |
| Exception::~Exception () |
| { |
| } |
| |
| /**************************************************************************/ |
| |
| struct ExceptionBase |
| { |
| private: |
| struct ExceptionString; |
| |
| public: |
| char buf_ [256]; |
| ExceptionString* ex_str_; |
| |
| ExceptionBase (); |
| ExceptionBase (const ExceptionBase&); |
| |
| ~ExceptionBase (); |
| |
| ExceptionBase& operator= (const ExceptionBase&); |
| |
| void format (const char* file, int line, const char* function, |
| const char* fmt, va_list va); |
| |
| const char* what () const; |
| |
| private: |
| |
| struct ExceptionString |
| { |
| long refs_; |
| char* str_; |
| |
| void init (char* str) |
| { |
| refs_ = 1; |
| str_ = str; |
| } |
| |
| void addref () { ++refs_; } |
| |
| long release () |
| { |
| if (0 == --refs_) { |
| free (str_); |
| str_ = 0; |
| } |
| return refs_; |
| } |
| |
| private: |
| // not defined |
| ExceptionString (const ExceptionString&); |
| ExceptionString& operator= (const ExceptionString&); |
| }; |
| |
| |
| void free_ (); |
| }; |
| |
| ExceptionBase::ExceptionBase () : ex_str_ (0) |
| { |
| buf_ [0] = '\0'; |
| } |
| |
| ExceptionBase::ExceptionBase (const ExceptionBase& ex) : ex_str_ (0) |
| { |
| *this = ex; |
| } |
| |
| ExceptionBase::~ExceptionBase () |
| { |
| free_ (); |
| } |
| |
| ExceptionBase& ExceptionBase::operator= (const ExceptionBase& ex) |
| { |
| if (&ex != this) { |
| |
| free_ (); |
| |
| if (ex.ex_str_) { |
| ex_str_ = ex.ex_str_; |
| ex_str_->addref (); |
| } |
| else |
| strcpy (buf_, ex.buf_); |
| } |
| |
| return *this; |
| } |
| |
| |
| void ExceptionBase:: |
| format (const char* file, int line, |
| const char* function, const char* fmt, va_list va) |
| { |
| free_ (); |
| |
| char* tmpbuf = 0; |
| size_t bufsize = 0; |
| |
| const int nchars = |
| _rw_format (&tmpbuf, &bufsize, file, line, function, fmt, va); |
| |
| if (0 > nchars) |
| return; |
| |
| if (sizeof buf_ <= size_t (nchars)) { |
| // tmpbuf_ size is too small |
| ex_str_ = _RWSTD_STATIC_CAST (ExceptionString*, |
| malloc (sizeof (*ex_str_))); |
| |
| if (ex_str_) { |
| ex_str_->init (tmpbuf); |
| return; |
| } |
| } |
| |
| // buf_ size if enough or cannot allocate memory for the ex_str_ |
| const size_t len = |
| size_t (nchars) < sizeof buf_ ? size_t (nchars) : sizeof buf_ - 1; |
| memcpy (buf_, tmpbuf, len); |
| buf_ [len] = '\0'; |
| free (tmpbuf); |
| } |
| |
| |
| const char* ExceptionBase::what () const |
| { |
| return ex_str_ && ex_str_->str_ ? ex_str_->str_ : buf_; |
| } |
| |
| void ExceptionBase::free_ () |
| { |
| buf_ [0] = '\0'; |
| |
| if (ex_str_ && 0 == ex_str_->release ()) { |
| free (ex_str_); |
| ex_str_ = 0; |
| } |
| } |
| |
| /**************************************************************************/ |
| |
| struct BadAlloc : std::bad_alloc, ExceptionBase |
| { |
| BadAlloc () |
| { |
| } |
| |
| BadAlloc (const ExceptionBase& ex) : ExceptionBase (ex) |
| { |
| } |
| |
| ~BadAlloc () _THROWS (()) {} |
| |
| const char* what () const _THROWS (()) |
| { |
| const char* msg = ExceptionBase::what (); |
| return (msg && msg[0]) ? msg : std::bad_alloc::what (); |
| } |
| }; |
| |
| /**************************************************************************/ |
| |
| struct StreamException : Exception, ExceptionBase |
| { |
| StreamException () : Exception (ex_stream) |
| { |
| } |
| |
| StreamException (const ExceptionBase& ex) : |
| Exception (ex_stream), ExceptionBase (ex) |
| { |
| } |
| |
| const char* what () const |
| { |
| return ExceptionBase::what (); |
| } |
| }; |
| |
| /**************************************************************************/ |
| |
| static int |
| _rw_format (char** pbuf, size_t* pbufsize, const char* file, int line, |
| const char* function, const char* fmt, va_list va) |
| { |
| const int nchars1 = function ? |
| rw_asnprintf (pbuf, pbufsize, "\"%s\", %d, \"%s\" ", |
| file, line, function) : |
| rw_asnprintf (pbuf, pbufsize, "\"%s\", %d, ", file, line); |
| |
| if (0 > nchars1) |
| return nchars1; |
| |
| char *tmpbuf = 0; |
| size_t tmpsize = 0; |
| |
| const int nchars2 = rw_vasnprintf (&tmpbuf, &tmpsize, fmt, va); |
| |
| if (0 > nchars2) { |
| free (tmpbuf); |
| return nchars1; |
| } |
| |
| const int nchars3 = rw_asnprintf (pbuf, pbufsize, "%{+}%s", tmpbuf); |
| |
| free (tmpbuf); |
| |
| return 0 > nchars3 ? nchars1 : nchars1 + nchars3; |
| } |
| |
| _TEST_EXPORT void |
| rw_throw (ExceptionId exid, const char *file, int line, |
| const char *function, const char *fmt, ...) |
| { |
| va_list va; |
| va_start (va, fmt); |
| |
| ExceptionBase base; |
| base.format (file, line, function, fmt, va); |
| |
| va_end (va); |
| |
| switch (exid) { |
| |
| case ex_stream: |
| throw StreamException (base); |
| |
| case ex_bad_alloc: |
| throw BadAlloc (base); |
| |
| default: |
| throw ex_unknown; |
| } |
| } |