Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / base / Exception.h
index 29f7eb9..4d0f5be 100644 (file)
 #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
 { /////////////////////////////////////////////////////////////////
@@ -53,7 +56,8 @@ 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 );
@@ -65,15 +69,26 @@ namespace zypp
   ///////////////////////////////////////////////////////////////////
   //
   //   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         {
@@ -93,12 +108,37 @@ namespace zypp
    *  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
   {
@@ -106,6 +146,9 @@ namespace zypp
 
   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.
@@ -117,6 +160,12 @@ namespace zypp
     */
     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();
 
@@ -128,22 +177,72 @@ namespace zypp
     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:
@@ -153,15 +252,25 @@ namespace zypp
     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;
   };
   ///////////////////////////////////////////////////////////////////
@@ -173,6 +282,8 @@ namespace zypp
 
   /** 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 );
@@ -189,11 +300,13 @@ namespace zypp
 
   /** 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;
     }
 
   ///////////////////////////////////////////////////////////////////
@@ -204,7 +317,7 @@ namespace zypp
   */
   //@{
   /** 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). */
@@ -217,28 +330,24 @@ namespace zypp
 
 
   /** 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) ) )
   //@}
 
   /////////////////////////////////////////////////////////////////