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
00031
00032
00033
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/Exception.hpp"
00041 #include "blocxx/StackTrace.hpp"
00042 #include "blocxx/Format.hpp"
00043 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00044 #include "blocxx/Mutex.hpp"
00045 #endif
00046 #include <string.h>
00047
00048
00049 #include <cstdlib>
00050 #if defined(BLOCXX_HAVE_ISTREAM) && defined(BLOCXX_HAVE_OSTREAM)
00051 #include <istream>
00052 #include <ostream>
00053 #else
00054 #include <iostream>
00055 #endif
00056 #include <algorithm>
00057
00058 namespace BLOCXX_NAMESPACE
00059 {
00060
00061 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00062 Mutex* Exception::m_mutex = new Mutex();
00063 #endif
00064
00065 static void freeBuf(char** ptr)
00066 {
00067 delete [] *ptr;
00068 *ptr = NULL;
00069 }
00071 char* Exception::dupString(const char* str)
00072 {
00073 if (!str)
00074 {
00075 return 0;
00076 }
00077 char* rv = new (std::nothrow) char[strlen(str)+1];
00078 if (!rv)
00079 {
00080 return 0;
00081 }
00082 strcpy(rv, str);
00083 return rv;
00084 }
00086 Exception::Exception(const char* file, int line, const char* msg)
00087 : std::exception()
00088 , m_file(dupString(file))
00089 , m_line(line)
00090 , m_msg(dupString(msg))
00091 , m_subClassId(UNKNOWN_SUBCLASS_ID)
00092 , m_subException(0)
00093 , m_errorCode(UNKNOWN_ERROR_CODE)
00094 {
00095 #ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00096 StackTrace::printStackTrace();
00097 #endif
00098 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00099 m_mutex->acquire();
00100 #endif
00101 }
00103 Exception::Exception(int subClassId, const char* file, int line, const char* msg, int errorCode, const Exception* subException)
00104 : std::exception()
00105 , m_file(dupString(file))
00106 , m_line(line)
00107 , m_msg(dupString(msg))
00108 , m_subClassId(subClassId)
00109 , m_subException(subException ? subException->clone() : 0)
00110 , m_errorCode(errorCode)
00111 {
00112 #ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00113 StackTrace::printStackTrace();
00114 #endif
00115 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00116 m_mutex->acquire();
00117 #endif
00118 }
00120 Exception::Exception(const char* file, int line, const char* msg, int errorCode, const Exception* subException, int subClassId)
00121 : std::exception()
00122 , m_file(dupString(file))
00123 , m_line(line)
00124 , m_msg(dupString(msg))
00125 , m_subClassId(subClassId)
00126 , m_subException(subException ? subException->clone() : 0)
00127 , m_errorCode(errorCode)
00128 {
00129 #ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
00130 StackTrace::printStackTrace();
00131 #endif
00132 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00133 m_mutex->acquire();
00134 #endif
00135 }
00137 Exception::Exception( const Exception& e )
00138 : std::exception(e)
00139 , m_file(dupString(e.m_file))
00140 , m_line(e.m_line)
00141 , m_msg(dupString(e.m_msg))
00142 , m_subClassId(e.m_subClassId)
00143 , m_subException(e.m_subException ? e.m_subException->clone() : 0)
00144 , m_errorCode(e.m_errorCode)
00145 {
00146 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00147 m_mutex->acquire();
00148 #endif
00149 }
00151 Exception::~Exception() throw()
00152 {
00153 try
00154 {
00155 delete m_subException;
00156 freeBuf(&m_file);
00157 freeBuf(&m_msg);
00158 #if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
00159 m_mutex->release();
00160 #endif
00161 }
00162 catch (...)
00163 {
00164
00165 }
00166 }
00168 Exception&
00169 Exception::operator=(const Exception& rhs)
00170 {
00171 Exception(rhs).swap(*this);
00172 return *this;
00173 }
00175 void
00176 Exception::swap(Exception& rhs)
00177 {
00178 std::swap(static_cast<std::exception&>(*this), static_cast<std::exception&>(rhs));
00179 std::swap(m_file, rhs.m_file);
00180 std::swap(m_line, rhs.m_line);
00181 std::swap(m_msg, rhs.m_msg);
00182 std::swap(m_subClassId, rhs.m_subClassId);
00183 std::swap(m_subException, rhs.m_subException);
00184 std::swap(m_errorCode, rhs.m_errorCode);
00185 }
00186
00188 const char*
00189 Exception::type() const
00190 {
00191 return "Exception";
00192 }
00193
00195 int
00196 Exception::getLine() const
00197 {
00198 return m_line;
00199 }
00200
00202 const char*
00203 Exception::getMessage() const
00204 {
00205 return (m_msg != NULL) ? m_msg : "";
00206 }
00208 const char*
00209 Exception::getFile() const
00210 {
00211 return (m_file != NULL) ? m_file : "";
00212 }
00214 std::ostream&
00215 operator<<(std::ostream& os, const Exception& e)
00216 {
00217 if (*e.getFile() == '\0')
00218 {
00219 os << "[no file]: ";
00220 }
00221 else
00222 {
00223 os << e.getFile() << ": ";
00224 }
00225
00226 if (e.getLine() == 0)
00227 {
00228 os << "[no line] ";
00229 }
00230 else
00231 {
00232 os << e.getLine() << ' ';
00233 }
00234
00235 os << e.type() << ": ";
00236
00237 if (e.getErrorCode() != Exception::UNKNOWN_ERROR_CODE)
00238 {
00239 os << e.getErrorCode() << ": ";
00240 }
00241
00242 if (*e.getMessage() == '\0')
00243 {
00244 os << "[no message]";
00245 }
00246 else
00247 {
00248 os << e.getMessage();
00249 }
00250
00251 const Exception* subEx = e.getSubException();
00252 if (subEx)
00253 {
00254 os << " <" << *subEx << '>';
00255 }
00256 return os;
00257 }
00259 const char*
00260 Exception::what() const throw()
00261 {
00262 return getMessage();
00263 }
00264
00266 int
00267 Exception::getSubClassId() const
00268 {
00269 return m_subClassId;
00270 }
00271
00273 void
00274 Exception::setSubClassId(int subClassId)
00275 {
00276 m_subClassId = subClassId;
00277 }
00278
00280 Exception*
00281 Exception::clone() const
00282 {
00283 return new(std::nothrow) Exception(*this);
00284 }
00285
00287 void Exception::rethrow() const
00288 {
00289 throw *this;
00290 }
00291
00293 const Exception*
00294 Exception::getSubException() const
00295 {
00296 return m_subException;
00297 }
00298
00300 int
00301 Exception::getErrorCode() const
00302 {
00303 return m_errorCode;
00304 }
00305
00307 void
00308 Exception::setErrorCode(int errorCode)
00309 {
00310 m_errorCode = errorCode;
00311 }
00312
00313 namespace ExceptionDetail
00314 {
00315
00316 // HPUX, solaris have a thread safe strerror(), windows doesn't have strerror_r(), and doesn't document whether strerror() is thread safe or not.
00317 #if defined(BLOCXX_HPUX) || defined(BLOCXX_SOLARIS) || defined(BLOCXX_WIN32) || defined(BLOCXX_NCR)
00318
00319 void portable_strerror_r(int errnum, char * buf, unsigned n)
00320 {
00321 ::strncpy(buf, strerror(errnum), n);
00322 buf[n-1] = '\0'; // just in case...
00323 }
00324
00325 #else
00326 typedef int (*posix_fct)(int, char *, ::std::size_t);
00327 typedef char * (*gnu_fct)(int, char *, ::std::size_t);
00328 typedef int (*aix_fct)(int, char *, int);
00329
00330 struct dummy
00331 {
00332 };
00333
00334 // We make the strerror_r_wrap functions into templates so that
00335 // code is generated only for the one that gets used.
00336
00337 template <typename Dummy>
00338 inline int
00339 strerror_r_wrap(posix_fct strerror_r, int errnum, char * buf, unsigned n,
00340 Dummy)
00341 {
00342 return strerror_r(errnum, buf, n);
00343 }
00344
00345 template <typename Dummy>
00346 inline int
00347 strerror_r_wrap(aix_fct strerror_r, int errnum, char * buf, unsigned n,
00348 Dummy)
00349 {
00350 return strerror_r(errnum, buf, n);
00351 }
00352
00353 template <typename Dummy>
00354 inline int
00355 strerror_r_wrap(gnu_fct strerror_r, int errnum, char * buf, unsigned n,
00356 Dummy)
00357 {
00358 char * errstr = strerror_r(errnum, buf, n);
00359 if (errstr != buf)
00360 {
00361 if (errstr)
00362 {
00363 ::strncpy(buf, errstr, n);
00364 }
00365 else
00366 {
00367 return -1;
00368 }
00369 }
00370 return 0;
00371 }
00372
00373 void portable_strerror_r(int errnum, char * buf, unsigned n)
00374 {
00375 int errc = strerror_r_wrap(&::strerror_r, errnum, buf, n, dummy());
00376 if (errc != 0)
00377 {
00378 ::strncpy(buf, "[Could not create error message for error code]", n);
00379 }
00380 buf[n-1] = '\0'; // just in case...
00381 }
00382 #endif
00383
00384 struct BLOCXX_COMMON_API FormatMsgImpl
00385 {
00386 String fm;
00387 };
00388
00389 FormatMsg::FormatMsg(char const * msg, int errnum)
00390 : pImpl(new FormatMsgImpl)
00391 {
00392 char arr[BUFSZ];
00393 portable_strerror_r(errnum, arr, BUFSZ);
00394 char const * sarr = static_cast<char const *>(arr);
00395 pImpl->fm = Format("%1: %2(%3)", msg, errnum, sarr).toString();
00396 }
00397
00398 FormatMsg::~FormatMsg()
00399 {
00400 }
00401
00402 char const * FormatMsg::get() const
00403 {
00404 return pImpl->fm.c_str();
00405 }
00406
00407 } // namespace ExceptionDetail
00408
00409 } // end namespace BLOCXX_NAMESPACE
00410