src/SDL_error.c
author Sam Lantinga
Mon, 09 Jan 2017 11:58:01 -0800
changeset 10802 6afc9b833867
parent 10737 3406a0f8b041
child 11137 15f027d062f8
permissions -rw-r--r--
We only need the first few keymaps corresponding to the following constants:
K_NORMTAB, K_SHIFTTAB, K_ALTTAB, K_ALTSHIFTTAB

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