src/SDL_assert.c
author David Ludwig <dludwig@pobox.com>
Wed, 25 Dec 2013 21:39:48 -0500
changeset 8563 c0e68f3b6bbb
parent 8535 e8ee0708ef5c
child 8583 fb2933ca805f
permissions -rw-r--r--
WinRT: compiled the d3d11 renderer's shaders into SDL itself

Previously, the shaders would get compiled separately, the output of which would need to be packaged into the app. This change should make SDL's dll be the only binary needed to include SDL in a WinRT app.
slouken@3647
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@3647
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@3647
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@3647
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@3647
    20
*/
slouken@6217
    21
#include "SDL_config.h"
slouken@3647
    22
slouken@7828
    23
#if defined(__WIN32__)
slouken@7828
    24
#include "core/windows/SDL_windows.h"
slouken@7828
    25
#endif
slouken@7828
    26
slouken@3651
    27
#include "SDL.h"
slouken@5006
    28
#include "SDL_atomic.h"
slouken@6621
    29
#include "SDL_messagebox.h"
slouken@6621
    30
#include "SDL_video.h"
slouken@3647
    31
#include "SDL_assert.h"
slouken@4472
    32
#include "SDL_assert_c.h"
slouken@3671
    33
#include "video/SDL_sysvideo.h"
slouken@3647
    34
slouken@5086
    35
#ifdef __WIN32__
slouken@5086
    36
#ifndef WS_OVERLAPPEDWINDOW
slouken@5086
    37
#define WS_OVERLAPPEDWINDOW 0
slouken@5086
    38
#endif
slouken@3647
    39
#else  /* fprintf, _exit(), etc. */
slouken@3647
    40
#include <stdio.h>
slouken@3647
    41
#include <stdlib.h>
dludwig@8341
    42
#if ! defined(__WINRT__)
icculus@3648
    43
#include <unistd.h>
slouken@3647
    44
#endif
dludwig@8341
    45
#endif
slouken@3647
    46
icculus@3670
    47
static SDL_assert_state
icculus@3670
    48
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
icculus@3670
    49
icculus@3670
    50
/*
icculus@3670
    51
 * We keep all triggered assertions in a singly-linked list so we can
slouken@3647
    52
 *  generate a report later.
slouken@3647
    53
 */
icculus@5541
    54
static SDL_assert_data *triggered_assertions = NULL;
icculus@3670
    55
icculus@3670
    56
static SDL_mutex *assertion_mutex = NULL;
icculus@3670
    57
static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion;
icculus@3670
    58
static void *assertion_userdata = NULL;
slouken@3647
    59
icculus@3648
    60
#ifdef __GNUC__
icculus@3661
    61
static void
icculus@3661
    62
debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
icculus@3648
    63
#endif
icculus@3648
    64
icculus@3648
    65
static void
icculus@3648
    66
debug_print(const char *fmt, ...)
slouken@3647
    67
{
slouken@3647
    68
    va_list ap;
slouken@3647
    69
    va_start(ap, fmt);
slouken@6621
    70
    SDL_LogMessageV(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, fmt, ap);
slouken@3647
    71
    va_end(ap);
slouken@3647
    72
}
slouken@3647
    73
slouken@3647
    74
slouken@3647
    75
static void SDL_AddAssertionToReport(SDL_assert_data *data)
slouken@3647
    76
{
slouken@3647
    77
    /* (data) is always a static struct defined with the assert macros, so
slouken@3647
    78
       we don't have to worry about copying or allocating them. */
icculus@5541
    79
    data->trigger_count++;
icculus@5541
    80
    if (data->trigger_count == 1) {  /* not yet added? */
slouken@3647
    81
        data->next = triggered_assertions;
slouken@3647
    82
        triggered_assertions = data;
slouken@3647
    83
    }
slouken@3647
    84
}
slouken@3647
    85
icculus@3670
    86
