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