123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: error.h,v 1.8 2001/05/07 05:06:52 jgg Exp $
- /* ######################################################################
-
- Global Erorr Class - Global error mechanism
- This class has a single global instance. When a function needs to
- generate an error condition, such as a read error, it calls a member
- in this class to add the error to a stack of errors.
-
- By using a stack the problem with a scheme like errno is removed and
- it allows a very detailed account of what went wrong to be transmitted
- to the UI for display. (Errno has problems because each function sets
- errno to 0 if it didn't have an error thus eraseing erno in the process
- of cleanup)
-
- Several predefined error generators are provided to handle common
- things like errno. The general idea is that all methods return a bool.
- If the bool is true then things are OK, if it is false then things
- should start being undone and the stack should unwind under program
- control.
-
- A Warning should not force the return of false. Things did not fail, but
- they might have had unexpected problems. Errors are stored in a FIFO
- so Pop will return the first item..
-
- I have some thoughts about extending this into a more general UI<->
- Engine interface, ie allowing the Engine to say 'The disk is full' in
- a dialog that says 'Panic' and 'Retry'.. The error generator functions
- like errno, Warning and Error return false always so this is normal:
- if (open(..))
- return _error->Errno(..);
-
- This source is placed in the Public Domain, do with it what you will
- It was originally written by Jason Gunthorpe.
-
- ##################################################################### */
- /*}}}*/
- #ifndef PKGLIB_ERROR_H
- #define PKGLIB_ERROR_H
- #include <apt-pkg/macros.h>
- #include <iostream>
- #include <list>
- #include <string>
- #include <stddef.h>
- #include <stdarg.h>
- class GlobalError /*{{{*/
- {
- 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
- };
- /** \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,...) APT_PRINTF(3) APT_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,...) APT_PRINTF(3) APT_COLD;
- /** \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,...) APT_PRINTF(3) APT_COLD;
- /** \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,...) APT_PRINTF(3) APT_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,...) APT_PRINTF(3) APT_COLD;
- /** \brief adds an errno message with the given type
- *
- * \param type of the error message
- * \param Function which failed
- * \param Description of the error
- */
- bool InsertErrno(MsgType const &type, const char* Function,
- const char* Description,...) APT_PRINTF(4) APT_COLD;
- /** \brief adds an errno message with the given type
- *
- * args needs to be initialized with va_start and terminated
- * with va_end by the caller. msgSize is also an out-parameter
- * in case the msgSize was not enough to store the complete message.
- *
- * \param type of the error message
- * \param Function which failed
- * \param Description is the format string for args
- * \param args list from a printf-like function
- * \param errsv is the errno the error is for
- * \param msgSize is the size of the char[] used to store message
- * \return true if the message was added, false if not - the caller
- * should call this method again in that case
- */
- bool InsertErrno(MsgType type, const char* Function,
- const char* Description, va_list &args,
- int const errsv, size_t &msgSize) APT_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 addition 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,...) APT_PRINTF(2) APT_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,...) APT_PRINTF(2) APT_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,...) APT_PRINTF(2) APT_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,...) APT_PRINTF(2) APT_COLD;
- /** \brief add a debug message to the list
- *
- * \param Description Format string for the message
- *
- * \return \b false
- */
- bool Debug(const char *Description,...) APT_PRINTF(2) APT_COLD;
- /** \brief adds an error message with the given type
- *
- * \param type of the error message
- * \param Description of the error
- */
- bool Insert(MsgType const &type, const char* Description,...) APT_PRINTF(3) APT_COLD;
- /** \brief adds an error message with the given type
- *
- * args needs to be initialized with va_start and terminated
- * with va_end by the caller. msgSize is also an out-parameter
- * in case the msgSize was not enough to store the complete message.
- *
- * \param type of the error message
- * \param Description is the format string for args
- * \param args list from a printf-like function
- * \param msgSize is the size of the char[] used to store message
- * \return true if the message was added, false if not - the caller
- * should call this method again in that case
- */
- bool Insert(MsgType type, const char* Description,
- va_list &args, size_t &msgSize) APT_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 APT_PURE {return PendingFlag;};
- /** \brief convert a stored error to a return code
- *
- * Put simply, the entire concept of PendingError() is flawed :/.
- *
- * The typical "if (PendingError()) return false;" check that is
- * strewn throughout the codebase "compounds", making it impossible
- * for there to be any nuance about the notion of "error" when a
- * subsystem needs to fail but a higher-level system needs to work.
- *
- * However, the codebase is also horribly broken with respect to
- * errors, as it fails to use C++ exceptions when warranted and
- * instead relies on this insane indirect error mechanism to check
- * the failure status of a constructor. What is thereby needed is
- * a way to clear the PendingError() flag without also discarding
- * the underlying errors, so we have to convert them to warnings.
- *
- * \return \b false
- */
- bool ReturnError() APT_COLD;
- /** \brief is the list empty?
- *
- * Can be used to check if the current stack level doesn't include
- * anything equal or more severe than a given threshold, defaulting
- * to warning level for historic reasons.
- *
- * \param threshold minimum level considered
- *
- * \return \b true if the list is empty, \b false otherwise
- */
- bool empty(MsgType const &threshold = WARNING) const APT_PURE;
- /** \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, even undisplayed ones.
- *
- * \param[out] out output stream to write the messages in
- * \param threshold minimum level considered
- * \param mergeStack if true recursively dumps the entire stack
- */
- void DumpErrors(std::ostream &out, MsgType const &threshold = WARNING,
- bool const &mergeStack = true);
- /** \brief dumps the list of messages to std::cerr
- *
- * Note that all messages are discarded, also the notices
- * displayed or not.
- *
- * \param threshold minimum level printed
- */
- void inline DumpErrors(MsgType const &threshold) {
- DumpErrors(std::cerr, threshold);
- }
- // mvo: we do this instead of using a default parameter in the
- // previous declaration to avoid a (subtle) API break for
- // e.g. sigc++ and mem_fun0
- /** \brief dumps the messages of type WARNING or higher to std::cerr
- *
- * Note that all messages are discarded, displayed or not.
- *
- */
- void inline DumpErrors() {
- DumpErrors(WARNING);
- }
- /** \brief put the current Messages into the stack
- *
- * All "old" messages will be pushed into a stack to
- * them later back, but for now the Message query will be
- * empty and performs as no messages were present before.
- *
- * The stack can be as deep as you want - all stack operations
- * will only operate on the last element in the stack.
- */
- void PushToStack();
- /** \brief throw away all current messages */
- void RevertToStack();
- /** \brief merge current and stack together */
- void MergeWithStack();
- /** \brief return the deep of the stack */
- size_t StackCount() const APT_PURE {
- return Stacks.size();
- }
- GlobalError();
- /*}}}*/
- private: /*{{{*/
- struct Item {
- std::string Text;
- MsgType Type;
- Item(char const *Text, MsgType const &Type) :
- Text(Text), Type(Type) {};
- APT_HIDDEN 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;
- }
- out << ": ";
- std::string::size_type line_start = 0;
- std::string::size_type line_end;
- while ((line_end = i.Text.find_first_of("\n\r", line_start)) != std::string::npos) {
- if (line_start != 0)
- out << std::endl << " ";
- out << i.Text.substr(line_start, line_end - line_start);
- line_start = i.Text.find_first_not_of("\n\r", line_end + 1);
- if (line_start == std::string::npos)
- break;
- }
- if (line_start == 0)
- out << i.Text;
- else if (line_start != std::string::npos)
- out << std::endl << " " << i.Text.substr(line_start);
- return out;
- }
- };
- std::list<Item> Messages;
- bool PendingFlag;
- struct MsgStack {
- std::list<Item> Messages;
- bool const PendingFlag;
- MsgStack(std::list<Item> const &Messages, bool const &Pending) :
- Messages(Messages), PendingFlag(Pending) {};
- };
- std::list<MsgStack> Stacks;
- /*}}}*/
- };
- /*}}}*/
- // The 'extra-ansi' syntax is used to help with collisions.
- GlobalError *_GetErrorObj();
- #define _error _GetErrorObj()
- #endif
|