slouken@3647
    87
static void SDL_GenerateAssertionReport(void)
slouken@3647
    88
{
icculus@5541
    89
    const SDL_assert_data *item = triggered_assertions;
icculus@3670
    90
icculus@3670
    91
    /* only do this if the app hasn't assigned an assertion handler. */
icculus@5541
    92
    if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
slouken@3647
    93
        debug_print("\n\nSDL assertion report.\n");
slouken@3647
    94
        debug_print("All SDL assertions between last init/quit:\n\n");
slouken@3647
    95
icculus@5541
    96
        while (item != NULL) {
slouken@3647
    97
            debug_print(
slouken@3647
    98
                "'%s'\n"
slouken@3647
    99
                "    * %s (%s:%d)\n"
slouken@3647
   100
                "    * triggered %u time%s.\n"
slouken@3647
   101
                "    * always ignore: %s.\n",
slouken@3647
   102
                item->condition, item->function, item->filename,
slouken@3647
   103
                item->linenum, item->trigger_count,
slouken@3647
   104
                (item->trigger_count == 1) ? "" : "s",
slouken@3647
   105
                item->always_ignore ? "yes" : "no");
slouken@3647
   106
            item = item->next;
slouken@3647
   107
        }
slouken@3647
   108
        debug_print("\n");
slouken@3647
   109
icculus@3670
   110
        SDL_ResetAssertionReport();
slouken@3647
   111
    }
slouken@3647
   112
}
slouken@3647
   113
icculus@3661
   114
static void SDL_ExitProcess(int exitcode)
slouken@3647
   115
{
slouken@5086
   116
#ifdef __WIN32__
icculus@6305
   117
    ExitProcess(exitcode);
slouken@3656
   118
#else
icculus@6305
   119
    _exit(exitcode);
slouken@3647
   120
#endif
slouken@3647
   121
}
icculus@3661
   122
icculus@3661
   123
static void SDL_AbortAssertion(void)
icculus@3661
   124
{
icculus@3661
   125
    SDL_Quit();
icculus@3661
   126
    SDL_ExitProcess(42);
icculus@3661
   127
}
icculus@3661
   128
slouken@3647
   129
icculus@3670
   130
