OW_Exception.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
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 // Not <cstring>, because strerror_r is not part of C or C++ standard lib,
00045 // but is a POSIX function defined to be in <string.h>.
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> // for std::swap
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       // don't let exceptions escape
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 // HPUX, solaris have a thread safe strerror(), windows doesn't have strerror_r(), and doesn't document whether strerror() is thread safe or not.
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'; // just in case...
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    // We make the strerror_r_wrap functions into templates so that
00321    // code is generated only for the one that gets used.
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'; // just in case...
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 } // namespace ExceptionDetail
00394 
00395 } // end namespace OW_NAMESPACE
00396 

Generated on Thu Feb 9 08:47:59 2006 for openwbem by  doxygen 1.4.6