1 | /* ========================================================================
|
---|
2 | * (C) 2000 Vienna University of Technology
|
---|
3 | * ========================================================================
|
---|
4 | * PROJECT: Urban Viz
|
---|
5 | * ========================================================================*/
|
---|
6 | /** several error checking/log facilities.
|
---|
7 | *
|
---|
8 | * for char-strings, 'String' is typedef'd for convenience
|
---|
9 | * This library can be used standalone, with old style iostreams
|
---|
10 | * (define \c OLDSTREAM for that) or new style iostreams
|
---|
11 | *
|
---|
12 | * $Header: /usr/local/cvsyare/cvsyamp/include/merror.h,v 1.3 2003/01/06 19:01:32 wimmer Exp $
|
---|
13 | * @author Michael Wimmer
|
---|
14 | * @file */
|
---|
15 | /* ========================================================================*/
|
---|
16 |
|
---|
17 | #ifndef NO_PRAGMA_ONCE
|
---|
18 | #pragma once
|
---|
19 | #endif
|
---|
20 |
|
---|
21 | #ifndef MERROR_H
|
---|
22 | #define MERROR_H
|
---|
23 |
|
---|
24 |
|
---|
25 | // this library can be used with new and old style iostreams
|
---|
26 | #ifndef OLDSTREAM
|
---|
27 | # include <iostream>
|
---|
28 | # define ERRSTD std
|
---|
29 | #else
|
---|
30 | # include <iostream.h>
|
---|
31 | # define ERRSTD
|
---|
32 | #endif
|
---|
33 |
|
---|
34 |
|
---|
35 | // ---------------------------------------------------------------------------
|
---|
36 | // General macros
|
---|
37 | // ---------------------------------------------------------------------------
|
---|
38 |
|
---|
39 | /// always use this to delete an object
|
---|
40 | #define DELPTR(ptr) do { if (ptr) { delete (ptr); (ptr) = NULL; } } while (0)
|
---|
41 | /// always use this to delete an array of objects
|
---|
42 | #define DELAPTR(ptr) do { if (ptr) { delete [] (ptr); (ptr) = NULL; } } while (0)
|
---|
43 |
|
---|
44 |
|
---|
45 | // ---------------------------------------------------------------------------
|
---|
46 | // Log file initialization
|
---|
47 | // ---------------------------------------------------------------------------
|
---|
48 |
|
---|
49 | // gets global logfile, used by OUT/ASSERT/etc macros, to allow
|
---|
50 | // logstream to be used in global constructors
|
---|
51 | ERRSTD::ostream &_GetLogStream();
|
---|
52 | // enables use of curses or other things
|
---|
53 | ERRSTD::ostream &_LogStreamDone(ERRSTD::ostream &os,
|
---|
54 | bool overrideconsole = false);
|
---|
55 |
|
---|
56 | /** an application can declare a function of this type to redirect
|
---|
57 | console output. */
|
---|
58 | typedef void (*LogStreamToConsoleFunc)(const char *consoleoutput);
|
---|
59 |
|
---|
60 | /// Set a handler to redirect console output
|
---|
61 | void SetConsoleStreamHandler(LogStreamToConsoleFunc handler);
|
---|
62 |
|
---|
63 | /// enables/disables logging to logfile (for performance reasons)
|
---|
64 | void SetLogToFile(bool yesno);
|
---|
65 |
|
---|
66 |
|
---|
67 | /** initializes the logfile for \c OUT/ASSERT etc macros - call once at
|
---|
68 | beginning if you desire file output
|
---|
69 | (for logtofile=false output goes to \c cerr initially) */
|
---|
70 | void InitLogStream(const char *filename = "error.log", bool logtofileonly = true);
|
---|
71 |
|
---|
72 | /// if true, logs to logfile, otherwise logs to console (\c cerr)
|
---|
73 | bool SetLogStream(bool logtofileonly);
|
---|
74 |
|
---|
75 |
|
---|
76 | // ---------------------------------------------------------------------------
|
---|
77 | // Log file definitions and macros
|
---|
78 | // ---------------------------------------------------------------------------
|
---|
79 |
|
---|
80 |
|
---|
81 | /** @name Logfile output macros
|
---|
82 | Any of those will write a string to the console and, if desired,
|
---|
83 | to the logfile.
|
---|
84 | They differ in the amount of tabs they prepend.
|
---|
85 | Note: all macros (except OUT0) PREPEND a carriage return!
|
---|
86 | */
|
---|
87 | //@{
|
---|
88 |
|
---|
89 |
|
---|
90 | /// stream a variable; example: \c OUT1(SV(refcount)) gives ' refcount = 5 '
|
---|
91 | #define SV(x) " " #x "=" << (x) << " "
|
---|
92 |
|
---|
93 | /// stream a string; example: \c OUT1(SS(filename)) gives ' filename = "abc" '
|
---|
94 | #define SS(x) "\"" << x << "\""
|
---|
95 |
|
---|
96 | // ------- logfile output macros
|
---|
97 |
|
---|
98 | /** stream to logfile.
|
---|
99 | (NOTE: don't insert \c endl here! use OUT1 for that - this is if you DON'T
|
---|
100 | want linebreaks!) */
|
---|
101 | #define OUT0(__xx) _LogStreamDone(_GetLogStream() << __xx)
|
---|
102 | /// stream to logfile (use if you want linebreaks!) - for normal use
|
---|
103 | #define OUT1(__xx) OUT0("\n" << __xx)
|
---|
104 | /// like \c OUT1, but with a TAB in front
|
---|
105 | #define OUT2(__xx) OUT1("\t" << __xx)
|
---|
106 | /// prepends 2 TABs
|
---|
107 | #define OUT3(__xx) OUT1("\t\t" << __xx)
|
---|
108 | /// prepends i TABs
|
---|
109 | #define OUTI(__ii,__xx) { _GetLogStream() << "\n"; \
|
---|
110 | for (int __jj = 0; __jj < __ii; __jj ++) \
|
---|
111 | _GetLogStream() << "\t"; \
|
---|
112 | _LogStreamDone(_GetLogStream() << __xx); }
|
---|
113 |
|
---|
114 | #define HERE " ("__FILE__", " << __LINE__ << ") ("__DATE__")"
|
---|
115 |
|
---|
116 | // internal macro to allow forced console output
|
---|
117 | #define _CONOUT(__xx) _LogStreamDone(_GetLogStream() << "\n" << __xx,true)
|
---|
118 |
|
---|
119 | /// error message with file, line and date information
|
---|
120 | #define EOUT(__xx) _CONOUT("ERROR: " << __xx << HERE)
|
---|
121 | /// warning message with file, line and date information
|
---|
122 | #define WOUT(__xx) _CONOUT("\tWARNING: " << __xx << HERE)
|
---|
123 |
|
---|
124 | //@}
|
---|
125 |
|
---|
126 | /* ---------------------------------------------------------------------------
|
---|
127 | Assertion macros: test the parameter result (if (!result) and take
|
---|
128 | approprate action if failed:
|
---|
129 |
|
---|
130 | ASM_xxx 2nd parameter specifies an error message for the logfile
|
---|
131 | ASS_xxx no error message
|
---|
132 | xxx if failed, just print error message
|
---|
133 | xxx_RETVAL if failed, the 3rd macro parameter is returned
|
---|
134 | xxx_RET return is called (for void functions)
|
---|
135 | xxx_ELSE if failed, output the error message, else execute following
|
---|
136 | statement
|
---|
137 | _ASM_TEMPLATE is used for creating the other macros.
|
---|
138 | -------------------------------------------------------------------------*/
|
---|
139 |
|
---|
140 | // used by ASM_*
|
---|
141 | #define _BLOCK do
|
---|
142 | #define _BLBEGIN _BLOCK {
|
---|
143 | #define _BLEND } while (0)
|
---|
144 | #define _NOP 4==4
|
---|
145 |
|
---|
146 | #ifndef RELEASE_BUILD
|
---|
147 | #define _ASM_TEMPLATE(result, errstr, stmt) \
|
---|
148 | _BLBEGIN if(!(result)) { EOUT(errstr); stmt; } _BLEND
|
---|
149 |
|
---|
150 | #define _ASS_TEMPLATE(result, stmt) \
|
---|
151 | _BLBEGIN if(!(result)) { stmt; } _BLEND
|
---|
152 |
|
---|
153 | #define _CHKM_TEMPLATE(result, errstr, stmt) \
|
---|
154 | _BLBEGIN if(!(result)) { EOUT(errstr); stmt; } _BLEND
|
---|
155 |
|
---|
156 | #define _CHKMS_TEMPLATE(result, stmt) \
|
---|
157 | _BLBEGIN if((result)==NULL) \
|
---|
158 | { DWORD errorValue = GetLastError(); EOUTMS( SV(errorValue) << \
|
---|
159 | GetErrorStringMS(errorValue)); stmt; } _BLEND
|
---|
160 |
|
---|
161 | #else
|
---|
162 | #define _ASM_TEMPLATE(result, errstr, stmt) _BLBEGIN _NOP; _BLEND
|
---|
163 | #define _ASS_TEMPLATE(result, stmt) _BLBEGIN _NOP; _BLEND
|
---|
164 | #define _CHKM_TEMPLATE(result, errstr, stmt) \
|
---|
165 | _BLBEGIN if (!(result)) { stmt }; _BLEND
|
---|
166 | #define _CHKMS_TEMPLATE(result, stmt) _CHKM_TEMPLATE(result, "", stmt)
|
---|
167 | #endif
|
---|
168 |
|
---|
169 | // ---------------------------------------------------------------------------
|
---|
170 | // ASSERT macros - code will NOT be executed in release builds
|
---|
171 | // ---------------------------------------------------------------------------
|
---|
172 |
|
---|
173 | /** @name Assertion and error checking macros
|
---|
174 | Use for ALL error checking in your code.
|
---|
175 | They are useful to check a return code, print a message
|
---|
176 | and take appropriate action.
|
---|
177 | Generally, ASM_* macros are for code consistency checks,
|
---|
178 | whereas CHK_* macros should be used for errors that could
|
---|
179 | occur also in the final program (like file not found etc.).
|
---|
180 | */
|
---|
181 | //@{
|
---|
182 |
|
---|
183 | /** logs error message, returns \c value if \c result==NULL
|
---|
184 | (all ASM_* map to a NOOP in Release builds - use CHKM_*
|
---|
185 | if the code needs to get executed!!!) */
|
---|
186 | #define ASM_RETVAL(result, errstr, value) \
|
---|
187 | _ASM_TEMPLATE(result, errstr, return (value))
|
---|
188 |
|
---|
189 | /// \c ASM_RETVAL for void-functions
|
---|
190 | #define ASM_RET(result, errstr) _ASM_TEMPLATE(result, errstr, return)
|
---|
191 |
|
---|
192 | /// like \c ASM_RETVAL, but does an \c exit(-1)
|
---|
193 | // NOTE: this should NOT have a CHKM-version, as this would result
|
---|
194 | // in a bad exit behaviour!
|
---|
195 | #define ASM_EXIT(result, errstr) _ASM_TEMPLATE(result, errstr, exit(-1))
|
---|
196 |
|
---|
197 | // ---------------------------------------------------------------------------
|
---|
198 | // CHECK macros - code WILL be executed in release builds
|
---|
199 | // ---------------------------------------------------------------------------
|
---|
200 |
|
---|
201 | /// \c ASM_RETVAL for code that needs to be executed also in release-builds
|
---|
202 | #define CHKM_RETVAL(result, errstr, value) \
|
---|
203 | _CHKM_TEMPLATE(result, errstr, return (value))
|
---|
204 | ///
|
---|
205 | #define CHKM_RET(result, errstr) _CHKM_TEMPLATE(result, errstr, return)
|
---|
206 |
|
---|
207 |
|
---|
208 | // ---------------------------------------------------------------------------
|
---|
209 | // Macros not used much
|
---|
210 | // ---------------------------------------------------------------------------
|
---|
211 |
|
---|
212 |
|
---|
213 | /// like \c ASM_RETVAL but without logging anything
|
---|
214 | #define ASS_RETVAL(result, value) _ASS_TEMPLATE(result, return (value))
|
---|
215 | /// like \c ASM_RET but without logging anything
|
---|
216 | #define ASS_RET(result, errstr) _ASS_TEMPLATE(result, return)
|
---|
217 |
|
---|
218 | #ifndef RELEASE_BUILD
|
---|
219 |
|
---|
220 | /// log error msg if result==NULL, no further action
|
---|
221 | #define ASM(result, errstr) _BLBEGIN if(!(result)) { EOUT(errstr); } _BLEND
|
---|
222 |
|
---|
223 | /** \c if(!result) and logs error msg. Example:
|
---|
224 | \code ASM_IF(res, "failed!") { do_cleanup; } else { do_good_code; }
|
---|
225 | \endcode */
|
---|
226 | #define ASM_IF(result, errstr) if((!(result)) ? (EOUT(errstr),true) : false)
|
---|
227 |
|
---|
228 | /** only the \c else -path of \c ASM_IF. Example:
|
---|
229 | \code ASM_ELSE(res, "bad input") { do_good_code; } \endcode */
|
---|
230 | #define ASM_ELSE(result, errstr) if (!(result)) { EOUT(errstr); } else
|
---|
231 |
|
---|
232 | /// \c ASM_IF that also evaluates \c result in release-builds
|
---|
233 | #define CHKM_IF(result, errstr) ASM_IF(result, errstr)
|
---|
234 |
|
---|
235 | /// see \c CHKM_IF
|
---|
236 | #define CHKM_ELSE(result, errstr) ASM_ELSE(result, errstr)
|
---|
237 |
|
---|
238 | /** special: if result is false, output the offending statement
|
---|
239 | (saves you the trouble of inventing error strings!) */
|
---|
240 | #define ASSERTSELF(result) _BLBEGIN if(!(result)) { EOUT(#result); } _BLEND
|
---|
241 |
|
---|
242 | /** for some Win32 API calls (those where the result contains errorcode):
|
---|
243 | print error msg if statement fails */
|
---|
244 | #define CHKMS_FORMAT(result) \
|
---|
245 | _BLBEGIN int hResult = (result); if((hResult) != NULL) \
|
---|
246 | { EOUT( GetAPIErrorString(hResult) + #result ); } _BLEND
|
---|
247 |
|
---|
248 | /// outputs any OpenGL error accumulated so far
|
---|
249 | #define CHKGL _BLBEGIN GLenum error; \
|
---|
250 | if ( (error = glGetError()) != GL_NO_ERROR) \
|
---|
251 | EOUT("gl error " << gluErrorString(error)); _BLEND;
|
---|
252 |
|
---|
253 | #ifdef WIN32
|
---|
254 | #include <malloc.h>
|
---|
255 | /// checks the heap for consistency (useful for errors seemingly in stl!)
|
---|
256 | #define CHKHEAP _BLBEGIN int hpres; if ( (hpres = _heapchk()) != _HEAPOK ) \
|
---|
257 | EOUT("Heap error: " << hpres); _BLEND;
|
---|
258 | #else
|
---|
259 | #define CHKHEAP
|
---|
260 | #endif
|
---|
261 |
|
---|
262 |
|
---|
263 | #ifndef DBG_LVL
|
---|
264 | /** override this define in C++-settings to change
|
---|
265 | behaviour of \c DBG and \c REL */
|
---|
266 | #define DBG_LVL 1
|
---|
267 | #endif
|
---|
268 |
|
---|
269 | #else
|
---|
270 |
|
---|
271 | #define ASM(result, errstr) _ASM_TEMPLATE(result, errstr, _NOP)
|
---|
272 |
|
---|
273 | #define ASSERTSELF(result) _BLBEGIN _NOP; _BLEND
|
---|
274 | #define CHKMS_FORMAT(result) _BLBEGIN (result); _BLEND
|
---|
275 |
|
---|
276 | #define ASM_IF(result, errstr) if(false)
|
---|
277 | #define ASM_ELSE(result, errstr) if (false) _NOP; else
|
---|
278 | #define CHKM_IF(result, errstr) if(!(result))
|
---|
279 | #define CHKM_ELSE(result, errstr) if(result)
|
---|
280 | #define CHKGL
|
---|
281 | #define CHKHEAP
|
---|
282 |
|
---|
283 | #ifndef DBG_LVL
|
---|
284 | #define DBG_LVL 0
|
---|
285 | #endif
|
---|
286 |
|
---|
287 | #endif
|
---|
288 |
|
---|
289 | #if DBG_LVL > 0
|
---|
290 | /** the following statement/block is only executed in debug-builds
|
---|
291 | (\c DBG_LVL = 1) */
|
---|
292 | #define DDBG if(true)
|
---|
293 | /** the following statement/block is only executed in release-builds
|
---|
294 | (\c DBG_LVL = 0) */
|
---|
295 | #define RREL if(false)
|
---|
296 | #else
|
---|
297 | #define DDBG if(false)
|
---|
298 | #define RREL if(true)
|
---|
299 | #endif
|
---|
300 |
|
---|
301 | //@}
|
---|
302 |
|
---|
303 | // ---------------------------------------------------------------------------
|
---|
304 | // Microsoft Win32 API errors
|
---|
305 | // ---------------------------------------------------------------------------
|
---|
306 |
|
---|
307 | /** @name Win32 only
|
---|
308 | These macros should be used for Win32 API-calls
|
---|
309 | */
|
---|
310 | //@{
|
---|
311 |
|
---|
312 | /// put a messagebox to screen - WIN32 only
|
---|
313 | void Msg(const char *message, const char *title = NULL);
|
---|
314 |
|
---|
315 | /// gets WIN32 API error message (used by CHKMS-macros)
|
---|
316 | extern char *GetErrorStringMS(unsigned long errorValue);
|
---|
317 |
|
---|
318 | #define EOUTMS(x) _CONOUT("\nERRMS: " << x << HERE)
|
---|
319 | #define WOUTMS(x) _CONOUT("\nWARNMS: " << x << HERE)
|
---|
320 |
|
---|
321 | /// for Win32 API calls: prints error message if statement fails
|
---|
322 | #define CHKMS(result) _CHKMS_TEMPLATE(result, _NOP)
|
---|
323 | /** for Win32 API calls: prints error message and returns value
|
---|
324 | if statement fails */
|
---|
325 | #define CHKMS_RETVAL(result, value) _CHKMS_TEMPLATE(result, return (value))
|
---|
326 | /// for Win32 API calls: prints error message and returns if statement fails
|
---|
327 | #define CHKMS_RET(result) _CHKMS_TEMPLATE(result, return)
|
---|
328 |
|
---|
329 | //@}
|
---|
330 |
|
---|
331 | // C4127: conditional expression is constant (because of merror)
|
---|
332 | // C4514 unreferenced inline function has been removed (also in stl.h)
|
---|
333 | #ifdef WIN32
|
---|
334 | #pragma warning(disable: 4127 4514)
|
---|
335 | #endif
|
---|
336 |
|
---|
337 | #undef ERRSTD
|
---|
338 |
|
---|
339 | #endif // MERROR_H
|
---|