static SDL_assert_state
icculus@3670
   131
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
slouken@3647
   132
{
icculus@6759
   133
#ifdef __WIN32__
icculus@6759
   134
    #define ENDLINE "\r\n"
icculus@6759
   135
#else
icculus@6759
   136
    #define ENDLINE "\n"
icculus@6759
   137
#endif
icculus@6759
   138
slouken@3647
   139
    const char *envr;
slouken@3657
   140
    SDL_assert_state state = SDL_ASSERTION_ABORT;
slouken@3685
   141
    SDL_Window *window;
slouken@6621
   142
    SDL_MessageBoxData messagebox;
slouken@6621
   143
    SDL_MessageBoxButtonData buttons[] = {
slouken@6621
   144
        {   0,  SDL_ASSERTION_RETRY,            "Retry" },
slouken@6621
   145
        {   0,  SDL_ASSERTION_BREAK,            "Break" },
slouken@6621
   146
        {   0,  SDL_ASSERTION_ABORT,            "Abort" },
slouken@6621
   147
        {   SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
slouken@6621
   148
                SDL_ASSERTION_IGNORE,           "Ignore" },
slouken@6621
   149
        {   SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
slouken@6621
   150
                SDL_ASSERTION_ALWAYS_IGNORE,    "Always Ignore" }
slouken@6621
   151
    };
slouken@6621
   152
    char *message;
slouken@6621
   153
    int selected;
slouken@3647
   154
icculus@3670
   155
    (void) userdata;  /* unused in default handler. */
icculus@3670
   156
slouken@6621
   157
    message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
slouken@6621
   158
    if (!message) {
slouken@6621
   159
        /* Uh oh, we're in real trouble now... */
slouken@6621
   160
        return SDL_ASSERTION_ABORT;
slouken@6621
   161
    }
slouken@6621
   162
    SDL_snprintf(message, SDL_MAX_LOG_MESSAGE,
icculus@6759
   163
                 "Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
icculus@6759
   164
                    "  '%s'",
slouken@6621
   165
                 data->function, data->filename, data->linenum,
slouken@6621
   166
                 data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
slouken@6621
   167
                 data->condition);
slouken@6621
   168
slouken@6621
   169
    debug_print("\n\n%s\n\n", message);
slouken@3647
   170
slouken@3655
   171
    /* let env. variable override, so unit tests won't block in a GUI. */
slouken@3647
   172
    envr = SDL_getenv("SDL_ASSERT");
slouken@3647
   173
    if (envr != NULL) {
slouken@6621
   174
        SDL_stack_free(message);
slouken@6621
   175
slouken@3647
   176
        if (SDL_strcmp(envr, "abort") == 0) {
slouken@3647
   177
            return SDL_ASSERTION_ABORT;
slouken@3647
   178
        } else if (SDL_strcmp(envr, "break") == 0) {
slouken@3647
   179
            return SDL_ASSERTION_BREAK;
slouken@3647
   180
        } else if (SDL_strcmp(envr, "retry") == 0) {
slouken@3647
   181
            return SDL_ASSERTION_RETRY;
slouken@3647
   182
        } else if (SDL_strcmp(envr, "ignore") == 0) {
slouken@3647
   183
            return SDL_ASSERTION_IGNORE;
slouken@3647
   184
        } else if (SDL_strcmp(envr, "always_ignore") == 0) {
slouken@3647
   185
            return SDL_ASSERTION_ALWAYS_IGNORE;
slouken@3647
   186
        } else {
slouken@3647
   187
            return SDL_ASSERTION_ABORT;  /* oh well. */
slouken@3647
   188
        }
slouken@3647
   189
    }
slouken@3647
   190
slouken@3657
   191
    /* Leave fullscreen mode, if possible (scary!) */
slouken@3657
   192
    window = SDL_GetFocusWindow();
slouken@3657
   193
    if (window) {
slouken@3657
   194
        if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
slouken@3657
   195
            SDL_MinimizeWindow(window);
slouken@3657
   196
        } else {
icculus@3670
   197
            /* !!! FIXME: ungrab the input if we're not fullscreen? */
slouken@3657
   198
            /* No need to mess with the window */
slouken@6621
   199
            window = NULL;
slouken@3657
   200
        }
slouken@3657
   201
    }
slouken@3657
   202
slouken@6621
   203
    /* Show a messagebox if we can, otherwise fall back to stdio */
slouken@6621
   204
    SDL_zero(messagebox);
slouken@6621
   205
    messagebox.flags = SDL_MESSAGEBOX_WARNING;
slouken@6621
   206
    messagebox.window = window;
slouken@6621
   207
    messagebox.title = "Assertion Failed";
slouken@6621
   208
    messagebox.message = message;
slouken@6621
   209
    messagebox.numbuttons = SDL_arraysize(buttons);
slouken@6621
   210
    messagebox.buttons = buttons;
slouken@3647
   211
slouken@6621
   212
    if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
slouken@6621
   213
        if (selected == -1) {
slouken@3657
   214
            state = SDL_ASSERTION_IGNORE;
slouken@6621
   215
        } else {
slouken@6621
   216
            state = (SDL_assert_state)selected;
slouken@3647
   217
        }
slouken@3647
   218
    }
slouken@6621
   219
#ifdef HAVE_STDIO_H
slouken@6621
   220
    else
