4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Exception public header */
31 #ifndef HH_SENF_Utils_Exception_
32 #define HH_SENF_Utils_Exception_ 1
39 #include <boost/utility.hpp>
40 #include <boost/type_traits/is_convertible.hpp>
41 #include <senf/config.hh>
42 #include "senfassert.hh"
45 //#include "Exception.mpp"
46 //-/////////////////////////////////////////////////////////////////////////////////////////////////
48 /** \defgroup exception Exception classes
50 All exceptions in %senf are derived from senf::Exception. This class adds the possibility to
51 extend the exception description while it is processed. The functionality is provided by a mixin
52 class senf::ExceptionMixin:
57 // Some code which might raise an arbitrary senf exception
60 catch (senf::ExceptionMixin & e) {
61 e << "\handling user " << user;
66 This will add the user information to any %senf exception thrown. The Exception is however not a
67 stream. If you need to do more extensive formating, either use an intermediate string-stream or
68 use <a href="http://www.boost.org/doc/libs/release/libs/format/index.html">Boost.Format</a>:
74 catch (senf::ExceptionMixin & e) {
75 e << boost::format("\n" "call id 0x%04x@%s") % id % address;
79 senf::SystemException is thrown for all operating system errors (failures which result in the
80 operating system setting the errno value). It is also derived from senf::Exception and can
81 therefore be extended as well.
83 Defining your own exception classes derived from senf::Exception is very simple:
86 struct FooException : public senf::Exception
87 { FooException() : senf::Exception("Foo hit the fan") {} };
90 If SENF is compiled in debug mode (SENF_DEBUG is defined), the exception message will
91 automatically include a stack backtrace. For this to work, you need to add the
92 <tt>-rdynamic</tt> option to all link commands. This feature depends on <tt>gcc</tt> and
95 To apply these features (extensibility, backtrace) to a non-senf exception, the non-senf
96 exception can be wrapped and re-thrown.
100 // ... code that might throw std::bad_cast or somelib::FooException
102 SENF_WRAP_EXC(std::bad_cast)
103 SENF_WRAP_EXC(somelib::FooException)
106 The re-thrown exception can then be caught as <tt>std::bad_cast</tt> or as senf::ExceptionMixin
107 as needed. It is safe, to wrap an exception twice (the macro will detect this case).
114 catch (senf::ExceptionMixin & ex) {
115 ex << "\n" "add this info";
118 catch (std::bad_cast const & ex) {
119 std::cerr << ex.what() << std::endl;
122 The final error output will include
123 \li a backtrace if compiled in debug mode
124 \li the original error message from the <tt>std::bad_cast</tt> exception
125 \li the additional error message "add this info"
127 \todo Link against libcwd to add file-name/line-number information to the backtrace and remove
128 the dependency on -rdynamic
129 \todo Or better, use addr2line to obtain that information when showing the backtrace when
130 catched within Daemon (<tt>addr2line -fsiCe argv[0]</tt>)
131 \todo Add signal handlers for the bad signals which writes a backtrace to stderr and
132 terminates. This should probably write out a raw backtrace without de-mangling or
133 line-numbers since we don't want to mess with dynamic memory when the heap might be
134 corrupted ... Another handler for e.g. SIGUSR2 is nice to show a debug backtrace on demand
139 /** \brief Generic extensible exception mixin
141 ExceptionMixin is a generic exception mixin which allows the exception to be later extended
142 by catching and re-throwing it (See example in \ref exception).
149 std::string message() const; ///< get exception description
150 std::string backtrace() const; ///< Return backtrace (if available)
152 void append(std::string text); ///< Extend exception description
153 /**< Adds \a text to the description text. */
156 explicit ExceptionMixin(std::string const & description = "");
157 ///< Initialize exception with string
158 /**< \a description is the initial error description
159 string. This should probably be a string constant
160 describing the exception for most derived
165 #ifdef SENF_BACKTRACE
169 std::string::size_type excLen_;
173 /** \brief Extensible exception base-class
175 This base-class is an exception which already includes the ExceptionMixin. All SENF
176 exceptions are derived from this class. Other user-exception may be defined by deriving from
184 : public ExceptionMixin, public std::exception
187 virtual ~Exception() throw();
189 virtual char const * what() const throw();
190 ///< get exception description and backtrace if available
191 /**< get description of the exception (message()) and backtrace
192 information if SENF is compiled with \c SENF_DEBUG */
195 explicit Exception(std::string const & description = "");
198 /** \brief Wrapper for standard non-senf exceptions
200 This class wraps an exception of type \a BaseException and adds functionality from
201 senf::ExceptionMixin.
205 template <class BaseException>
207 : public ExceptionMixin, public BaseException
210 typedef BaseException Base;
212 WrapException(BaseException const & base);
213 virtual ~WrapException() throw();
215 virtual char const * what() const throw();
218 /** \brief Wrap a non-senf exception
220 This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
221 using the WrapException template. For an example, see \ref exception.
225 # define SENF_WRAP_EXC(Ex) \
226 catch (Ex const & base) { \
227 if (dynamic_cast<senf::ExceptionMixin const *>(&base)) \
230 throw senf::WrapException<Ex>(base); \
233 template <class Exc, class Arg>
234 typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
235 operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
236 /**< Adds \a arg converted to string to the end of the
237 exception description string. This operator allows to
238 use Exception instances like streams. The conversion is
239 performed using <code>boost::lexical_cast</code> and is
240 therefor identical to a streaming operation.
241 \see \ref exception */
245 # define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
246 # define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
247 # define _SENF_EXC_DEBUG_ARGS_P ,file,line
249 # define _SENF_EXC_DEBUG_ARGS
250 # define _SENF_EXC_DEBUG_ARGS_ND
251 # define _SENF_EXC_DEBUG_ARGS_P
254 /** \brief Exception handling standard UNIX errors (errno)
256 This exception is thrown to signal generic \c errno failures. Normally the \c errno value is
257 automatically taken from the \c errno variable but it may also be specified explicitly:
260 // Standard usage: Take \c errno from environment
261 throw senf::SystemException("::open()")
262 << " while opening configuration file: " << filename;
264 // You may however explicitly specify the errno value
265 throw senf::SystemException("::open()", ENOFILE)
267 // Or leave the location information empty
268 throw senf::SystemException(ENOFILE);
269 throw senf::SystemException();
272 From within SENF (<em>and only there because it depends on the \c SENF_DEBUG symbol</em>),
273 SystemException should be thrown using wrapper macros which add additional information to
274 the exception description:
276 // Standard usage: Take \c errno from environment
277 SENF_THROW_SYSTEM_EXCEPTION("::open()")
278 << " while opening configuration file: " << filename;
280 // You may however explicitly specify the errno value
281 throw senf::SystemException("::open()", ENOFILE SENF_EXC_DEBUGINFO)
286 class SystemException : public Exception
289 //-////////////////////////////////////////////////////////////////////////
290 ///\name Structors and default members
293 explicit SystemException(std::string const & descr = "" _SENF_EXC_DEBUG_ARGS);
294 explicit SystemException(int code _SENF_EXC_DEBUG_ARGS);
295 SystemException(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS);
297 virtual ~SystemException() throw();
300 //-////////////////////////////////////////////////////////////////////////
302 int errorNumber() const; ///< Error code (\c errno number)
303 char const * errorString() const; ///< Error string (\c strerror() value)
305 bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0,
306 int c6=0, int c7=0, int c8=0, int c9=0) const;
307 ///< \c true, if errorNumber() is one of \a c0 ... \a c9
310 void init(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS_ND);
316 # define SENF_EXC_DEBUGINFO ,__FILE__,__LINE__
318 # define SENF_EXC_DEBUGINFO
321 # define SENF_THROW_SYSTEM_EXCEPTION(desc) \
322 SENF_STATIC_ASSERT( sizeof(desc) > 1, \
323 EMPTY_DESCRIPTION_FOR_SYSTEM_EXCEPTION_NOT_ALLOWED); \
324 throw senf::SystemException(desc SENF_EXC_DEBUGINFO)
328 //-/////////////////////////////////////////////////////////////////////////////////////////////////
329 #include "Exception.cci"
330 //#include "Exception.ct"
331 #include "Exception.cti"
338 // c-file-style: "senf"
339 // indent-tabs-mode: nil
340 // ispell-local-dictionary: "american"
341 // compile-command: "scons -u test"
342 // comment-column: 40