comparison src/SDL_assert.c @ 3670:62b6a5b99918

Clean up assertion API for public use.
author Ryan C. Gordon <icculus@icculus.org>
date Wed, 13 Jan 2010 19:29:33 +0000
parents 46d27a9571fa
children 0d6f520c0eb9
comparison
equal deleted inserted replaced
3669:46d27a9571fa 3670:62b6a5b99918
20 slouken@libsdl.org 20 slouken@libsdl.org
21 */ 21 */
22 22
23 #include "SDL.h" 23 #include "SDL.h"
24 #include "SDL_assert.h" 24 #include "SDL_assert.h"
25
26 #if (SDL_ASSERT_LEVEL > 0)
27 25
28 #ifdef _WINDOWS 26 #ifdef _WINDOWS
29 #define WIN32_LEAN_AND_MEAN 1 27 #define WIN32_LEAN_AND_MEAN 1
30 #include <windows.h> 28 #include <windows.h>
31 #else /* fprintf, _exit(), etc. */ 29 #else /* fprintf, _exit(), etc. */
32 #include <stdio.h> 30 #include <stdio.h>
33 #include <stdlib.h> 31 #include <stdlib.h>
34 #include <unistd.h> 32 #include <unistd.h>
35 #endif 33 #endif
36 34
37 /* We can keep all triggered assertions in a singly-linked list so we can 35 static SDL_assert_state
36 SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
37
38 /*
39 * We keep all triggered assertions in a singly-linked list so we can
38 * generate a report later. 40 * generate a report later.
39 */ 41 */
40 #if !SDL_ASSERTION_REPORT_DISABLED
41 static SDL_assert_data assertion_list_terminator = { 0, 0, 0, 0, 0, 0, 0 }; 42 static SDL_assert_data assertion_list_terminator = { 0, 0, 0, 0, 0, 0, 0 };
42 static SDL_assert_data *triggered_assertions = &assertion_list_terminator; 43 static SDL_assert_data *triggered_assertions = &assertion_list_terminator;
43 #endif 44
45 static SDL_mutex *assertion_mutex = NULL;
46 static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion;
47 static void *assertion_userdata = NULL;
44 48
45 #ifdef __GNUC__ 49 #ifdef __GNUC__
46 static void 50 static void
47 debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 51 debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
48 #endif 52 #endif
196 #endif 200 #endif
197 201
198 202
199 static void SDL_AddAssertionToReport(SDL_assert_data *data) 203 static void SDL_AddAssertionToReport(SDL_assert_data *data)
200 { 204 {
201 #if !SDL_ASSERTION_REPORT_DISABLED
202 /* (data) is always a static struct defined with the assert macros, so 205 /* (data) is always a static struct defined with the assert macros, so
203 we don't have to worry about copying or allocating them. */ 206 we don't have to worry about copying or allocating them. */
204 if (data->next == NULL) { /* not yet added? */ 207 if (data->next == NULL) { /* not yet added? */
205 data->next = triggered_assertions; 208 data->next = triggered_assertions;
206 triggered_assertions = data; 209 triggered_assertions = data;
207 } 210 }
208 #endif 211 }
209 } 212
210 213
211 static void SDL_GenerateAssertionReport(void) 214 static void SDL_GenerateAssertionReport(void)
212 { 215 {
213 #if !SDL_ASSERTION_REPORT_DISABLED 216 const SDL_assert_data *item;
214 if (triggered_assertions != &assertion_list_terminator) 217
218 /* only do this if the app hasn't assigned an assertion handler. */
219 if (assertion_handler != SDL_PromptAssertion)
220 return;
221
222 item = SDL_GetAssertionReport();
223 if (item->condition)
215 { 224 {
216 SDL_assert_data *item = triggered_assertions;
217
218 debug_print("\n\nSDL assertion report.\n"); 225 debug_print("\n\nSDL assertion report.\n");
219 debug_print("All SDL assertions between last init/quit:\n\n"); 226 debug_print("All SDL assertions between last init/quit:\n\n");
220 227
221 while (item != &assertion_list_terminator) { 228 while (item->condition) {
222 debug_print( 229 debug_print(
223 "'%s'\n" 230 "'%s'\n"
224 " * %s (%s:%d)\n" 231 " * %s (%s:%d)\n"
225 " * triggered %u time%s.\n" 232 " * triggered %u time%s.\n"
226 " * always ignore: %s.\n", 233 " * always ignore: %s.\n",
230 item->always_ignore ? "yes" : "no"); 237 item->always_ignore ? "yes" : "no");
231 item = item->next; 238 item = item->next;
232 } 239 }
233 debug_print("\n"); 240 debug_print("\n");
234 241
235 triggered_assertions = &assertion_list_terminator; 242 SDL_ResetAssertionReport();
236 } 243 }
237 #endif
238 } 244 }
239 245
240 static void SDL_ExitProcess(int exitcode) 246 static void SDL_ExitProcess(int exitcode)
241 { 247 {
242 #ifdef _WINDOWS 248 #ifdef _WINDOWS
251 SDL_Quit(); 257 SDL_Quit();
252 SDL_ExitProcess(42); 258 SDL_ExitProcess(42);
253 } 259 }
254 260
255 261
256 static SDL_assert_state SDL_PromptAssertion(const SDL_assert_data *data) 262 static SDL_assert_state
263 SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
257 { 264 {
258 const char *envr; 265 const char *envr;
259 SDL_assert_state state = SDL_ASSERTION_ABORT; 266 SDL_assert_state state = SDL_ASSERTION_ABORT;
260 SDL_WindowID window; 267 SDL_WindowID window;
268
269 (void) userdata; /* unused in default handler. */
261 270
262 debug_print("\n\n" 271 debug_print("\n\n"
263 "Assertion failure at %s (%s:%d), triggered %u time%s:\n" 272 "Assertion failure at %s (%s:%d), triggered %u time%s:\n"
264 " '%s'\n" 273 " '%s'\n"
265 "\n", 274 "\n",
289 window = SDL_GetFocusWindow(); 298 window = SDL_GetFocusWindow();
290 if (window) { 299 if (window) {
291 if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) { 300 if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
292 SDL_MinimizeWindow(window); 301 SDL_MinimizeWindow(window);
293 } else { 302 } else {
303 /* !!! FIXME: ungrab the input if we're not fullscreen? */
294 /* No need to mess with the window */ 304 /* No need to mess with the window */
295 window = 0; 305 window = 0;
296 } 306 }
297 } 307 }
298 308
341 } 351 }
342 352
343 return state; 353 return state;
344 } 354 }
345 355
346
347 static SDL_mutex *assertion_mutex = NULL;
348 356
349 SDL_assert_state 357 SDL_assert_state
350 SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file, 358 SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
351 int line) 359 int line)
352 { 360 {
389 while (1) { /* do nothing but spin; what else can you do?! */ } 397 while (1) { /* do nothing but spin; what else can you do?! */ }
390 } 398 }
391 } 399 }
392 400
393 if (!data->always_ignore) { 401 if (!data->always_ignore) {
394 state = SDL_PromptAssertion(data); 402 state = assertion_handler(data, assertion_userdata);
395 } 403 }
396 404
397 switch (state) 405 switch (state)
398 { 406 {
399 case SDL_ASSERTION_ABORT: 407 case SDL_ASSERTION_ABORT:
415 SDL_UnlockMutex(assertion_mutex); 423 SDL_UnlockMutex(assertion_mutex);
416 424
417 return state; 425 return state;
418 } 426 }
419 427
420 #endif /* SDL_ASSERT_LEVEL > 0 */
421
422 428
423 int SDL_AssertionsInit(void) 429 int SDL_AssertionsInit(void)
424 { 430 {
425 /* this is a no-op at the moment. */ 431 /* this is a no-op at the moment. */
426 return 0; 432 return 0;
427 } 433 }
428 434
429 void SDL_AssertionsQuit(void) 435 void SDL_AssertionsQuit(void)
430 { 436 {
431 #if (SDL_ASSERT_LEVEL > 0)
432 SDL_GenerateAssertionReport(); 437 SDL_GenerateAssertionReport();
433 if (assertion_mutex != NULL) { 438 if (assertion_mutex != NULL) {
434 SDL_DestroyMutex(assertion_mutex); 439 SDL_DestroyMutex(assertion_mutex);
435 assertion_mutex = NULL; 440 assertion_mutex = NULL;
436 } 441 }
437 #endif 442 }
443
444 void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
445 {
446 if (handler != NULL) {
447 assertion_handler = handler;
448 assertion_userdata = userdata;
449 } else {
450 assertion_handler = SDL_PromptAssertion;
451 assertion_userdata = NULL;
452 }
453 }
454
455 const SDL_assert_data *SDL_GetAssertionReport(void)
456 {
457 return triggered_assertions;
458 }
459
460 void SDL_ResetAssertionReport(void)
461 {
462 SDL_assert_data *item = triggered_assertions;
463 SDL_assert_data *next = NULL;
464 for (item = triggered_assertions; item->condition; item = next) {
465 next = (SDL_assert_data *) item->next;
466 item->always_ignore = SDL_FALSE;
467 item->trigger_count = 0;
468 item->next = NULL;
469 }
470
471 triggered_assertions = &assertion_list_terminator;
438 } 472 }
439 473
440 /* vi: set ts=4 sw=4 expandtab: */ 474 /* vi: set ts=4 sw=4 expandtab: */