1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/Exception.h
12 #ifndef ZYPP_BASE_EXCEPTION_H
13 #define ZYPP_BASE_EXCEPTION_H
20 #include <type_traits>
22 #include "zypp/base/Errno.h"
24 ///////////////////////////////////////////////////////////////////
26 { /////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////
28 namespace exception_detail
29 { /////////////////////////////////////////////////////////////////
31 /** Keep _FILE_, _FUNCTION_ and _LINE_.
32 * Construct it using the \ref ZYPP_EX_CODELOCATION macro.
36 friend std::ostream & operator<<( std::ostream & str, const CodeLocation & obj );
44 CodeLocation( const std::string & file_r,
45 const std::string & func_r,
47 : _file( file_r ), _func( func_r ), _line( line_r )
50 /** Location as string */
51 std::string asString() const;
58 ///////////////////////////////////////////////////////////////////
60 /** Create CodeLocation object storing the current location. */
61 //#define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(__FILE__,__FUNCTION__,__LINE__)
62 #define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(( *__FILE__ == '/' ? strrchr( __FILE__, '/' ) + 1 : __FILE__ ),__FUNCTION__,__LINE__)
64 /** \relates CodeLocation Stream output */
65 std::ostream & operator<<( std::ostream & str, const CodeLocation & obj );
67 /////////////////////////////////////////////////////////////////
68 } // namespace exception_detail
69 ///////////////////////////////////////////////////////////////////
71 ///////////////////////////////////////////////////////////////////
73 // CLASS NAME : Exception
74 /** Base class for Exception.
76 * Exception offers to store a message string passed to the ctor.
77 * Derived classes may provide additional information. Overload
78 * \ref dumpOn to provide a proper error text.
80 * \li Use \ref ZYPP_THROW to throw exceptions.
81 * \li Use \ref ZYPP_CAUGHT If you caught an exceptions in order to handle it.
82 * \li Use \ref ZYPP_RETHROW to rethrow a caught exception.
84 * The use of these macros is not mandatory. but \c ZYPP_THROW and
85 * \c ZYPP_RETHROW will adjust the code location information stored in
86 * the Exception. All three macros will drop a line in the logfile.
93 * 47 ZYPP_THROW( Exception("Something bad happened.") );
95 * 49 catch ( Exception & excpt )
97 * 51 ZYPP_RETHROW( excpt );
101 * 55 catch ( Exception & excpt )
103 * 57 ZYPP_CAUGHT( excpt );
106 * The above produces the following log lines:
108 * Main.cc(main):47 THROW: Main.cc(main):47: Something bad happened.
109 * Main.cc(main):51 RETHROW: Main.cc(main):47: Something bad happened.
110 * Main.cc(main):57 CAUGHT: Main.cc(main):51: Something bad happened.
114 * Class Exception now offers a history list of message strings.
115 * These messages should describe what lead to the exception.
117 * The Exceptions message itself is NOT included in the history.
119 * Rethrow, remembering an old exception:
125 * catch( const Exception & olderr_r )
127 * ZYPP_CAUGHT( olderr_r )
128 * HighLevelException newerr( "Something failed." );
129 * newerr.rember( olderr_r );
130 * ZYPP_THROW( newerr );
134 * Print an Exception followed by it's history if available:
137 * ERR << error << endl << error.historyAsString();
140 * \todo That's a draft to have a common way of throwing exceptions.
141 * Most probabely we'll finally use blocxx exceptions. Here, but not
142 * in the remaining code of zypp. If we can we should try to wrap
143 * the blocxx macros and typedef the classes in here.
145 class Exception : public std::exception
147 friend std::ostream & operator<<( std::ostream & str, const Exception & obj );
150 typedef exception_detail::CodeLocation CodeLocation;
151 typedef std::list<std::string> History;
152 typedef History::const_iterator HistoryIterator;
153 typedef History::size_type HistorySize;
156 * Use \ref ZYPP_THROW to throw exceptions.
160 /** Ctor taking a message.
161 * Use \ref ZYPP_THROW to throw exceptions.
163 Exception( const std::string & msg_r );
165 Exception( std::string && msg_r );
167 /** Ctor taking a message and an exception to remember as history
169 * Use \ref ZYPP_THROW to throw exceptions.
171 Exception( const std::string & msg_r, const Exception & history_r );
172 /** \overload moving */
173 Exception( std::string && msg_r, const Exception & history_r );
174 /** \overload moving */
175 Exception( const std::string & msg_r, Exception && history_r );
176 /** \overload moving */
177 Exception( std::string && msg_r, Exception && history_r );
180 virtual ~Exception() throw();
182 /** Return CodeLocation. */
183 const CodeLocation & where() const
186 /** Exchange location on rethrow. */
187 void relocate( const CodeLocation & where_r ) const
188 { _where = where_r; }
190 /** Return the message string provided to the ctor.
191 * \note This is not necessarily the complete error message.
192 * The whole error message is provided by \ref asString or
195 const std::string & msg() const
198 /** Error message provided by \ref dumpOn as string. */
199 std::string asString() const;
201 /** Translated error message as string suitable for the user.
202 * \see \ref asUserStringHistory
204 std::string asUserString() const;
207 /** \name History list of message strings.
208 * Maintain a simple list of individual error messages, that lead
209 * to this Exception. The Exceptions message itself is not included
210 * in the history. The History list stores the most recent message
215 /** Store an other Exception as history. */
216 void remember( const Exception & old_r );
217 /** \overload moving */
218 void remember( Exception && old_r );
220 /** Add some message text to the history. */
221 void addHistory( const std::string & msg_r );
222 /** \overload moving */
223 void addHistory( std::string && msg_r );
225 /** \ref addHistory from string container types (oldest first) */
226 template<class TContainer>
227 void addToHistory( const TContainer & msgc_r )
229 for ( const std::string & el : msgc_r )
232 /** \ref addHistory from string container types (oldest first) moving */
233 template<class TContainer>
234 void moveToHistory( TContainer && msgc_r )
236 for ( std::string & el : msgc_r )
237 addHistory( std::move(el) );
240 /** Iterator pointing to the most recent message. */
241 HistoryIterator historyBegin() const
242 { return _history.begin(); }
244 /** Iterator pointing behind the last message. */
245 HistoryIterator historyEnd() const
246 { return _history.end(); }
248 /** Whether the history list is empty. */
249 bool historyEmpty() const
250 { return _history.empty(); }
252 /** The size of the history list. */
253 HistorySize historySize() const
254 { return _history.size(); }
256 /** The history as string. Empty if \ref historyEmpty.
260 * - most recent message
266 std::string historyAsString() const;
268 /** A single (multiline) string composed of \ref asUserString and \ref historyAsString. */
269 std::string asUserHistory() const;
274 /** Overload this to print a proper error message. */
275 virtual std::ostream & dumpOn( std::ostream & str ) const;
278 /** Make a string from \a errno_r. */
279 static std::string strErrno( int errno_r );
280 /** Make a string from \a errno_r and \a msg_r. */
281 static std::string strErrno( int errno_r, const std::string & msg_r );
282 /** \overload moving */
283 static std::string strErrno( int errno_r, std::string && msg_r );
286 /** Drop a logline on throw, catch or rethrow.
287 * Used by \ref ZYPP_THROW macros.
289 static void log( const Exception & excpt_r, const CodeLocation & where_r,
290 const char *const prefix_r );
291 /** \overrload for not-Exception types thrown via ZYPP_THROW */
292 static void log( const char * typename_r, const CodeLocation & where_r,
293 const char *const prefix_r );
295 mutable CodeLocation _where;
299 /** Return message string. */
300 virtual const char * what() const throw()
301 { return _msg.c_str(); }
303 /** Called by <tt>std::ostream & operator\<\<</tt>.
304 * Prints \ref CodeLocation and the error message provided by
307 std::ostream & dumpError( std::ostream & str ) const;
309 ///////////////////////////////////////////////////////////////////
311 /** \relates Exception Stream output */
312 std::ostream & operator<<( std::ostream & str, const Exception & obj );
314 ///////////////////////////////////////////////////////////////////
315 namespace exception_detail
317 /** SFINAE: Hide template signature unless \a TExcpt is derived from \ref Exception. */
318 template<class TExcpt>
319 using EnableIfIsException = typename std::enable_if< std::is_base_of<Exception,TExcpt>::value, int>::type;
321 /** SFINAE: Hide template signature if \a TExcpt is derived from \ref Exception. */
322 template<class TExcpt>
323 using EnableIfNotException = typename std::enable_if< !std::is_base_of<Exception,TExcpt>::value, int>::type;
326 /** Helper for \ref ZYPP_THROW( Exception ). */
327 template<class TExcpt, EnableIfIsException<TExcpt> = 0>
328 void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
329 template<class TExcpt, EnableIfIsException<TExcpt>>
330 void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r )
332 excpt_r.relocate( where_r );
333 Exception::log( excpt_r, where_r, "THROW: " );
337 /** Helper for \ref ZYPP_THROW( not Exception ). */
338 template<class TExcpt, EnableIfNotException<TExcpt> = 0>
339 void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
340 template<class TExcpt, EnableIfNotException<TExcpt>>
341 void do_ZYPP_THROW( const TExcpt & excpt_r, const CodeLocation & where_r )
343 Exception::log( typeid(excpt_r).name(), where_r, "THROW: " );
348 /** Helper for \ref ZYPP_THROW( Exception ). */
349 template<class TExcpt, EnableIfIsException<TExcpt> = 0>
350 void do_ZYPP_CAUGHT( const TExcpt & excpt_r, const CodeLocation & where_r )
352 Exception::log( excpt_r, where_r, "CAUGHT: " );
355 /** Helper for \ref ZYPP_THROW( not Exception ). */
356 template<class TExcpt, EnableIfNotException<TExcpt> = 0>
357 void do_ZYPP_CAUGHT( const TExcpt & excpt_r, const CodeLocation & where_r )
359 Exception::log( typeid(excpt_r).name(), where_r, "CAUGHT: " );
363 /** Helper for \ref ZYPP_THROW( Exception ). */
364 template<class TExcpt, EnableIfIsException<TExcpt> = 0>
365 void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
366 template<class TExcpt, EnableIfIsException<TExcpt>>
367 void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r )
369 Exception::log( excpt_r, where_r, "RETHROW: " );
370 excpt_r.relocate( where_r );
374 /** Helper for \ref ZYPP_THROW( not Exception ). */
375 template<class TExcpt, EnableIfNotException<TExcpt> = 0>
376 void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r ) __attribute__((noreturn));
377 template<class TExcpt, EnableIfNotException<TExcpt>>
378 void do_ZYPP_RETHROW( const TExcpt & excpt_r, const CodeLocation & where_r )
380 Exception::log( excpt_r, where_r, "RETHROW: " );
383 } // namespace exception_detail
384 ///////////////////////////////////////////////////////////////////
386 /** \defgroup ZYPP_THROW ZYPP_THROW macros
387 * Macros for throwing Exception.
388 * \see \ref zypp::Exception for an example.
391 /** Drops a logline and throws the Exception. */
392 #define ZYPP_THROW(EXCPT)\
393 ::zypp::exception_detail::do_ZYPP_THROW( EXCPT, ZYPP_EX_CODELOCATION )
395 /** Drops a logline telling the Exception was caught (in order to handle it). */
396 #define ZYPP_CAUGHT(EXCPT)\
397 ::zypp::exception_detail::do_ZYPP_CAUGHT( EXCPT, ZYPP_EX_CODELOCATION )
399 /** Drops a logline and rethrows, updating the CodeLocation. */
400 #define ZYPP_RETHROW(EXCPT)\
401 ::zypp::exception_detail::do_ZYPP_RETHROW( EXCPT, ZYPP_EX_CODELOCATION )
404 /** Throw Exception built from a message string. */
405 #define ZYPP_THROW_MSG(EXCPTTYPE, MSG)\
406 ZYPP_THROW( EXCPTTYPE( MSG ) )
408 /** Throw Exception built from errno. */
409 #define ZYPP_THROW_ERRNO(EXCPTTYPE)\
410 ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno) ) )
412 /** Throw Exception built from errno provided as argument. */
413 #define ZYPP_THROW_ERRNO1(EXCPTTYPE, ERRNO)\
414 ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO) ) )
416 /** Throw Exception built from errno and a message string. */
417 #define ZYPP_THROW_ERRNO_MSG(EXCPTTYPE, MSG)\
418 ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno,MSG) ) )
420 /** Throw Exception built from errno provided as argument and a message string */
421 #define ZYPP_THROW_ERRNO_MSG1(EXCPTTYPE, ERRNO,MSG)\
422 ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO,MSG) ) )
425 /////////////////////////////////////////////////////////////////
427 ///////////////////////////////////////////////////////////////////
428 #endif // ZYPP_BASE_EXCEPTION_H