src/SDL_error.c
author Ryan C. Gordon
Mon, 01 Jan 2018 19:16:51 -0500
changeset 11803 454f6dc9cb85
parent 11137 15f027d062f8
child 11811 5d94cb6b24d3
permissions -rw-r--r--
windows: Remove references to GetVersionExA (thanks, Andrew Pilley!).

"GetVersionExA is deprecated in windows 8.1 and above's SDK, causing a warning
when building against the win10 SDK. Attached patch cleans up the usage for a
warning-free build.

GetVersionExA was being used to test to see if SDL was running on win9x or
winnt. A quick chat with Ryan on twitter suggested that SDL doesn't
officially support win9x anymore, so the call to this can be outright removed.

As an aside, replacing the call to GetVersionExA with VerifyVersionInfoA (the
recommended path) would have been pointless, as VerifyVersionInfoA only
supports VER_PLATFORM_WIN32_NT and doesn't officially support any other value
for dwPlatformId currently. (And it's probable that win9x SDKs didn't have
VerifyVersionInfo* in them anyway.)"

Fixes Bugzilla #4019.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@0
     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@0
     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@0
    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@0
    20
*/
icculus@8093
    21
#include "./SDL_internal.h"
slouken@0
    22
slouken@0
    23
/* Simple error handling in SDL */
slouken@0
    24
slouken@5221
    25
#include "SDL_log.h"
slouken@0
    26
#include "SDL_error.h"
slouken@0
    27
#include "SDL_error_c.h"
slouken@0
    28
slouken@4618
    29
slouken@1361
    30
/* Routine to get the thread-specific error variable */
slouken@1361
    31
#if SDL_THREADS_DISABLED
slouken@4627
    32
/* The default (non-thread-safe) global error variable */
slouken@0
    33
static SDL_error SDL_global_error;
slouken@7191
    34
#define SDL_GetErrBuf() (&SDL_global_error)
slouken@1361
    35
#else
slouken@1361
    36
extern SDL_error *SDL_GetErrBuf(void);
slouken@1361
    37
#endif /* SDL_THREADS_DISABLED */
slouken@0
    38
slouken@7191
    39
#define SDL_ERRBUFIZE   1024
slouken@0
    40
slouken@0
    41
/* Private functions */
slouken@0
    42
slouken@1895
    43
static const char *
slouken@1895
    44
SDL_LookupString(const char *key)
slouken@0
    45
{
slouken@1895
    46
    /* FIXME: Add code to lookup key in language string hash-table */
slouken@1895
    47
    return key;
slouken@0
    48
}
slouken@0
    49
slouken@0
    50
/* Public functions */
slouken@0
    51
slouken@11137
    52
static char *SDL_GetErrorMsg(char *errstr, int maxlen);
slouken@11137
    53
icculus@7037
    54
int
slouken@8820
    55
SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
slouken@0
    56
{
slouken@1895
    57
    va_list ap;
slouken@1895
    58
    SDL_error *error;
slouken@0
    59
aschiffler@5766
    60
    /* Ignore call if invalid format pointer was passed */
icculus@7037
    61
    if (fmt == NULL) return -1;
slouken@7191
    62
slouken@1895
    63
    /* Copy in the key, mark error as valid */
slouken@1895
    64
    error = SDL_GetErrBuf();
slouken@1895
    65
    error->error = 1;
slouken@1895
    66
    SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
slouken@0
    67
slouken@1895
    68
    va_start(ap, fmt);
slouken@1895
    69
    error->argc = 0;
slouken@1895
    70
    while (*fmt) {
slouken@1895
    71
        if (*fmt++ == '%') {
slouken@1895
    72
            while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
slouken@1895
    73
                ++fmt;
slouken@1895
    74
            }
slouken@1895
    75
            switch (*fmt++) {
slouken@1895
    76
            case 0:            /* Malformed format string.. */
slouken@1895
    77
                --fmt;
slouken@1895
    78
                break;
slouken@1895
    79
            case 'c':
slouken@1895
    80
            case 'i':
slouken@1895
    81
            case 'd':
slouken@1895
    82
            case 'u':
slouken@1895
    83
            case 'o':
slouken@1895
    84
            case 'x':
slouken@1895
    85
            case 'X':
slouken@1895
    86
                error->args[error->argc++].value_i = va_arg(ap, int);
slouken@1895
    87
                break;
slouken@1895
    88
            case 'f':
slouken@1895
    89
                error->args[error->argc++].value_f = va_arg(ap, double);
slouken@1895
    90
                break;
slouken@1895
    91
            case 'p':
slouken@1895
    92
                error->args[error->argc++].value_ptr = va_arg(ap, void *);
slouken@1895
    93
                break;
slouken@1895
    94
            case 's':
slouken@1895
    95
                {
slouken@1895
    96
                    int i = error->argc;
slouken@1895
    97
                    const char *str = va_arg(ap, const char *);
slouken@1895
    98
                    if (str == NULL)
slouken@1895
    99
                        str = "(null)";
slouken@1895
   100
                    SDL_strlcpy((char *) error->args[i].buf, str,
slouken@1895
   101
                                ERR_MAX_STRLEN);
slouken@1895
   102
                    error->argc++;
slouken@1895
   103
                }
slouken@1895
   104
                break;
slouken@1895
   105
            default:
slouken@1895
   106
                break;
slouken@1895
   107
            }
slouken@1895
   108
            if (error->argc >= ERR_MAX_ARGS) {
slouken@1895
   109
                break;
slouken@1895
   110
            }
slouken@1895
   111
        }
slouken@1895
   112
    }
