Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / base / Exception.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/Exception.h
10  *
11 */
12 #ifndef ZYPP_BASE_EXCEPTION_H
13 #define ZYPP_BASE_EXCEPTION_H
14
15 #include <iosfwd>
16 #include <string>
17 #include <list>
18 #include <stdexcept>
19
20 #include "zypp/base/Errno.h"
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 { /////////////////////////////////////////////////////////////////
25   ///////////////////////////////////////////////////////////////////
26   namespace exception_detail
27   { /////////////////////////////////////////////////////////////////
28
29     /** Keep _FILE_, _FUNCTION_ and _LINE_.
30      * Construct it using the \ref ZYPP_EX_CODELOCATION macro.
31     */
32     struct CodeLocation
33     {
34       friend std::ostream & operator<<( std::ostream & str, const CodeLocation & obj );
35
36       /** Ctor */
37       CodeLocation()
38       : _line( 0 )
39       {}
40
41       /** Ctor */
42       CodeLocation( const std::string & file_r,
43                     const std::string & func_r,
44                     unsigned            line_r )
45       : _file( file_r ), _func( func_r ), _line( line_r )
46       {}
47
48       /** Location as string */
49       std::string asString() const;
50
51     private:
52       std::string _file;
53       std::string _func;
54       unsigned    _line;
55     };
56     ///////////////////////////////////////////////////////////////////
57
58     /** Create CodeLocation object storing the current location. */
59     //#define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(__FILE__,__FUNCTION__,__LINE__)
60 #define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(( *__FILE__ == '/' ? strrchr( __FILE__, '/' ) + 1 : __FILE__ ),__FUNCTION__,__LINE__)
61
62     /** \relates CodeLocation Stream output */
63     std::ostream & operator<<( std::ostream & str, const CodeLocation & obj );
64
65     /////////////////////////////////////////////////////////////////
66   } // namespace exception_detail
67   ///////////////////////////////////////////////////////////////////
68
69   ///////////////////////////////////////////////////////////////////
70   //
71   //    CLASS NAME : Exception
72   /** Base class for Exception.
73    *
74    * Exception offers to store a message string passed to the ctor.
75    * Derived classes may provide additional information. Overload
76    * \ref dumpOn to provide a proper error text.
77    *
78    * \li Use \ref ZYPP_THROW to throw exceptions.
79    * \li Use \ref ZYPP_CAUGHT If you caught an exceptions in order to handle it.
80    * \li Use \ref ZYPP_RETHROW to rethrow a caught exception.
81    *
82    * The use of these macros is not mandatory. but \c ZYPP_THROW and
83    * \c ZYPP_RETHROW will adjust the code location information stored in
84    * the Exception. All three macros will drop a line in the logfile.
85
86    * \code
87    *  43   try
88    *  44     {
89    *  45       try
90    *  46         {
91    *  47           ZYPP_THROW( Exception("Something bad happened.") );
92    *  48         }
93    *  49       catch ( Exception & excpt )
94    *  50         {
95    *  51           ZYPP_RETHROW( excpt );
96    *  52         }
97    *  53
98    *  54     }
99    *  55   catch ( Exception & excpt )
100    *  56     {
101    *  57       ZYPP_CAUGHT( excpt );
102    *  58     }
103    * \endcode
104    * The above produces the following log lines:
105    * \code
106    *  Main.cc(main):47 THROW:    Main.cc(main):47: Something bad happened.
107    *  Main.cc(main):51 RETHROW:  Main.cc(main):47: Something bad happened.
108    *  Main.cc(main):57 CAUGHT:   Main.cc(main):51: Something bad happened.
109    * \endcode
110    *
111    *
112    * Class Exception now offers a history list of message strings.
113    * These messages should describe what lead to the exception.
114    *
115    * The Exceptions message itself is NOT included in the history.
116    *
117    * Rethrow, remembering an old exception:
118    * \code
119    * try
120    * {
121    *   ....
122    * }
123    * catch( const Exception & olderr_r )
124    * {
125    *    ZYPP_CAUGHT( olderr_r )
126    *    HighLevelException newerr( "Something failed." );
127    *    newerr.rember( olderr_r );
128    *    ZYPP_THROW( newerr );
129    * }
130    * \endcode
131    *
132    * Print an Exception followed by it's history if available:
133    * \code
134    * Exception error;
135    * ERR << error << endl << error.historyAsString();
136    * \endcode
137    *
138    * \todo That's a draft to have a common way of throwing exceptions.
139    * Most probabely we'll finally use blocxx exceptions. Here, but not
140    * in the remaining code of zypp. If we can we should try to wrap
141    * the blocxx macros and typedef the classes in here.
142    **/
143   class Exception : public std::exception
144   {
145     friend std::ostream & operator<<( std::ostream & str, const Exception & obj );
146
147   public:
148     typedef exception_detail::CodeLocation CodeLocation;
149     typedef std::list<std::string>         History;
150     typedef History::const_iterator        HistoryIterator;
151     typedef History::size_type             HistorySize;
152
153     /** Default ctor.
154      * Use \ref ZYPP_THROW to throw exceptions.
155     */
156     Exception();
157
158     /** Ctor taking a message.
159      * Use \ref ZYPP_THROW to throw exceptions.
160     */
161     Exception( const std::string & msg_r );
162
163     /** Ctor taking a message and an exception to remember as history
164      * \see \ref remember
165      * Use \ref ZYPP_THROW to throw exceptions.
166     */
167     Exception( const std::string & msg_r, const Exception & history_r );
168
169     /** Dtor. */
170     virtual ~Exception() throw();
171
172     /** Return CodeLocation. */
173     const CodeLocation & where() const
174     { return _where; }
175
176     /** Exchange location on rethrow. */
177     void relocate( const CodeLocation & where_r ) const
178     { _where = where_r; }
179
180     /** Return the message string provided to the ctor.
181      * \note This is not necessarily the complete error message.
182      * The whole error message is provided by \ref asString or
183      * \ref dumpOn.
184     */
185     const std::string & msg() const
186     { return _msg; }
187
188     /** Error message provided by \ref dumpOn as string. */
189     std::string asString() const;
190
191     /** Translated error message as string suitable for the user.
192      * \see \ref asUserStringHistory
193     */
194     std::string asUserString() const;
195
196   public:
197     /** \name History list of message strings.
198      * Maintain a simple list of individual error messages, that lead
199      * to this Exception. The Exceptions message itself is not included
200      * in the history. The History list stores the most recent message
201      * fist.
202      */
203     //@{
204
205     /** Store an other Exception as history. */
206     void remember( const Exception & old_r );
207
208     /** Add some message text to the history. */
209     void addHistory( const std::string & msg_r );
210
211     /** Iterator pointing to the most recent message. */
212     HistoryIterator historyBegin() const
213     { return _history.begin(); }
214
215     /** Iterator pointing behind the last message. */
216     HistoryIterator historyEnd() const
217     { return _history.end(); }
218
219     /** Whether the history list is empty. */
220     bool historyEmpty() const
221     { return _history.empty(); }
222
223     /** The size of the history list. */
224     HistorySize historySize() const
225     { return _history.size(); }
226
227     /** The history as string. Empty if \ref historyEmpty.
228      * Otherwise:
229      * \code
230      * History:
231      *  - most recent message
232      *  - 2nd message
233      * ...
234      *  - oldest message
235      * \endcode
236     */
237     std::string historyAsString() const;
238
239     /** A single (multiline) string composed of \ref asUserString  and  \ref historyAsString. */
240     std::string asUserHistory() const;
241     //@}
242
243   protected:
244
245     /** Overload this to print a proper error message. */
246     virtual std::ostream & dumpOn( std::ostream & str ) const;
247
248   public:
249      /** Make a string from \a errno_r. */
250     static std::string strErrno( int errno_r );
251      /** Make a string from \a errno_r and \a msg_r. */
252     static std::string strErrno( int errno_r, const std::string & msg_r );
253
254   public:
255     /** Drop a logline on throw, catch or rethrow.
256      * Used by \ref ZYPP_THROW macros.
257     */
258     static void log( const Exception & excpt_r, const CodeLocation & where_r,
259                      const char *const prefix_r );
260
261   private:
262     mutable CodeLocation _where;
263     std::string          _msg;
264     History              _history;
265
266     /** Return message string. */
267     virtual const char * what() const throw()
268     { return _msg.c_str(); }
269
270     /** Called by <tt>std::ostream & operator\<\<</tt>.
271      * Prints \ref CodeLocation and the error message provided by
272      * \ref dumpOn.
273     */
274     std::ostream & dumpError( std::ostream & str ) const;
275   };
276   ///////////////////////////////////////////////////////////////////
277
278   /** \relates Exception Stream output */
279   std::ostream & operator<<( std::ostream & str, const Exception & obj );
280
281   ///////////////////////////////////////////////////////////////////
282   namespace exception_detail
283   {
284     /** Helper for \ref ZYPP_THROW. */
285     template<class TExcpt>
286     void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
287     template<class TExcpt>
288     void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r )
289     {
290       excpt_r.relocate( where_r );
291       Exception::log( excpt_r, where_r, "THROW:   " );
292       throw( excpt_r );
293     }
294
295     /** Helper for \ref ZYPP_THROW. */
296     template<class TExcpt>
297     void do_ZYPP_CAUGHT( const TExcpt & excpt_r, const CodeLocation & where_r )
298     {
299       Exception::log( excpt_r, where_r, "CAUGHT:  " );
300     }
301
302     /** Helper for \ref ZYPP_THROW. */
303     template<class TExcpt>
304     void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
305     template<class TExcpt>
306     void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r )
307     {
308       Exception::log( excpt_r, where_r, "RETHROW: " );
309       excpt_r.relocate( where_r );
310       throw;
311     }
312   } // namespace exception_detail
313   ///////////////////////////////////////////////////////////////////
314
315   /** \defgroup ZYPP_THROW ZYPP_THROW macros
316    * Macros for throwing Exception.
317    * \see \ref zypp::Exception for an example.
318   */
319   //@{
320   /** Drops a logline and throws the Exception. */
321 #define ZYPP_THROW(EXCPT)\
322   ::zypp::exception_detail::do_ZYPP_THROW( EXCPT, ZYPP_EX_CODELOCATION )
323
324   /** Drops a logline telling the Exception was caught (in order to handle it). */
325 #define ZYPP_CAUGHT(EXCPT)\
326   ::zypp::exception_detail::do_ZYPP_CAUGHT( EXCPT, ZYPP_EX_CODELOCATION )
327
328   /** Drops a logline and rethrows, updating the CodeLocation. */
329 #define ZYPP_RETHROW(EXCPT)\
330   ::zypp::exception_detail::do_ZYPP_RETHROW( EXCPT, ZYPP_EX_CODELOCATION )
331
332
333   /** Throw Exception built from a message string. */
334 #define ZYPP_THROW_MSG(EXCPTTYPE, MSG)\
335   ZYPP_THROW( EXCPTTYPE( MSG ) )
336
337   /** Throw Exception built from errno. */
338 #define ZYPP_THROW_ERRNO(EXCPTTYPE)\
339   ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno) ) )
340
341   /** Throw Exception built from errno provided as argument. */
342 #define ZYPP_THROW_ERRNO1(EXCPTTYPE, ERRNO)\
343   ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO) ) )
344
345   /** Throw Exception built from errno and a message string. */
346 #define ZYPP_THROW_ERRNO_MSG(EXCPTTYPE, MSG)\
347   ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno,MSG) ) )
348
349   /** Throw Exception built from errno provided as argument and a message string */
350 #define ZYPP_THROW_ERRNO_MSG1(EXCPTTYPE, ERRNO,MSG)\
351   ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO,MSG) ) )
352   //@}
353
354   /////////////////////////////////////////////////////////////////
355 } // namespace zypp
356 ///////////////////////////////////////////////////////////////////
357 #endif // ZYPP_BASE_EXCEPTION_H