error.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: error.h,v 1.8 2001/05/07 05:06:52 jgg Exp $
  4. /* ######################################################################
  5. Global Erorr Class - Global error mechanism
  6. This class has a single global instance. When a function needs to
  7. generate an error condition, such as a read error, it calls a member
  8. in this class to add the error to a stack of errors.
  9. By using a stack the problem with a scheme like errno is removed and
  10. it allows a very detailed account of what went wrong to be transmitted
  11. to the UI for display. (Errno has problems because each function sets
  12. errno to 0 if it didn't have an error thus eraseing erno in the process
  13. of cleanup)
  14. Several predefined error generators are provided to handle common
  15. things like errno. The general idea is that all methods return a bool.
  16. If the bool is true then things are OK, if it is false then things
  17. should start being undone and the stack should unwind under program
  18. control.
  19. A Warning should not force the return of false. Things did not fail, but
  20. they might have had unexpected problems. Errors are stored in a FIFO
  21. so Pop will return the first item..
  22. I have some thoughts about extending this into a more general UI<->
  23. Engine interface, ie allowing the Engine to say 'The disk is full' in
  24. a dialog that says 'Panic' and 'Retry'.. The error generator functions
  25. like errno, Warning and Error return false always so this is normal:
  26. if (open(..))
  27. return _error->Errno(..);
  28. This source is placed in the Public Domain, do with it what you will
  29. It was originally written by Jason Gunthorpe.
  30. ##################################################################### */
  31. /*}}}*/
  32. #ifndef PKGLIB_ERROR_H
  33. #define PKGLIB_ERROR_H
  34. #include <apt-pkg/macros.h>
  35. #include <iostream>
  36. #include <list>
  37. #include <string>
  38. #include <stddef.h>
  39. #include <stdarg.h>
  40. class GlobalError /*{{{*/
  41. {
  42. public: /*{{{*/
  43. /** \brief a message can have one of following severity */
  44. enum MsgType {
  45. /** \brief Message will be printed instantly as it is likely that
  46. this error will lead to a complete crash */
  47. FATAL = 40,
  48. /** \brief An error does hinder the correct execution and should be corrected */
  49. ERROR = 30,
  50. /** \brief indicates problem that can lead to errors later on */
  51. WARNING = 20,
  52. /** \brief deprecation warnings, old fallback behavior, … */
  53. NOTICE = 10,
  54. /** \brief for developers only in areas it is hard to print something directly */
  55. DEBUG = 0
  56. };
  57. /** \brief add a fatal error message with errno to the list
  58. *
  59. * \param Function name of the function generating the error
  60. * \param Description format string for the error message
  61. *
  62. * \return \b false
  63. */
  64. bool FatalE(const char *Function,const char *Description,...) APT_PRINTF(3) APT_COLD;
  65. /** \brief add an Error message with errno to the list
  66. *
  67. * \param Function name of the function generating the error
  68. * \param Description format string for the error message
  69. *
  70. * \return \b false
  71. */
  72. bool Errno(const char *Function,const char *Description,...) APT_PRINTF(3) APT_COLD;
  73. /** \brief add a warning message with errno to the list
  74. *
  75. * A warning should be considered less severe than an error and
  76. * may be ignored by the client.
  77. *
  78. * \param Function Name of the function generates the warning.
  79. * \param Description Format string for the warning message.
  80. *
  81. * \return \b false
  82. */
  83. bool WarningE(const char *Function,const char *Description,...) APT_PRINTF(3) APT_COLD;
  84. /** \brief add a notice message with errno to the list
  85. *
  86. * \param Function name of the function generating the error
  87. * \param Description format string for the error message
  88. *
  89. * \return \b false
  90. */
  91. bool NoticeE(const char *Function,const char *Description,...) APT_PRINTF(3) APT_COLD;
  92. /** \brief add a debug message with errno to the list
  93. *
  94. * \param Function name of the function generating the error
  95. * \param Description format string for the error message
  96. *
  97. * \return \b false
  98. */
  99. bool DebugE(const char *Function,const char *Description,...) APT_PRINTF(3) APT_COLD;
  100. /** \brief adds an errno message with the given type
  101. *
  102. * \param type of the error message
  103. * \param Function which failed
  104. * \param Description of the error
  105. */
  106. bool InsertErrno(MsgType const &type, const char* Function,
  107. const char* Description,...) APT_PRINTF(4) APT_COLD;
  108. /** \brief adds an errno message with the given type
  109. *
  110. * args needs to be initialized with va_start and terminated
  111. * with va_end by the caller. msgSize is also an out-parameter
  112. * in case the msgSize was not enough to store the complete message.
  113. *
  114. * \param type of the error message
  115. * \param Function which failed
  116. * \param Description is the format string for args
  117. * \param args list from a printf-like function
  118. * \param errsv is the errno the error is for
  119. * \param msgSize is the size of the char[] used to store message
  120. * \return true if the message was added, false if not - the caller
  121. * should call this method again in that case
  122. */
  123. bool InsertErrno(MsgType type, const char* Function,
  124. const char* Description, va_list &args,
  125. int const errsv, size_t &msgSize) APT_COLD;
  126. /** \brief add an fatal error message to the list
  127. *
  128. * Most of the stuff we consider as "error" is also "fatal" for
  129. * the user as the application will not have the expected result,
  130. * but a fatal message here means that it gets printed directly
  131. * to stderr in addition to adding it to the list as the error
  132. * leads sometimes to crashes and a maybe duplicated message
  133. * is better than "Segfault" as the only displayed text
  134. *
  135. * \param Description Format string for the fatal error message.
  136. *
  137. * \return \b false
  138. */
  139. bool Fatal(const char *Description,...) APT_PRINTF(2) APT_COLD;
  140. /** \brief add an Error message to the list
  141. *
  142. * \param Description Format string for the error message.
  143. *
  144. * \return \b false
  145. */
  146. bool Error(const char *Description,...) APT_PRINTF(2) APT_COLD;
  147. /** \brief add a warning message to the list
  148. *
  149. * A warning should be considered less severe than an error and
  150. * may be ignored by the client.
  151. *
  152. * \param Description Format string for the message
  153. *
  154. * \return \b false
  155. */
  156. bool Warning(const char *Description,...) APT_PRINTF(2) APT_COLD;
  157. /** \brief add a notice message to the list
  158. *
  159. * A notice should be considered less severe than an error or a
  160. * warning and can be ignored by the client without further problems
  161. * for some times, but he should consider fixing the problem.
  162. * This error type can be used for e.g. deprecation warnings of options.
  163. *
  164. * \param Description Format string for the message
  165. *
  166. * \return \b false
  167. */
  168. bool Notice(const char *Description,...) APT_PRINTF(2) APT_COLD;
  169. /** \brief add a debug message to the list
  170. *
  171. * \param Description Format string for the message
  172. *
  173. * \return \b false
  174. */
  175. bool Debug(const char *Description,...) APT_PRINTF(2) APT_COLD;
  176. /** \brief adds an error message with the given type
  177. *
  178. * \param type of the error message
  179. * \param Description of the error
  180. */
  181. bool Insert(MsgType const &type, const char* Description,...) APT_PRINTF(3) APT_COLD;
  182. /** \brief adds an error message with the given type
  183. *
  184. * args needs to be initialized with va_start and terminated
  185. * with va_end by the caller. msgSize is also an out-parameter
  186. * in case the msgSize was not enough to store the complete message.
  187. *
  188. * \param type of the error message
  189. * \param Description is the format string for args
  190. * \param args list from a printf-like function
  191. * \param msgSize is the size of the char[] used to store message
  192. * \return true if the message was added, false if not - the caller
  193. * should call this method again in that case
  194. */
  195. bool Insert(MsgType type, const char* Description,
  196. va_list &args, size_t &msgSize) APT_COLD;
  197. /** \brief is an error in the list?
  198. *
  199. * \return \b true if an error is included in the list, \b false otherwise
  200. */
  201. inline bool PendingError() const APT_PURE {return PendingFlag;};
  202. /** \brief convert a stored error to a return code
  203. *
  204. * Put simply, the entire concept of PendingError() is flawed :/.
  205. *
  206. * The typical "if (PendingError()) return false;" check that is
  207. * strewn throughout the codebase "compounds", making it impossible
  208. * for there to be any nuance about the notion of "error" when a
  209. * subsystem needs to fail but a higher-level system needs to work.
  210. *
  211. * However, the codebase is also horribly broken with respect to
  212. * errors, as it fails to use C++ exceptions when warranted and
  213. * instead relies on this insane indirect error mechanism to check
  214. * the failure status of a constructor. What is thereby needed is
  215. * a way to clear the PendingError() flag without also discarding
  216. * the underlying errors, so we have to convert them to warnings.
  217. *
  218. * \return \b false
  219. */
  220. bool ReturnError() APT_COLD;
  221. /** \brief is the list empty?
  222. *
  223. * Can be used to check if the current stack level doesn't include
  224. * anything equal or more severe than a given threshold, defaulting
  225. * to warning level for historic reasons.
  226. *
  227. * \param threshold minimum level considered
  228. *
  229. * \return \b true if the list is empty, \b false otherwise
  230. */
  231. bool empty(MsgType const &threshold = WARNING) const APT_PURE;
  232. /** \brief returns and removes the first (or last) message in the list
  233. *
  234. * \param[out] Text message of the first/last item
  235. *
  236. * \return \b true if the message was an error, \b false otherwise
  237. */
  238. bool PopMessage(std::string &Text);
  239. /** \brief clears the list of messages */
  240. void Discard();
  241. /** \brief outputs the list of messages to the given stream
  242. *
  243. * Note that all messages are discarded, even undisplayed ones.
  244. *
  245. * \param[out] out output stream to write the messages in
  246. * \param threshold minimum level considered
  247. * \param mergeStack if true recursively dumps the entire stack
  248. */
  249. void DumpErrors(std::ostream &out, MsgType const &threshold = WARNING,
  250. bool const &mergeStack = true);
  251. /** \brief dumps the list of messages to std::cerr
  252. *
  253. * Note that all messages are discarded, also the notices
  254. * displayed or not.
  255. *
  256. * \param threshold minimum level printed
  257. */
  258. void inline DumpErrors(MsgType const &threshold) {
  259. DumpErrors(std::cerr, threshold);
  260. }
  261. // mvo: we do this instead of using a default parameter in the
  262. // previous declaration to avoid a (subtle) API break for
  263. // e.g. sigc++ and mem_fun0
  264. /** \brief dumps the messages of type WARNING or higher to std::cerr
  265. *
  266. * Note that all messages are discarded, displayed or not.
  267. *
  268. */
  269. void inline DumpErrors() {
  270. DumpErrors(WARNING);
  271. }
  272. /** \brief put the current Messages into the stack
  273. *
  274. * All "old" messages will be pushed into a stack to
  275. * them later back, but for now the Message query will be
  276. * empty and performs as no messages were present before.
  277. *
  278. * The stack can be as deep as you want - all stack operations
  279. * will only operate on the last element in the stack.
  280. */
  281. void PushToStack();
  282. /** \brief throw away all current messages */
  283. void RevertToStack();
  284. /** \brief merge current and stack together */
  285. void MergeWithStack();
  286. /** \brief return the deep of the stack */
  287. size_t StackCount() const APT_PURE {
  288. return Stacks.size();
  289. }
  290. GlobalError();
  291. /*}}}*/
  292. private: /*{{{*/
  293. struct Item {
  294. std::string Text;
  295. MsgType Type;
  296. Item(char const *Text, MsgType const &Type) :
  297. Text(Text), Type(Type) {};
  298. APT_HIDDEN friend std::ostream& operator<< (std::ostream &out, Item i) {
  299. switch(i.Type) {
  300. case FATAL:
  301. case ERROR: out << 'E'; break;
  302. case WARNING: out << 'W'; break;
  303. case NOTICE: out << 'N'; break;
  304. case DEBUG: out << 'D'; break;
  305. }
  306. out << ": ";
  307. std::string::size_type line_start = 0;
  308. std::string::size_type line_end;
  309. while ((line_end = i.Text.find_first_of("\n\r", line_start)) != std::string::npos) {
  310. if (line_start != 0)
  311. out << std::endl << " ";
  312. out << i.Text.substr(line_start, line_end - line_start);
  313. line_start = i.Text.find_first_not_of("\n\r", line_end + 1);
  314. if (line_start == std::string::npos)
  315. break;
  316. }
  317. if (line_start == 0)
  318. out << i.Text;
  319. else if (line_start != std::string::npos)
  320. out << std::endl << " " << i.Text.substr(line_start);
  321. return out;
  322. }
  323. };
  324. std::list<Item> Messages;
  325. bool PendingFlag;
  326. struct MsgStack {
  327. std::list<Item> Messages;
  328. bool const PendingFlag;
  329. MsgStack(std::list<Item> const &Messages, bool const &Pending) :
  330. Messages(Messages), PendingFlag(Pending) {};
  331. };
  332. std::list<MsgStack> Stacks;
  333. /*}}}*/
  334. };
  335. /*}}}*/
  336. // The 'extra-ansi' syntax is used to help with collisions.
  337. GlobalError *_GetErrorObj();
  338. #define _error _GetErrorObj()
  339. #endif