]>
Commit | Line | Data |
---|---|---|
7407ac7f BB |
1 | /* |
2 | Simple DirectMedia Layer | |
3 | Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org> | |
4 | ||
5 | This software is provided 'as-is', without any express or implied | |
6 | warranty. In no event will the authors be held liable for any damages | |
7 | arising from the use of this software. | |
8 | ||
9 | Permission is granted to anyone to use this software for any purpose, | |
10 | including commercial applications, and to alter it and redistribute it | |
11 | freely, subject to the following restrictions: | |
12 | ||
13 | 1. The origin of this software must not be misrepresented; you must not | |
14 | claim that you wrote the original software. If you use this software | |
15 | in a product, an acknowledgment in the product documentation would be | |
16 | appreciated but is not required. | |
17 | 2. Altered source versions must be plainly marked as such, and must not be | |
18 | misrepresented as being the original software. | |
19 | 3. This notice may not be removed or altered from any source distribution. | |
20 | */ | |
21 | ||
22 | #ifndef _SDL_assert_h | |
23 | #define _SDL_assert_h | |
24 | ||
25 | #include "SDL_config.h" | |
26 | ||
27 | #include "begin_code.h" | |
28 | /* Set up for C function definitions, even when using C++ */ | |
29 | #ifdef __cplusplus | |
30 | extern "C" { | |
31 | #endif | |
32 | ||
33 | #ifndef SDL_ASSERT_LEVEL | |
34 | #ifdef SDL_DEFAULT_ASSERT_LEVEL | |
35 | #define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL | |
36 | #elif defined(_DEBUG) || defined(DEBUG) || \ | |
37 | (defined(__GNUC__) && !defined(__OPTIMIZE__)) | |
38 | #define SDL_ASSERT_LEVEL 2 | |
39 | #else | |
40 | #define SDL_ASSERT_LEVEL 1 | |
41 | #endif | |
42 | #endif /* SDL_ASSERT_LEVEL */ | |
43 | ||
44 | /* | |
45 | These are macros and not first class functions so that the debugger breaks | |
46 | on the assertion line and not in some random guts of SDL, and so each | |
47 | assert can have unique static variables associated with it. | |
48 | */ | |
49 | ||
50 | #if defined(_MSC_VER) | |
51 | /* Don't include intrin.h here because it contains C++ code */ | |
52 | extern void __cdecl __debugbreak(void); | |
53 | #define SDL_TriggerBreakpoint() __debugbreak() | |
54 | #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) | |
55 | #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" ) | |
56 | #elif defined(HAVE_SIGNAL_H) | |
57 | #include <signal.h> | |
58 | #define SDL_TriggerBreakpoint() raise(SIGTRAP) | |
59 | #else | |
60 | /* How do we trigger breakpoints on this platform? */ | |
61 | #define SDL_TriggerBreakpoint() | |
62 | #endif | |
63 | ||
64 | #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */ | |
65 | # define SDL_FUNCTION __func__ | |
66 | #elif ((__GNUC__ >= 2) || defined(_MSC_VER)) | |
67 | # define SDL_FUNCTION __FUNCTION__ | |
68 | #else | |
69 | # define SDL_FUNCTION "???" | |
70 | #endif | |
71 | #define SDL_FILE __FILE__ | |
72 | #define SDL_LINE __LINE__ | |
73 | ||
74 | /* | |
75 | sizeof (x) makes the compiler still parse the expression even without | |
76 | assertions enabled, so the code is always checked at compile time, but | |
77 | doesn't actually generate code for it, so there are no side effects or | |
78 | expensive checks at run time, just the constant size of what x WOULD be, | |
79 | which presumably gets optimized out as unused. | |
80 | This also solves the problem of... | |
81 | ||
82 | int somevalue = blah(); | |
83 | SDL_assert(somevalue == 1); | |
84 | ||
85 | ...which would cause compiles to complain that somevalue is unused if we | |
86 | disable assertions. | |
87 | */ | |
88 | ||
89 | #define SDL_disabled_assert(condition) \ | |
90 | do { (void) sizeof ((condition)); } while (0) | |
91 | ||
92 | typedef enum | |
93 | { | |
94 | SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */ | |
95 | SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */ | |
96 | SDL_ASSERTION_ABORT, /**< Terminate the program. */ | |
97 | SDL_ASSERTION_IGNORE, /**< Ignore the assert. */ | |
98 | SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */ | |
99 | } SDL_assert_state; | |
100 | ||
101 | typedef struct SDL_assert_data | |
102 | { | |
103 | int always_ignore; | |
104 | unsigned int trigger_count; | |
105 | const char *condition; | |
106 | const char *filename; | |
107 | int linenum; | |
108 | const char *function; | |
109 | const struct SDL_assert_data *next; | |
110 | } SDL_assert_data; | |
111 | ||
112 | #if (SDL_ASSERT_LEVEL > 0) | |
113 | ||
114 | /* Never call this directly. Use the SDL_assert* macros. */ | |
115 | extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, | |
116 | const char *, | |
117 | const char *, int); | |
118 | ||
119 | /* the do {} while(0) avoids dangling else problems: | |
120 | if (x) SDL_assert(y); else blah(); | |
121 | ... without the do/while, the "else" could attach to this macro's "if". | |
122 | We try to handle just the minimum we need here in a macro...the loop, | |
123 | the static vars, and break points. The heavy lifting is handled in | |
124 | SDL_ReportAssertion(), in SDL_assert.c. | |
125 | */ | |
126 | #define SDL_enabled_assert(condition) \ | |
127 | do { \ | |
128 | while ( !(condition) ) { \ | |
129 | static struct SDL_assert_data assert_data = { \ | |
130 | 0, 0, #condition, 0, 0, 0, 0 \ | |
131 | }; \ | |
132 | const SDL_assert_state state = SDL_ReportAssertion(&assert_data, \ | |
133 | SDL_FUNCTION, \ | |
134 | SDL_FILE, \ | |
135 | SDL_LINE); \ | |
136 | if (state == SDL_ASSERTION_RETRY) { \ | |
137 | continue; /* go again. */ \ | |
138 | } else if (state == SDL_ASSERTION_BREAK) { \ | |
139 | SDL_TriggerBreakpoint(); \ | |
140 | } \ | |
141 | break; /* not retrying. */ \ | |
142 | } \ | |
143 | } while (0) | |
144 | ||
145 | #endif /* enabled assertions support code */ | |
146 | ||
147 | /* Enable various levels of assertions. */ | |
148 | #if SDL_ASSERT_LEVEL == 0 /* assertions disabled */ | |
149 | # define SDL_assert(condition) SDL_disabled_assert(condition) | |
150 | # define SDL_assert_release(condition) SDL_disabled_assert(condition) | |
151 | # define SDL_assert_paranoid(condition) SDL_disabled_assert(condition) | |
152 | #elif SDL_ASSERT_LEVEL == 1 /* release settings. */ | |
153 | # define SDL_assert(condition) SDL_disabled_assert(condition) | |
154 | # define SDL_assert_release(condition) SDL_enabled_assert(condition) | |
155 | # define SDL_assert_paranoid(condition) SDL_disabled_assert(condition) | |
156 | #elif SDL_ASSERT_LEVEL == 2 /* normal settings. */ | |
157 | # define SDL_assert(condition) SDL_enabled_assert(condition) | |
158 | # define SDL_assert_release(condition) SDL_enabled_assert(condition) | |
159 | # define SDL_assert_paranoid(condition) SDL_disabled_assert(condition) | |
160 | #elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */ | |
161 | # define SDL_assert(condition) SDL_enabled_assert(condition) | |
162 | # define SDL_assert_release(condition) SDL_enabled_assert(condition) | |
163 | # define SDL_assert_paranoid(condition) SDL_enabled_assert(condition) | |
164 | #else | |
165 | # error Unknown assertion level. | |
166 | #endif | |
167 | ||
168 | ||
169 | typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)( | |
170 | const SDL_assert_data* data, void* userdata); | |
171 | ||
172 | /** | |
173 | * \brief Set an application-defined assertion handler. | |
174 | * | |
175 | * This allows an app to show its own assertion UI and/or force the | |
176 | * response to an assertion failure. If the app doesn't provide this, SDL | |
177 | * will try to do the right thing, popping up a system-specific GUI dialog, | |
178 | * and probably minimizing any fullscreen windows. | |
179 | * | |
180 | * This callback may fire from any thread, but it runs wrapped in a mutex, so | |
181 | * it will only fire from one thread at a time. | |
182 | * | |
183 | * Setting the callback to NULL restores SDL's original internal handler. | |
184 | * | |
185 | * This callback is NOT reset to SDL's internal handler upon SDL_Quit()! | |
186 | * | |
187 | * \return SDL_assert_state value of how to handle the assertion failure. | |
188 | * | |
189 | * \param handler Callback function, called when an assertion fails. | |
190 | * \param userdata A pointer passed to the callback as-is. | |
191 | */ | |
192 | extern DECLSPEC void SDLCALL SDL_SetAssertionHandler( | |
193 | SDL_AssertionHandler handler, | |
194 | void *userdata); | |
195 | ||
196 | /** | |
197 | * \brief Get a list of all assertion failures. | |
198 | * | |
199 | * Get all assertions triggered since last call to SDL_ResetAssertionReport(), | |
200 | * or the start of the program. | |
201 | * | |
202 | * The proper way to examine this data looks something like this: | |
203 | * | |
204 | * <code> | |
205 | * const SDL_assert_data *item = SDL_GetAssertionReport(); | |
206 | * while (item) { | |
207 | * printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", | |
208 | * item->condition, item->function, item->filename, | |
209 | * item->linenum, item->trigger_count, | |
210 | * item->always_ignore ? "yes" : "no"); | |
211 | * item = item->next; | |
212 | * } | |
213 | * </code> | |
214 | * | |
215 | * \return List of all assertions. | |
216 | * \sa SDL_ResetAssertionReport | |
217 | */ | |
218 | extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void); | |
219 | ||
220 | /** | |
221 | * \brief Reset the list of all assertion failures. | |
222 | * | |
223 | * Reset list of all assertions triggered. | |
224 | * | |
225 | * \sa SDL_GetAssertionReport | |
226 | */ | |
227 | extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void); | |
228 | ||
229 | /* Ends C function definitions when using C++ */ | |
230 | #ifdef __cplusplus | |
231 | } | |
232 | #endif | |
233 | #include "close_code.h" | |
234 | ||
235 | #endif /* _SDL_assert_h */ | |
236 | ||
237 | /* vi: set ts=4 sw=4 expandtab: */ |