src/SDL_error.c
author Andreas Schiffler <aschiffler@ferzkopp.net>
Sun, 17 Jul 2011 20:59:34 -0700
changeset 5766 8cc2ae74cd83
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Fixed SDL_SetError() by making NULL fmt a no-op, update test automation
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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_config.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 void
    53 SDL_SetError(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;
    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_LogError(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError());
   115 }
   116 
   117 /* This function has a bit more overhead than most error functions
   118    so that it supports internationalization and thread-safe errors.
   119 */
   120 static char *
   121 SDL_GetErrorMsg(char *errstr, unsigned int maxlen)
   122 {
   123     SDL_error *error;
   124 
   125     /* Clear the error string */
   126     *errstr = '\0';
   127     --maxlen;
   128 
   129     /* Get the thread-safe error, and print it out */
   130     error = SDL_GetErrBuf();
   131     if (error->error) {
   132         const char *fmt;
   133         char *msg = errstr;
   134         int len;
   135         int argi;
   136 
   137         fmt = SDL_LookupString(error->key);
   138         argi = 0;
   139         while (*fmt && (maxlen > 0)) {
   140             if (*fmt == '%') {
   141                 char tmp[32], *spot = tmp;
   142                 *spot++ = *fmt++;
   143                 while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
   144                        && spot < (tmp + SDL_arraysize(tmp) - 2)) {
   145                     *spot++ = *fmt++;
   146                 }
   147                 *spot++ = *fmt++;
   148                 *spot++ = '\0';
   149                 switch (spot[-2]) {
   150                 case '%':
   151                     *msg++ = '%';
   152                     maxlen -= 1;
   153                     break;
   154                 case 'c':
   155                 case 'i':
   156                 case 'd':
   157                 case 'u':
   158                 case 'o':
   159                 case 'x':
   160                 case 'X':
   161                     len =
   162                         SDL_snprintf(msg, maxlen, tmp,
   163                                      error->args[argi++].value_i);
   164                     msg += len;
   165                     maxlen -= len;
   166                     break;
   167                 case 'f':
   168                     len =
   169                         SDL_snprintf(msg, maxlen, tmp,
   170                                      error->args[argi++].value_f);
   171                     msg += len;
   172                     maxlen -= len;
   173                     break;
   174                 case 'p':
   175                     len =
   176                         SDL_snprintf(msg, maxlen, tmp,
   177                                      error->args[argi++].value_ptr);
   178                     msg += len;
   179                     maxlen -= len;
   180                     break;
   181                 case 's':
   182                     len =
   183                         SDL_snprintf(msg, maxlen, tmp,
   184                                      SDL_LookupString(error->args[argi++].
   185                                                       buf));
   186                     msg += len;
   187                     maxlen -= len;
   188                     break;
   189                 }
   190             } else {
   191                 *msg++ = *fmt++;
   192                 maxlen -= 1;
   193             }
   194         }
   195         *msg = 0;               /* NULL terminate the string */
   196     }
   197     return (errstr);
   198 }
   199 
   200 /* Available for backwards compatibility */
   201 const char *
   202 SDL_GetError(void)
   203 {
   204     static char errmsg[SDL_ERRBUFIZE];
   205 
   206     return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
   207 }
   208 
   209 void
   210 SDL_ClearError(void)
   211 {
   212     SDL_error *error;
   213 
   214     error = SDL_GetErrBuf();
   215     error->error = 0;
   216 }
   217 
   218 /* Very common errors go here */
   219 void
   220 SDL_Error(SDL_errorcode code)
   221 {
   222     switch (code) {
   223     case SDL_ENOMEM:
   224         SDL_SetError("Out of memory");
   225         break;
   226     case SDL_EFREAD:
   227         SDL_SetError("Error reading from datastream");
   228         break;
   229     case SDL_EFWRITE:
   230         SDL_SetError("Error writing to datastream");
   231         break;
   232     case SDL_EFSEEK:
   233         SDL_SetError("Error seeking in datastream");
   234         break;
   235     case SDL_UNSUPPORTED:
   236         SDL_SetError("That operation is not supported");
   237         break;
   238     default:
   239         SDL_SetError("Unknown SDL error");
   240         break;
   241     }
   242 }
   243 
   244 #ifdef TEST_ERROR
   245 int
   246 main(int argc, char *argv[])
   247 {
   248     char buffer[BUFSIZ + 1];
   249 
   250     SDL_SetError("Hi there!");
   251     printf("Error 1: %s\n", SDL_GetError());
   252     SDL_ClearError();
   253     SDL_memset(buffer, '1', BUFSIZ);
   254     buffer[BUFSIZ] = 0;
   255     SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
   256     printf("Error 2: %s\n", SDL_GetError());
   257     exit(0);
   258 }
   259 #endif
   260 
   261 /* vi: set ts=4 sw=4 expandtab: */