slouken@1895
   113
    va_end(ap);
slouken@0
   114
slouken@11137
   115
    if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
slouken@11137
   116
        /* If we are in debug mode, print out an error message
slouken@11137
   117
         * Avoid stomping on the static buffer in GetError, just
slouken@11137
   118
         * in case this is called while processing a ShowMessageBox to
slouken@11137
   119
         * show an error already in that static buffer.
slouken@11137
   120
         */
slouken@11137
   121
        char errmsg[SDL_ERRBUFIZE];
slouken@11137
   122
        SDL_GetErrorMsg(errmsg, sizeof(errmsg));
slouken@11137
   123
        SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", errmsg);
slouken@11137
   124
    }
icculus@7037
   125
    return -1;
slouken@0
   126
}
slouken@0
   127
icculus@10643
   128
/* Available for backwards compatibility */
icculus@10643
   129
const char *
icculus@10643
   130
SDL_GetError(void)
icculus@10643
   131
{
icculus@10643
   132
    static char errmsg[SDL_ERRBUFIZE];
icculus@10643
   133
icculus@10643
   134
    return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
icculus@10643
   135
}
icculus@10643
   136
icculus@10643
   137
void
icculus@10643
   138
SDL_ClearError(void)
icculus@10643
   139
{
icculus@10643
   140
    SDL_error *error;
icculus@10643
   141
icculus@10643
   142
    error = SDL_GetErrBuf();
icculus@10643
   143
    error->error = 0;
icculus@10643
   144
}
icculus@10643
   145
icculus@10643
   146
/* Very common errors go here */
icculus@10643
   147
int
icculus@10643
   148
SDL_Error(SDL_errorcode code)
icculus@10643
   149
{
icculus@10643
   150
    switch (code) {
icculus@10643
   151
    case SDL_ENOMEM:
icculus@10643
   152
        return SDL_SetError("Out of memory");
icculus@10643
   153
    case SDL_EFREAD:
icculus@10643
   154
        return SDL_SetError("Error reading from datastream");
icculus@10643
   155
    case SDL_EFWRITE:
icculus@10643
   156
        return SDL_SetError("Error writing to datastream");
icculus@10643
   157
    case SDL_EFSEEK:
icculus@10643
   158
        return SDL_SetError("Error seeking in datastream");
icculus@10643
   159
    case SDL_UNSUPPORTED:
icculus@10643
   160
        return SDL_SetError("That operation is not supported");
icculus@10643
   161
    default:
icculus@10643
   162
        return SDL_SetError("Unknown SDL error");
icculus@10643
   163
    }
icculus@10643
   164
}
icculus@10643
   165
icculus@10643
   166
#ifdef TEST_ERROR
icculus@10643
   167
int
icculus@10643
   168
main(int argc, char *argv[])
icculus@10643
   169
{
icculus@10643
   170
    char buffer[BUFSIZ + 1];
icculus@10643
   171
icculus@10643
   172
    SDL_SetError("Hi there!");
icculus@10643
   173
    printf("Error 1: %s\n", SDL_GetError());
icculus@10643
   174
    SDL_ClearError();
icculus@10643
   175
    SDL_memset(buffer, '1', BUFSIZ);
icculus@10643
   176
    buffer[BUFSIZ] = 0;
icculus@10643
   177
    SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
icculus@10643
   178
    printf("Error 2: %s\n", SDL_GetError());
icculus@10643
   179
    exit(0);
icculus@10643
   180
}
icculus@10643
   181
#endif
icculus@10643
   182
icculus@10643
   183
icculus@10643
   184
/* keep this at the end of the file so it works with GCC builds that don't
icculus@10643
   185
   support "#pragma GCC diagnostic push" ... we'll just leave the warning
icculus@10643
   186
   disabled after this. */
icculus@10644
   187
/* this pragma arrived in GCC 4.2 and causes a warning on older GCCs! Sigh. */
icculus@10644
   188
#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 2))))
hadess@10396
   189
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
slouken@10403
   190
#endif
icculus@10644
   191
slouken@0
   192
/* This function has a bit more overhead than most error functions
slouken@0
   193
   so that it supports internationalization and thread-safe errors.
slouken@0
   194
*/
slouken@4472
   195
