src/SDL_error.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 30 Oct 2016 21:01:33 +0100
changeset 10563 e3d84016cb79
parent 10403 a0c76d344583
child 10643 930938c7ca82
permissions -rw-r--r--
Fixed outdated info in README.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "./SDL_internal.h"
    22 
    23 /* Simple error handling in SDL */
    24 
    25 #include "SDL_log.h"
    26 #include "SDL_error.h"
    27 #include "SDL_error_c.h"
    28 
    29 
    30 /* Routine to get the thread-specific error variable */
    31 #if SDL_THREADS_DISABLED
    32 /* The default (non-thread-safe) global error variable */
    33 static SDL_error SDL_global_error;
    34 #define SDL_GetErrBuf() (&SDL_global_error)
    35 #else
    36 extern SDL_error *SDL_GetErrBuf(void);
    37 #endif /* SDL_THREADS_DISABLED */
    38 
    39 #define SDL_ERRBUFIZE   1024
    40 
    41 /* Private functions */
    42 
    43 static const char *
    44 SDL_LookupString(const char *key)
    45 {
    46     /* FIXME: Add code to lookup key in language string hash-table */
    47     return key;
    48 }
    49 
    50 /* Public functions */
    51 
    52 int
    53 SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
    54 {
    55     va_list ap;
    56     SDL_error *error;
    57 
    58     /* Ignore call if invalid format pointer was passed */
    59     if (fmt == NULL) return -1;
    60 
    61     /* Copy in the key, mark error as valid */
    62     error = SDL_GetErrBuf();
    63     error->error = 1;
    64     SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
    65 
    66     va_start(ap, fmt);
    67     error->argc = 0;
    68     while (*fmt) {
    69         if (*fmt++ == '%') {
    70             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
    71                 ++fmt;
    72             }
    73             switch (*fmt++) {
    74             case 0:            /* Malformed format string.. */
    75                 --fmt;
    76                 break;
    77             case 'c':
    78             case 'i':
    79             case 'd':
    80             case 'u':
    81             case 'o':
    82             case 'x':
    83             case 'X':
    84                 error->args[error->argc++].value_i = va_arg(ap, int);
    85                 break;
    86             case 'f':
    87                 error->args[error->argc++].value_f = va_arg(ap, double);
    88                 break;
    89             case 'p':
    90                 error->args[error->argc++].value_ptr = va_arg(ap, void *);
    91                 break;
    92             case 's':
    93                 {
    94                     int i = error->argc;
    95                     const char *str = va_arg(ap, const char *);
    96                     if (str == NULL)
    97                         str = "(null)";
    98                     SDL_strlcpy((char *) error->args[i].buf, str,
    99                                 ERR_MAX_STRLEN);
   100                     error->argc++;
   101                 }
   102                 break;
   103             default:
   104                 break;
   105             }
   106             if (error->argc >= ERR_MAX_ARGS) {
   107                 break;
   108             }
   109         }
   110     }
   111     va_end(ap);
   112 
   113     /* If we are in debug mode, print out an error message */
   114     SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError());
   115 
   116     return -1;
   117 }
   118 
   119 #ifdef __GNUC__
   120 #pragma GCC diagnostic push
   121 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
   122 #endif
   123 /* This function has a bit more overhead than most error functions
   124    so that it supports internationalization and thread-safe errors.
   125 */
   126 static char *
   127 SDL_GetErrorMsg(char *errstr, int maxlen)
   128 {
   129     SDL_error *error;
   130 
   131     /* Clear the error string */
   132     *errstr = '\0';
   133     --maxlen;
   134 
   135     /* Get the thread-safe error, and print it out */
   136     error = SDL_GetErrBuf();
   137     if (error->error) {
   138         const char *fmt;
   139         char *msg = errstr;
   140         int len;
   141         int argi;
   142 
   143         fmt = SDL_LookupString(error->key);
   144         argi = 0;
   145         while (*fmt && (maxlen > 0)) {
   146             if (*fmt == '%') {
   147                 char tmp[32], *spot = tmp;
   148                 *spot++ = *fmt++;
   149                 while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
   150                        && spot < (tmp + SDL_arraysize(tmp) - 2)) {
   151                     *spot++ = *fmt++;
   152                 }
   153                 *spot++ = *fmt++;
   154                 *spot++ = '\0';
   155                 switch (spot[-2]) {
   156                 case '%':
   157                     *msg++ = '%';
   158                     maxlen -= 1;
   159                     break;
   160                 case 'c':
   161                 case 'i':
   162                 case 'd':
   163                 case 'u':
   164                 case 'o':
   165                 case 'x':
   166                 case 'X':
   167                     len =
   168                         SDL_snprintf(msg, maxlen, tmp,
   169                                      error->args[argi++].value_i);
   170                     if (len > 0) {
   171                         msg += len;
   172                         maxlen -= len;
   173                     }
   174                     break;
   175 
   176                 case 'f':
   177                     len =
   178                         SDL_snprintf(msg, maxlen, tmp,
   179                                      error->args[argi++].value_f);
   180                     if (len > 0) {
   181                         msg += len;
   182                         maxlen -= len;
   183                     }
   184                     break;
   185 
   186                 case 'p':
   187                     len =
   188                         SDL_snprintf(msg, maxlen, tmp,
   189                                      error->args[argi++].value_ptr);
   190                     if (len > 0) {
   191                         msg += len;
   192                         maxlen -= len;
   193                     }
   194                     break;
   195 
   196                 case 's':
   197                     len =
   198                         SDL_snprintf(msg, maxlen, tmp,
   199                                      SDL_LookupString(error->args[argi++].
   200                                                       buf));
   201                     if (len > 0) {
   202                         msg += len;
   203                         maxlen -= len;
   204                     }
   205                     break;
   206 
   207                 }
   208             } else {
   209                 *msg++ = *fmt++;
   210                 maxlen -= 1;
   211             }
   212         }
   213 
   214         /* slide back if we've overshot the end of our buffer. */
   215         if (maxlen < 0) {
   216             msg -= (-maxlen) + 1;
   217         }
   218 
   219         *msg = 0;               /* NULL terminate the string */
   220     }
   221     return (errstr);
   222 }
   223 #ifdef __GNUC__
   224 #pragma GCC diagnostic pop
   225 #endif
   226 
   227 /* Available for backwards compatibility */
   228 const char *
   229 SDL_GetError(void)
   230 {
   231     static char errmsg[SDL_ERRBUFIZE];
   232 
   233     return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
   234 }
   235 
   236 void
   237 SDL_ClearError(void)
   238 {
   239     SDL_error *error;
   240 
   241     error = SDL_GetErrBuf();
   242     error->error = 0;
   243 }
   244 
   245 /* Very common errors go here */
   246 int
   247 SDL_Error(SDL_errorcode code)
   248 {
   249     switch (code) {
   250     case SDL_ENOMEM:
   251         return SDL_SetError("Out of memory");
   252     case SDL_EFREAD:
   253         return SDL_SetError("Error reading from datastream");
   254     case SDL_EFWRITE:
   255         return SDL_SetError("Error writing to datastream");
   256     case SDL_EFSEEK:
   257         return SDL_SetError("Error seeking in datastream");
   258     case SDL_UNSUPPORTED:
   259         return SDL_SetError("That operation is not supported");
   260     default:
   261         return SDL_SetError("Unknown SDL error");
   262     }
   263 }
   264 
   265 #ifdef TEST_ERROR
   266 int
   267 main(int argc, char *argv[])
   268 {
   269     char buffer[BUFSIZ + 1];
   270 
   271     SDL_SetError("Hi there!");
   272     printf("Error 1: %s\n", SDL_GetError());
   273     SDL_ClearError();
   274     SDL_memset(buffer, '1', BUFSIZ);
   275     buffer[BUFSIZ] = 0;
   276     SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
   277     printf("Error 2: %s\n", SDL_GetError());
   278     exit(0);
   279 }
   280 #endif
   281 
   282 /* vi: set ts=4 sw=4 expandtab: */