]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode: cpp; mode: fold -*- | |
2 | // Description /*{{{*/ | |
3 | // $Id: error.h,v 1.8 2001/05/07 05:06:52 jgg Exp $ | |
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 | /*}}}*/ | |
40 | #ifndef PKGLIB_ERROR_H | |
41 | #define PKGLIB_ERROR_H | |
42 | ||
43 | #include <apt-pkg/macros.h> | |
44 | ||
45 | #include <iostream> | |
46 | #include <list> | |
47 | #include <string> | |
48 | ||
49 | #include <stdarg.h> | |
50 | ||
51 | class GlobalError /*{{{*/ | |
52 | { | |
53 | public: /*{{{*/ | |
54 | /** \brief a message can have one of following severity */ | |
55 | enum MsgType { | |
56 | /** \brief Message will be printed instantly as it is likely that | |
57 | this error will lead to a complete crash */ | |
58 | FATAL = 40, | |
59 | /** \brief An error does hinder the correct execution and should be corrected */ | |
60 | ERROR = 30, | |
61 | /** \brief indicates problem that can lead to errors later on */ | |
62 | WARNING = 20, | |
63 | /** \brief deprecation warnings, old fallback behavior, … */ | |
64 | NOTICE = 10, | |
65 | /** \brief for developers only in areas it is hard to print something directly */ | |
66 | DEBUG = 0 | |
67 | }; | |
68 | ||
69 | /** \brief add a fatal error message with errno to the list | |
70 | * | |
71 | * \param Function name of the function generating the error | |
72 | * \param Description format string for the error message | |
73 | * | |
74 | * \return \b false | |
75 | */ | |
76 | bool FatalE(const char *Function,const char *Description,...) __like_printf(3) __cold; | |
77 | ||
78 | /** \brief add an Error message with errno to the list | |
79 | * | |
80 | * \param Function name of the function generating the error | |
81 | * \param Description format string for the error message | |
82 | * | |
83 | * \return \b false | |
84 | */ | |
85 | bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold; | |
86 | ||
87 | /** \brief add a warning message with errno to the list | |
88 | * | |
89 | * A warning should be considered less severe than an error and | |
90 | * may be ignored by the client. | |
91 | * | |
92 | * \param Function Name of the function generates the warning. | |
93 | * \param Description Format string for the warning message. | |
94 | * | |
95 | * \return \b false | |
96 | */ | |
97 | bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold; | |
98 | ||
99 | /** \brief add a notice message with errno to the list | |
100 | * | |
101 | * \param Function name of the function generating the error | |
102 | * \param Description format string for the error message | |
103 | * | |
104 | * \return \b false | |
105 | */ | |
106 | bool NoticeE(const char *Function,const char *Description,...) __like_printf(3) __cold; | |
107 | ||
108 | /** \brief add a debug message with errno to the list | |
109 | * | |
110 | * \param Function name of the function generating the error | |
111 | * \param Description format string for the error message | |
112 | * | |
113 | * \return \b false | |
114 | */ | |
115 | bool DebugE(const char *Function,const char *Description,...) __like_printf(3) __cold; | |
116 | ||
117 | /** \brief adds an errno message with the given type | |
118 | * | |
119 | * \param type of the error message | |
120 | * \param Function which failed | |
121 | * \param Description of the error | |
122 | */ | |
123 | bool InsertErrno(MsgType const &type, const char* Function, | |
124 | const char* Description,...) __like_printf(4) __cold; | |
125 | ||
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 addiction 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,...) __like_printf(2) __cold; | |
140 | ||
141 | /** \brief add an Error message to the list | |
142 | * | |
143 | * \param Description Format string for the error message. | |
144 | * | |
145 | * \return \b false | |
146 | */ | |
147 | bool Error(const char *Description,...) __like_printf(2) __cold; | |
148 | ||
149 | /** \brief add a warning message to the list | |
150 | * | |
151 | * A warning should be considered less severe than an error and | |
152 | * may be ignored by the client. | |
153 | * | |
154 | * \param Description Format string for the message | |
155 | * | |
156 | * \return \b false | |
157 | */ | |
158 | bool Warning(const char *Description,...) __like_printf(2) __cold; | |
159 | ||
160 | /** \brief add a notice message to the list | |
161 | * | |
162 | * A notice should be considered less severe than an error or a | |
163 | * warning and can be ignored by the client without further problems | |
164 | * for some times, but he should consider fixing the problem. | |
165 | * This error type can be used for e.g. deprecation warnings of options. | |
166 | * | |
167 | * \param Description Format string for the message | |
168 | * | |
169 | * \return \b false | |
170 | */ | |
171 | bool Notice(const char *Description,...) __like_printf(2) __cold; | |
172 | ||
173 | /** \brief add a debug message to the list | |
174 | * | |
175 | * \param Description Format string for the message | |
176 | * | |
177 | * \return \b false | |
178 | */ | |
179 | bool Debug(const char *Description,...) __like_printf(2) __cold; | |
180 | ||
181 | /** \brief adds an error message with the given type | |
182 | * | |
183 | * \param type of the error message | |
184 | * \param Description of the error | |
185 | */ | |
186 | bool Insert(MsgType const &type, const char* Description,...) __like_printf(3) __cold; | |
187 | ||
188 | /** \brief is an error in the list? | |
189 | * | |
190 | * \return \b true if an error is included in the list, \b false otherwise | |
191 | */ | |
192 | inline bool PendingError() const {return PendingFlag;}; | |
193 | ||
194 | /** \brief is the list empty? | |
195 | * | |
196 | * The default checks if the list is empty or contains only notices, | |
197 | * if you want to check if also no notices happend set the parameter | |
198 | * flag to \b false. | |
199 | * | |
200 | * \param WithoutNotice does notices count, default is \b true, so no | |
201 | * | |
202 | * \return \b true if an the list is empty, \b false otherwise | |
203 | */ | |
204 | bool empty(MsgType const &trashhold = WARNING) const; | |
205 | ||
206 | /** \brief returns and removes the first (or last) message in the list | |
207 | * | |
208 | * \param[out] Text message of the first/last item | |
209 | * | |
210 | * \return \b true if the message was an error, \b false otherwise | |
211 | */ | |
212 | bool PopMessage(std::string &Text); | |
213 | ||
214 | /** \brief clears the list of messages */ | |
215 | void Discard(); | |
216 | ||
217 | /** \brief outputs the list of messages to the given stream | |
218 | * | |
219 | * Note that all messages are discarded, also the notices | |
220 | * displayed or not. | |
221 | * | |
222 | * \param[out] out output stream to write the messages in | |
223 | * \param threshold minimim level considered | |
224 | * \param mergeStack | |
225 | */ | |
226 | void DumpErrors(std::ostream &out, MsgType const &threshold = WARNING, | |
227 | bool const &mergeStack = true); | |
228 | ||
229 | /** \brief dumps the list of messages to std::cerr | |
230 | * | |
231 | * Note that all messages are discarded, also the notices | |
232 | * displayed or not. | |
233 | * | |
234 | * \param threshold minimum level printed | |
235 | */ | |
236 | void inline DumpErrors(MsgType const &threshold) { | |
237 | DumpErrors(std::cerr, threshold); | |
238 | } | |
239 | ||
240 | // mvo: we do this instead of using a default parameter in the | |
241 | // previous declaration to avoid a (subtle) API break for | |
242 | // e.g. sigc++ and mem_fun0 | |
243 | /** \brief dumps the messages of type WARNING or higher to std::cerr | |
244 | * | |
245 | * Note that all messages are discarded, displayed or not. | |
246 | * | |
247 | */ | |
248 | void inline DumpErrors() { | |
249 | DumpErrors(WARNING); | |
250 | } | |
251 | ||
252 | /** \brief put the current Messages into the stack | |
253 | * | |
254 | * All "old" messages will be pushed into a stack to | |
255 | * them later back, but for now the Message query will be | |
256 | * empty and performs as no messages were present before. | |
257 | * | |
258 | * The stack can be as deep as you want - all stack operations | |
259 | * will only operate on the last element in the stack. | |
260 | */ | |
261 | void PushToStack(); | |
262 | ||
263 | /** \brief throw away all current messages */ | |
264 | void RevertToStack(); | |
265 | ||
266 | /** \brief merge current and stack together */ | |
267 | void MergeWithStack(); | |
268 | ||
269 | /** \brief return the deep of the stack */ | |
270 | size_t StackCount() const { | |
271 | return Stacks.size(); | |
272 | } | |
273 | ||
274 | GlobalError(); | |
275 | /*}}}*/ | |
276 | private: /*{{{*/ | |
277 | struct Item { | |
278 | std::string Text; | |
279 | MsgType Type; | |
280 | ||
281 | Item(char const *Text, MsgType const &Type) : | |
282 | Text(Text), Type(Type) {}; | |
283 | ||
284 | friend std::ostream& operator<< (std::ostream &out, Item i) { | |
285 | switch(i.Type) { | |
286 | case FATAL: | |
287 | case ERROR: out << "E"; break; | |
288 | case WARNING: out << "W"; break; | |
289 | case NOTICE: out << "N"; break; | |
290 | case DEBUG: out << "D"; break; | |
291 | } | |
292 | return out << ": " << i.Text; | |
293 | } | |
294 | }; | |
295 | ||
296 | std::list<Item> Messages; | |
297 | bool PendingFlag; | |
298 | ||
299 | struct MsgStack { | |
300 | std::list<Item> const Messages; | |
301 | bool const PendingFlag; | |
302 | ||
303 | MsgStack(std::list<Item> const &Messages, bool const &Pending) : | |
304 | Messages(Messages), PendingFlag(Pending) {}; | |
305 | }; | |
306 | ||
307 | std::list<MsgStack> Stacks; | |
308 | ||
309 | bool InsertErrno(MsgType type, const char* Function, | |
310 | const char* Description, va_list &args, | |
311 | int const errsv, size_t &msgSize); | |
312 | bool Insert(MsgType type, const char* Description, | |
313 | va_list &args, size_t &msgSize); | |
314 | /*}}}*/ | |
315 | }; | |
316 | /*}}}*/ | |
317 | ||
318 | // The 'extra-ansi' syntax is used to help with collisions. | |
319 | GlobalError *_GetErrorObj(); | |
320 | #define _error _GetErrorObj() | |
321 | ||
322 | #endif |