src/SDL_assert.c
changeset 6621 25504f9ab078
parent 6305 601b0e251822
child 6759 b74da0b33530
child 8337 4a67a3cca43d
     1.1 --- a/src/SDL_assert.c	Tue Oct 30 18:59:56 2012 -0700
     1.2 +++ b/src/SDL_assert.c	Tue Oct 30 19:00:43 2012 -0700
     1.3 @@ -22,6 +22,8 @@
     1.4  
     1.5  #include "SDL.h"
     1.6  #include "SDL_atomic.h"
     1.7 +#include "SDL_messagebox.h"
     1.8 +#include "SDL_video.h"
     1.9  #include "SDL_assert.h"
    1.10  #include "SDL_assert_c.h"
    1.11  #include "video/SDL_sysvideo.h"
    1.12 @@ -59,160 +61,13 @@
    1.13  static void
    1.14  debug_print(const char *fmt, ...)
    1.15  {
    1.16 -#ifdef __WIN32__
    1.17 -    /* Format into a buffer for OutputDebugStringA(). */
    1.18 -    char buf[1024];
    1.19 -    char *startptr;
    1.20 -    char *ptr;
    1.21 -    LPTSTR tstr;
    1.22 -    int len;
    1.23      va_list ap;
    1.24      va_start(ap, fmt);
    1.25 -    len = (int) SDL_vsnprintf(buf, sizeof (buf), fmt, ap);
    1.26 +    SDL_LogMessageV(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, fmt, ap);
    1.27      va_end(ap);
    1.28 -
    1.29 -    /* Visual C's vsnprintf() may not null-terminate the buffer. */
    1.30 -    if ((len >= sizeof (buf)) || (len < 0)) {
    1.31 -        buf[sizeof (buf) - 1] = '\0';
    1.32 -    }
    1.33 -
    1.34 -    /* Write it, sorting out the Unix newlines... */
    1.35 -    startptr = buf;
    1.36 -    for (ptr = startptr; *ptr; ptr++) {
    1.37 -        if (*ptr == '\n') {
    1.38 -            *ptr = '\0';
    1.39 -            tstr = WIN_UTF8ToString(startptr);
    1.40 -            OutputDebugString(tstr);
    1.41 -            SDL_free(tstr);
    1.42 -            OutputDebugString(TEXT("\r\n"));
    1.43 -            startptr = ptr+1;
    1.44 -        }
    1.45 -    }
    1.46 -
    1.47 -    /* catch that last piece if it didn't have a newline... */
    1.48 -    if (startptr != ptr) {
    1.49 -        tstr = WIN_UTF8ToString(startptr);
    1.50 -        OutputDebugString(tstr);
    1.51 -        SDL_free(tstr);
    1.52 -    }
    1.53 -#else
    1.54 -    /* Unix has it easy. Just dump it to stderr. */
    1.55 -    va_list ap;
    1.56 -    va_start(ap, fmt);
    1.57 -    vfprintf(stderr, fmt, ap);
    1.58 -    va_end(ap);
    1.59 -    fflush(stderr);
    1.60 -#endif
    1.61  }
    1.62  
    1.63  
    1.64 -#ifdef __WIN32__
    1.65 -static SDL_assert_state SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT;
    1.66 -static const SDL_assert_data *SDL_Windows_AssertData = NULL;
    1.67 -
    1.68 -static LRESULT CALLBACK
    1.69 -SDL_Assertion_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    1.70 -{
    1.71 -    switch (msg)
    1.72 -    {
    1.73 -        case WM_CREATE:
    1.74 -        {
    1.75 -            /* !!! FIXME: all this code stinks. */
    1.76 -            const SDL_assert_data *data = SDL_Windows_AssertData;
    1.77 -            char buf[1024];
    1.78 -            LPTSTR tstr;
    1.79 -            const int w = 100;
    1.80 -            const int h = 25;
    1.81 -            const int gap = 10;
    1.82 -            int x = gap;
    1.83 -            int y = 50;
    1.84 -            int len;
    1.85 -            int i;
    1.86 -            static const struct { 
    1.87 -                LPCTSTR name;
    1.88 -                SDL_assert_state state;
    1.89 -            } buttons[] = {
    1.90 -                {TEXT("Abort"), SDL_ASSERTION_ABORT },
    1.91 -                {TEXT("Break"), SDL_ASSERTION_BREAK },
    1.92 -                {TEXT("Retry"), SDL_ASSERTION_RETRY },
    1.93 -                {TEXT("Ignore"), SDL_ASSERTION_IGNORE },
    1.94 -                {TEXT("Always Ignore"), SDL_ASSERTION_ALWAYS_IGNORE },
    1.95 -            };
    1.96 -
    1.97 -            len = (int) SDL_snprintf(buf, sizeof (buf), 
    1.98 -                         "Assertion failure at %s (%s:%d), triggered %u time%s:\r\n  '%s'",
    1.99 -                         data->function, data->filename, data->linenum,
   1.100 -                         data->trigger_count, (data->trigger_count == 1) ? "" : "s",
   1.101 -                         data->condition);
   1.102 -            if ((len < 0) || (len >= sizeof (buf))) {
   1.103 -                buf[sizeof (buf) - 1] = '\0';
   1.104 -            }
   1.105 -
   1.106 -            tstr = WIN_UTF8ToString(buf);
   1.107 -            CreateWindow(TEXT("STATIC"), tstr,
   1.108 -                         WS_VISIBLE | WS_CHILD | SS_LEFT,
   1.109 -                         x, y, 550, 100,
   1.110 -                         hwnd, (HMENU) 1, NULL, NULL);
   1.111 -            SDL_free(tstr);
   1.112 -            y += 110;
   1.113 -
   1.114 -            for (i = 0; i < (sizeof (buttons) / sizeof (buttons[0])); i++) {
   1.115 -                CreateWindow(TEXT("BUTTON"), buttons[i].name,
   1.116 -                         WS_VISIBLE | WS_CHILD,
   1.117 -                         x, y, w, h,
   1.118 -                         hwnd, (HMENU) buttons[i].state, NULL, NULL);
   1.119 -                x += w + gap;
   1.120 -            }
   1.121 -            break;
   1.122 -        }
   1.123 -
   1.124 -        case WM_COMMAND:
   1.125 -            SDL_Windows_AssertChoice = ((SDL_assert_state) (LOWORD(wParam)));
   1.126 -            SDL_Windows_AssertData = NULL;
   1.127 -            break;
   1.128 -
   1.129 -        case WM_DESTROY:
   1.130 -            SDL_Windows_AssertData = NULL;
   1.131 -            break;
   1.132 -    }
   1.133 -
   1.134 -    return DefWindowProc(hwnd, msg, wParam, lParam);
   1.135 -}
   1.136 -
   1.137 -static SDL_assert_state
   1.138 -SDL_PromptAssertion_windows(const SDL_assert_data *data)
   1.139 -{
   1.140 -    HINSTANCE hInstance = 0;  /* !!! FIXME? */
   1.141 -    HWND hwnd;
   1.142 -    MSG msg;
   1.143 -    WNDCLASS wc = {0};
   1.144 -
   1.145 -    SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT;
   1.146 -    SDL_Windows_AssertData = data;
   1.147 -
   1.148 -    wc.lpszClassName = TEXT("SDL_assert");
   1.149 -    wc.hInstance = hInstance ;
   1.150 -    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
   1.151 -    wc.lpfnWndProc = SDL_Assertion_WndProc;
   1.152 -    wc.hCursor = LoadCursor(0, IDC_ARROW);
   1.153 -  
   1.154 -    RegisterClass(&wc);
   1.155 -    hwnd = CreateWindow(wc.lpszClassName, TEXT("SDL assertion failure"),
   1.156 -                 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
   1.157 -                 150, 150, 570, 260, 0, 0, hInstance, 0);  
   1.158 -
   1.159 -    while (GetMessage(&msg, NULL, 0, 0) && (SDL_Windows_AssertData != NULL)) {
   1.160 -        TranslateMessage(&msg);
   1.161 -        DispatchMessage(&msg);
   1.162 -    }
   1.163 -
   1.164 -    DestroyWindow(hwnd);
   1.165 -    UnregisterClass(wc.lpszClassName, hInstance);
   1.166 -    return SDL_Windows_AssertChoice;
   1.167 -}
   1.168 -#endif
   1.169 -
   1.170 -
   1.171  static void SDL_AddAssertionToReport(SDL_assert_data *data)
   1.172  {
   1.173      /* (data) is always a static struct defined with the assert macros, so
   1.174 @@ -274,20 +129,39 @@
   1.175      const char *envr;
   1.176      SDL_assert_state state = SDL_ASSERTION_ABORT;
   1.177      SDL_Window *window;
   1.178 +    SDL_MessageBoxData messagebox;
   1.179 +    SDL_MessageBoxButtonData buttons[] = {
   1.180 +        {   0,  SDL_ASSERTION_RETRY,            "Retry" },
   1.181 +        {   0,  SDL_ASSERTION_BREAK,            "Break" },
   1.182 +        {   0,  SDL_ASSERTION_ABORT,            "Abort" },
   1.183 +        {   SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
   1.184 +                SDL_ASSERTION_IGNORE,           "Ignore" },
   1.185 +        {   SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
   1.186 +                SDL_ASSERTION_ALWAYS_IGNORE,    "Always Ignore" }
   1.187 +    };
   1.188 +    char *message;
   1.189 +    int selected;
   1.190  
   1.191      (void) userdata;  /* unused in default handler. */
   1.192  
   1.193 -    debug_print("\n\n"
   1.194 -                "Assertion failure at %s (%s:%d), triggered %u time%s:\n"
   1.195 -                "  '%s'\n"
   1.196 -                "\n",
   1.197 -                data->function, data->filename, data->linenum,
   1.198 -                data->trigger_count, (data->trigger_count == 1) ? "" : "s",
   1.199 -                data->condition);
   1.200 +    message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
   1.201 +    if (!message) {
   1.202 +        /* Uh oh, we're in real trouble now... */
   1.203 +        return SDL_ASSERTION_ABORT;
   1.204 +    }
   1.205 +    SDL_snprintf(message, SDL_MAX_LOG_MESSAGE,
   1.206 +                 "Assertion failure at %s (%s:%d), triggered %u %s:\r\n  '%s'",
   1.207 +                 data->function, data->filename, data->linenum,
   1.208 +                 data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
   1.209 +                 data->condition);
   1.210 +
   1.211 +    debug_print("\n\n%s\n\n", message);
   1.212  
   1.213      /* let env. variable override, so unit tests won't block in a GUI. */
   1.214      envr = SDL_getenv("SDL_ASSERT");
   1.215      if (envr != NULL) {
   1.216 +        SDL_stack_free(message);
   1.217 +
   1.218          if (SDL_strcmp(envr, "abort") == 0) {
   1.219              return SDL_ASSERTION_ABORT;
   1.220          } else if (SDL_strcmp(envr, "break") == 0) {
   1.221 @@ -311,54 +185,65 @@
   1.222          } else {
   1.223              /* !!! FIXME: ungrab the input if we're not fullscreen? */
   1.224              /* No need to mess with the window */
   1.225 -            window = 0;
   1.226 +            window = NULL;
   1.227          }
   1.228      }
   1.229  
   1.230 -    /* platform-specific UI... */
   1.231 +    /* Show a messagebox if we can, otherwise fall back to stdio */
   1.232 +    SDL_zero(messagebox);
   1.233 +    messagebox.flags = SDL_MESSAGEBOX_WARNING;
   1.234 +    messagebox.window = window;
   1.235 +    messagebox.title = "Assertion Failed";
   1.236 +    messagebox.message = message;
   1.237 +    messagebox.numbuttons = SDL_arraysize(buttons);
   1.238 +    messagebox.buttons = buttons;
   1.239  
   1.240 -#ifdef __WIN32__
   1.241 -    state = SDL_PromptAssertion_windows(data);
   1.242 -
   1.243 -#elif defined __MACOSX__ && defined SDL_VIDEO_DRIVER_COCOA
   1.244 -    /* This has to be done in an Objective-C (*.m) file, so we call out. */
   1.245 -    extern SDL_assert_state SDL_PromptAssertion_cocoa(const SDL_assert_data *);
   1.246 -    state = SDL_PromptAssertion_cocoa(data);
   1.247 -
   1.248 -#else
   1.249 -    /* this is a little hacky. */
   1.250 -    for ( ; ; ) {
   1.251 -        char buf[32];
   1.252 -        fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
   1.253 -        fflush(stderr);
   1.254 -        if (fgets(buf, sizeof (buf), stdin) == NULL) {
   1.255 -            break;
   1.256 -        }
   1.257 -
   1.258 -        if (SDL_strcmp(buf, "a") == 0) {
   1.259 -            state = SDL_ASSERTION_ABORT;
   1.260 -            break;
   1.261 -        } else if (SDL_strcmp(buf, "b") == 0) {
   1.262 -            state = SDL_ASSERTION_BREAK;
   1.263 -            break;
   1.264 -        } else if (SDL_strcmp(buf, "r") == 0) {
   1.265 -            state = SDL_ASSERTION_RETRY;
   1.266 -            break;
   1.267 -        } else if (SDL_strcmp(buf, "i") == 0) {
   1.268 +    if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
   1.269 +        if (selected == -1) {
   1.270              state = SDL_ASSERTION_IGNORE;
   1.271 -            break;
   1.272 -        } else if (SDL_strcmp(buf, "A") == 0) {
   1.273 -            state = SDL_ASSERTION_ALWAYS_IGNORE;
   1.274 -            break;
   1.275 +        } else {
   1.276 +            state = (SDL_assert_state)selected;
   1.277          }
   1.278      }
   1.279 -#endif
   1.280 +#ifdef HAVE_STDIO_H
   1.281 +    else
   1.282 +    {
   1.283 +        /* this is a little hacky. */
   1.284 +        for ( ; ; ) {
   1.285 +            char buf[32];
   1.286 +            fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
   1.287 +            fflush(stderr);
   1.288 +            if (fgets(buf, sizeof (buf), stdin) == NULL) {
   1.289 +                break;
   1.290 +            }
   1.291 +
   1.292 +            if (SDL_strcmp(buf, "a") == 0) {
   1.293 +                state = SDL_ASSERTION_ABORT;
   1.294 +                break;
   1.295 +            } else if (SDL_strcmp(buf, "b") == 0) {
   1.296 +                state = SDL_ASSERTION_BREAK;
   1.297 +                break;
   1.298 +            } else if (SDL_strcmp(buf, "r") == 0) {
   1.299 +                state = SDL_ASSERTION_RETRY;
   1.300 +                break;
   1.301 +            } else if (SDL_strcmp(buf, "i") == 0) {
   1.302 +                state = SDL_ASSERTION_IGNORE;
   1.303 +                break;
   1.304 +            } else if (SDL_strcmp(buf, "A") == 0) {
   1.305 +                state = SDL_ASSERTION_ALWAYS_IGNORE;
   1.306 +                break;
   1.307 +            }
   1.308 +        }
   1.309 +    }
   1.310 +#endif /* HAVE_STDIO_H */
   1.311  
   1.312      /* Re-enter fullscreen mode */
   1.313      if (window) {
   1.314          SDL_RestoreWindow(window);
   1.315      }
   1.316  
   1.317 +    SDL_stack_free(message);
   1.318 +
   1.319      return state;
   1.320  }
   1.321