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>
38 #include <senf/config.hh>
40 //#include "Exception.mpp"
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
43 /** \defgroup exception Exception classes
45 All exceptions in %senf are derived from senf::Exception. This class adds the possibility to
46 extend the exception description while it is processed. The functionality is provided by a mixin
47 class senf::ExceptionMixin:
52 // Some code which might raise an arbitrary senf exception
55 catch (senf::ExceptionMixin & e) {
56 e << "\handling user " << user;
61 This will add the user information to any %senf exception thrown. The Exception is however not a
62 stream. If you need to do more extensive formating, either use an intermediate string-stream or
63 use <a href="http://www.boost.org/doc/libs/release/libs/format/index.html">Boost.Format</a>:
69 catch (senf::ExceptionMixin & e) {
70 e << boost::format("\n" "call id 0x%04x@%s") % id % address;
74 senf::SystemException is thrown for all operating system errors (failures which result in the
75 operating system setting the errno value). It is also derived from senf::Exception and can
76 therefore be extended as well.
78 Defining your own exception classes derived from senf::Exception is very simple:
81 struct FooException : public senf::Exception
82 { FooException() : senf::Exception("Foo hit the fan") {} };
85 If SENF is compiled in debug mode (SENF_DEBUG is defined), the exception message will
86 automatically include a stack backtrace. For this to work, you need to add the
87 <tt>-rdynamic</tt> option to all link commands. This feature depends on <tt>gcc</tt> and
90 To apply these features (extensibility, backtrace) to a non-senf exception, the non-senf
91 exception can be wrapped and re-thrown.
95 // ... code that might throw std::bad_cast or somelib::FooException
97 SENF_WRAP_EXC(std::bad_cast)
98 SENF_WRAP_EXC(somelib::FooException)
101 The re-thrown exception can then be caught as <tt>std::bad_cast</tt> or as senf::ExceptionMixin
102 as needed. It is safe, to wrap an exception twice (the macro will detect this case).
109 catch (senf::ExceptionMixin & ex) {
110 ex << "\n" "add this info";
113 catch (std::bad_cast const & ex) {
114 std::cerr << ex.what() << std::endl;
117 The final error output will include
118 \li a backtrace if compiled in debug mode
119 \li the original error message from the <tt>std::bad_cast</tt> exception
120 \li the additional error message "add this info"
122 \todo Link against libcwd to add file-name/line-number information to the backtrace and remove
123 the dependency on -rdynamic
124 \todo Or better, use addr2line to obtain that information when showing the backtrace when
125 catched within Daemon (<tt>addr2line -fsiCe argv[0]</tt>)
126 \todo Add signal handlers for the bad signals which writes a backtrace to stderr and
127 terminates. This should probably write out a raw backtrace without de-mangling or
128 line-numbers since we don't want to mess with dynamic memory when the heap might be
129 corrupted ... Another handler for e.g. SIGUSR2 is nice to show a debug backtrace on demand
134 /** \brief Generic extensible exception mixin
136 ExceptionMixin is a generic exception mixin which allows the exception to be later extended
137 by catching and re-throwing it (See example in \ref exception).
144 std::string message() const; ///< get exception description
145 std::string backtrace() const; ///< Return backtrace (if available)
147 void append(std::string text); ///< Extend exception description
148 /**< Adds \a text to the description text. */
151 explicit ExceptionMixin(std::string const & description = "");
152 ///< Initialize exception with string
153 /**< \a description is the initial error description
154 string. This should probably be a string constant
155 describing the exception for most derived
160 #ifdef SENF_BACKTRACE
164 std::string::size_type excLen_;
168 /** \brief Extensible exception base-class
170 This base-class is an exception which already includes the ExceptionMixin. All SENF
171 exceptions are derived from this class. Other user-exception may be defined by deriving from
179 : public ExceptionMixin, public std::exception
182 virtual ~Exception() throw();
184 virtual char const * what() const throw();
185 ///< get exception description and backtrace if available
186 /**< get description of the exception (message()) and backtrace
187 information if SENF is compiled with \c SENF_DEBUG */
190 explicit Exception(std::string const & description = "");
193 /** \brief Wrapper for standard non-senf exceptions
195 This class wraps an exception of type \a BaseException and adds functionality from
196 senf::ExceptionMixin.
200 template <class BaseException>
202 : public ExceptionMixin, public BaseException
205 typedef BaseException Base;
207 WrapException(BaseException const & base);
208 virtual ~WrapException() throw();
210 virtual char const * what() const throw();
213 /** \brief Wrap a non-senf exception
215 This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
216 using the WrapException template. For an example, see \ref exception.
220 # define SENF_WRAP_EXC(Ex) \
221 catch (Ex const & base) { \
222 if (dynamic_cast<senf::ExceptionMixin const *>(&base)) \
225 throw senf::WrapException<Ex>(base); \
228 template <class Exc, class Arg>
229 typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
230 operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
231 /**< Adds \a arg converted to string to the end of the
232 exception description string. This operator allows to
233 use Exception instances like streams. The conversion is
234 performed using <code>boost::lexical_cast</code> and is
235 therefor identical to a streaming operation.
236 \see \ref exception */
240 # define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
241 # define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
242 # define _SENF_EXC_DEBUG_ARGS_P ,file,line
244 # define _SENF_EXC_DEBUG_ARGS
245 # define _SENF_EXC_DEBUG_ARGS_ND
246 # define _SENF_EXC_DEBUG_ARGS_P
249 /** \brief Exception handling standard UNIX errors (errno)
251 This exception is thrown to signal generic \c errno failures. Normally the \c errno value is
252 automatically taken from the \c errno variable but it may also be specified explicitly:
255 // Standard usage: Take \c errno from environment
256 throw senf::SystemException("::open()")
257 << " while opening configuration file: " << filename;
259 // You may however explicitly specify the errno value
260 throw senf::SystemException("::open()", ENOFILE)
262 // Or leave the location information empty
263 throw senf::SystemException(ENOFILE);
264 throw senf::SystemException();
267 From within SENF (<em>and only there because it depends on the \c SENF_DEBUG symbol</em>),
268 SystemException should be thrown using wrapper macros which add additional information to
269 the exception description:
271 // Standard usage: Take \c errno from environment
272 SENF_THROW_SYSTEM_EXCEPTION("::open()")
273 << " while opening configuration file: " << filename;
275 // You may however explicitly specify the errno value
276 throw senf::SystemException("::open()", ENOFILE SENF_EXC_DEBUGINFO)
281 class SystemException : public Exception
284 //-////////////////////////////////////////////////////////////////////////
285 ///\name Structors and default members
288 explicit SystemException(std::string const & descr = "" _SENF_EXC_DEBUG_ARGS);
289 explicit SystemException(int code _SENF_EXC_DEBUG_ARGS);
290 SystemException(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS);
292 virtual ~SystemException() throw();
295 //-////////////////////////////////////////////////////////////////////////
297 int errorNumber() const; ///< Error code (\c errno number)
298 char const * errorString() const; ///< Error string (\c strerror() value)
300 bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0,
301 int c6=0, int c7=0, int c8=0, int c9=0) const;
302 ///< \c true, if errorNumber() is one of \a c0 ... \a c9
305 void init(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS_ND);
311 # define SENF_EXC_DEBUGINFO ,__FILE__,__LINE__
313 # define SENF_EXC_DEBUGINFO
316 # define SENF_THROW_SYSTEM_EXCEPTION(desc) throw senf::SystemException(desc SENF_EXC_DEBUGINFO)
320 //-/////////////////////////////////////////////////////////////////////////////////////////////////
321 #include "Exception.cci"
322 //#include "Exception.ct"
323 #include "Exception.cti"
330 // c-file-style: "senf"
331 // indent-tabs-mode: nil
332 // ispell-local-dictionary: "american"
333 // compile-command: "scons -u test"
334 // comment-column: 40