00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00036 #include "OW_config.h"
00037 #include "OW_Exception.hpp"
00038 #include "OW_StackTrace.hpp"
00039 #include "OW_Format.hpp"
00040 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00041 #include "OW_Mutex.hpp"
00042 #endif
00043 #include <string.h>
00044 
00045 
00046 #include <cstdlib>
00047 #if defined(OW_HAVE_ISTREAM) && defined(OW_HAVE_OSTREAM)
00048 #include <istream>
00049 #include <ostream>
00050 #else
00051 #include <iostream>
00052 #endif
00053 #include <algorithm> 
00054 
00055 namespace OW_NAMESPACE
00056 {
00057 
00058 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00059 Mutex* Exception::m_mutex = new Mutex();
00060 #endif
00061 
00062 static void freeBuf(char** ptr)
00063 {
00064    delete [] *ptr;
00065    *ptr = NULL;
00066 }
00068 char* Exception::dupString(const char* str)
00069 {
00070    if (!str)
00071    {
00072       return 0;
00073    }
00074    char* rv = new (std::nothrow) char[strlen(str)+1];
00075    if (!rv)
00076    {
00077       return 0;
00078    }
00079    strcpy(rv, str);
00080    return rv;
00081 }
00083 Exception::Exception(const char* file, int line, const char* msg)
00084    : std::exception()
00085    , m_file(dupString(file))
00086    , m_line(line)
00087    , m_msg(dupString(msg))
00088    , m_subClassId(UNKNOWN_SUBCLASS_ID)
00089    , m_subException(0)
00090    , m_errorCode(UNKNOWN_ERROR_CODE)
00091 {
00092 #ifdef OW_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00093    StackTrace::printStackTrace();
00094 #endif
00095 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00096    m_mutex->acquire();
00097 #endif
00098 }
00100 Exception::Exception(int subClassId, const char* file, int line, const char* msg, int errorCode, const Exception* subException)
00101    : std::exception()
00102    , m_file(dupString(file))
00103    , m_line(line)
00104    , m_msg(dupString(msg))
00105    , m_subClassId(subClassId)
00106    , m_subException(subException ? subException->clone() : 0)
00107    , m_errorCode(errorCode)
00108 {
00109 #ifdef OW_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00110    StackTrace::printStackTrace();
00111 #endif
00112 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00113    m_mutex->acquire();
00114 #endif
00115 }
00117 Exception::Exception(const char* file, int line, const char* msg, int errorCode, const Exception* subException, int subClassId)
00118    : std::exception()
00119    , m_file(dupString(file))
00120    , m_line(line)
00121    , m_msg(dupString(msg))
00122    , m_subClassId(subClassId)
00123    , m_subException(subException ? subException->clone() : 0)
00124    , m_errorCode(errorCode)
00125 {
00126 #ifdef OW_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00127    StackTrace::printStackTrace();
00128 #endif
00129 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00130    m_mutex->acquire();
00131 #endif
00132 }
00134 Exception::Exception( const Exception& e )
00135     : std::exception(e)
00136     , m_file(dupString(e.m_file))
00137     , m_line(e.m_line)
00138     , m_msg(dupString(e.m_msg))
00139    , m_subClassId(e.m_subClassId)
00140     , m_subException(e.m_subException ? e.m_subException->clone() : 0)
00141    , m_errorCode(e.m_errorCode)
00142 {
00143 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00144     m_mutex->acquire();
00145 #endif
00146 }
00148 Exception::~Exception() throw()
00149 {
00150    try
00151    {
00152       delete m_subException;
00153       freeBuf(&m_file);
00154       freeBuf(&m_msg);
00155 #if defined(OW_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00156       m_mutex->release();
00157 #endif
00158    }
00159    catch (...)
00160    {
00161       
00162    }
00163 }
00165 Exception&
00166 Exception::operator=(const Exception& rhs)
00167 {
00168     Exception(rhs).swap(*this);
00169     return *this;
00170 }
00172 void
00173 Exception::swap(Exception& rhs)
00174 {
00175    std::swap(static_cast<std::exception&>(*this), static_cast<std::exception&>(rhs));
00176    std::swap(m_file, rhs.m_file);
00177    std::swap(m_line, rhs.m_line);
00178    std::swap(m_msg, rhs.m_msg);
00179    std::swap(m_subClassId, rhs.m_subClassId);
00180    std::swap(m_subException, rhs.m_subException);
00181    std::swap(m_errorCode, rhs.m_errorCode);
00182 }
00183       
00185 const char*
00186 Exception::type() const
00187 {
00188    return "Exception";
00189 }
00190 
00192 int
00193 Exception::getLine() const
00194 {
00195    return m_line;
00196 }
00197 
00199 const char*
00200 Exception::getMessage() const
00201 {
00202    return (m_msg != NULL) ? m_msg : "";
00203 }
00205 const char*
00206 Exception::getFile() const
00207 {
00208    return (m_file != NULL) ? m_file : "";
00209 }
00211 std::ostream&
00212 operator<<(std::ostream& os, const Exception& e)
00213 {
00214    if (*e.getFile() == '\0')
00215    {
00216       os << "[no file]: ";
00217    }
00218    else
00219    {
00220       os << e.getFile() << ": ";
00221    }
00222    
00223    if (e.getLine() == 0)
00224    {
00225       os << "[no line] ";
00226    }
00227    else
00228    {
00229       os << e.getLine() << ' ';
00230    }
00231    
00232    os << e.type() << ": ";
00233    
00234    if (*e.getMessage() == '\0')
00235    {
00236       os << "[no message]";
00237    }
00238    else
00239    {
00240       os << e.getMessage();
00241    }
00242 
00243    const Exception* subEx = e.getSubException();
00244    if (subEx)
00245    {
00246       os << " <" << *subEx << '>';
00247    }
00248    return os;
00249 }
00251 const char*
00252 Exception::what() const throw()
00253 {
00254    return getMessage();
00255 }
00256 
00258 int
00259 Exception::getSubClassId() const
00260 {
00261    return m_subClassId;
00262 }
00263 
00265 void
00266 Exception::setSubClassId(int subClassId)
00267 {
00268    m_subClassId = subClassId;
00269 }
00270 
00272 Exception*
00273 Exception::clone() const
00274 {
00275    return new(std::nothrow) Exception(*this);
00276 }
00277 
00279 const Exception*
00280 Exception::getSubException() const
00281 {
00282    return m_subException;
00283 }
00284 
00286 int
00287 Exception::getErrorCode() const
00288 {
00289    return m_errorCode;
00290 }
00291 
00293 void
00294 Exception::setErrorCode(int errorCode)
00295 {
00296    m_errorCode = errorCode;
00297 }
00298 
00299 namespace ExceptionDetail
00300 {
00301 
00302 
00303 #if defined(OW_HPUX) || defined(OW_SOLARIS) || defined(OW_WIN32)
00304 
00305    void portable_strerror_r(int errnum, char * buf, unsigned n)
00306    {
00307       ::strncpy(buf, strerror(errnum), n);
00308       buf[n-1] = '\0'; 
00309    }
00310 
00311 #else
00312    typedef int (*posix_fct)(int, char *, ::std::size_t);
00313    typedef char * (*gnu_fct)(int, char *, ::std::size_t);
00314    typedef int (*aix_fct)(int, char *, int);
00315 
00316    struct dummy
00317    {
00318    };
00319 
00320    
00321    
00322 
00323    template <typename Dummy>
00324    inline int
00325    strerror_r_wrap(posix_fct strerror_r, int errnum, char * buf, unsigned n,
00326                    Dummy)
00327    {
00328       return strerror_r(errnum, buf, n);
00329    }
00330 
00331    template <typename Dummy>
00332    inline int
00333    strerror_r_wrap(aix_fct strerror_r, int errnum, char * buf, unsigned n,
00334                    Dummy)
00335    {
00336       return strerror_r(errnum, buf, n);
00337    }
00338 
00339    template <typename Dummy>
00340    inline int
00341    strerror_r_wrap(gnu_fct strerror_r, int errnum, char * buf, unsigned n,
00342                    Dummy)
00343    {
00344       char * errstr = strerror_r(errnum, buf, n);
00345       if (errstr != buf)
00346       {
00347          if (errstr)
00348          {
00349             ::strncpy(buf, errstr, n);
00350          }
00351          else
00352          {
00353             return -1;
00354          }
00355       }
00356       return 0;
00357    }
00358 
00359    void portable_strerror_r(int errnum, char * buf, unsigned n)
00360    {
00361       int errc = strerror_r_wrap(&::strerror_r, errnum, buf, n, dummy());
00362       if (errc != 0)
00363       {
00364          ::strncpy(buf, "[Could not create error message for error code]", n);
00365       }
00366       buf[n-1] = '\0'; 
00367    }
00368 #endif
00369 
00370    struct OW_COMMON_API FormatMsgImpl
00371    {
00372       String fm;
00373    };
00374 
00375    FormatMsg::FormatMsg(char const * msg, int errnum)
00376       : pImpl(new FormatMsgImpl)
00377    {
00378       char arr[BUFSZ];
00379       portable_strerror_r(errnum, arr, BUFSZ);
00380       char const * sarr = static_cast<char const *>(arr);
00381       pImpl->fm = Format("%1: %2(%3)", msg, errnum, sarr).toString();
00382    }
00383 
00384    FormatMsg::~FormatMsg()
00385    {
00386    }
00387 
00388    char const * FormatMsg::get() const
00389    {
00390       return pImpl->fm.c_str();
00391    }
00392 
00393 } 
00394 
00395 } 
00396