Socket/Protocols/INet: Allow socket address string representation to omit the address...
[senf.git] / Utils / Exception.hh
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief Exception public header */
25
26 #ifndef HH_Exception_
27 #define HH_Exception_ 1
28
29 // Custom includes
30 #include <exception>
31 #include <string>
32 #include <iostream>
33 #include <sstream>
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
39 //#include "Exception.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 /** \defgroup exception Exception classes
43
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:
47
48     \code
49     try {
50
51         // Some code which might raise an arbitrary senf exception
52
53     }
54     catch (senf::ExceptionMixin & e) {
55         e << "\handling user " << user;
56         throw;
57     }
58     \endcode
59
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>:
63
64     \code
65     try { 
66         // ...
67     }
68     catch (senf::ExceptionMixin & e) {
69         e << boost::format("\ncall id 0x%04x@%s") % id % address;
70     }
71     \endcode
72
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.
76
77     Defining your own exception classes derived from senf::Exception is very simple:
78
79     \code
80     struct FooException : public senf::Exception
81     { FooException() : senf::Exception("Foo hit the fan") {} };
82     \endcode
83
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
87     the GNU-libc.
88
89     To apply these features (extensibility, backtrace) to a non-senf exception, the non-senf
90     exception can be wrapped and rethrown.
91     \code
92     void foo() {
93         try {
94             // ... code that might throw std::bad_cast or somelib::FooException
95         }
96         SENF_WRAP_EXC(std::bad_cast)
97         SENF_WRAP_EXC(somelib::FooException)
98     }
99     \endcode The re-thrown exception can then be caught as <tt>std::bad_cast</tt> or as
100     senf::ExceptionMixin as needed. It is safe, to wrap an exception twice (the macro will detect
101     this case).
102     \code
103     bar() {
104     try {
105         try {
106             foo();
107         }
108         catch (senf::ExceptionMixin & ex) {
109             ex << "\nadd this info";
110         }
111     }
112     catch (std::bad_cast const & ex) {
113         std::cerr << ex.what() << std::endl;
114     }
115     \endcode
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"
120
121     \todo Link against libcwd to add file-name/line-number information to the backtrace and remove
122         the dependency on -rdynamic
123  */
124
125 namespace senf {
126
127     /** \brief Generic extensible exception mixin
128
129         ExceptionMixin is a generic exception mixin which allows the exception to be later extended
130         by catching and re-throwing it (See example in \ref exception).
131
132         \ingroup exception
133       */
134     class ExceptionMixin
135     {
136     public:
137         std::string const & message() const;
138
139         void append(std::string text); ///< Extend exception description
140                                         /**< Adds \a text to the description text. */
141
142     protected:
143         explicit ExceptionMixin(std::string const & description = ""); 
144                                         ///< Initialize exception with string
145                                         /**< \a description is the initial error description
146                                              string. This should probably be a string constant
147                                              describing the exception for most derived
148                                              exceptions. */
149
150     private:
151 #ifdef SENF_DEBUG
152         void addBacktrace();
153 #endif
154         std::string message_;
155     };
156
157     /** \brief Extensible exception base-class
158
159         This base-class is an exception which already includes the ExceptionMixin. All SENF
160         exceptions are derived from this class. Other user-exception may be defined by deriving from
161         this class too.
162
163         \see \ref exception
164
165         \ingroup exception
166      */
167     class Exception
168         : public ExceptionMixin, public std::exception
169     {
170     public:
171         virtual ~Exception() throw();
172
173         virtual char const * what() const throw();
174
175     protected:
176         explicit Exception(std::string const & description = "");
177     };
178     
179     /** \brief Wrapper for standard non-senf exceptions
180
181         This class wraps an exception of type \a BaseException and adds functionality from
182         senf::ExceptionMixin.
183
184         \ingroup exception
185      */
186     template <class BaseException>
187     class WrapException
188         : public ExceptionMixin, public BaseException
189     {
190     public:
191         typedef BaseException Base;
192
193         WrapException(BaseException const & base);
194         virtual ~WrapException() throw();
195
196         virtual char const * what() const throw();
197     };
198
199     /** \brief Wrap a non-senf exception
200
201         This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
202         using the WrapException template. For an example, see \ref exception.
203
204         \ingroup exception
205      */
206 #   define SENF_WRAP_EXC(Ex)                                                                      \
207         catch (Ex const & base) {                                                                 \
208             if (dynamic_cast<senf::ExceptionMixin const *>(&base))                                \
209                 throw;                                                                            \
210             else                                                                                  \
211                 throw senf::WrapException<Ex>(base);                                              \
212         }
213
214     template <class Exc, class Arg>
215     typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
216     operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
217                                         /**< Adds \a arg converted to string to the end of the
218                                              exception description string. This operator allows to
219                                              use Exception instances like streams. The conversion is
220                                              performed using <code>boost::lexical_cast</code> and is
221                                              therefor identical to a streaming operation. 
222                                              \see \ref exception */
223
224
225 #   ifdef SENF_DEBUG
226 #       define _SENF_EXC_DEBUG_ARGS ,char const * file=0,int line=0
227 #       define _SENF_EXC_DEBUG_ARGS_ND ,char const *file,int line
228 #       define _SENF_EXC_DEBUG_ARGS_P ,file,line
229 #   else
230 #       define _SENF_EXC_DEBUG_ARGS
231 #       define _SENF_EXC_DEBUG_ARGS_ND
232 #       define _SENF_EXC_DEBUG_ARGS_P
233 #   endif
234
235     /** \brief Exception handling standard UNIX errors (errno)
236
237         This exception is thrown to signal generic \c errno failures. Normally the \c errno value is
238         automatically taken from the \c errno variable but it may also be specified explicitly:
239
240         \code
241         // Standard usage: Take \c errno from environment
242         throw senf::SystemException("::open()") 
243             << " while opening configuration file: " << filename;
244
245         // You may however explicitly specify the errno value
246         throw senf::SystemException("::open()", ENOFILE)
247
248         // Or leave the location information empty
249         throw senf::SystemException(ENOFILE);
250         throw senf::SystemException();
251         \endcode
252
253         From within SENF (<em>and only there because it depends on the \c SENF_DEBUG symbol</em>),
254         SystemException should be thrown using wrapper macros which add additional information to
255         the exception description:
256         \code
257         // Standard usage: Take \c errno from environment
258         SENF_THROW_SYSTEM_EXCEPTION()
259             << " while opening configuration file: " << filename;
260
261         // You may however explicitly specify the errno value
262         throw senf::SystemException("::open()", ENOFILE SENF_EXC_DEBUGINFO)
263         \endcode
264
265         \ingroup exception
266      */
267     class SystemException : public Exception
268     {
269     public:
270         ///////////////////////////////////////////////////////////////////////////
271         ///\name Structors and default members
272         ///@{
273
274         explicit SystemException(std::string const & descr = "" _SENF_EXC_DEBUG_ARGS);
275         explicit SystemException(int code _SENF_EXC_DEBUG_ARGS);
276         SystemException(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS);
277
278         virtual ~SystemException() throw();
279
280         ///@}
281         ///////////////////////////////////////////////////////////////////////////
282
283         int errorNumber() const;        ///< Error code (\c errno number)
284         char const * errorString() const; ///< Error string (\c strerror() value)
285
286         bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0, 
287                    int c6=0, int c7=0, int c8=0, int c9=0);
288                                         ///< \c true, if errorNumber() is one of \a c0 ... \a c9
289
290
291
292     private:
293         void init(std::string const & descr, int code _SENF_EXC_DEBUG_ARGS_ND);
294         
295         int code_;
296         std::string what_;
297     };
298
299 #   ifdef SENF_DEBUG
300 #       define SENF_EXC_DEBUGINFO ,__FILE__,__LINE__
301 #   else
302 #       define SENF_EXC_DEBUGINFO
303 #   endif
304
305 #   define SENF_THROW_SYSTEM_EXCEPTION(desc) throw SystemException(desc SENF_EXC_DEBUGINFO)
306
307 }
308
309 ///////////////////////////////hh.e////////////////////////////////////////
310 #include "Exception.cci"
311 //#include "Exception.ct"
312 #include "Exception.cti"
313 #endif
314
315 \f
316 // Local Variables:
317 // mode: c++
318 // fill-column: 100
319 // c-file-style: "senf"
320 // indent-tabs-mode: nil
321 // ispell-local-dictionary: "american"
322 // compile-command: "scons -u test"
323 // comment-column: 40
324 // End: