4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Exception public header */
26 #ifndef HH_SENF_Utils_Exception_
27 #define HH_SENF_Utils_Exception_ 1
34 #include <boost/preprocessor/repeat.hpp>
35 #include <boost/preprocessor/cat.hpp>
36 #include <boost/utility.hpp>
37 #include <boost/type_traits/is_convertible.hpp>
39 //#include "Exception.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
42 /** \defgroup exception Exception classes
44 All exceptions in %senf are derived from senf::Exception. This class adds the possibility to
45 extend the exception description while it is processed. The functionality is provided by a mixin
46 class senf::ExceptionMixin:
51 // Some code which might raise an arbitrary senf exception
54 catch (senf::ExceptionMixin & e) {
55 e << "\handling user " << user;
60 This will add the user information to any %senf exception thrown. The Exception is however not a
61 stream. If you need to do more extensive formating, either use an intermediate string-stream or
62 use <a href="http://www.boost.org/libs/format/doc/format.html">Boost.Format</a>:
68 catch (senf::ExceptionMixin & e) {
69 e << boost::format("\n" "call id 0x%04x@%s") % id % address;
73 senf::SystemException is thrown for all operating system errors (failures which result in the
74 operating system setting the errno value). It is also derived from senf::Exception and can
75 therefore be extended as well.
77 Defining your own exception classes derived from senf::Exception is very simple:
80 struct FooException : public senf::Exception
81 { FooException() : senf::Exception("Foo hit the fan") {} };
84 If SENF is compiled in debug mode (SENF_DEBUG is defined), the exception message will
85 automatically include a stack backtrace. For this to work, you need to add the
86 <tt>-rdynamic</tt> option to all link commands. This feature depends on <tt>gcc</tt> and
89 To apply these features (extensibility, backtrace) to a non-senf exception, the non-senf
90 exception can be wrapped and re-thrown.
94 // ... code that might throw std::bad_cast or somelib::FooException
96 SENF_WRAP_EXC(std::bad_cast)
97 SENF_WRAP_EXC(somelib::FooException)
100 The re-thrown exception can then be caught as <tt>std::bad_cast</tt> or as senf::ExceptionMixin
101 as needed. It is safe, to wrap an exception twice (the macro will detect this case).
108 catch (senf::ExceptionMixin & ex) {
109 ex << "\n" "add this info";
112 catch (std::bad_cast const & ex) {
113 std::cerr << ex.what() << std::endl;
116 The final error output will include
117 \li a backtrace if compiled in debug mode
118 \li the original error message from the <tt>std::bad_cast</tt> exception
119 \li the additional error message "add this info"
121 \todo Link against libcwd to add file-name/line-number information to the backtrace and remove
122 the dependency on -rdynamic
123 \todo Or better, use addr2line to obtain that information when showing the backtrace when
124 catched within Daemon (<tt>addr2line -fsiCe argv[0]</tt>)
125 \todo Add signal handlers for the bad signals which writes a backtrace to stderr and
126 terminates. This should probably write out a raw backtrace without de-mangling or
127 line-numbers since we don't want to mess with dynamic memory when the heap might be
128 corrupted ... Another handler for e.g. SIGUSR2 is nice to show a debug backtrace on demand
133 /** \brief Generic extensible exception mixin
135 ExceptionMixin is a generic exception mixin which allows the exception to be later extended
136 by catching and re-throwing it (See example in \ref exception).
143 std::string const & message() const; ///< get exception description
145 void append(std::string text); ///< Extend exception description
146 /**< Adds \a text to the description text. */
149 explicit ExceptionMixin(std::string const & description = "");
150 ///< Initialize exception with string
151 /**< \a description is the initial error description
152 string. This should probably be a string constant
153 describing the exception for most derived
160 std::string message_;
163 /** \brief Extensible exception base-class
165 This base-class is an exception which already includes the ExceptionMixin. All SENF
166 exceptions are derived from this class. Other user-exception may be defined by deriving from
174 : public ExceptionMixin, public std::exception
177 virtual ~Exception() throw();
179 virtual char const * what() const throw();
180 ///< get exception description and backtrace if available
181 /**< get description of the exception (message()) and backtrace
182 information if SENF is compiled with \c SENF_DEBUG */
185 explicit Exception(std::string const & description = "");
188 /** \brief Wrapper for standard non-senf exceptions
190 This class wraps an exception of type \a BaseException and adds functionality from
191 senf::ExceptionMixin.
195 template <class BaseException>
197 : public ExceptionMixin, public BaseException
200 typedef BaseException Base;
202 WrapException(BaseException const & base);
203 virtual ~WrapException() throw();
205 virtual char const * what() const throw();
208 /** \brief Wrap a non-senf exception
210 This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
211 using the WrapException template. For an example, see \ref exception.
215 # define SENF_WRAP_EXC(Ex) \
216 catch (Ex const & base) { \
217 if (dynamic_cast<senf::ExceptionMixin const *>(&base)) \
220 throw senf::WrapException<Ex>(base); \
223 template <class Exc, class Arg>
224 typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
225 operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
226 /**< Adds \a arg converted to string to the end of the
227 exception description string. This operator allows to
228 use Exception instances like streams. The conversion is
229 performed using <code>boost::lexical_cast</code> and is
230 therefor identical to a streaming operation.
231 \see \ref exception */
235 # define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
236 # define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
237 # define _SENF_EXC_DEBUG_ARGS_P ,file,line
239 # define _SENF_EXC_DEBUG_ARGS
240 # define _SENF_EXC_DEBUG_ARGS_ND
241 # define _SENF_EXC_DEBUG_ARGS_P
244 /** \brief Exception handling standard UNIX errors (errno)
246 This exception is thrown to signal generic \c errno failures. Normally the \c errno value is
247 automatically taken from the \c errno variable but it may also be specified explicitly:
250 // Standard usage: Take \c errno from environment
251 throw senf::SystemException("::open()")
252 << " while opening configuration file: " << filename;
254 // You may however explicitly specify the errno value
255 throw senf::SystemException("::open()", ENOFILE)
257 // Or leave the location information empty
258 throw senf::SystemException(ENOFILE);
259 throw senf::SystemException();
262 From within SENF (<em>and only there because it depends on the \c SENF_DEBUG symbol</em>),
263 SystemException should be thrown using wrapper macros which add additional information to
264 the exception description:
266 // Standard usage: Take \c errno from environment
267 SENF_THROW_SYSTEM_EXCEPTION("::open()")
268 << " while opening configuration file: " << filename;
270 // You may however explicitly specify the errno value
271 throw senf::SystemException("::open()", ENOFILE SENF_EXC_DEBUGINFO)
276 class SystemException : public Exception
279 ///////////////////////////////////////////////////////////////////////////
280 ///\name Structors and default members
283 explicit SystemException(std::string const & descr = "" _SENF_EXC_DEBUG_ARGS);
284 explicit SystemException(int code _SENF_EXC_DEBUG_ARGS);
285 SystemException(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS);
287 virtual ~SystemException() throw();
290 ///////////////////////////////////////////////////////////////////////////
292 int errorNumber() const; ///< Error code (\c errno number)
293 char const * errorString() const; ///< Error string (\c strerror() value)
295 bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0,
296 int c6=0, int c7=0, int c8=0, int c9=0);
297 ///< \c true, if errorNumber() is one of \a c0 ... \a c9
302 void init(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS_ND);
308 # define SENF_EXC_DEBUGINFO ,__FILE__,__LINE__
310 # define SENF_EXC_DEBUGINFO
313 # define SENF_THROW_SYSTEM_EXCEPTION(desc) throw senf::SystemException(desc SENF_EXC_DEBUGINFO)
317 ///////////////////////////////hh.e////////////////////////////////////////
318 #include "Exception.cci"
319 //#include "Exception.ct"
320 #include "Exception.cti"
327 // c-file-style: "senf"
328 // indent-tabs-mode: nil
329 // ispell-local-dictionary: "american"
330 // compile-command: "scons -u test"
331 // comment-column: 40