slouken@6621
   221
    {
slouken@6621
   222
        /* this is a little hacky. */
slouken@6621
   223
        for ( ; ; ) {
slouken@6621
   224
            char buf[32];
slouken@6621
   225
            fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
slouken@6621
   226
            fflush(stderr);
slouken@6621
   227
            if (fgets(buf, sizeof (buf), stdin) == NULL) {
slouken@6621
   228
                break;
slouken@6621
   229
            }
slouken@6621
   230
slouken@6621
   231
            if (SDL_strcmp(buf, "a") == 0) {
slouken@6621
   232
                state = SDL_ASSERTION_ABORT;
slouken@6621
   233
                break;
slouken@6621
   234
            } else if (SDL_strcmp(buf, "b") == 0) {
slouken@6621
   235
                state = SDL_ASSERTION_BREAK;
slouken@6621
   236
                break;
slouken@6621
   237
            } else if (SDL_strcmp(buf, "r") == 0) {
slouken@6621
   238
                state = SDL_ASSERTION_RETRY;
slouken@6621
   239
                break;
slouken@6621
   240
            } else if (SDL_strcmp(buf, "i") == 0) {
slouken@6621
   241
                state = SDL_ASSERTION_IGNORE;
slouken@6621
   242
                break;
slouken@6621
   243
            } else if (SDL_strcmp(buf, "A") == 0) {
slouken@6621
   244
                state = SDL_ASSERTION_ALWAYS_IGNORE;
slouken@6621
   245
                break;
slouken@6621
   246
            }
slouken@6621
   247
        }
slouken@6621
   248
    }
slouken@6621
   249
#endif /* HAVE_STDIO_H */
slouken@3647
   250
slouken@3657
   251
    /* Re-enter fullscreen mode */
slouken@3657
   252
    if (window) {
slouken@3657
   253
        SDL_RestoreWindow(window);
slouken@3657
   254
    }
slouken@3657
   255
slouken@6621
   256
    SDL_stack_free(message);
slouken@6621
   257
slouken@3657
   258
    return state;
slouken@3647
   259
}
slouken@3647
   260
slouken@3647
   261
slouken@3647
   262
SDL_assert_state
slouken@3655
   263
SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
slouken@3655
   264
                    int line)
slouken@3647
   265
{
icculus@3661
   266
    static int assertion_running = 0;
icculus@3662
   267
    static SDL_SpinLock spinlock = 0;
icculus@3661
   268
    SDL_assert_state state = SDL_ASSERTION_IGNORE;
slouken@3647
   269
icculus@3662
   270
    SDL_AtomicLock(&spinlock);
icculus@3662
   271
    if (assertion_mutex == NULL) { /* never called SDL_Init()? */
icculus@3662
   272
        assertion_mutex = SDL_CreateMutex();
icculus@3662
   273
        if (assertion_mutex == NULL) {
icculus@3662
   274
            SDL_AtomicUnlock(&spinlock);
icculus@3662
   275
            return SDL_ASSERTION_IGNORE;   /* oh well, I guess. */
icculus@3662
   276
        }
icculus@3662
   277
    }
icculus@3662
   278
    SDL_AtomicUnlock(&spinlock);
icculus@3662
   279
slouken@3647
   280
    if (SDL_LockMutex(assertion_mutex) < 0) {
slouken@3647
   281
        return SDL_ASSERTION_IGNORE;   /* oh well, I guess. */
slouken@3647
   282
    }
slouken@3647
   283
slouken@3647
   284
    /* doing this because Visual C is upset over assigning in the macro. */
slouken@3647
   285
    if (data->trigger_count == 0) {
slouken@3647
   286
        data->function = func;
slouken@3655
   287
        data->filename = file;
slouken@3655
   288
        data->linenum = line;
slouken@3647
   289
    }
slouken@3647
   290
slouken@3647
   291
    SDL_AddAssertionToReport(data);
slouken@3647
   292
icculus@3661
   293
    assertion_running++;
icculus@3661
   294
    if (assertion_running > 1) {   /* assert during assert! Abort. */
icculus@3661
   295
        if (assertion_running == 2) {
icculus@3661
   296
            SDL_AbortAssertion();
icculus@3661
   297
        } else if (assertion_running == 3) {  /* Abort asserted! */
icculus@3661
   298
            SDL_ExitProcess(42);
icculus@3661
   299
        } else {
icculus@3661
   300
            while (1) { /* do nothing but spin; what else can you do?! */ }
icculus@3661
   301
        }
slouken@3647
   302
    }
slouken@3647
   303
icculus@3661
   304
    if (!data->always_ignore) {
icculus@3670
   305
        state = assertion_handler(data, assertion_userdata);
icculus@3661
   306
    }
slouken@3647
   307
slouken@3647
   308
    switch (state)
slouken@3647
   309
    {
slouken@3647
   310
        case SDL_ASSERTION_ABORT:
slouken@3647
   311
            SDL_AbortAssertion();
slouken@3647
   312
            return SDL_ASSERTION_IGNORE;  /* shouldn't return, but oh well. */
slouken@3647
   313
slouken@3647
   314
        case SDL_ASSERTION_ALWAYS_IGNORE:
slouken@3647
   315
            state = SDL_ASSERTION_IGNORE;
slouken@3647
   316
            data->always_ignore = 1;
slouken@3647
   317
            break;
slouken@3647
   318
slouken@3647
   319
        case SDL_ASSERTION_IGNORE:
slouken@3647
   320
        case SDL_ASSERTION_RETRY:
slouken@3647
   321
        case SDL_ASSERTION_BREAK:
slouken@3647
   322
            break;  /* macro handles these. */
slouken@3647
   323
    }
slouken@3647
   324
icculus@3661
   325
    assertion_running--;
slouken@3647
   326
    SDL_UnlockMutex(assertion_mutex);
slouken@3647
   327
slouken@3647
   328
    return state;
slouken@3647
   329
}
slouken@3647
   330
