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