First pass at Ryan's assertion code, minor tweaks to come.
--HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%404398
This commit is contained in:
parent
7f6c455755
commit
a8a1ac9acd
15 changed files with 667 additions and 1 deletions
|
@ -36,6 +36,7 @@ src/SDL.c \
|
|||
src/SDL_compat.c \
|
||||
src/SDL_error.c \
|
||||
src/SDL_fatal.c \
|
||||
src/SDL_assert.c \
|
||||
src/audio/nds/SDL_ndsaudio.c \
|
||||
src/audio/SDL_audio.c \
|
||||
src/audio/SDL_audiocvt.c \
|
||||
|
|
26
configure.in
26
configure.in
|
@ -134,6 +134,32 @@ AC_C_CONST
|
|||
AC_C_INLINE
|
||||
AC_C_VOLATILE
|
||||
|
||||
dnl See whether we want assertions for debugging/sanity checking SDL itself.
|
||||
AC_ARG_ENABLE(assertions,
|
||||
AC_HELP_STRING([--enable-assertions],
|
||||
[Enable internal sanity checks (yes/no/release/paranoid) [[default=release]]]),
|
||||
, enable_assertions=release)
|
||||
sdl_valid_assertion_level=no
|
||||
if test x$enable_assertions = xno; then
|
||||
sdl_valid_assertion_level=yes
|
||||
AC_DEFINE(SDL_ASSERT_LEVEL, 0)
|
||||
fi
|
||||
if test x$enable_assertions = xrelease; then
|
||||
sdl_valid_assertion_level=yes
|
||||
AC_DEFINE(SDL_ASSERT_LEVEL, 1)
|
||||
fi
|
||||
if test x$enable_assertions = xyes; then
|
||||
sdl_valid_assertion_level=yes
|
||||
AC_DEFINE(SDL_ASSERT_LEVEL, 2)
|
||||
fi
|
||||
if test x$enable_assertions = xparanoid; then
|
||||
sdl_valid_assertion_level=yes
|
||||
AC_DEFINE(SDL_ASSERT_LEVEL, 3)
|
||||
fi
|
||||
if test x$sdl_valid_assertion_level = xno; then
|
||||
AC_MSG_ERROR([*** unknown assertion level. stop.])
|
||||
fi
|
||||
|
||||
dnl See whether we can use gcc style dependency tracking
|
||||
AC_ARG_ENABLE(dependency-tracking,
|
||||
AC_HELP_STRING([--enable-dependency-tracking],
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
|
||||
#include "SDL_main.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_atomic.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_cpuinfo.h"
|
||||
|
@ -89,8 +90,8 @@
|
|||
#include "SDL_rwops.h"
|
||||
#include "SDL_thread.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_video.h"
|
||||
#include "SDL_version.h"
|
||||
#include "SDL_video.h"
|
||||
#include "SDL_compat.h"
|
||||
|
||||
#include "begin_code.h"
|
||||
|
|
151
include/SDL_assert.h
Normal file
151
include/SDL_assert.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2009 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
/* This is an assert macro for SDL's internal use. Not for the public API! */
|
||||
|
||||
#ifndef _SDL_assert_h
|
||||
#define _SDL_assert_h
|
||||
|
||||
#ifndef SDL_ASSERT_LEVEL
|
||||
#error SDL_ASSERT_LEVEL is not defined. Please fix your SDL_config.h.
|
||||
#endif
|
||||
|
||||
/*
|
||||
sizeof (x) makes the compiler still parse the expression even without
|
||||
assertions enabled, so the code is always checked at compile time, but
|
||||
doesn't actually generate code for it, so there are no side effects or
|
||||
expensive checks at run time, just the constant size of what x WOULD be,
|
||||
which presumably gets optimized out as unused.
|
||||
This also solves the problem of...
|
||||
|
||||
int somevalue = blah();
|
||||
SDL_assert(somevalue == 1);
|
||||
|
||||
...which would cause compiles to complain that somevalue is unused if we
|
||||
disable assertions.
|
||||
*/
|
||||
|
||||
#define SDL_disabled_assert(condition) \
|
||||
do { (void) sizeof ((condition)); } while (0)
|
||||
|
||||
#if (SDL_ASSERT_LEVEL > 0)
|
||||
|
||||
/*
|
||||
These are macros and not first class functions so that the debugger breaks
|
||||
on the assertion line and not in some random guts of SDL, and so each
|
||||
macro can have unique static variables associated with it.
|
||||
*/
|
||||
|
||||
#if (defined(_MSC_VER) && ((_M_IX86) || (_M_X64)))
|
||||
#define SDL_TriggerBreakpoint() __asm { int 3 }
|
||||
#elif (defined(__GNUC__) && ((__i386__) || (__x86_64__)))
|
||||
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
|
||||
#elif defined(unix)
|
||||
#include <signal.h>
|
||||
#define SDL_TriggerBreakpoint() raise(SIGTRAP)
|
||||
#else
|
||||
#error Please define your platform or set SDL_ASSERT_LEVEL to 0.
|
||||
#endif
|
||||
|
||||
#if (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
|
||||
# define SDL_FUNCTION __func__
|
||||
#elif ((__GNUC__ >= 2) || defined(_MSC_VER))
|
||||
# define SDL_FUNCTION __FUNCTION__
|
||||
#else
|
||||
# define SDL_FUNCTION "???"
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
|
||||
SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
|
||||
SDL_ASSERTION_ABORT, /**< Terminate the program. */
|
||||
SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
|
||||
SDL_ASSERTION_ALWAYS_IGNORE, /**< Ignore the assert from now on. */
|
||||
} SDL_assert_state;
|
||||
|
||||
typedef struct SDL_assert_data
|
||||
{
|
||||
int always_ignore;
|
||||
unsigned int trigger_count;
|
||||
const char *condition;
|
||||
const char *filename;
|
||||
int linenum;
|
||||
const char *function;
|
||||
struct SDL_assert_data *next;
|
||||
} SDL_assert_data;
|
||||
|
||||
SDL_assert_state SDL_ReportAssertion(SDL_assert_data *, const char *, int);
|
||||
|
||||
/* the do {} while(0) avoids dangling else problems:
|
||||
if (x) SDL_assert(y); else blah();
|
||||
... without the do/while, the "else" could attach to this macro's "if".
|
||||
We try to handle just the minimum we need here in a macro...the loop,
|
||||
the static vars, and break points. The heavy lifting is handled in
|
||||
SDL_ReportAssertion(), in SDL_assert.c.
|
||||
*/
|
||||
#define SDL_enabled_assert(condition) \
|
||||
do { \
|
||||
while ( !(condition) ) { \
|
||||
static struct SDL_assert_data assert_data = { \
|
||||
0, 0, #condition, __FILE__, 0, 0, 0 \
|
||||
}; \
|
||||
const SDL_assert_state state = SDL_ReportAssertion(&assert_data, \
|
||||
SDL_FUNCTION, \
|
||||
__LINE__); \
|
||||
if (state == SDL_ASSERTION_RETRY) { \
|
||||
continue; /* go again. */ \
|
||||
} else if (state == SDL_ASSERTION_BREAK) { \
|
||||
SDL_TriggerBreakpoint(); \
|
||||
} \
|
||||
break; /* not retrying. */ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* enabled assertions support code */
|
||||
|
||||
/* Enable various levels of assertions. */
|
||||
#if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
|
||||
# define SDL_assert(condition) SDL_disabled_assert(condition)
|
||||
# define SDL_assert_release(condition) SDL_disabled_assert(condition)
|
||||
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||
#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
|
||||
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
|
||||
#elif SDL_ASSERT_LEVEL == 2 /* normal settings. */
|
||||
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||
#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
|
||||
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
|
||||
#else
|
||||
# error Unknown assertion level. Please fix your SDL_config.h.
|
||||
#endif
|
||||
|
||||
#endif /* _SDL_assert_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -162,6 +162,9 @@
|
|||
#include <stdarg.h>
|
||||
#endif /* HAVE_LIBC */
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#undef SDL_ASSERT_LEVEL
|
||||
|
||||
/* Allow disabling of core subsystems */
|
||||
#undef SDL_AUDIO_DISABLED
|
||||
#undef SDL_CPUINFO_DISABLED
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include "SDL_platform.h"
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
/* This is a set of defines to configure the SDL features */
|
||||
|
||||
#ifdef __LP64__
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
/* This is a set of defines to configure the SDL features */
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
/* General platform specific identifiers */
|
||||
#include "SDL_platform.h"
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
#define SDL_HAS_64BIT_TYPE 1
|
||||
#define SDL_BYTEORDER 1234
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
/* This is a set of defines to configure the SDL features */
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
|
||||
#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
|
||||
#define HAVE_STDINT_H 1
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
/* General platform specific identifiers */
|
||||
#include "SDL_platform.h"
|
||||
|
||||
/* SDL internal assertion support */
|
||||
#define SDL_ASSERT_LEVEL 1
|
||||
|
||||
/* Make sure that this isn't included by Visual C++ */
|
||||
#ifdef _MSC_VER
|
||||
#error You should copy include/SDL_config.h.default to include/SDL_config.h
|
||||
|
|
27
src/SDL.c
27
src/SDL.c
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "SDL.h"
|
||||
#include "SDL_fatal.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
#if !SDL_VIDEO_DISABLED
|
||||
#include "video/SDL_leaks.h"
|
||||
#endif
|
||||
|
@ -52,6 +54,9 @@ extern int SDL_HelperWindowCreate(void);
|
|||
extern int SDL_HelperWindowDestroy(void);
|
||||
#endif
|
||||
|
||||
extern int SDL_AssertionsInit(void);
|
||||
extern void SDL_AssertionsQuit(void);
|
||||
|
||||
/* The initialized subsystems */
|
||||
static Uint32 SDL_initialized = 0;
|
||||
static Uint32 ticks_started = 0;
|
||||
|
@ -153,6 +158,10 @@ SDL_Init(Uint32 flags)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (SDL_AssertionsInit() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clear the error message */
|
||||
SDL_ClearError();
|
||||
|
||||
|
@ -171,6 +180,21 @@ SDL_Init(Uint32 flags)
|
|||
if (!(flags & SDL_INIT_NOPARACHUTE)) {
|
||||
SDL_InstallParachute();
|
||||
}
|
||||
|
||||
/* brief sanity checks for the sanity checks. :) */
|
||||
SDL_assert(1);
|
||||
SDL_assert_release(1);
|
||||
SDL_assert_paranoid(1);
|
||||
SDL_assert(0 || 1);
|
||||
SDL_assert_release(0 || 1);
|
||||
SDL_assert_paranoid(0 || 1);
|
||||
|
||||
#if 0 /* enable this to test assertion failures. */
|
||||
SDL_assert_release(1 == 2);
|
||||
SDL_assert_release(5 < 4);
|
||||
SDL_assert_release(0 && "This is a test");
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -239,6 +263,7 @@ SDL_Quit(void)
|
|||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
/* !!! FIXME: make this an assertion. */
|
||||
/* Print the number of surfaces not freed */
|
||||
if (surfaces_allocated != 0) {
|
||||
fprintf(stderr, "SDL Warning: %d SDL surfaces extant\n",
|
||||
|
@ -253,6 +278,8 @@ SDL_Quit(void)
|
|||
/* Uninstall any parachute signal handlers */
|
||||
SDL_UninstallParachute();
|
||||
|
||||
SDL_AssertionsQuit();
|
||||
|
||||
#if !SDL_THREADS_DISABLED && SDL_THREAD_PTH
|
||||
pth_kill();
|
||||
#endif
|
||||
|
|
396
src/SDL_assert.c
Normal file
396
src/SDL_assert.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2009 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL.h"
|
||||
|
||||
#if (SDL_ASSERT_LEVEL > 0)
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#else /* fprintf, _exit(), etc. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/* We can keep all triggered assertions in a singly-linked list so we can
|
||||
* generate a report later.
|
||||
*/
|
||||
#if !SDL_ASSERTION_REPORT_DISABLED
|
||||
static SDL_assert_data assertion_list_terminator = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
static SDL_assert_data *triggered_assertions = &assertion_list_terminator;
|
||||
#endif
|
||||
|
||||
static void
|
||||
debug_print(const char *fmt, ...)
|
||||
//#ifdef __GNUC__
|
||||
//__attribute__((format (printf, 1, 2)))
|
||||
//#endif
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
/* Format into a buffer for OutputDebugStringA(). */
|
||||
char buf[1024];
|
||||
char *startptr;
|
||||
char *ptr;
|
||||
int len;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
len = (int) SDL_vsnprintf(buf, sizeof (buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Visual C's vsnprintf() may not null-terminate the buffer. */
|
||||
if ((len >= sizeof (buf)) || (len < 0)) {
|
||||
buf[sizeof (buf) - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Write it, sorting out the Unix newlines... */
|
||||
startptr = buf;
|
||||
for (ptr = startptr; *ptr; ptr++) {
|
||||
if (*ptr == '\n') {
|
||||
*ptr = '\0';
|
||||
OutputDebugStringA(startptr);
|
||||
OutputDebugStringA("\r\n");
|
||||
startptr = ptr+1;
|
||||
}
|
||||
}
|
||||
|
||||
/* catch that last piece if it didn't have a newline... */
|
||||
if (startptr != ptr) {
|
||||
OutputDebugStringA(startptr);
|
||||
}
|
||||
#else
|
||||
/* Unix has it easy. Just dump it to stderr. */
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WINDOWS
|
||||
static SDL_assert_state SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT;
|
||||
static const SDL_assert_data *SDL_Windows_AssertData = NULL;
|
||||
|
||||
static LRESULT CALLBACK
|
||||
SDL_Assertion_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
{
|
||||
/* !!! FIXME: all this code stinks. */
|
||||
const SDL_assert_data *data = SDL_Windows_AssertData;
|
||||
char buf[1024];
|
||||
const int w = 100;
|
||||
const int h = 25;
|
||||
const int gap = 10;
|
||||
int x = gap;
|
||||
int y = 50;
|
||||
int len;
|
||||
int i;
|
||||
static const struct {
|
||||
const char *name;
|
||||
SDL_assert_state state;
|
||||
} buttons[] = {
|
||||
{"Abort", SDL_ASSERTION_ABORT },
|
||||
{"Break", SDL_ASSERTION_BREAK },
|
||||
{"Retry", SDL_ASSERTION_RETRY },
|
||||
{"Ignore", SDL_ASSERTION_IGNORE },
|
||||
{"Always Ignore", SDL_ASSERTION_ALWAYS_IGNORE },
|
||||
};
|
||||
|
||||
len = (int) SDL_snprintf(buf, sizeof (buf),
|
||||
"Assertion failure at %s (%s:%d), triggered %u time%s:\r\n '%s'",
|
||||
data->function, data->filename, data->linenum,
|
||||
data->trigger_count, (data->trigger_count == 1) ? "" : "s",
|
||||
data->condition);
|
||||
if ((len < 0) || (len >= sizeof (buf))) {
|
||||
buf[sizeof (buf) - 1] = '\0';
|
||||
}
|
||||
|
||||
CreateWindowA("STATIC", buf,
|
||||
WS_VISIBLE | WS_CHILD | SS_LEFT,
|
||||
x, y, 550, 100,
|
||||
hwnd, (HMENU) 1, NULL, NULL);
|
||||
y += 110;
|
||||
|
||||
for (i = 0; i < (sizeof (buttons) / sizeof (buttons[0])); i++) {
|
||||
CreateWindowA("BUTTON", buttons[i].name,
|
||||
WS_VISIBLE | WS_CHILD,
|
||||
x, y, w, h,
|
||||
hwnd, (HMENU) buttons[i].state, NULL, NULL);
|
||||
x += w + gap;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
SDL_Windows_AssertChoice = ((SDL_assert_state) (LOWORD(wParam)));
|
||||
SDL_Windows_AssertData = NULL;
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
SDL_Windows_AssertData = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
static SDL_assert_state
|
||||
SDL_PromptAssertion_windows(const SDL_assert_data *data)
|
||||
{
|
||||
HINSTANCE hInstance = 0; /* !!! FIXME? */
|
||||
HWND hwnd;
|
||||
MSG msg;
|
||||
WNDCLASS wc = {0};
|
||||
|
||||
SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT;
|
||||
SDL_Windows_AssertData = data;
|
||||
|
||||
wc.lpszClassName = TEXT("SDL_assert");
|
||||
wc.hInstance = hInstance ;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
wc.lpfnWndProc = SDL_Assertion_WndProc;
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
|
||||
RegisterClass(&wc);
|
||||
hwnd = CreateWindow(wc.lpszClassName, TEXT("SDL assertion failure"),
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
150, 150, 570, 260, 0, 0, hInstance, 0);
|
||||
|
||||
while (GetMessage(&msg, NULL, 0, 0) && (SDL_Windows_AssertData != NULL)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
DestroyWindow(hwnd);
|
||||
UnregisterClass(wc.lpszClassName, hInstance);
|
||||
return SDL_Windows_AssertChoice;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void SDL_AddAssertionToReport(SDL_assert_data *data)
|
||||
{
|
||||
#if !SDL_ASSERTION_REPORT_DISABLED
|
||||
/* (data) is always a static struct defined with the assert macros, so
|
||||
we don't have to worry about copying or allocating them. */
|
||||
if (data->next == NULL) { /* not yet added? */
|
||||
data->next = triggered_assertions;
|
||||
triggered_assertions = data;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SDL_GenerateAssertionReport(void)
|
||||
{
|
||||
#if !SDL_ASSERTION_REPORT_DISABLED
|
||||
if (triggered_assertions != &assertion_list_terminator)
|
||||
{
|
||||
SDL_assert_data *item = triggered_assertions;
|
||||
|
||||
debug_print("\n\nSDL assertion report.\n");
|
||||
debug_print("All SDL assertions between last init/quit:\n\n");
|
||||
|
||||
while (item != &assertion_list_terminator) {
|
||||
debug_print(
|
||||
"'%s'\n"
|
||||
" * %s (%s:%d)\n"
|
||||
" * triggered %u time%s.\n"
|
||||
" * always ignore: %s.\n",
|
||||
item->condition, item->function, item->filename,
|
||||
item->linenum, item->trigger_count,
|
||||
(item->trigger_count == 1) ? "" : "s",
|
||||
item->always_ignore ? "yes" : "no");
|
||||
item = item->next;
|
||||
}
|
||||
debug_print("\n");
|
||||
|
||||
triggered_assertions = &assertion_list_terminator;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void SDL_AbortAssertion(void)
|
||||
{
|
||||
SDL_Quit();
|
||||
#ifdef _WINDOWS
|
||||
ExitProcess(42);
|
||||
#elif unix || __APPLE__
|
||||
_exit(42);
|
||||
#else
|
||||
#error Please define your platform or set SDL_ASSERT_LEVEL to 0.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static SDL_assert_state SDL_PromptAssertion(const SDL_assert_data *data)
|
||||
{
|
||||
const char *envr;
|
||||
|
||||
debug_print("\n\n"
|
||||
"Assertion failure at %s (%s:%d), triggered %u time%s:\n"
|
||||
" '%s'\n"
|
||||
"\n",
|
||||
data->function, data->filename, data->linenum,
|
||||
data->trigger_count, (data->trigger_count == 1) ? "" : "s",
|
||||
data->condition);
|
||||
|
||||
/* let env. variable override, so unit tests won't block in a GUI. */
|
||||
envr = SDL_getenv("SDL_ASSERT");
|
||||
if (envr != NULL) {
|
||||
if (SDL_strcmp(envr, "abort") == 0) {
|
||||
return SDL_ASSERTION_ABORT;
|
||||
} else if (SDL_strcmp(envr, "break") == 0) {
|
||||
return SDL_ASSERTION_BREAK;
|
||||
} else if (SDL_strcmp(envr, "retry") == 0) {
|
||||
return SDL_ASSERTION_RETRY;
|
||||
} else if (SDL_strcmp(envr, "ignore") == 0) {
|
||||
return SDL_ASSERTION_IGNORE;
|
||||
} else if (SDL_strcmp(envr, "always_ignore") == 0) {
|
||||
return SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
} else {
|
||||
return SDL_ASSERTION_ABORT; /* oh well. */
|
||||
}
|
||||
}
|
||||
|
||||
/* platform-specific UI... */
|
||||
|
||||
#ifdef _WINDOWS
|
||||
return SDL_PromptAssertion_windows(data);
|
||||
|
||||
#elif __APPLE__
|
||||
/* This has to be done in an Objective-C (*.m) file, so we call out. */
|
||||
extern SDL_assert_state SDL_PromptAssertion_cocoa(const SDL_assert_data *);
|
||||
return SDL_PromptAssertion_cocoa(data);
|
||||
|
||||
#elif unix
|
||||
/* this is a little hacky. */
|
||||
for ( ; ; ) {
|
||||
char buf[32];
|
||||
fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
|
||||
fflush(stderr);
|
||||
if (fgets(buf, sizeof (buf), stdin) == NULL) {
|
||||
return SDL_ASSERTION_ABORT;
|
||||
}
|
||||
|
||||
if (SDL_strcmp(buf, "a") == 0) {
|
||||
return SDL_ASSERTION_ABORT;
|
||||
} else if (SDL_strcmp(envr, "b") == 0) {
|
||||
return SDL_ASSERTION_BREAK;
|
||||
} else if (SDL_strcmp(envr, "r") == 0) {
|
||||
return SDL_ASSERTION_RETRY;
|
||||
} else if (SDL_strcmp(envr, "i") == 0) {
|
||||
return SDL_ASSERTION_IGNORE;
|
||||
} else if (SDL_strcmp(envr, "A") == 0) {
|
||||
return SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#error Please define your platform or set SDL_ASSERT_LEVEL to 0.
|
||||
#endif
|
||||
|
||||
return SDL_ASSERTION_ABORT;
|
||||
}
|
||||
|
||||
|
||||
static SDL_mutex *assertion_mutex = NULL;
|
||||
|
||||
SDL_assert_state
|
||||
SDL_ReportAssertion(SDL_assert_data *data, const char *func, int line)
|
||||
{
|
||||
SDL_assert_state state;
|
||||
|
||||
if (SDL_LockMutex(assertion_mutex) < 0) {
|
||||
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
|
||||
}
|
||||
|
||||
/* doing this because Visual C is upset over assigning in the macro. */
|
||||
if (data->trigger_count == 0) {
|
||||
data->function = func;
|
||||
data->linenum = line;
|
||||
}
|
||||
|
||||
SDL_AddAssertionToReport(data);
|
||||
|
||||
data->trigger_count++;
|
||||
if (data->always_ignore) {
|
||||
SDL_UnlockMutex(assertion_mutex);
|
||||
return SDL_ASSERTION_IGNORE;
|
||||
}
|
||||
|
||||
state = SDL_PromptAssertion(data);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SDL_ASSERTION_ABORT:
|
||||
SDL_UnlockMutex(assertion_mutex); /* in case we assert in quit. */
|
||||
SDL_AbortAssertion();
|
||||
return SDL_ASSERTION_IGNORE; /* shouldn't return, but oh well. */
|
||||
|
||||
case SDL_ASSERTION_ALWAYS_IGNORE:
|
||||
state = SDL_ASSERTION_IGNORE;
|
||||
data->always_ignore = 1;
|
||||
break;
|
||||
|
||||
case SDL_ASSERTION_IGNORE:
|
||||
case SDL_ASSERTION_RETRY:
|
||||
case SDL_ASSERTION_BREAK:
|
||||
break; /* macro handles these. */
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(assertion_mutex);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
#endif /* SDL_ASSERT_LEVEL > 0 */
|
||||
|
||||
|
||||
int SDL_AssertionsInit(void)
|
||||
{
|
||||
#if (SDL_ASSERT_LEVEL > 0)
|
||||
assertion_mutex = SDL_CreateMutex();
|
||||
if (assertion_mutex == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SDL_AssertionsQuit(void)
|
||||
{
|
||||
#if (SDL_ASSERT_LEVEL > 0)
|
||||
SDL_GenerateAssertionReport();
|
||||
SDL_DestroyMutex(assertion_mutex);
|
||||
assertion_mutex = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -135,4 +135,44 @@ Cocoa_VideoQuit(_THIS)
|
|||
Cocoa_QuitMouse(_this);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Mac OS X assertion support.
|
||||
*
|
||||
* This doesn't really have aything to do with the interfaces of the SDL video
|
||||
* subsystem, but we need to stuff this into an Objective-C source code file.
|
||||
*/
|
||||
|
||||
SDL_assert_state
|
||||
SDL_PromptAssertion_cocoa(const SDL_assert_data *data)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSString *msg = [NSString stringWithFormat:
|
||||
@"Assertion failure at %s (%s:%d), triggered %u time%s:\n '%s'",
|
||||
data->function, data->filename, data->linenum,
|
||||
data->trigger_count, (data->trigger_count == 1) ? "" : "s",
|
||||
data->condition];
|
||||
|
||||
NSLog(msg);
|
||||
|
||||
/*
|
||||
* !!! FIXME: this code needs to deal with fullscreen modes:
|
||||
* !!! FIXME: reset to default desktop, runModal, reset to current?
|
||||
*/
|
||||
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSCriticalAlertStyle];
|
||||
[alert setMessageText:msg];
|
||||
[alert addButtonWithTitle:@"Retry"];
|
||||
[alert addButtonWithTitle:@"Break"];
|
||||
[alert addButtonWithTitle:@"Abort"];
|
||||
[alert addButtonWithTitle:@"Ignore"];
|
||||
[alert addButtonWithTitle:@"Always Ignore"];
|
||||
const NSInteger clicked = [alert runModal];
|
||||
[pool release];
|
||||
return (SDL_assert_state) (clicked - NSAlertFirstButtonReturn);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 expandtab: */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue