zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_assert.c
Go to the documentation of this file.
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 #include "SDL_config.h"
22 
23 #include "SDL.h"
24 #include "SDL_atomic.h"
25 #include "SDL_messagebox.h"
26 #include "SDL_video.h"
27 #include "SDL_assert.h"
28 #include "SDL_assert_c.h"
29 #include "video/SDL_sysvideo.h"
30 
31 #ifdef __WIN32__
33 
34 #ifndef WS_OVERLAPPEDWINDOW
35 #define WS_OVERLAPPEDWINDOW 0
36 #endif
37 #else /* fprintf, _exit(), etc. */
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #endif
42 
43 static SDL_assert_state
44 SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
45 
46 /*
47  * We keep all triggered assertions in a singly-linked list so we can
48  * generate a report later.
49  */
51 
54 static void *assertion_userdata = NULL;
55 
56 #ifdef __GNUC__
57 static void
58 debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
59 #endif
60 
61 static void
62 debug_print(const char *fmt, ...)
63 {
64  va_list ap;
65  va_start(ap, fmt);
67  va_end(ap);
68 }
69 
70 
72 {
73  /* (data) is always a static struct defined with the assert macros, so
74  we don't have to worry about copying or allocating them. */
75  data->trigger_count++;
76  if (data->trigger_count == 1) { /* not yet added? */
77  data->next = triggered_assertions;
78  triggered_assertions = data;
79  }
80 }
81 
82 
83 static void SDL_GenerateAssertionReport(void)
84 {
86 
87  /* only do this if the app hasn't assigned an assertion handler. */
88  if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
89  debug_print("\n\nSDL assertion report.\n");
90  debug_print("All SDL assertions between last init/quit:\n\n");
91 
92  while (item != NULL) {
94  "'%s'\n"
95  " * %s (%s:%d)\n"
96  " * triggered %u time%s.\n"
97  " * always ignore: %s.\n",
98  item->condition, item->function, item->filename,
99  item->linenum, item->trigger_count,
100  (item->trigger_count == 1) ? "" : "s",
101  item->always_ignore ? "yes" : "no");
102  item = item->next;
103  }
104  debug_print("\n");
105 
107  }
108 }
109 
110 static void SDL_ExitProcess(int exitcode)
111 {
112 #ifdef __WIN32__
113  ExitProcess(exitcode);
114 #else
115  _exit(exitcode);
116 #endif
117 }
118 
119 static void SDL_AbortAssertion(void)
120 {
121  SDL_Quit();
122  SDL_ExitProcess(42);
123 }
124 
125 
126 static SDL_assert_state
127 SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
128 {
129 #ifdef __WIN32__
130  #define ENDLINE "\r\n"
131 #else
132  #define ENDLINE "\n"
133 #endif
134 
135  const char *envr;
137  SDL_Window *window;
138  SDL_MessageBoxData messagebox;
139  SDL_MessageBoxButtonData buttons[] = {
140  { 0, SDL_ASSERTION_RETRY, "Retry" },
141  { 0, SDL_ASSERTION_BREAK, "Break" },
142  { 0, SDL_ASSERTION_ABORT, "Abort" },
144  SDL_ASSERTION_IGNORE, "Ignore" },
146  SDL_ASSERTION_ALWAYS_IGNORE, "Always Ignore" }
147  };
148  char *message;
149  int selected;
150 
151  (void) userdata; /* unused in default handler. */
152 
153  message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
154  if (!message) {
155  /* Uh oh, we're in real trouble now... */
156  return SDL_ASSERTION_ABORT;
157  }
159  "Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
160  " '%s'",
161  data->function, data->filename, data->linenum,
162  data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
163  data->condition);
164 
165  debug_print("\n\n%s\n\n", message);
166 
167  /* let env. variable override, so unit tests won't block in a GUI. */
168  envr = SDL_getenv("SDL_ASSERT");
169  if (envr != NULL) {
170  SDL_stack_free(message);
171 
172  if (SDL_strcmp(envr, "abort") == 0) {
173  return SDL_ASSERTION_ABORT;
174  } else if (SDL_strcmp(envr, "break") == 0) {
175  return SDL_ASSERTION_BREAK;
176  } else if (SDL_strcmp(envr, "retry") == 0) {
177  return SDL_ASSERTION_RETRY;
178  } else if (SDL_strcmp(envr, "ignore") == 0) {
179  return SDL_ASSERTION_IGNORE;
180  } else if (SDL_strcmp(envr, "always_ignore") == 0) {
182  } else {
183  return SDL_ASSERTION_ABORT; /* oh well. */
184  }
185  }
186 
187  /* Leave fullscreen mode, if possible (scary!) */
188  window = SDL_GetFocusWindow();
189  if (window) {
191  SDL_MinimizeWindow(window);
192  } else {
193  /* !!! FIXME: ungrab the input if we're not fullscreen? */
194  /* No need to mess with the window */
195  window = NULL;
196  }
197  }
198 
199  /* Show a messagebox if we can, otherwise fall back to stdio */
200  SDL_zero(messagebox);
201  messagebox.flags = SDL_MESSAGEBOX_WARNING;
202  messagebox.window = window;
203  messagebox.title = "Assertion Failed";
204  messagebox.message = message;
205  messagebox.numbuttons = SDL_arraysize(buttons);
206  messagebox.buttons = buttons;
207 
208  if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
209  if (selected == -1) {
210  state = SDL_ASSERTION_IGNORE;
211  } else {
212  state = (SDL_assert_state)selected;
213  }
214  }
215 #ifdef HAVE_STDIO_H
216  else
217  {
218  /* this is a little hacky. */
219  for ( ; ; ) {
220  char buf[32];
221  fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
222  fflush(stderr);
223  if (fgets(buf, sizeof (buf), stdin) == NULL) {
224  break;
225  }
226 
227  if (SDL_strcmp(buf, "a") == 0) {
228  state = SDL_ASSERTION_ABORT;
229  break;
230  } else if (SDL_strcmp(buf, "b") == 0) {
231  state = SDL_ASSERTION_BREAK;
232  break;
233  } else if (SDL_strcmp(buf, "r") == 0) {
234  state = SDL_ASSERTION_RETRY;
235  break;
236  } else if (SDL_strcmp(buf, "i") == 0) {
237  state = SDL_ASSERTION_IGNORE;
238  break;
239  } else if (SDL_strcmp(buf, "A") == 0) {
241  break;
242  }
243  }
244  }
245 #endif /* HAVE_STDIO_H */
246 
247  /* Re-enter fullscreen mode */
248  if (window) {
249  SDL_RestoreWindow(window);
250  }
251 
252  SDL_stack_free(message);
253 
254  return state;
255 }
256 
257 
259 SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
260  int line)
261 {
262  static int assertion_running = 0;
263  static SDL_SpinLock spinlock = 0;
265 
266  SDL_AtomicLock(&spinlock);
267  if (assertion_mutex == NULL) { /* never called SDL_Init()? */
269  if (assertion_mutex == NULL) {
270  SDL_AtomicUnlock(&spinlock);
271  return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
272  }
273  }
274  SDL_AtomicUnlock(&spinlock);
275 
276  if (SDL_LockMutex(assertion_mutex) < 0) {
277  return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
278  }
279 
280  /* doing this because Visual C is upset over assigning in the macro. */
281  if (data->trigger_count == 0) {
282  data->function = func;
283  data->filename = file;
284  data->linenum = line;
285  }
286 
288 
289  assertion_running++;
290  if (assertion_running > 1) { /* assert during assert! Abort. */
291  if (assertion_running == 2) {
293  } else if (assertion_running == 3) { /* Abort asserted! */
294  SDL_ExitProcess(42);
295  } else {
296  while (1) { /* do nothing but spin; what else can you do?! */ }
297  }
298  }
299 
300  if (!data->always_ignore) {
301  state = assertion_handler(data, assertion_userdata);
302  }
303 
304  switch (state)
305  {
306  case SDL_ASSERTION_ABORT:
308  return SDL_ASSERTION_IGNORE; /* shouldn't return, but oh well. */
309 
311  state = SDL_ASSERTION_IGNORE;
312  data->always_ignore = 1;
313  break;
314 
316  case SDL_ASSERTION_RETRY:
317  case SDL_ASSERTION_BREAK:
318  break; /* macro handles these. */
319  }
320 
321  assertion_running--;
323 
324  return state;
325 }
326 
327 
329 {
331  if (assertion_mutex != NULL) {
334  }
335 }
336 
337 void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
338 {
339  if (handler != NULL) {
340  assertion_handler = handler;
341  assertion_userdata = userdata;
342  } else {
345  }
346 }
347 
349 {
350  return triggered_assertions;
351 }
352 
354 {
355  SDL_assert_data *next = NULL;
356  SDL_assert_data *item;
357  for (item = triggered_assertions; item != NULL; item = next) {
358  next = (SDL_assert_data *) item->next;
359  item->always_ignore = SDL_FALSE;
360  item->trigger_count = 0;
361  item->next = NULL;
362  }
363 
364  triggered_assertions = NULL;
365 }
366 
367 /* vi: set ts=4 sw=4 expandtab: */
static SDL_AssertionHandler assertion_handler
Definition: SDL_assert.c:53
const char * message
#define SDL_MAX_LOG_MESSAGE
The maximum size of a log message.
Definition: SDL_log.h:54
static void SDL_GenerateAssertionReport(void)
Definition: SDL_assert.c:83
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
GLsizei GLenum GLuint GLuint GLsizei GLchar * message
Definition: glew.h:2540
static SDL_assert_data * triggered_assertions
Definition: SDL_assert.c:50
const char * title
DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock)
Unlock a spin lock by setting it to 0. Always returns immediately.
Definition: SDL_spinlock.c:109
SDL_Window * window
#define NULL
Definition: ftobjs.h:61
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
Definition: SDL_string.c:1277
static void SDL_AbortAssertion(void)
Definition: SDL_assert.c:119
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:227
DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:73
SDL_assert_state
Definition: SDL_assert.h:98
DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void)
Definition: SDL_sysmutex.c:38
FILE * file
Definition: visualinfo.c:88
static void * assertion_userdata
Definition: SDL_assert.c:54
DECLSPEC void SDLCALL SDL_Quit(void)
Definition: SDL.c:342
GLenum func
Definition: SDL_opengl.h:5654
static SDL_assert_state SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
Definition: SDL_assert.c:127
static void debug_print(const char *fmt,...)
Definition: SDL_assert.c:62
DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:160
unsigned int trigger_count
Definition: SDL_assert.h:110
Individual button data.
const char * condition
Definition: SDL_assert.h:111
DECLSPEC void SDLCALL SDL_MinimizeWindow(SDL_Window *window)
Minimize a window to an iconic representation.
Definition: SDL_video.c:1783
void SDL_AssertionsQuit(void)
Definition: SDL_assert.c:328
DECLSPEC void SDLCALL SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
Log a message with the specified category and priority.
Definition: SDL_log.c:267
DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock)
Lock a spin lock by setting it to a non-zero value.
Definition: SDL_spinlock.c:100
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
SDL_Window * SDL_GetFocusWindow(void)
Definition: SDL_video.c:2138
DECLSPEC void SDLCALL SDL_RestoreWindow(SDL_Window *window)
Restore the size and position of a minimized or maximized window.
Definition: SDL_video.c:1799
DECLSPEC void SDLCALL SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
Set an application-defined assertion handler.
Definition: SDL_assert.c:337
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
DECLSPEC Uint32 SDLCALL SDL_GetWindowFlags(SDL_Window *window)
Get the window flags.
Definition: SDL_video.c:1409
const SDL_MessageBoxButtonData * buttons
MessageBox structure containing title, text, window, etc.
SDL_assert_state(SDLCALL * SDL_AssertionHandler)(const SDL_assert_data *data, void *userdata)
Definition: SDL_assert.h:178
static void SDL_AddAssertionToReport(SDL_assert_data *data)
Definition: SDL_assert.c:71
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
struct SDL_mutex SDL_mutex
Definition: SDL_mutex.h:59
GLenum GLuint GLsizei const GLchar * buf
Definition: glew.h:2539
static SDL_mutex * assertion_mutex
Definition: SDL_assert.c:52
const char * filename
Definition: SDL_assert.h:112
struct SDL_assert_data * next
Definition: SDL_assert.h:115
DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, const char *, const char *, int)
Definition: SDL_assert.c:259
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:226
DECLSPEC const SDL_assert_data *SDLCALL SDL_GetAssertionReport(void)
Get a list of all assertion failures.
Definition: SDL_assert.c:348
DECLSPEC char *SDLCALL SDL_getenv(const char *name)
Definition: SDL_getenv.c:179
#define SDL_zero(x)
Definition: SDL_stdinc.h:254
DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:61
int SDL_SpinLock
Definition: SDL_atomic.h:96
#define ENDLINE
DECLSPEC int SDLCALL SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
Create a modal message box.
Definition: SDL_video.c:3122
DECLSPEC void SDLCALL SDL_ResetAssertionReport(void)
Reset the list of all assertion failures.
Definition: SDL_assert.c:353
static void SDL_ExitProcess(int exitcode)
Definition: SDL_assert.c:110
const char * function
Definition: SDL_assert.h:114