slouken@3647
   331
slouken@3647
   332
void SDL_AssertionsQuit(void)
slouken@3647
   333
{
slouken@3647
   334
    SDL_GenerateAssertionReport();
icculus@3664
   335
    if (assertion_mutex != NULL) {
icculus@3664
   336
        SDL_DestroyMutex(assertion_mutex);
icculus@3664
   337
        assertion_mutex = NULL;
icculus@3664
   338
    }
icculus@3670
   339
}
icculus@3670
   340
icculus@3670
   341
void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
icculus@3670
   342
{
icculus@3670
   343
    if (handler != NULL) {
icculus@3670
   344
        assertion_handler = handler;
icculus@3670
   345
        assertion_userdata = userdata;
icculus@3670
   346
    } else {
icculus@3670
   347
        assertion_handler = SDL_PromptAssertion;
icculus@3670
   348
        assertion_userdata = NULL;
icculus@3670
   349
    }
icculus@3670
   350
}
icculus@3670
   351
icculus@3670
   352
const SDL_assert_data *SDL_GetAssertionReport(void)
icculus@3670
   353
{
icculus@3670
   354
    return triggered_assertions;
icculus@3670
   355
}
icculus@3670
   356
icculus@3670
   357
void SDL_ResetAssertionReport(void)
icculus@3670
   358
{
icculus@3670
   359
    SDL_assert_data *next = NULL;
icculus@5541
   360
    SDL_assert_data *item;
icculus@5541
   361
    for (item = triggered_assertions; item != NULL; item = next) {
icculus@3670
   362
        next = (SDL_assert_data *) item->next;
icculus@3670
   363
        item->always_ignore = SDL_FALSE;
icculus@3670
   364
        item->trigger_count = 0;
icculus@3670
   365
        item->next = NULL;
icculus@3670
   366
    }
icculus@3670
   367
icculus@5541
   368
    triggered_assertions = NULL;
slouken@3647
   369
}
slouken@3647
   370
slouken@3647
   371
/* vi: set ts=4 sw=4 expandtab: */