#ifndef ZYPP_BASE_EXCEPTION_H
#define ZYPP_BASE_EXCEPTION_H
-#include <cerrno>
#include <iosfwd>
+#include <string>
+#include <list>
#include <stdexcept>
+#include "zypp/base/Errno.h"
+
///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/** Create CodeLocation object storing the current location. */
- #define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(__FILE__,__FUNCTION__,__LINE__)
+ //#define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(__FILE__,__FUNCTION__,__LINE__)
+#define ZYPP_EX_CODELOCATION ::zypp::exception_detail::CodeLocation(( *__FILE__ == '/' ? strrchr( __FILE__, '/' ) + 1 : __FILE__ ),__FUNCTION__,__LINE__)
/** \relates CodeLocation Stream output */
std::ostream & operator<<( std::ostream & str, const CodeLocation & obj );
///////////////////////////////////////////////////////////////////
//
// CLASS NAME : Exception
- /** Exception stores message and \ref CodeLocation.
+ /** Base class for Exception.
+ *
+ * Exception offers to store a message string passed to the ctor.
+ * Derived classes may provide additional information. Overload
+ * \ref dumpOn to provide a proper error text.
+ *
+ * \li Use \ref ZYPP_THROW to throw exceptions.
+ * \li Use \ref ZYPP_CAUGHT If you caught an exceptions in order to handle it.
+ * \li Use \ref ZYPP_RETHROW to rethrow a caught exception.
*
- * Use \ref ZYPP_THROW to throw exceptions.
+ * The use of these macros is not mandatory. but \c ZYPP_THROW and
+ * \c ZYPP_RETHROW will adjust the code location information stored in
+ * the Exception. All three macros will drop a line in the logfile.
+
* \code
* 43 try
* 44 {
* 45 try
* 46 {
- * 47 ZYPP_THROW( Exception, "Something bad happened." );
+ * 47 ZYPP_THROW( Exception("Something bad happened.") );
* 48 }
* 49 catch ( Exception & excpt )
* 50 {
* Main.cc(main):57 CAUGHT: Main.cc(main):51: Something bad happened.
* \endcode
*
+ *
+ * Class Exception now offers a history list of message strings.
+ * These messages should describe what lead to the exception.
+ *
+ * The Exceptions message itself is NOT included in the history.
+ *
+ * Rethrow, remembering an old exception:
+ * \code
+ * try
+ * {
+ * ....
+ * }
+ * catch( const Exception & olderr_r )
+ * {
+ * ZYPP_CAUGHT( olderr_r )
+ * HighLevelException newerr( "Something failed." );
+ * newerr.rember( olderr_r );
+ * ZYPP_THROW( newerr );
+ * }
+ * \endcode
+ *
+ * Print an Exception followed by it's history if available:
+ * \code
+ * Exception error;
+ * ERR << error << endl << error.historyAsString();
+ * \endcode
+ *
* \todo That's a draft to have a common way of throwing exceptions.
* Most probabely we'll finally use blocxx exceptions. Here, but not
* in the remaining code of zypp. If we can we should try to wrap
* the blocxx macros and typedef the classes in here.
- *
- * \todo maybe location and message stack.
**/
class Exception : public std::exception
{
public:
typedef exception_detail::CodeLocation CodeLocation;
+ typedef std::list<std::string> History;
+ typedef History::const_iterator HistoryIterator;
+ typedef History::size_type HistorySize;
/** Default ctor.
* Use \ref ZYPP_THROW to throw exceptions.
*/
Exception( const std::string & msg_r );
+ /** Ctor taking a message and an exception to remember as history
+ * \see \ref remember
+ * Use \ref ZYPP_THROW to throw exceptions.
+ */
+ Exception( const std::string & msg_r, const Exception & history_r );
+
/** Dtor. */
virtual ~Exception() throw();
void relocate( const CodeLocation & where_r ) const
{ _where = where_r; }
- /** Return the provided message string. */
+ /** Return the message string provided to the ctor.
+ * \note This is not necessarily the complete error message.
+ * The whole error message is provided by \ref asString or
+ * \ref dumpOn.
+ */
const std::string & msg() const
{ return _msg; }
- /** Return message string. */
- virtual const char * what() const throw()
- { return _msg.c_str(); }
-
- /** Exception as string */
+ /** Error message provided by \ref dumpOn as string. */
std::string asString() const;
- protected:
+ /** Translated error message as string suitable for the user.
+ * \see \ref asUserStringHistory
+ */
+ std::string asUserString() const;
- /** Overload this to print a proper error message.
- * CodeLocation is prepended automatically.
+ public:
+ /** \name History list of message strings.
+ * Maintain a simple list of individual error messages, that lead
+ * to this Exception. The Exceptions message itself is not included
+ * in the history. The History list stores the most recent message
+ * fist.
+ */
+ //@{
+
+ /** Store an other Exception as history. */
+ void remember( const Exception & old_r );
+
+ /** Add some message text to the history. */
+ void addHistory( const std::string & msg_r );
+
+ /** Iterator pointing to the most recent message. */
+ HistoryIterator historyBegin() const
+ { return _history.begin(); }
+
+ /** Iterator pointing behind the last message. */
+ HistoryIterator historyEnd() const
+ { return _history.end(); }
+
+ /** Whether the history list is empty. */
+ bool historyEmpty() const
+ { return _history.empty(); }
+
+ /** The size of the history list. */
+ HistorySize historySize() const
+ { return _history.size(); }
+
+ /** The history as string. Empty if \ref historyEmpty.
+ * Otherwise:
+ * \code
+ * History:
+ * - most recent message
+ * - 2nd message
+ * ...
+ * - oldest message
+ * \endcode
*/
+ std::string historyAsString() const;
+
+ /** A single (multiline) string composed of \ref asUserString and \ref historyAsString. */
+ std::string asUserHistory() const;
+ //@}
+
+ protected:
+
+ /** Overload this to print a proper error message. */
virtual std::ostream & dumpOn( std::ostream & str ) const;
public:
static std::string strErrno( int errno_r, const std::string & msg_r );
public:
- /** Drop a logline. */
+ /** Drop a logline on throw, catch or rethrow.
+ * Used by \ref ZYPP_THROW macros.
+ */
static void log( const Exception & excpt_r, const CodeLocation & where_r,
const char *const prefix_r );
private:
mutable CodeLocation _where;
- std::string _msg;
+ std::string _msg;
+ History _history;
- /** Called by <tt>std::ostream & operator\<\<</tt> */
+ /** Return message string. */
+ virtual const char * what() const throw()
+ { return _msg.c_str(); }
+
+ /** Called by <tt>std::ostream & operator\<\<</tt>.
+ * Prints \ref CodeLocation and the error message provided by
+ * \ref dumpOn.
+ */
std::ostream & dumpError( std::ostream & str ) const;
};
///////////////////////////////////////////////////////////////////
/** Helper for \ref ZYPP_THROW. */
template<class _Excpt>
+ void _ZYPP_THROW( const _Excpt & excpt_r, const exception_detail::CodeLocation & where_r ) __attribute__((noreturn));
+ template<class _Excpt>
void _ZYPP_THROW( const _Excpt & excpt_r, const exception_detail::CodeLocation & where_r )
{
excpt_r.relocate( where_r );
/** Helper for \ref ZYPP_THROW. */
template<class _Excpt>
+ void _ZYPP_RETHROW( const _Excpt & excpt_r, const exception_detail::CodeLocation & where_r ) __attribute__((noreturn));
+ template<class _Excpt>
void _ZYPP_RETHROW( const _Excpt & excpt_r, const exception_detail::CodeLocation & where_r )
{
Exception::log( excpt_r, where_r, "RETHROW: " );
excpt_r.relocate( where_r );
- throw excpt_r;
+ throw;
}
///////////////////////////////////////////////////////////////////
*/
//@{
/** Drops a logline and throws the Exception. */
-#define ZYPP_DOTHROW(EXCPT)\
+#define ZYPP_THROW(EXCPT)\
_ZYPP_THROW( EXCPT, ZYPP_EX_CODELOCATION )
/** Drops a logline telling the Exception was caught (in order to handle it). */
/** Throw Exception built from a message string. */
-#define ZYPP_THROW(EXCPTTYPE, MSG)\
- ZYPP_DOTHROW( EXCPTTYPE( MSG ) )
-
- /** Throw Exception built from a message string. */
#define ZYPP_THROW_MSG(EXCPTTYPE, MSG)\
- ZYPP_DOTHROW( EXCPTTYPE( MSG ) )
+ ZYPP_THROW( EXCPTTYPE( MSG ) )
/** Throw Exception built from errno. */
#define ZYPP_THROW_ERRNO(EXCPTTYPE)\
- ZYPP_DOTHROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno) ) )
+ ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno) ) )
/** Throw Exception built from errno provided as argument. */
#define ZYPP_THROW_ERRNO1(EXCPTTYPE, ERRNO)\
- ZYPP_DOTHROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO) ) )
+ ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO) ) )
/** Throw Exception built from errno and a message string. */
#define ZYPP_THROW_ERRNO_MSG(EXCPTTYPE, MSG)\
- ZYPP_DOTHROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno,MSG) ) )
+ ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(errno,MSG) ) )
/** Throw Exception built from errno provided as argument and a message string */
#define ZYPP_THROW_ERRNO_MSG1(EXCPTTYPE, ERRNO,MSG)\
- ZYPP_DOTHROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO,MSG) ) )
+ ZYPP_THROW( EXCPTTYPE( ::zypp::Exception::strErrno(ERRNO,MSG) ) )
//@}
/////////////////////////////////////////////////////////////////