1 /* error.hpp -- handling errors/warnings etc.
2  * by pts@fazekas.hu at Fri Mar  1 11:32:36 CET 2002
3  */
4 
5 #ifdef __GNUC__
6 #ifndef __clang__
7 #pragma interface
8 #endif
9 #endif
10 
11 #ifndef ERROR_HPP
12 #define ERROR_HPP 1
13 
14 #include "config2.h"
15 #include "gensi.hpp"
16 
17 /** This may be usafe if an error happens inside an error. Usage:
18  * Error::sev(Error::WARNING) << "Zero-length image." << (Error*)0;
19  */
20 class Error {
21  public:
22   static char const* banner0;
23   static char const* argv0;
24   static char const* tmpargv0;
25   static char const* long_argv0;
26   /** Error types. */
27   BEGIN_STATIC_ENUM(int,level_t)
28     ASSERT=4, FATAL=3,
29     EERROR=2, /* ERROR conflicts with the Win32 API :-( */
30     ERROR_CONT=-2, /* error, but continue running program */
31     WARNING=-3,
32     WARNING_DEFER=-4, /* warning, but defer (and later possibly omit) displaying it */
33     NOTICE=-5,
34     NOTICE_DEFER=-6, INFO=-111, DEBUG=-222
35   END_STATIC_ENUM()
36   /** Standard error stream (stderr) of the current process. */
37   static GenBuffer::Writable * serr;
38   /** Returns address to statically allocated buffer. */
39   static char const*level2str(level_t level);
40   /** This is the (carefully hidden :-)) method of raising errors (i.e
41    * displaying error messages and terminating the program).
42    * Example usage:
43    *   Error::sev(Error::WARNING_DEFER) << "check_rule: /BMP requires "
44    *                                       "/Predictor " << 1 << (Error*)0;
45    * The error is interpreted according to the current policy. The policy
46    * divides errors into three categories:
47    *
48    * -- secret: nothing happens (even the error message is _not_ printed)
49    * -- recorded: nothing happens (even the error message is _not_ printed),
50    *    but the message is remembered for further processing.
51    * -- printed: the error message is printed, and program execution continues
52    *    Before printing this message, all recorded errors on the policy stack
53    *    are also printed (deepest first).
54    * -- killer: like `printed', but runs cleanup handlers and terminates the
55    *    program immediately.
56    *
57    * @param level is one of the constants mentioned above (FATAL, EERROR,
58    *   WARNING, NOTICE etc). Can be positive, zero or negative. The larger
59    *   the `level', the more severe the error is. The default policy is:
60    *   level>=0 errors are killer, -99<=level<=-1 errors are printed,
61    *   -199<=level<=-100 are recorded and level<=-200 errors are secret.
62    */
63   static GenBuffer::Writable& sev(level_t level);
64 
65  public:
66   /** The field order is important in this struct, because of the initializers. */
67   struct Policy {
68     /** All recorded messages. Default: NULL. This means empty. */
69     SimBuffer::B *record;
70     /** The highest level of Secret category encountered so far. Default: -9999 */
71     level_t topSecret;
72     /** The highest level of Recorded category encountered so far. Default: -9999 */
73     level_t topRecorded;
74     /** Lower bound of these categories in this policy. */
75     level_t killer, printed, recorded;
76     /** Error stream to print printed and killer messages. */
77     GenBuffer::Writable *err;
78     /** NULL for top policy */
79     Policy *prev, *next;
80     /** Level of the current error being raised. */
81     level_t curlev;
82   };
83  protected:
84   /** Boundaries of the policy stack. */
85   static Policy *policy_top, *policy_bottom;
86  public:
87   friend GenBuffer::Writable& operator <<(GenBuffer::Writable&,Error*);
88   /** Creates a new policy and makes it active by pushing it onto the top of
89    * the policy stack.
90    */
91   static void pushPolicy(level_t killer_, level_t printed_, level_t recorded_, GenBuffer::Writable *err=(GenBuffer::Writable*)NULLP);
92   /** @return the messages already recorded, and clears the `record' entry
93    * of the current policy. The caller is responsible for deleting the
94    * pointer returned. May return NULLP for empty records. Typical example:
95    *   delete Error::getRecorded();
96    */
97   static SimBuffer::B *getRecorded();
98   /** Prints all recorded error messages, and removes the topmost element of
99    * the policy stack. Typical example:
100    *   delete Error::getRecorded();  popPolicy();
101    */
102   static void popPolicy();
103 
104   /** @example Error::setTopPrinted(Error::ERROR_CONT); suppress anything
105    * below error, such as warnings.
106    */
107   static void setTopPrinted(level_t printed_);
108 
109   static level_t getTopPrinted();
110 
111   /** The Cleanup mechanism is similar to atexit(3) and on_exit(3). This is
112    * just a simple struct with no destructors, virtual methods or inheritance.
113    *
114    * Additional data (char[] buffer) can be allocated and stored right
115    * after the object (this+1), it can be retrieved with getBuf(), and it will
116    * be deleted when the object is deleted by runCleanups().
117    */
118   struct Cleanup {
119     /** Must _not_ cause any Errors.
120      * @return an exit code. If larger than the current one, replaces it
121      */
122     typedef int (*handler_t)(Cleanup*);
123     /** Owned externally. */
124     handler_t handler;
125     /** size of extra data allocated at getBuf(). */
126     slen_t bufSize;
127     /** Arbitrary data, owned by `handler': handler' must delete `data'
128      * when called.
129      */
130     void *data;
131     /** NULLP: no next, end of chain */
132     Cleanup *next;
getBufError::Cleanup133     inline char *getBuf()   { return (char*)(this+1); }
getSizeError::Cleanup134     inline slen_t getSize() { return bufSize; }
135   };
136   /** Creates and returns a new Cleanup, and registers it in front of the
137    * existing ones. Copies `handler' and `data' to it. Also allocates `bufSize' bytes
138    * of char[] buffer (at result->getBuf()) owned by the cleanup, but doesn't
139    * initialize the buffer.
140    *
141    * Doesn't take ownership of `handler', takes ownership of `data'.
142    * `handler' must delete `data' or pass on ownership when called,
143    * typically by runCleanups().
144    */
145   static Cleanup* newCleanup(Cleanup::handler_t handler, void *data, slen_t bufSize);
146   /** Creates and returns a new Cleanup, and registers it in front of the
147    * existing ones. Copies `handler' and `data' to it. Also allocates
148    * strlen(bufCstr)+1 bytes of char[] buffer (at result->getBuf()) owned by
149    * the cleanup, and initializes it from bufCstr.
150    *
151    * Doesn't take ownership of `handler', takes ownership of `data'.
152    * `handler' must delete `data' or pass on ownership when called,
153    * typically by runCleanups().
154    */
155   static Cleanup* newCleanup(Cleanup::handler_t handler, void *data, char const*bufCstr);
156   /** Reverts to the default logging policy,
157    * executes the cleanup handlers (in reverse-registration order),
158    * unregisters and deletes all the cleanups, and returns the
159    * new exit code, which is at least exitCode.
160    */
161   static int runCleanups(int exitCode);
162   /* Exits from the process with the specified exit code. */
163   static void cexit(int exitCode);
164  protected:
165   static Cleanup *first_cleanup;
166 };
167 
168 GenBuffer::Writable& operator <<(GenBuffer::Writable&,Error*);
169 
170 #endif
171