* apt-pkg/contrib/error.{cc,h}:
authorDavid Kalnischkies <kalnischkies@gmail.com>
Fri, 25 Jun 2010 06:01:48 +0000 (08:01 +0200)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Fri, 25 Jun 2010 06:01:48 +0000 (08:01 +0200)
  - complete rewrite but use the same API
  - add NOTICE and DEBUG as new types of a message

apt-pkg/contrib/error.cc
apt-pkg/contrib/error.h
debian/changelog

dissimilarity index 71%
index 927b7e0..837d9e6 100644 (file)
-// -*- mode: cpp; mode: fold -*-
-// Description                                                         /*{{{*/
-// $Id: error.cc,v 1.11 2002/03/26 07:38:58 jgg Exp $
-/* ######################################################################
-   
-   Global Erorr Class - Global error mechanism
-
-   We use a simple STL vector to store each error record. A PendingFlag
-   is kept which indicates when the vector contains a Sever error.
-   
-   This source is placed in the Public Domain, do with it what you will
-   It was originally written by Jason Gunthorpe.
-   
-   ##################################################################### */
-                                                                       /*}}}*/
-// Include Files                                                       /*{{{*/
-#include <apt-pkg/error.h>
-
-#include <iostream>
-#include <errno.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-
-#include <string>
-#include <cstring>
-
-#include "config.h"
-                                                                       /*}}}*/
-
-using namespace std;
-
-// Global Error Object                                                 /*{{{*/
-/* If the implementation supports posix threads then the accessor function
-   is compiled to be thread safe otherwise a non-safe version is used. A
-   Per-Thread error object is maintained in much the same manner as libc
-   manages errno */
-#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
- #include <pthread.h>
-
- static pthread_key_t ErrorKey;
- static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
- static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
-
- GlobalError *_GetErrorObj()
- {
-    static pthread_once_t Once = PTHREAD_ONCE_INIT;
-    pthread_once(&Once,KeyAlloc);
-    
-    void *Res = pthread_getspecific(ErrorKey);
-    if (Res == 0)
-       pthread_setspecific(ErrorKey,Res = new GlobalError);
-    return (GlobalError *)Res;
- }
-#else
- GlobalError *_GetErrorObj()
- {
-    static GlobalError *Obj = new GlobalError;
-    return Obj;
- }
-#endif
-                                                                       /*}}}*/
-
-// GlobalError::GlobalError - Constructor                              /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-GlobalError::GlobalError() : List(0), PendingFlag(false)
-{
-}
-                                                                       /*}}}*/
-// GlobalError::Errno - Get part of the error string from errno                /*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
-   a user string that leads the text. Form is:
-     Description - Function (errno: strerror)
-   Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::Errno(const char *Function,const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
-
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-   snprintf(S + strlen(S),sizeof(S) - strlen(S),
-           " - %s (%i: %s)",Function,errno,strerror(errno));
-
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = true;
-   Insert(Itm);
-
-   PendingFlag = true;
-
-   return false;
-}
-                                                                       /*}}}*/
-// GlobalError::WarningE - Get part of the warn string from errno      /*{{{*/
-// ---------------------------------------------------------------------
-/* Function indicates the stdlib function that failed and Description is
-   a user string that leads the text. Form is:
-     Description - Function (errno: strerror)
-   Carefull of the buffer overrun, sprintf.
- */
-bool GlobalError::WarningE(const char *Function,const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
-
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-   snprintf(S + strlen(S),sizeof(S) - strlen(S),
-           " - %s (%i: %s)",Function,errno,strerror(errno));
-
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = false;
-   Insert(Itm);
-
-   return false;
-}
-                                                                       /*}}}*/
-// GlobalError::Error - Add an error to the list                       /*{{{*/
-// ---------------------------------------------------------------------
-/* Just vsprintfs and pushes */
-bool GlobalError::Error(const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
-
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = true;
-   Insert(Itm);
-   
-   PendingFlag = true;
-   
-   return false;
-}
-                                                                       /*}}}*/
-// GlobalError::Warning - Add a warning to the list                    /*{{{*/
-// ---------------------------------------------------------------------
-/* This doesn't set the pending error flag */
-bool GlobalError::Warning(const char *Description,...)
-{
-   va_list args;
-   va_start(args,Description);
-
-   // sprintf the description
-   char S[400];
-   vsnprintf(S,sizeof(S),Description,args);
-
-   // Put it on the list
-   Item *Itm = new Item;
-   Itm->Text = S;
-   Itm->Error = false;
-   Insert(Itm);
-   
-   return false;
-}
-                                                                       /*}}}*/
-// GlobalError::PopMessage - Pulls a single message out                        /*{{{*/
-// ---------------------------------------------------------------------
-/* This should be used in a loop checking empty() each cycle. It returns
-   true if the message is an error. */
-bool GlobalError::PopMessage(string &Text)
-{
-   if (List == 0)
-      return false;
-      
-   bool Ret = List->Error;
-   Text = List->Text;
-   Item *Old = List;
-   List = List->Next;
-   delete Old;
-   
-   // This really should check the list to see if only warnings are left..
-   if (List == 0)
-      PendingFlag = false;
-   
-   return Ret;
-}
-                                                                       /*}}}*/
-// GlobalError::DumpErrors - Dump all of the errors/warns to cerr      /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::DumpErrors()
-{
-   // Print any errors or warnings found
-   string Err;
-   while (empty() == false)
-   {
-      bool Type = PopMessage(Err);
-      if (Type == true)
-        cerr << "E: " << Err << endl;
-      else
-        cerr << "W: " << Err << endl;
-   }
-}
-                                                                       /*}}}*/
-// GlobalError::Discard - Discard                                                                      /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Discard()
-{
-   while (List != 0)
-   {
-      Item *Old = List;
-      List = List->Next;
-      delete Old;
-   }
-   
-   PendingFlag = false;
-};
-                                                                       /*}}}*/
-// GlobalError::Insert - Insert a new item at the end                  /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void GlobalError::Insert(Item *Itm)
-{
-   Item **End = &List;
-   for (Item *I = List; I != 0; I = I->Next)
-      End = &I->Next;
-   Itm->Next = *End;
-   *End = Itm;
-}
-                                                                       /*}}}*/
+// -*- mode: cpp; mode: fold -*-
+// Description                                                         /*{{{*/
+/* ######################################################################
+
+   Global Error Class - Global error mechanism
+
+   We use a simple STL vector to store each error record. A PendingFlag
+   is kept which indicates when the vector contains a Sever error.
+
+   This source is placed in the Public Domain, do with it what you will
+   It was originally written by Jason Gunthorpe.
+
+   ##################################################################### */
+                                                                       /*}}}*/
+// Include Files                                                       /*{{{*/
+#include <apt-pkg/error.h>
+
+#include <iostream>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <string>
+#include <cstring>
+
+#include "config.h"
+                                                                       /*}}}*/
+
+// Global Error Object                                                 /*{{{*/
+/* If the implementation supports posix threads then the accessor function
+   is compiled to be thread safe otherwise a non-safe version is used. A
+   Per-Thread error object is maintained in much the same manner as libc
+   manages errno */
+#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
+       #include <pthread.h>
+
+       static pthread_key_t ErrorKey;
+       static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
+       static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
+
+       GlobalError *_GetErrorObj() {
+               static pthread_once_t Once = PTHREAD_ONCE_INIT;
+               pthread_once(&Once,KeyAlloc);
+
+               void *Res = pthread_getspecific(ErrorKey);
+               if (Res == 0)
+                       pthread_setspecific(ErrorKey,Res = new GlobalError);
+               return (GlobalError *)Res;
+       }
+#else
+       GlobalError *_GetErrorObj() {
+               static GlobalError *Obj = new GlobalError;
+               return Obj;
+       }
+#endif
+                                                                       /*}}}*/
+// GlobalError::GlobalError - Constructor                              /*{{{*/
+GlobalError::GlobalError() : PendingFlag(false) {}
+                                                                       /*}}}*/
+// GlobalError::FatalE - Get part of the error string from errno       /*{{{*/
+bool GlobalError::FatalE(const char *Function,const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return InsertErrno(FATAL, Function, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Errno - Get part of the error string from errno                /*{{{*/
+bool GlobalError::Errno(const char *Function,const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return InsertErrno(ERROR, Function, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::WarningE - Get part of the warning string from errno   /*{{{*/
+bool GlobalError::WarningE(const char *Function,const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return InsertErrno(WARNING, Function, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::NoticeE - Get part of the notice string from errno     /*{{{*/
+bool GlobalError::NoticeE(const char *Function,const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return InsertErrno(NOTICE, Function, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::DebugE - Get part of the debug string from errno       /*{{{*/
+bool GlobalError::DebugE(const char *Function,const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return InsertErrno(DEBUG, Function, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::InsertErrno - formats an error message with the errno  /*{{{*/
+bool GlobalError::InsertErrno(MsgType type, const char* Function,
+                             const char* Description, va_list const &args) {
+       char S[400];
+       vsnprintf(S,sizeof(S),Description,args);
+       snprintf(S + strlen(S),sizeof(S) - strlen(S),
+                " - %s (%i: %s)", Function, errno, strerror(errno));
+       return Insert(type, S, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Fatal - Add a fatal error to the list                  /*{{{*/
+bool GlobalError::Fatal(const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return Insert(FATAL, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Error - Add an error to the list                       /*{{{*/
+bool GlobalError::Error(const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return Insert(ERROR, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Warning - Add a warning to the list                    /*{{{*/
+bool GlobalError::Warning(const char *Description,...) {
+       va_list args;
+       va_start(args,Description);
+       return Insert(WARNING, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Notice - Add a notice to the list                      /*{{{*/
+bool GlobalError::Notice(const char *Description,...)
+{
+       va_list args;
+       va_start(args,Description);
+       return Insert(NOTICE, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Debug - Add a debug to the list                                /*{{{*/
+bool GlobalError::Debug(const char *Description,...)
+{
+       va_list args;
+       va_start(args,Description);
+       return Insert(DEBUG, Description, args);
+}
+                                                                       /*}}}*/
+// GlobalError::Insert - Insert a new item at the end                  /*{{{*/
+bool GlobalError::Insert(MsgType type, const char* Description,
+                        va_list const &args) {
+       char S[400];
+       vsnprintf(S,sizeof(S),Description,args);
+
+       Item const m(S, type);
+       Messages.push_back(m);
+
+       if (type == ERROR || type == FATAL)
+               PendingFlag = true;
+
+       if (type == FATAL || type == DEBUG)
+               std::clog << m << std::endl;
+
+       return false;
+}
+                                                                       /*}}}*/
+// GlobalError::PopMessage - Pulls a single message out                        /*{{{*/
+bool GlobalError::PopMessage(std::string &Text) {
+       if (Messages.empty() == true)
+               return false;
+
+       Item const msg = Messages.front();
+       Messages.pop_front();
+
+       bool const Ret = (msg.Type == ERROR || msg.Type == FATAL);
+       Text = msg.Text;
+       if (PendingFlag == false || Ret == false)
+               return Ret;
+
+       // check if another error message is pending
+       for (std::list<Item>::const_iterator m = Messages.begin();
+            m != Messages.end(); m++)
+               if (m->Type == ERROR || m->Type == FATAL)
+                       return Ret;
+
+       PendingFlag = false;
+       return Ret;
+}
+                                                                       /*}}}*/
+// GlobalError::DumpErrors - Dump all of the errors/warns to cerr      /*{{{*/
+void GlobalError::DumpErrors(std::ostream &out, MsgType const &trashhold) {
+       for (std::list<Item>::const_iterator m = Messages.begin();
+            m != Messages.end(); m++)
+               if (m->Type >= trashhold)
+                       out << (*m) << std::endl;
+       Discard();
+}
+                                                                       /*}}}*/
+// GlobalError::Discard - Discard                                      /*{{{*/
+void GlobalError::Discard() {
+       Messages.clear();
+       PendingFlag = false;
+};
+                                                                       /*}}}*/
+// GlobalError::empty - does our error list include anything?          /*{{{*/
+bool GlobalError::empty(MsgType const &trashhold) const {
+       if (PendingFlag == true)
+               return false;
+
+       if (Messages.empty() == true)
+               return true;
+
+       for (std::list<Item>::const_iterator m = Messages.begin();
+            m != Messages.end(); m++)
+               if (m->Type >= trashhold)
+                       return false;
+
+       return true;
+}
+                                                                       /*}}}*/
index 8d5ec05..fc7b38f 100644 (file)
 
 #include <apt-pkg/macros.h>
 
+#include <iostream>
+#include <list>
 #include <string>
 
-class GlobalError
+#include <stdarg.h>
+
+class GlobalError                                                      /*{{{*/
 {
-   struct Item
-   {
-      std::string Text;
-      bool Error;
-      Item *Next;
-   };
-   
-   Item *List;
-   bool PendingFlag;
-   void Insert(Item *I);
-   
-   public:
+public:                                                                        /*{{{*/
+       /** \brief a message can have one of following severity */
+       enum MsgType {
+               /** \brief Message will be printed instantly as it is likely that
+                       this error will lead to a complete crash */
+               FATAL = 40,
+               /** \brief An error does hinder the correct execution and should be corrected */
+               ERROR = 30,
+               /** \brief indicates problem that can lead to errors later on */
+               WARNING = 20,
+               /** \brief deprecation warnings, old fallback behavior, … */
+               NOTICE = 10,
+               /** \brief for developers only in areas it is hard to print something directly */
+               DEBUG = 0
+       };
 
-   // Call to generate an error from a library call.
-   bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
-   bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+       /** \brief add a fatal error message with errno to the list
+        *
+        *  \param Function name of the function generating the error
+        *  \param Description format string for the error message
+        *
+        *  \return \b false
+        */
+       bool FatalE(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
-   /* A warning should be considered less severe than an error, and may be
-      ignored by the client. */
-   bool Error(const char *Description,...) __like_printf(2) __cold;
-   bool Warning(const char *Description,...) __like_printf(2) __cold;
+       /** \brief add an Error message with errno to the list
+        *
+        *  \param Function name of the function generating the error
+        *  \param Description format string for the error message
+        *
+        *  \return \b false
+        */
+       bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
-   // Simple accessors
-   inline bool PendingError() {return PendingFlag;};
-   inline bool empty() {return List == 0;};
-   bool PopMessage(std::string &Text);
-   void Discard();
+       /** \brief add a warning message with errno to the list
+        *
+        *  A warning should be considered less severe than an error and
+        *  may be ignored by the client.
+        *
+        *  \param Function Name of the function generates the warning.
+        *  \param Description Format string for the warning message.
+        *
+        *  \return \b false
+        */
+       bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold;
 
-   // Usefull routine to dump to cerr
-   void DumpErrors();
-   
-   GlobalError();
+       /** \brief add a notice message with errno to the list
+        *
+        *  \param Function name of the function generating the error
+        *  \param Description format string for the error message
+        *
+        *  \return \b false
+        */
+       bool NoticeE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+       /** \brief add a debug message with errno to the list
+        *
+        *  \param Function name of the function generating the error
+        *  \param Description format string for the error message
+        *
+        *  \return \b false
+        */
+       bool DebugE(const char *Function,const char *Description,...) __like_printf(3) __cold;
+
+       /** \brief add an fatal error message to the list
+        *
+        *  Most of the stuff we consider as "error" is also "fatal" for
+        *  the user as the application will not have the expected result,
+        *  but a fatal message here means that it gets printed directly
+        *  to stderr in addiction to adding it to the list as the error
+        *  leads sometimes to crashes and a maybe duplicated message
+        *  is better than "Segfault" as the only displayed text
+        *
+        *  \param Description Format string for the fatal error message.
+        *
+        *  \return \b false
+        */
+       bool Fatal(const char *Description,...) __like_printf(2) __cold;
+
+       /** \brief add an Error message to the list
+        *
+        *  \param Description Format string for the error message.
+        *
+        *  \return \b false
+        */
+       bool Error(const char *Description,...) __like_printf(2) __cold;
+
+       /** \brief add a warning message to the list
+        *
+        *  A warning should be considered less severe than an error and
+        *  may be ignored by the client.
+        *
+        *  \param Description Format string for the message
+        *
+        *  \return \b false
+        */
+       bool Warning(const char *Description,...) __like_printf(2) __cold;
+
+       /** \brief add a notice message to the list
+        *
+        *  A notice should be considered less severe than an error or a
+        *  warning and can be ignored by the client without further problems
+        *  for some times, but he should consider fixing the problem.
+        *  This error type can be used for e.g. deprecation warnings of options.
+        *
+        *  \param Description Format string for the message
+        *
+        *  \return \b false
+        */
+       bool Notice(const char *Description,...) __like_printf(2) __cold;
+
+       /** \brief add a debug message to the list
+        *
+        *  \param Description Format string for the message
+        *
+        *  \return \b false
+        */
+       bool Debug(const char *Description,...) __like_printf(2) __cold;
+
+       /** \brief is an error in the list?
+        *
+        *  \return \b true if an error is included in the list, \b false otherwise
+        */
+       inline bool PendingError() const {return PendingFlag;};
+
+       /** \brief is the list empty?
+        *
+        *  The default checks if the list is empty or contains only notices,
+        *  if you want to check if also no notices happend set the parameter
+        *  flag to \b false.
+        *
+        *  \param WithoutNotice does notices count, default is \b true, so no
+        *
+        *  \return \b true if an the list is empty, \b false otherwise
+        */
+       bool empty(MsgType const &trashhold = WARNING) const;
+
+       /** \brief returns and removes the first (or last) message in the list
+        *
+        *  \param[out] Text message of the first/last item
+        *
+        *  \return \b true if the message was an error, \b false otherwise
+        */
+       bool PopMessage(std::string &Text);
+
+       /** \brief clears the list of messages */
+       void Discard();
+
+       /** \brief outputs the list of messages to the given stream
+        *
+        *  Note that all messages are discarded, also the notices
+        *  displayed or not.
+        *
+        *  \param[out] out output stream to write the messages in
+        *  \param WithoutNotice output notices or not
+        */
+       void DumpErrors(std::ostream &out, MsgType const &trashhold = WARNING);
+
+       /** \brief dumps the list of messages to std::cerr
+        *
+        *  Note that all messages are discarded, also the notices
+        *  displayed or not.
+        *
+        *  \param WithoutNotice print notices or not
+        */
+       void inline DumpErrors(MsgType const &trashhold = WARNING) {
+               DumpErrors(std::cerr, trashhold);
+       }
+
+       GlobalError();
+                                                                       /*}}}*/
+private:                                                               /*{{{*/
+       struct Item {
+               std::string Text;
+               MsgType Type;
+
+               Item(char const *Text, MsgType const &Type) :
+                       Text(Text), Type(Type) {};
+
+               friend std::ostream& operator<< (std::ostream &out, Item i) {
+                       switch(i.Type) {
+                       case FATAL:
+                       case ERROR: out << "E"; break;
+                       case WARNING: out << "W"; break;
+                       case NOTICE: out << "N"; break;
+                       case DEBUG: out << "D"; break;
+                       }
+                       return out << ": " << i.Text;
+               }
+       };
+
+       std::list<Item> Messages;
+       bool PendingFlag;
+
+       bool InsertErrno(MsgType type, const char* Function,
+                        const char* Description, va_list const &args);
+       bool Insert(MsgType type, const char* Description,
+                        va_list const &args);
+                                                                       /*}}}*/
 };
+                                                                       /*}}}*/
 
 // The 'extra-ansi' syntax is used to help with collisions. 
 GlobalError *_GetErrorObj();
index 00877ee..3e7b16d 100644 (file)
@@ -16,8 +16,11 @@ apt (0.7.26~exp8) UNRELEASED; urgency=low
   * apt-pkg/depcache.cc:
     - SetCandidateVer for all pseudo packages
     - SetReInstall for the "all" package of a pseudo package
+  * apt-pkg/contrib/error.{cc,h}:
+    - complete rewrite but use the same API
+    - add NOTICE and DEBUG as new types of a message
 
- -- David Kalnischkies <kalnischkies@gmail.com>  Thu, 10 Jun 2010 16:36:58 +0200
+ -- David Kalnischkies <kalnischkies@gmail.com>  Fri, 25 Jun 2010 08:01:14 +0200
 
 apt (0.7.26~exp7) experimental; urgency=low