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/doc/libs/release/libs/format/index.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 message() const; ///< get exception description
144 std::string backtrace() const; ///< Return backtrace (if available)
146 void append(std::string text); ///< Extend exception description
147 /**< Adds \a text to the description text. */
150 explicit ExceptionMixin(std::string const & description = "");
151 ///< Initialize exception with string
152 /**< \a description is the initial error description
153 string. This should probably be a string constant
154 describing the exception for most derived
161 std::string::size_type excLen_;
165 /** \brief Extensible exception base-class
167 This base-class is an exception which already includes the ExceptionMixin. All SENF
168 exceptions are derived from this class. Other user-exception may be defined by deriving from
176 : public ExceptionMixin, public std::exception
179 virtual ~Exception() throw();
181 virtual char const * what() const throw();
182 ///< get exception description and backtrace if available
183 /**< get description of the exception (message()) and backtrace
184 information if SENF is compiled with \c SENF_DEBUG */
187 explicit Exception(std::string const & description = "");
190 /** \brief Wrapper for standard non-senf exceptions
192 This class wraps an exception of type \a BaseException and adds functionality from
193 senf::ExceptionMixin.
197 template <class BaseException>
199 : public ExceptionMixin, public BaseException
202 typedef BaseException Base;
204 WrapException(BaseException const & base);
205 virtual ~WrapException() throw();
207 virtual char const * what() const throw();
210 /** \brief Wrap a non-senf exception
212 This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
213 using the WrapException template. For an example, see \ref exception.
217 # define SENF_WRAP_EXC(Ex) \
218 catch (Ex const & base) { \
219 if (dynamic_cast<senf::ExceptionMixin const *>(&base)) \
222 throw senf::WrapException<Ex>(base); \
225 template <class Exc, class Arg>
226 typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
227 operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
228 /**< Adds \a arg converted to string to the end of the
229 exception description string. This operator allows to
230 use Exception instances like streams. The conversion is
231 performed using <code>boost::lexical_cast</code> and is
232 therefor identical to a streaming operation.
233 \see \ref exception */
237 # define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
238 # define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
239 # define _SENF_EXC_DEBUG_ARGS_P ,file,line
241 # define _SENF_EXC_DEBUG_ARGS
242 # define _SENF_EXC_DEBUG_ARGS_ND
243 # define _SENF_EXC_DEBUG_ARGS_P
246 /** \brief Exception handling standard UNIX errors (errno)
248 This exception is thrown to signal generic \c errno failures. Normally the \c errno value is
249 automatically taken from the \c errno variable but it may also be specified explicitly:
252 // Standard usage: Take \c errno from environment
253 throw senf::SystemException("::open()")
254 << " while opening configuration file: " << filename;
256 // You may however explicitly specify the errno value
257 throw senf::SystemException("::open()", ENOFILE)
259 // Or leave the location information empty
260 throw senf::SystemException(ENOFILE);
261 throw senf::SystemException();
264 From within SENF (<em>and only there because it depends on the \c SENF_DEBUG symbol</em>),
265 SystemException should be thrown using wrapper macros which add additional information to
266 the exception description:
268 // Standard usage: Take \c errno from environment
269 SENF_THROW_SYSTEM_EXCEPTION("::open()")
270 << " while opening configuration file: " << filename;
272 // You may however explicitly specify the errno value
273 throw senf::SystemException("::open()", ENOFILE SENF_EXC_DEBUGINFO)
278 class SystemException : public Exception
281 ///////////////////////////////////////////////////////////////////////////
282 ///\name Structors and default members
285 explicit SystemException(std::string const & descr = "" _SENF_EXC_DEBUG_ARGS);
286 explicit SystemException(int code _SENF_EXC_DEBUG_ARGS);
287 SystemException(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS);
289 virtual ~SystemException() throw();
292 ///////////////////////////////////////////////////////////////////////////
294 int errorNumber() const; ///< Error code (\c errno number)
295 char const * errorString() const; ///< Error string (\c strerror() value)
297 bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0,
298 int c6=0, int c7=0, int c8=0, int c9=0) const;
299 ///< \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