blocxx
Exception.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
38
39#include "blocxx/BLOCXX_config.h"
40#include "blocxx/Exception.hpp"
41#include "blocxx/StackTrace.hpp"
42#include "blocxx/Format.hpp"
43#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
44#include "blocxx/Mutex.hpp"
45#endif
46#include <string.h>
47// Not <cstring>, because strerror_r is not part of C or C++ standard lib,
48// but is a POSIX function defined to be in <string.h>.
49#include <cstdlib>
50#if defined(BLOCXX_HAVE_ISTREAM) && defined(BLOCXX_HAVE_OSTREAM)
51#include <istream>
52#include <ostream>
53#else
54#include <iostream>
55#endif
56#include <algorithm> // for std::swap
57
58namespace BLOCXX_NAMESPACE
59{
60
61#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
62Mutex* Exception::m_mutex = new Mutex();
63#endif
65static void freeBuf(char** ptr)
66{
67 delete [] *ptr;
68 *ptr = NULL;
69}
70
71char* Exception::dupString(const char* str)
72{
73 if (!str)
74 {
75 return 0;
76 }
77 char* rv = new (std::nothrow) char[strlen(str)+1];
78 if (!rv)
79 {
80 return 0;
81 }
82 strcpy(rv, str);
83 return rv;
84}
85
86Exception::Exception(const char* file, int line, const char* msg)
87 : std::exception()
88 , m_file(dupString(file))
89 , m_line(line)
90 , m_msg(dupString(msg))
94{
95#ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
97#endif
98#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
99 m_mutex->acquire();
100#endif
101}
102
103Exception::Exception(int subClassId, const char* file, int line, const char* msg, int errorCode, const Exception* subException)
104 : std::exception()
105 , m_file(dupString(file))
106 , m_line(line)
107 , m_msg(dupString(msg))
108 , m_subClassId(subClassId)
109 , m_subException(subException ? subException->clone() : 0)
110 , m_errorCode(errorCode)
111{
112#ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
114#endif
115#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
116 m_mutex->acquire();
117#endif
118}
119
120Exception::Exception(const char* file, int line, const char* msg, int errorCode, const Exception* subException, int subClassId)
121 : std::exception()
122 , m_file(dupString(file))
123 , m_line(line)
124 , m_msg(dupString(msg))
125 , m_subClassId(subClassId)
126 , m_subException(subException ? subException->clone() : 0)
127 , m_errorCode(errorCode)
128{
129#ifdef BLOCXX_ENABLE_STACK_TRACE_ON_EXCEPTIONS
131#endif
132#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
133 m_mutex->acquire();
134#endif
135}
136
138 : std::exception(e)
140 , m_line(e.m_line)
141 , m_msg(dupString(e.m_msg))
145{
146#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
147 m_mutex->acquire();
148#endif
149}
150
152{
153 try
154 {
155 delete m_subException;
156 freeBuf(&m_file);
157 freeBuf(&m_msg);
158#if defined(BLOCXX_NON_THREAD_SAFE_EXCEPTION_HANDLING)
159 m_mutex->release();
160#endif
161 }
162 catch (...)
163 {
164 // don't let exceptions escape
165 }
166}
167
170{
171 Exception(rhs).swap(*this);
172 return *this;
173}
174
175void
177{
178 std::swap(static_cast<std::exception&>(*this), static_cast<std::exception&>(rhs));
179 std::swap(m_file, rhs.m_file);
180 std::swap(m_line, rhs.m_line);
181 std::swap(m_msg, rhs.m_msg);
182 std::swap(m_subClassId, rhs.m_subClassId);
183 std::swap(m_subException, rhs.m_subException);
184 std::swap(m_errorCode, rhs.m_errorCode);
185}
186
188const char*
190{
191 return "Exception";
192}
193
195int
197{
198 return m_line;
199}
200
202const char*
204{
205 return (m_msg != NULL) ? m_msg : "";
206}
207
208const char*
210{
211 return (m_file != NULL) ? m_file : "";
212}
213
214std::ostream&
215operator<<(std::ostream& os, const Exception& e)
216{
217 if (*e.getFile() == '\0')
218 {
219 os << "[no file]: ";
220 }
221 else
222 {
223 os << e.getFile() << ": ";
224 }
225
226 if (e.getLine() == 0)
227 {
228 os << "[no line] ";
229 }
230 else
231 {
232 os << e.getLine() << ' ';
233 }
234
235 os << e.type() << ": ";
236
238 {
239 os << e.getErrorCode() << ": ";
240 }
241
242 if (*e.getMessage() == '\0')
243 {
244 os << "[no message]";
245 }
246 else
247 {
248 os << e.getMessage();
249 }
250
251 const Exception* subEx = e.getSubException();
252 if (subEx)
253 {
254 os << " <" << *subEx << '>';
255 }
256 return os;
257}
258
259const char*
260Exception::what() const throw()
261{
262 return getMessage();
263}
264
266int
268{
269 return m_subClassId;
270}
271
273void
275{
276 m_subClassId = subClassId;
277}
278
282{
283 return new(std::nothrow) Exception(*this);
284}
285
288{
289 throw *this;
290}
291
293const Exception*
295{
296 return m_subException;
297}
298
300int
302{
303 return m_errorCode;
304}
305
307void
309{
310 m_errorCode = errorCode;
311}
312
314{
315
316// HPUX, solaris have a thread safe strerror(), windows doesn't have strerror_r(), and doesn't document whether strerror() is thread safe or not.
317#if defined(BLOCXX_HPUX) || defined(BLOCXX_SOLARIS) || defined(BLOCXX_WIN32) || defined(BLOCXX_NCR)
318
319 void portable_strerror_r(int errnum, char * buf, unsigned n)
320 {
321 ::strncpy(buf, strerror(errnum), n);
322 buf[n-1] = '\0'; // just in case...
323 }
324
325#else
326 typedef int (*posix_fct)(int, char *, ::std::size_t);
327 typedef char * (*gnu_fct)(int, char *, ::std::size_t);
328 typedef int (*aix_fct)(int, char *, int);
329
330 struct dummy
331 {
332 };
333
334 // We make the strerror_r_wrap functions into templates so that
335 // code is generated only for the one that gets used.
336
337 template <typename Dummy>
338 inline int
339 strerror_r_wrap(posix_fct strerror_r, int errnum, char * buf, unsigned n,
340 Dummy)
341 {
342 return strerror_r(errnum, buf, n);
343 }
344
345 template <typename Dummy>
346 inline int
347 strerror_r_wrap(aix_fct strerror_r, int errnum, char * buf, unsigned n,
348 Dummy)
349 {
350 return strerror_r(errnum, buf, n);
351 }
352
353 template <typename Dummy>
354 inline int
355 strerror_r_wrap(gnu_fct strerror_r, int errnum, char * buf, unsigned n,
356 Dummy)
357 {
358 char * errstr = strerror_r(errnum, buf, n);
359 if (errstr != buf)
360 {
361 if (errstr)
362 {
363 ::strncpy(buf, errstr, n);
364 }
365 else
366 {
367 return -1;
368 }
369 }
370 return 0;
371 }
372
373 void portable_strerror_r(int errnum, char * buf, unsigned n)
374 {
375 int errc = strerror_r_wrap(&::strerror_r, errnum, buf, n, dummy());
376 if (errc != 0)
377 {
378 ::strncpy(buf, "[Could not create error message for error code]", n);
379 }
380 buf[n-1] = '\0'; // just in case...
381 }
382#endif
383
384 struct BLOCXX_COMMON_API FormatMsgImpl
385 {
387 };
388
389 FormatMsg::FormatMsg(char const * msg, int errnum)
390 : pImpl(new FormatMsgImpl)
391 {
392 char arr[BUFSZ];
393 portable_strerror_r(errnum, arr, BUFSZ);
394 char const * sarr = static_cast<char const *>(arr);
395 pImpl->fm = Format("%1: %2(%3)", msg, errnum, sarr).toString();
396 }
397
401
402 char const * FormatMsg::get() const
403 {
404 return pImpl->fm.c_str();
405 }
406
407} // namespace ExceptionDetail
408
409} // end namespace BLOCXX_NAMESPACE
410
FormatMsg(char const *msg, int errnum)
This class is the base of all exceptions thrown by BloCxx code.
Definition Exception.hpp:66
static const int UNKNOWN_SUBCLASS_ID
virtual const char * what() const
Returns getMessage()
int getErrorCode() const
Returns the error code representing the error which occurred.
void setSubClassId(int subClassId)
virtual const char * getMessage() const
Returns the message.
const Exception * m_subException
Exception(const char *file, int line, const char *msg) BLOCXX_DEPRECATED
This constructor is deprecated.
Definition Exception.cpp:86
const char * getFile() const
Returns the file.
void setErrorCode(int errorCode)
virtual void rethrow() const
Re-throws the exception.
const Exception * getSubException() const
Returns the sub exception if available, otherwise 0.
virtual const char * type() const
Returns a string representing the concrete type.
static const int UNKNOWN_ERROR_CODE
void swap(Exception &x)
char * dupString(const char *str)
Utility function to copy a string.
Definition Exception.cpp:71
Exception & operator=(const Exception &rhs)
virtual Exception * clone() const
Make a copy of this exception object.
String toString() const
Definition Format.cpp:50
This String class is an abstract data type that represents as NULL terminated string of characters.
Definition String.hpp:67
int(* aix_fct)(int, char *, int)
char *(* gnu_fct)(int, char *, ::std::size_t)
int strerror_r_wrap(posix_fct strerror_r, int errnum, char *buf, unsigned n, Dummy)
void portable_strerror_r(int errnum, char *buf, unsigned n)
int(* posix_fct)(int, char *, ::std::size_t)
BLOCXX_COMMON_API void printStackTrace(EDoStackTraceFlag=E_CHECK_ENV_VAR)
Taken from RFC 1321.
static void freeBuf(char **ptr)
Definition Exception.cpp:65
ostream & operator<<(ostream &ostrm, const Bool &arg)
Definition Bool.cpp:77