Listing 1

//=============================================================
//  rerr.h - rich error interface.

#include <string>
#include <iostream>

#if defined(_WIN32)
# if defined(RERR_EXPORTS)
#  define RERR_API __declspec(dllexport)
# else
#  define RERR_API __declspec(dllimport)
# endif
#else
# define RERR_API
#endif

//-------------------------------------------------------------
struct IRichErrorBase
{
    virtual std::ostream & printerr(
            std::ostream & os) const = 0;
};
//-------------------------------------------------------------
struct IRichErrorStack : IRichErrorBase
{
    virtual void release(void) = 0;
    virtual int pusherr(int err, const char * descr, 
            IRichErrorBase * xinfop, const char * filename, int line) = 0;
    virtual void clearerr(void) = 0;
    virtual bool haserr(void) = 0;
};
//-------------------------------------------------------------
extern "C" RERR_API IRichErrorStack * 
        getThreadRichErrorStack(bool create);

//-------------------------------------------------------------
// All IRichErrorBase-drived objects can be dumped to any std::ostream.
std::ostream & operator << (std::ostream & os, 
        const IRichErrorBase & reb) { return reb.printerr(os); }

//-------------------------------------------------------------
// CLASS RichError - instantiate one of these as a local variable at the 
// top of the call stack where rich error information is desired.
class RichError : public IRichErrorBase
{
    IRichErrorStack * m_stk;
    int ipusherr(int err, const char * descr, 
            IRichErrorBase * xinfop, const char * filename, 
            int line) { return m_stk? m_stk->pusherr(err, 
                    descr, xinfop, filename, line): err; }
    void iclearerr(void) { if (m_stk) m_stk->clearerr(); }

    // not implemented - copying not allowed
    RichError(const RichError & rhs);

public:
    RichError(bool create = true) : 
            m_stk(getThreadRichErrorStack(create)) {}
    ~RichError(void) { if (m_stk) m_stk->release(); }

    static int pusherr(int err, const char * descr, 
            IRichErrorBase * xinfop, const char * filename, 
                    int line) { return RichError(false).ipusherr(
                            err, descr, xinfop, filename, line); }
    static void clearerr(void) { RichError(false).iclearerr(); }

    bool haserr(void) { return m_stk? m_stk->haserr(): false; }
    std::ostream & printerr(std::ostream & os) const
           { return m_stk? os << *m_stk: os; }
};
//-------------------------------------------------------------
// Use these macros to push error info on this thread's stack
#define RePush(e)               \
        RichError::pusherr((e), 0 , 0 ,__FILE__,__LINE__)
#define RePushStr(e,d)      \
        RichError::pusherr((e),(d), 0 ,__FILE__,__LINE__)
#define RePushStrXi(e,d,x)  \
        RichError::pusherr((e),(d),(x),__FILE__,__LINE__)

// Use this macro to clear this thread's error stack
#define ReClear             RichError::clearerr

//=============================================================