Re: [ROOT] getting the last error

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Tue Feb 05 2002 - 21:28:37 MET


Helloe Joe :-) 

[sorry, couldn't resist]

On Mon, 4 Feb 2002 9:30:57 -0500
joer00@bellsouth.net wrote
concerning "[ROOT] getting the last error":
> Hi Rooters,
> 
> I posted this before and got the impression that I just cant check
> for errors, but Anton Fokin told me it shouls be possible via
> SetErrorHandler(). But HOW ?? There is no documentaion in the root 
> docs, none in the class index and serach the root page did not
> return any result. 

If you bothered to look for the implmentation of SetErrorHandler,
which is easy using the LXR interface at the ROOT web-site, then you'd
have found it straight of - that's what I just did.  And I assume
reading some 30 lines of code is not something that bothers you,
seeing that you're developing stuff yourself :-) 
 
> So all I need is to NOT print errors in the console window (if i set
> ignore levele to 5000, the default error handler just aborts !) and
> GET the last occured error to decide what my programm is
> doing. Something simple like: 
> 
> SomeClass.SomeMethod("This might set an Error");
> if(gError)
> {
> QMessageBox::warning(this,"test",gErrorMessage);
> DoSomething;
> }

See the declaration file base/inc/TError.h, and the corresponding
implementation file base/src/TError.cxx.  

In base/inc/TError.h the type ErrorHandlerFunc_t is defined as a
pointer to a funtion, like 

  typedef void (*ErrorHandlerFunc_t)(int level, 
                                     Bool_t abort, 
                                     const char *location,
                                     const char *msg);

which is the type that SetErrorHandler expects.  Hence, you can not
have a member function of a class directly as a error handler but,
your error handler function can be a wrapper that uses a static/global
pointer to an object of some class:
  
  void MyErrorHandler(int lvl, Bool abt, const char* loc, const char* msg)
  {
     // Get a pointer to the current error handler class 
     MyErrorClass* errorObject = MyErrorClass::Instance(); 

     if (errorObject)
       // Use it if it exists
       errorObject->ErrorHandler(lvl, abt, loc, msg); 
     else 
       // Fall-back to normal ROOT error handler 
       DefaultErrorHandler(lvl, abt, loc, msg);
  }

  class MyErrorClass  {
  protected: 
    ostream* fStream; 
    static MyErrorClass* fgInstance; 
  public: 
    MyErrorClass() { fStream = &cerr;  }
    static MyErrorClass Instance() { return fgInstance; }
    virtual void ErrorHandler(int lvl, Bool abt, const char* loc, 
                              const char* msg) = 0;
    virtual void SetStream(const ostream& stream=cerr) { fStream = &stream; }
  }; 

  static MyErrorClass* MyErrorClass::fgInstance; 

  class QtErrorClass : public MyErrorClass 
  {
  public: 
    QtErrorClass() {  fStream = 0;  fgInstance = this; }
    virtual ~QtErrorClass() { fgInstance = 0; }
    virtual void ErrorHandler(int lvl, Bool abt, const char* loc, 
                              const char* msg) { 
      TString errMessage(msg);
      TString errTitle; 
      if (level >= kInfo)
        errTitle = "Info";
      if (level >= kWarning)
        errTitle = "Warning";
      if (level >= kError)
        errTitle = "Error";
      if (level >= kSysError)
        errTitle = "SysError";
      if (level >= kFatal)
        errTitle = "Fatal";

      if (loc && loc[0] != '\0') {
        errTitle += " in <";
        errTitle += loc; 
        errTitle += ">"; 
      }

      if (abt)   
        errorMessage += "\nAborting!"; 

      QMessageBox::warning(this, errTitle.Data(), errorMessage.Data());

      if (abt) 
        ::abort();
    }
  }

I prefer static members to global variables, though they are almost
the same thing, since it looks more OO, and it's easier to make
reentrant (thread safe) code that way. 

You can then enable the use of MyErrorHandler with 

  Init() { 
    SetErrorHandler(MyErrorHandler); 
    // and use the Qt one 
    new QtErrorClass; 
  }

  int main(int argc, char** argv) { 
    Init();
    ...
  }
  
A word of caution: I have not tried this, but in principal is should
work.  You may need to specify "C" linkage for MyErrorHandler, but I
don't think so. 

Yours, 

Christian Holm Christensen -------------------------------------------
Address: Sankt Hansgade 23, 1. th.           Phone:  (+45) 35 35 96 91 
         DK-2200 Copenhagen N                Cell:   (+45) 28 82 16 23
         Denmark                             Office: (+45) 353  25 305 
Email:   cholm@nbi.dk                        Web:    www.nbi.dk/~cholm



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:50:41 MET