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