summaryrefslogtreecommitdiff
path: root/graphics/sam2p/error.hpp
blob: af9a58ed207ead4cb4bd997fb14f1490c16ac4d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* error.hpp -- handling errors/warnings etc.
 * by pts@fazekas.hu at Fri Mar  1 11:32:36 CET 2002
 */

#ifdef __GNUC__
#ifndef __clang__
#pragma interface
#endif
#endif

#ifndef ERROR_HPP
#define ERROR_HPP 1

#include "config2.h"
#include "gensi.hpp"

/** This may be usafe if an error happens inside an error. Usage:
 * Error::sev(Error::WARNING) << "Zero-length image." << (Error*)0;
 */
class Error {
 public:
  static char const* banner0;
  static char const* argv0;
  static char const* tmpargv0;
  static char const* long_argv0;
  /** Error types. */
  BEGIN_STATIC_ENUM(int,level_t)
    ASSERT=4, FATAL=3,
    EERROR=2, /* ERROR conflicts with the Win32 API :-( */
    ERROR_CONT=-2, /* error, but continue running program */
    WARNING=-3,
    WARNING_DEFER=-4, /* warning, but defer (and later possibly omit) displaying it */
    NOTICE=-5,
    NOTICE_DEFER=-6, INFO=-111, DEBUG=-222
  END_STATIC_ENUM()
  /** Standard error stream (stderr) of the current process. */
  static GenBuffer::Writable * serr;
  /** Returns address to statically allocated buffer. */
  static char const*level2str(level_t level);
  /** This is the (carefully hidden :-)) method of raising errors (i.e
   * displaying error messages and terminating the program).
   * Example usage: 
   *   Error::sev(Error::WARNING_DEFER) << "check_rule: /BMP requires "
   *                                       "/Predictor " << 1 << (Error*)0;
   * The error is interpreted according to the current policy. The policy
   * divides errors into three categories:
   *
   * -- secret: nothing happens (even the error message is _not_ printed)
   * -- recorded: nothing happens (even the error message is _not_ printed),
   *    but the message is remembered for further processing.
   * -- printed: the error message is printed, and program execution continues
   *    Before printing this message, all recorded errors on the policy stack
   *    are also printed (deepest first).
   * -- killer: like `printed', but runs cleanup handlers and terminates the
   *    program immediately.
   *
   * @param level is one of the constants mentioned above (FATAL, EERROR,
   *   WARNING, NOTICE etc). Can be positive, zero or negative. The larger
   *   the `level', the more severe the error is. The default policy is:
   *   level>=0 errors are killer, -99<=level<=-1 errors are printed,
   *   -199<=level<=-100 are recorded and level<=-200 errors are secret.
   */
  static GenBuffer::Writable& sev(level_t level);
  
 public:
  /** The field order is important in this struct, because of the initializers. */
  struct Policy {
    /** All recorded messages. Default: NULL. This means empty. */
    SimBuffer::B *record;
    /** The highest level of Secret category encountered so far. Default: -9999 */
    level_t topSecret;
    /** The highest level of Recorded category encountered so far. Default: -9999 */
    level_t topRecorded;
    /** Lower bound of these categories in this policy. */    
    level_t killer, printed, recorded;
    /** Error stream to print printed and killer messages. */
    GenBuffer::Writable *err;
    /** NULL for top policy */
    Policy *prev, *next;
    /** Level of the current error being raised. */
    level_t curlev;
  };
 protected:
  /** Boundaries of the policy stack. */
  static Policy *policy_top, *policy_bottom;  
 public:
  friend GenBuffer::Writable& operator <<(GenBuffer::Writable&,Error*);
  /** Creates a new policy and makes it active by pushing it onto the top of
   * the policy stack.
   */
  static void pushPolicy(level_t killer_, level_t printed_, level_t recorded_, GenBuffer::Writable *err=(GenBuffer::Writable*)NULLP);
  /** @return the messages already recorded, and clears the `record' entry
   * of the current policy. The caller is responsible for deleting the
   * pointer returned. May return NULLP for empty records. Typical example:
   *   delete Error::getRecorded();
   */
  static SimBuffer::B *getRecorded();
  /** Prints all recorded error messages, and removes the topmost element of
   * the policy stack. Typical example:
   *   delete Error::getRecorded();  popPolicy();
   */
  static void popPolicy();

  /** @example Error::setTopPrinted(Error::ERROR_CONT); suppress anything
   * below error, such as warnings.
   */
  static void setTopPrinted(level_t printed_);
  
  static level_t getTopPrinted();
  
  /** The Cleanup mechanism is similar to atexit(3) and on_exit(3). This is
   * just a simple struct with no destructors, virtual methods or inheritance.
   *
   * Additional data (char[] buffer) can be allocated and stored right
   * after the object (this+1), it can be retrieved with getBuf(), and it will
   * be deleted when the object is deleted by runCleanups().
   */
  struct Cleanup {
    /** Must _not_ cause any Errors.
     * @return an exit code. If larger than the current one, replaces it
     */
    typedef int (*handler_t)(Cleanup*);
    /** Owned externally. */
    handler_t handler;
    /** size of extra data allocated at getBuf(). */
    slen_t bufSize;
    /** Arbitrary data, owned by `handler': handler' must delete `data'
     * when called.
     */
    void *data;
    /** NULLP: no next, end of chain */
    Cleanup *next;
    inline char *getBuf()   { return (char*)(this+1); }
    inline slen_t getSize() { return bufSize; }
  };
  /** Creates and returns a new Cleanup, and registers it in front of the
   * existing ones. Copies `handler' and `data' to it. Also allocates `bufSize' bytes
   * of char[] buffer (at result->getBuf()) owned by the cleanup, but doesn't
   * initialize the buffer.
   *
   * Doesn't take ownership of `handler', takes ownership of `data'.
   * `handler' must delete `data' or pass on ownership when called,
   * typically by runCleanups().
   */
  static Cleanup* newCleanup(Cleanup::handler_t handler, void *data, slen_t bufSize);
  /** Creates and returns a new Cleanup, and registers it in front of the
   * existing ones. Copies `handler' and `data' to it. Also allocates
   * strlen(bufCstr)+1 bytes of char[] buffer (at result->getBuf()) owned by
   * the cleanup, and initializes it from bufCstr.
   *
   * Doesn't take ownership of `handler', takes ownership of `data'.
   * `handler' must delete `data' or pass on ownership when called,
   * typically by runCleanups().
   */
  static Cleanup* newCleanup(Cleanup::handler_t handler, void *data, char const*bufCstr);
  /** Reverts to the default logging policy,
   * executes the cleanup handlers (in reverse-registration order),
   * unregisters and deletes all the cleanups, and returns the
   * new exit code, which is at least exitCode.
   */
  static int runCleanups(int exitCode);
  /* Exits from the process with the specified exit code. */
  static void cexit(int exitCode);
 protected:
  static Cleanup *first_cleanup;
};

GenBuffer::Writable& operator <<(GenBuffer::Writable&,Error*);
 
#endif