aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/include/G3D/debugAssert.h
blob: edff671061dfef0dfcc73bb141f7b31049187868 (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/**
  @file debugAssert.h
 
  debugAssert(expression);
  debugAssertM(expression, message);
 
  @cite
     John Robbins, Microsoft Systems Journal Bugslayer Column, Feb 1999.
     <A HREF="http://msdn.microsoft.com/library/periodic/period99/feb99_BUGSLAYE_BUGSLAYE.htm">
     http://msdn.microsoft.com/library/periodic/period99/feb99_BUGSLAYE_BUGSLAYE.htm</A>
 
  @cite 
     Douglas Cox, An assert() Replacement, Code of The Day, flipcode, Sept 19, 2000
     <A HREF="http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-AssertReplace&forum=cotd&id=-1">
     http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-AssertReplace&forum=cotd&id=-1</A>
 
  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
 
  @created 2001-08-26
  @edited  2006-01-12

 Copyright 2000-2006, Morgan McGuire.
 All rights reserved.
 */

#ifndef G3D_DEBUGASSERT_H
#define G3D_DEBUGASSERT_H

#include <string>
#include "G3D/platform.h"

#include <cstdlib>

#ifdef _MSC_VER
// conditional expression is constant
#   pragma warning (disable : 4127)
#endif

#ifdef G3D_LINUX
    // Needed so we can define a global display
    // pointer for debugAssert.
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/Xatom.h>
#endif
#endif


/**
 @def debugBreak()
 
 Break at the current location (i.e. don't push a procedure stack frame
 before breaking).
 */

/**
  @def debugAssert(exp)
  Breaks if the expression is false. If G3D_DEBUG_NOGUI is defined, prompts at
  the console, otherwise pops up a dialog.  The user may then break (debug), 
  ignore, or halt the program.
 
  The assertion is also posted to the clipboard under Win32.
 */

/**
  @def debugAssertM(exp, msg)
  Breaks if the expression is false and displays a message. If G3D_DEBUG_NOGUI 
  is defined, prompts at the console, otherwise pops up a dialog.  The user may
  then break (debug), ignore, or halt the program.
 
  The assertion is also posted to the clipboard under Win32.
 */

/**
 @def alwaysAssertM(exp, msg)
 Same as debugAssertM except that it asserts in release builds as well.
 */

namespace G3D {
typedef bool (*AssertionHook)(
    const char* _expression,
    const std::string& message,
    const char* filename,
    int lineNumber,
    bool useGuiPrompt);

/** 
  Allows customization of the global function invoked when a debugAssert fails.
  The initial value is G3D::_internal::_handleDebugAssert_.  G3D will invoke
  rawBreak if the hook returns true.  If NULL, assertions are not handled.
*/
void setAssertionHook(AssertionHook hook);

AssertionHook assertionHook();

/**
 Called by alwaysAssertM in case of failure in release mode.  If returns
 true then the program exits with -1 (you can replace this with your own
 version that throws an exception or has other failure modes).
 */
void setFailureHook(AssertionHook hook);
AssertionHook failureHook();

namespace _internal {
    extern AssertionHook _debugHook;
    extern AssertionHook _failureHook;
} // internal
} // G3D

/**
 @def __debugPromptShowDialog__
 @internal
 */

#ifdef G3D_DEBUG

#    if defined(_MSC_VER) 
#       define rawBreak()  ::DebugBreak();
#    elif defined(__i386__)
        // gcc on intel
#       define rawBreak() __asm__ __volatile__ ( "int $3" ); 
#    else
        // some other gcc
#      define rawBreak() ::abort()
#   endif


#    define debugBreak() G3D::_internal::_releaseInputGrab_(); rawBreak(); G3D::_internal::_restoreInputGrab_();
#    define debugAssert(exp) debugAssertM(exp, "Debug assertion failure")

    #ifdef G3D_DEBUG_NOGUI
        #define __debugPromptShowDialog__ false
    #else
        #define __debugPromptShowDialog__ true
    #endif

    #define debugAssertM(exp, message) do { \
        if (!(exp)) { \
            G3D::_internal::_releaseInputGrab_(); \
            if ((G3D::_internal::_debugHook != NULL) && \
                G3D::_internal::_debugHook((const char*)(#exp), message, __FILE__, __LINE__, __debugPromptShowDialog__)) { \
                 rawBreak(); \
            } \
            G3D::_internal::_restoreInputGrab_(); \
        } \
    } while (0)

    #define alwaysAssertM debugAssertM

#else  // Release
    #ifdef G3D_DEBUG_NOGUI
        #define __debugPromptShowDialog__ false
    #else
        #define __debugPromptShowDialog__ true
    #endif

    // In the release build, just define away assertions.
    #define rawBreak() do {} while (0)
    #define debugAssert(exp) do {} while (0)
    #define debugAssertM(exp, message) do {} while (0)
    #define debugBreak() do {} while (0)

    // But keep the 'always' assertions
    #define alwaysAssertM(exp, message) { \
        if (!(exp)) { \
            G3D::_internal::_releaseInputGrab_(); \
            if ((G3D::_internal::_failureHook != NULL) && \
                G3D::_internal::_failureHook(#exp, message, __FILE__, __LINE__, __debugPromptShowDialog__)) { \
                ::exit(-1);                                             \
            } \
            G3D::_internal::_restoreInputGrab_(); \
         } \
    }

#endif  // if debug



namespace G3D {  namespace _internal {

#ifdef G3D_LINUX
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
    /**
     A pointer to the X11 display.  Initially NULL.  If set to a
     non-null value (e.g. by SDLWindow), debugAssert attempts to use
     this display to release the mouse/input grab when an assertion
     fails.
     */
    extern Display*      x11Display;

    /**
     A pointer to the X11 window.  Initially NULL.  If set to a
     non-null value (e.g. by SDLWindow), debugAssert attempts to use
     this window to release the mouse/input grab when an assertion
     fails.
     */
    extern Window        x11Window;
#endif
#endif

/**
 Pops up an assertion dialog or prints an assertion

 ignoreAlways      - return result of pressing the ignore button.
 useGuiPrompt      - if true, shows a dialog
 */
bool _handleDebugAssert_(
    const char* expression,
    const std::string& message,
    const char* filename,
    int         lineNumber,
    bool        useGuiPrompt);

bool _handleErrorCheck_(
    const char* expression,
    const std::string& message,
    const char* filename,
    int         lineNumber,
    bool        useGuiPrompt);

/** Attempts to give the user back their mouse and keyboard if they 
    were locked to the current window.  
    @internal*/
void _releaseInputGrab_();

/** Attempts to restore the state before _releaseInputGrab_.  
    @internal*/
void _restoreInputGrab_();

}; }; // namespace

#endif