From: Teiniker E. <tei...@us...> - 2007-01-22 10:09:04
|
Update of /cvsroot/ccmtools/cpp-environment/utils/error In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv14231/utils/error Added Files: error_macros.h ms_eh.cc errortrace.cc errorout_ostream.cc .cvsignore errorout_ostream.h Confix2.dir error_impl.h errortrace.h doxyerror.h error.h error_impl.cc Log Message: Added utils/code and utils/error to the runtime lib --- NEW FILE: errorout_ostream.h --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #ifndef wx_utils_error_errorout_ostream_h #define wx_utils_error_errorout_ostream_h #include <iosfwd> #include <wamas/platform/utils/smartptr.h> namespace wamas { namespace platform { namespace utils { class Error; class ErrorNode; class ErrorTrace; void output(const SmartPtr<ErrorNode>&, std::ostream&, int offset=0); void output(const ErrorTrace&, std::ostream&, int offset=0); void output(const Error&, std::ostream&, int offset=0); inline std::ostream& operator<<(std::ostream& s, const ErrorTrace& e) { output(e, s); return s; } inline std::ostream& operator<<(std::ostream& s, const Error& e) { output(e, s); return s; } } // /namespace } // /namespace } // /namespace #endif --- NEW FILE: doxyerror.h --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // namespace wamas { namespace platform { namespace utils { /** \defgroup utils_error Error Handling Several classes to be used in error handling. Supposed to be used in exception design. There is no multilinguality yet, just the same as it misses other things like error IDs and such. However, these things are supposed grow as our experience grows - so don't be upset. \ingroup utils */ } // /namespace } // /namespace } // /namespace --- NEW FILE: error.h --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #ifndef wx_utils_error_error_h #define wx_utils_error_error_h #include "error_impl.h" #include "errorout_ostream.h" #include "error_macros.h" #include "errortrace.h" namespace wamas { namespace platform { namespace utils { } // /namespace } // /namespace } // /namespace #endif --- NEW FILE: errortrace.cc --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #include "errortrace.h" namespace wamas { namespace platform { namespace utils { using namespace std; static const deque<SmartPtr<ErrorNode> > empty_trace; // -------------------------------------------------------------------- void ErrorTraceImpl::append(const SmartPtr<ErrorNode>& n) { trace_.push_back(n); } // -------------------------------------------------------------------- ErrorTrace& ErrorTrace::append(const SmartPtr<ErrorNode>& n) { if (!ptr()) eat(new ErrorTraceImpl); ptr()->append(n); return *this; } const deque<SmartPtr<ErrorNode> >& ErrorTrace::trace() const { return cptr()? cptr()->trace(): empty_trace; } } // /namespace } // /namespace } // /namespace --- NEW FILE: errortrace.h --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #ifndef wx_utils_error_errortrace_h #define wx_utils_error_errortrace_h #include "error.h" #include <wamas/platform/utils/smartptr.h> #include <deque> namespace wamas { namespace platform { namespace utils { class ErrorTraceImpl : public RefCounted { public: void append(const SmartPtr<ErrorNode>&); const std::deque<SmartPtr<ErrorNode> >& trace() const { return trace_; } private: std::deque<SmartPtr<ErrorNode> > trace_; }; /** \ingroup utils_error \brief A list (possibly nested - a tree) of Error objects, each carrying descriptions of particular errors that have happened along execution of a code path. Supposed to be thrown as exception. For a more detailed description and examples see the documentation of class Error. */ class ErrorTrace : private SmartPtr<ErrorTraceImpl> { public: ErrorTrace() {} ErrorTrace(const ErrorTrace&); ErrorTrace& operator=(const ErrorTrace&); ErrorTrace& append(const SmartPtr<ErrorNode>&); int n() const { return trace().size(); } const std::deque<SmartPtr<ErrorNode> >& trace() const; }; inline ErrorTrace::ErrorTrace(const ErrorTrace& t) : SmartPtr<ErrorTraceImpl>(t) {} inline ErrorTrace& ErrorTrace::operator=(const ErrorTrace& t) { SmartPtr<ErrorTraceImpl>::operator=(t); return *this; } } // /namespace } // /namespace } // /namespace #endif --- NEW FILE: error_impl.h --- //// -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #ifndef wx_utils_error_error_impl_h #define wx_utils_error_error_impl_h #include "errorout_ostream.h" #include <wamas/platform/utils/linkassert.h> #include <wamas/platform/utils/smartptr.h> #include <string> #include <sstream> #include <exception> namespace wamas { namespace platform { namespace utils { // we cannot have an ErrorTrace automatic member because errortrace.h // in turn includes this file, which would end up in circular // includes. so we have to forward declare it and manage it in the .cc // file instead. class ErrorTrace; /** \ingroup utils_error \brief Conceptually, An Error object is a description of an error that happened, either directly or indirectly. Supposed to be thrown as exception. As objects of type Error are supposed to be thrown as exceptions, it makes sense to derive from them (Error itself derives from std::exception) to emphasize a specific failure condition at a particular point in code, but still provide the common Error interface (which is described in the remainder). An Error carries a punctual description (message()) of an error that has happened. Along with this description it can (should) carry the file name and a line number (file(), line()) of the code location where it happened. An Error can own a nested ErrorTrace object, which is basically a list of Error objects. For example, a common use for this is if you are calling a function which throws an Error object as exception. Then you may want to decribe this error in your own (more high level) terms, like "Could not write this record to disk because the marshaller failed (detailed description follows)" (what follows is the marshaller's Error, contained in the trace). Here's a small example of how to use it. \code Error caught; // e.g. caught by an exception handler Error error; SmartPtr<ErrorNode> node( new ErrorNode(__FILE__,__LINE__,"My own high level description")); node->children(caught.root()); error.root(node); throw error; \endcode So, this example isn't really small as it introduces all of Error at once. Fortunately, there are helper macros which make life a lot easier. Typical uses are \code #include <wamas/platform/utils/error_macros.h> COMPOSE_ERROR_MSG(DerivedError, err, "My " << 2 << " bucks here"); \endcode which declares a variable err of type DerivedError (which, as the name suggests, is derived from class Error). Note the demonstrative use of the output operator: you compose a message just as you do with ostreams. Another typical use is \code #include <wamas/platform/utils/error_macros.h> THROW_ERROR_MSG(DerivedError, "My " << 2 << " bucks here"); \endcode which does the same as above, except that it throws the object immediately instead. */ class ErrorNode : public RefCounted { public: ErrorNode(); ErrorNode(const SmartPtr<ErrorNode>&); ErrorNode(const char *, int, const char *); ErrorNode(const char *, int, const char *, const SmartPtr<ErrorNode>&); ~ErrorNode() throw(); ErrorNode& file(const std::string& f) { file_ = f; return *this; } ErrorNode& line(int l) { line_ = l; return *this; } ErrorNode& message(const std::string& m) { message_ = m; return *this; } ErrorNode& addChild(const SmartPtr<ErrorNode>&); const std::string& file() const { return file_; } int line() const { return line_; } const std::string& message() const { return message_; } const ErrorTrace& children() const { return *children_; } ErrorNode& operator=(const ErrorNode&); private: std::string file_; int line_; std::string message_; ErrorTrace* children_; }; class Error : public std::exception { public: Error() {} Error(const SmartPtr<ErrorNode>& n) { root_ = n; } Error(const Error& e) { root_ = e.root(); } Error(Error* e) { root_ = e->root(); } ~Error() throw() {} const SmartPtr<ErrorNode>& root() const { return root_; }; Error& root(const SmartPtr<ErrorNode>& root) { root_ = root; return *this; } template<class T> void addChildren(const T& children) { if ( !this->root_ ) this->root_.eat(new ErrorNode); for ( typename T::const_iterator i=children.begin(); i != children.end(); ++i ) { this->root_->addChild(i->root()); } } Error& operator=(const Error&); bool good() const { return !root_; } operator bool() const { return !good(); } virtual const char* what() const throw (); LTA_MEMDECL(3); private: SmartPtr<ErrorNode> root_; mutable std::string what_; }; LTA_STATDEF(Error, 3); } // /namespace } // /namespace } // /namespace #endif --- NEW FILE: error_macros.h --- #ifndef wx_utils_error_error_macros_h #define wx_utils_error_error_macros_h #include <sstream> namespace wamas { namespace platform { namespace utils { /** \def COMPOSE_ERROR(ErrorType, var) \ingroup utils_error \brief Instantiate an error of type \c ErrorType, with name \c var */ #define COMPOSE_ERROR(ErrorType, var) \ ErrorType var; \ /** \def COMPOSE_ERROR_ERROR(ErrorType, var, e) \ingroup utils_error \brief Instantiate an error of type \c ErrorType, with name \c var, which contains the nested error \c e */ #define COMPOSE_ERROR_ERROR(ErrorType, var, e) \ COMPOSE_ERROR(ErrorType, var);\ { \ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> const& child = e.root(); \ if ( child.ptr() ) { \ var.root(child);\ } \ } /** \def COMPOSE_NODE_NO_MSG \ingroup utils_error \brief Instantiate an node of type \c ErrorNode, with name \c node, contains the message \c msg. \c msg is an expression that can contain anything an \c ostream can take. */ #define COMPOSE_NODE_NO_MSG \ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> node(new wamas::platform::utils::ErrorNode); \ node->file(__FILE__); \ node->line(__LINE__); /** \def COMPOSE_NODE_MSG(msg) \ingroup utils_error \brief Instantiate an node of type \c ErrorNode, with name \c node, contains the message \c msg. \c msg is an expression that can contain anything an \c ostream can take. */ #define COMPOSE_NODE_MSG(msg) \ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> node(new wamas::platform::utils::ErrorNode); \ std::ostringstream os; \ os << msg; \ node->file(__FILE__); \ node->line(__LINE__); \ node->message(os.str()); /** \def COMPOSE_ERROR_MSG(ErrorType, var, msg) \ingroup utils_error \brief Instantiate an error of type \c ErrorType, with name \c var, which contains the message \c msg Instantiate an error of type \c ErrorType, with name \c var, which contains the message \c msg. \c msg is an expression that can contain anything an \c ostream can take. */ #define COMPOSE_ERROR_MSG_MAKE_MSG(var, msg) \ { \ COMPOSE_NODE_MSG(msg) \ var.root(node); \ } #define COMPOSE_ERROR_MSG(ErrorType, var, msg) \ COMPOSE_ERROR(ErrorType, var) \ COMPOSE_ERROR_MSG_MAKE_MSG(var, msg) \ /** \def COMPOSE_ERROR_TRACE_MSG(ErrorType, var, tr, msg) \ingroup utils_error \brief Instantiate an error of type \c ErrorType, with name \c var, which contains a nested list of errors, \c tr, and contains the message \c msg Instantiate an error of type \c ErrorType, with name \c var, which contains a nested list of errors, \c tr, and contains the message \c msg. \c msg is an expression that can contain anything an \c ostream can take. */ #define COMPOSE_ERROR_TRACE_MSG(ErrorType, var, tr, msg) \ COMPOSE_ERROR_MSG(ErrorType, var, msg) \ { \ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> root(var.root()); \ root->addChild(tr); \ } /** \def COMPOSE_ERROR_ERROR_MSG(ErrorType, var, e, msg) \ingroup utils_error \brief Instantiate an error of type \c ErrorType, with name \c var, which contains a nested error, \c e, and contains the message \c msg Instantiate an error of type \c ErrorType, with name \c var, which contains a nested error, \c e, and contains the message \c msg. \c msg is an expression that can contain anything an \c ostream can take. */ #define COMPOSE_ERROR_ERROR_MSG(ErrorType, var, e, msg) \ COMPOSE_ERROR_MSG(ErrorType, var, msg) \ {\ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> root = var.root(); \ wamas::platform::utils::SmartPtr<wamas::platform::utils::ErrorNode> const& child = e.root(); \ if ( child.ptr() ) { \ root->addChild(e.root());\ } \ } /** \def THROW_ERROR(ErrorType) \ingroup utils_error \brief Throws an error that is composed using \ref COMPOSE_ERROR */ #define THROW_ERROR(ErrorType) \ { \ COMPOSE_ERROR(ErrorType, var); \ { \ COMPOSE_NODE_NO_MSG \ var.root(node); \ }\ throw var; \ } /** \def THROW_ERROR_MSG(ErrorType, msg) \ingroup utils_error \brief Throws an error that is composed using \ref COMPOSE_ERROR_MSG */ #define THROW_ERROR_MSG(ErrorType, msg) \ { \ COMPOSE_ERROR_MSG(ErrorType, var, msg); \ throw var; \ } /** \def THROW_ERROR_TRACE_MSG(ErrorType, tr, msg) \ingroup utils_error \brief Throws an error that is composed using \ref COMPOSE_ERROR_TRACE_MSG */ #define THROW_ERROR_TRACE_MSG(ErrorType, tr, msg) \ { \ COMPOSE_ERROR_TRACE_MSG(ErrorType, var, tr, msg); \ throw var; \ } /** \def THROW_ERROR_ERROR_MSG(ErrorType, e, msg) \ingroup utils_error \brief Throws an error that is composed using \ref COMPOSE_ERROR_ERROR_MSG */ #define THROW_ERROR_ERROR_MSG(ErrorType, e, msg) \ { \ COMPOSE_ERROR_ERROR_MSG(ErrorType, var, e, msg); \ throw var; \ } /** \def THROW_ERROR_APPEND_MSG(e, msg) \ingroup utils_error \brief Throws an error that is composed using \ref COMPOSE_ERROR_ERROR_MSG */ #define THROW_ERROR_APPEND_MSG(e, msg)\ { \ COMPOSE_NODE_MSG(msg) \ node->addChild(e.root()); \ e.root(node); \ throw; \ } /** \def THROW_ERRORLIST(e, list, msg) \param e error class \param list any STL-compatible type which provides begin() and end() \param msg error message \ingroup utils_error \brief Throws a list of errors. */ #define THROW_ERRORLIST(ErrorType, list, msg) \ { \ COMPOSE_ERROR_MSG( ErrorType, var, msg); \ var.addChildren(list); \ throw var; \ } /** * \def CONVERT_UNKNOWN_ERROR(ErrorType,msg) * * \brief catches and converts unknown exceptions * * \param ErrorType error class to convert to * \param msg error message * * \ingroup utils_error */ #define CONVERT_UNKNOWN_ERROR(ErrorType, msg) \ catch(const wamas::platform::utils::Error& e) \ { THROW_ERROR_ERROR_MSG(ErrorType, e, msg); } \ catch(const std::exception& e) \ { THROW_ERROR_MSG(ErrorType, msg << '\n' << e.what()); } \ catch(...) \ { THROW_ERROR_MSG(ErrorType, msg << "\nUNKNOWN EXCEPTION"); } #define CONVERT_UNKNOWN_ERROR1(ErrorType1, msg) \ catch(const ErrorType1&) { throw; } \ CONVERT_UNKNOWN_ERROR(ErrorType1, msg) #define CONVERT_UNKNOWN_ERROR2(ErrorType1, ErrorType2, msg) \ catch(const ErrorType2&) { throw; } \ CONVERT_UNKNOWN_ERROR1(ErrorType1, msg) #define CONVERT_UNKNOWN_ERROR3(ErrorType1, ErrorType2, ErrorType3, msg) \ catch(const ErrorType3&) { throw; } \ CONVERT_UNKNOWN_ERROR2(ErrorType1, ErrorType2, msg) } // /namespace } // /namespace } // /namespace #endif --- NEW FILE: error_impl.cc --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #include "error_impl.h" #include "errortrace.h" #include "errorout_ostream.h" #include <sstream> #if !defined(_WIN32) # include <unistd.h> #endif namespace wamas { namespace platform { namespace utils { using namespace std; static const ErrorTrace empty_trace; // -------------------------------------------------------------------- LTA_MEMDEF(Error, 3, "$Id$"); // -------------------------------------------------------------------- // class ErrorNode ErrorNode::ErrorNode() : line_(0), children_(new ErrorTrace) {} ErrorNode::ErrorNode(const SmartPtr<ErrorNode>& n) : line_(0), children_(new ErrorTrace) { children_->append(n); } ErrorNode::ErrorNode(const char*f, const int l, const char* m) : file_(f), line_(l), message_(m), children_(new ErrorTrace) {} ErrorNode::ErrorNode(const char* f, int l, const char* m, const SmartPtr<ErrorNode>& n) : file_(f), line_(l), message_(m), children_(new ErrorTrace) { children_->append(n); } ErrorNode::~ ErrorNode() throw() { try { delete children_; } catch (...) { // we caught an exception from code we assumed to be // trivial. obviously we cannot assume iostream is still ok, so // we write this message with brute raw force. static const char* msg = "ErrorNode::~ErrorNode(): caught an exception\n"; #if defined(_WIN32) fprintf(stderr,"%s",msg); #else ::write(STDERR_FILENO, msg, strlen(msg)); #endif abort(); } } ErrorNode& ErrorNode::addChild(const SmartPtr<ErrorNode>& n) { children_->append(n); return *this; } ErrorNode& ErrorNode::operator =(const ErrorNode& e) { file_ = e.file_; line_ = e.line_; message_ = e.message_; *children_ = e.children(); return *this; } // -------------------------------------------------------------------- // class Error Error& Error::operator =(const Error& e) { root(e.root()); return *this; } const char* Error::what() const throw() { try { ostringstream os; output(*this, os); what_ = os.str(); return what_.c_str(); } catch (...) { // we caught an exception from code we assumed to be // trivial. obviously we cannot assume iostream is still ok, so // we write this message with brute raw force. static const char* msg = "Error::what(): caught an exception\n"; #if defined(_WIN32) fprintf(stderr,"%s",msg); #else ::write(STDERR_FILENO, msg, strlen(msg)); #endif abort(); } } } // /namespace } // /namespace } // /namespace --- NEW FILE: Confix2.dir --- --- NEW FILE: errorout_ostream.cc --- // -*- mode: C++; c-basic-offset: 3 -*- // // $Id$ // #include "errorout_ostream.h" #include "error_impl.h" #include "errortrace.h" namespace wamas { namespace platform { namespace utils { using namespace std; // -------------------------------------------------------------------- static inline void output_offset(ostream& o, int offset) { for (int i=0; i<offset; i++) o << ' '; } void output(const SmartPtr<ErrorNode>& n, ostream& o, int offset) { output_offset(o, offset); o << n->message() << " (" << ( n->file().size() ? n->file(): "(unknown)") << ':' << n->line() << ":)\n"; } void output(const ErrorTrace& t, ostream& o, int offset) { for (int i=0; i<(int)t.trace().size(); i++) { if(i) o << '\n'; output(t.trace()[i], o, offset); if (t.trace()[i]->children().trace().size()) { output(t.trace()[i]->children(), o, offset+2); } } } void output(const Error& e, ostream& o, int offset) { SmartPtr<ErrorNode> root=e.root(); if ( root ) { output(root, o, offset); if (root->children().trace().size()) output(root->children(), o, offset+2); } } } // /namespace } // /namespace } // /namespace --- NEW FILE: ms_eh.cc --- /** @file ms_eh.cc @brief converts MS-SEH-exceptions into wamas::platform::utils::Error */ #include "error.h" #ifdef _MSC_VER #include <excpt.h> #include <windows.h> #define CONVERT_SE(SE) case SE: s= #SE ; break; namespace wamas { namespace platform { namespace utils { namespace MS_SEH { static void se_translator(unsigned int i, EXCEPTION_POINTERS* p) { std::string s; switch(i) { CONVERT_SE(EXCEPTION_ACCESS_VIOLATION) CONVERT_SE(EXCEPTION_BREAKPOINT) CONVERT_SE(EXCEPTION_DATATYPE_MISALIGNMENT) CONVERT_SE(EXCEPTION_SINGLE_STEP) CONVERT_SE(EXCEPTION_ARRAY_BOUNDS_EXCEEDED) CONVERT_SE(EXCEPTION_FLT_DENORMAL_OPERAND) CONVERT_SE(EXCEPTION_FLT_DIVIDE_BY_ZERO) CONVERT_SE(EXCEPTION_FLT_INEXACT_RESULT) CONVERT_SE(EXCEPTION_FLT_INVALID_OPERATION) CONVERT_SE(EXCEPTION_FLT_OVERFLOW) CONVERT_SE(EXCEPTION_FLT_STACK_CHECK) CONVERT_SE(EXCEPTION_FLT_UNDERFLOW) CONVERT_SE(EXCEPTION_INT_DIVIDE_BY_ZERO) CONVERT_SE(EXCEPTION_INT_OVERFLOW) CONVERT_SE(EXCEPTION_PRIV_INSTRUCTION) CONVERT_SE(EXCEPTION_NONCONTINUABLE_EXCEPTION) default: THROW_ERROR_MSG(wamas::platform::utils::Error, "MS-SE with unknown id " << i); } THROW_ERROR_MSG(wamas::platform::utils::Error, "MS-SE : " << s); } struct SetTranslator { SetTranslator() { _set_se_translator(se_translator); } }; SetTranslator GLOBAL_SE_TRANSLATOR; } // /namespace } // /namespace } // /namespace } // /namespace #endif // _MSC_VER --- NEW FILE: .cvsignore --- Makefile.am Makefile.in |