static char *
icculus@9430
   196
SDL_GetErrorMsg(char *errstr, int maxlen)
slouken@0
   197
{
slouken@1895
   198
    SDL_error *error;
slouken@0
   199
slouken@1895
   200
    /* Clear the error string */
slouken@1895
   201
    *errstr = '\0';
slouken@1895
   202
    --maxlen;
slouken@1895
   203
slouken@1895
   204
    /* Get the thread-safe error, and print it out */
slouken@1895
   205
    error = SDL_GetErrBuf();
slouken@1895
   206
    if (error->error) {
slouken@1895
   207
        const char *fmt;
slouken@1895
   208
        char *msg = errstr;
slouken@1895
   209
        int len;
slouken@1895
   210
        int argi;
slouken@0
   211
slouken@1895
   212
        fmt = SDL_LookupString(error->key);
slouken@1895
   213
        argi = 0;
slouken@1895
   214
        while (*fmt && (maxlen > 0)) {
slouken@1895
   215
            if (*fmt == '%') {
slouken@1895
   216
                char tmp[32], *spot = tmp;
slouken@1895
   217
                *spot++ = *fmt++;
slouken@1895
   218
                while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
slouken@1895
   219
                       && spot < (tmp + SDL_arraysize(tmp) - 2)) {
slouken@1895
   220
                    *spot++ = *fmt++;
slouken@1895
   221
                }
slouken@1895
   222
                *spot++ = *fmt++;
slouken@1895
   223
                *spot++ = '\0';
slouken@1895
   224
                switch (spot[-2]) {
slouken@1895
   225
                case '%':
slouken@1895
   226
                    *msg++ = '%';
slouken@1895
   227
                    maxlen -= 1;
slouken@1895
   228
                    break;
slouken@1895
   229
                case 'c':
slouken@1895
   230
                case 'i':
slouken@1895
   231
                case 'd':
slouken@1895
   232
                case 'u':
slouken@1895
   233
                case 'o':
slouken@1895
   234
                case 'x':
slouken@1895
   235
                case 'X':
slouken@1895
   236
                    len =
slouken@1895
   237
                        SDL_snprintf(msg, maxlen, tmp,
slouken@1895
   238
                                     error->args[argi++].value_i);
icculus@9430
   239
                    if (len > 0) {
icculus@9430
   240
                        msg += len;
icculus@9430
   241
                        maxlen -= len;
icculus@9430
   242
                    }
slouken@1895
   243
                    break;
icculus@9430
   244
slouken@1895
   245
                case 'f':
slouken@1895
   246
                    len =
slouken@1895
   247
                        SDL_snprintf(msg, maxlen, tmp,
slouken@1895
   248
                                     error->args[argi++].value_f);
icculus@9430
   249
                    if (len > 0) {
icculus@9430
   250
                        msg += len;
icculus@9430
   251
                        maxlen -= len;
icculus@9430
   252
                    }
slouken@1895
   253
                    break;
icculus@9430
   254
slouken@1895
   255
                case 'p':
slouken@1895
   256
                    len =
slouken@1895
   257
                        SDL_snprintf(msg, maxlen, tmp,
slouken@1895
   258
                                     error->args[argi++].value_ptr);
icculus@9430
   259
                    if (len > 0) {
icculus@9430
   260
                        msg += len;
icculus@9430
   261
                        maxlen -= len;
icculus@9430
   262
                    }
slouken@1895
   263
                    break;
icculus@9430
   264
slouken@1895
   265
                case 's':
slouken@1895
   266
                    len =
slouken@1895
   267
                        SDL_snprintf(msg, maxlen, tmp,
slouken@3013
   268
                                     SDL_LookupString(error->args[argi++].
slouken@3013
   269
                                                      buf));
icculus@9430
   270
                    if (len > 0) {
icculus@9430
   271
                        msg += len;
icculus@9430
   272
                        maxlen -= len;
icculus@9430
   273
                    }
slouken@1895
   274
                    break;
icculus@9430
   275
slouken@1895
   276
                }
slouken@1895
   277
            } else {
slouken@1895
   278
                *msg++ = *fmt++;
slouken@1895
   279
                maxlen -= 1;
slouken@1895
   280
            }
slouken@1895
   281
        }
icculus@9430
   282
icculus@9430
   283
        /* slide back if we've overshot the end of our buffer. */
icculus@9430
   284
        if (maxlen < 0) {
icculus@9430
   285
            msg -= (-maxlen) + 1;
icculus@9430
   286
        }
icculus@9430
   287
slouken@1895
   288
        *msg = 0;               /* NULL terminate the string */
slouken@1895
   289
    }
slouken@1895
   290
    return (errstr);
slouken@0
   291
}
slouken@4992
   292
slouken@1895
   293
/* vi: set ts=4 sw=4 expandtab: */