src/SDL_error.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5262 b530ef003506
child 5766 8cc2ae74cd83
permissions -rw-r--r--
SDL 1.3 is now under the zlib license.
     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     /* Copy in the key, mark error as valid */
    59     error = SDL_GetErrBuf();
    60     error->error = 1;
    61     SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
    62 
    63     va_start(ap, fmt);
    64     error->argc = 0;
    65     while (*fmt) {
    66         if (*fmt++ == '%') {
    67             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
    68                 ++fmt;
    69             }
    70             switch (*fmt++) {
    71             case 0:            /* Malformed format string.. */
    72                 --fmt;
    73                 break;
    74             case 'c':
    75             case 'i':
    76             case 'd':
    77             case 'u':
    78             case 'o':
    79             case 'x':
    80             case 'X':
    81                 error->args[error->argc++].value_i = va_arg(ap, int);
    82                 break;
    83             case 'f':
    84                 error->args[error->argc++].value_f = va_arg(ap, double);
    85                 break;
    86             case 'p':
    87                 error->args[error->argc++].value_ptr = va_arg(ap, void *);
    88                 break;
    89             case 's':
    90                 {
    91                     int i = error->argc;
    92                     const char *str = va_arg(ap, const char *);
    93                     if (str == NULL)
    94                         str = "(null)";
    95                     SDL_strlcpy((char *) error->args[i].buf, str,
    96                                 ERR_MAX_STRLEN);
    97                     error->argc++;
    98                 }
    99                 break;
   100             default:
   101                 break;
   102             }
   103             if (error->argc >= ERR_MAX_ARGS) {
   104                 break;
   105             }
   106         }
   107     }
   108     va_end(ap);
   109 
   110     /* If we are in debug mode, print out an error message */
   111     SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError());
   112 }
   113 
   114 /* This function has a bit more overhead than most error functions
   115    so that it supports internationalization and thread-safe errors.
   116 */
   117 static char *
   118 SDL_GetErrorMsg(char *errstr, unsigned int maxlen)
   119 {
   120     SDL_error *error;
   121 
   122     /* Clear the error string */
   123     *errstr = '\0';
   124     --maxlen;
   125 
   126     /* Get the thread-safe error, and print it out */
   127     error = SDL_GetErrBuf();
   128     if (error->error) {
   129         const char *fmt;
   130         char *msg = errstr;
   131         int len;
   132         int argi;
   133 
   134         fmt = SDL_LookupString(error->key);
   135         argi = 0;
   136         while (*fmt && (maxlen > 0)) {
   137             if (*fmt == '%') {
   138                 char tmp[32], *spot = tmp;
   139                 *spot++ = *fmt++;
   140                 while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
   141                        && spot < (tmp + SDL_arraysize(tmp) - 2)) {
   142                     *spot++ = *fmt++;
   143                 }
   144                 *spot++ = *fmt++;
   145                 *spot++ = '\0';
   146                 switch (spot[-2]) {
   147                 case '%':
   148                     *msg++ = '%';
   149                     maxlen -= 1;
   150                     break;
   151                 case 'c':
   152                 case 'i':
   153                 case 'd':
   154                 case 'u':
   155                 case 'o':
   156                 case 'x':
   157                 case 'X':
   158                     len =
   159                         SDL_snprintf(msg, maxlen, tmp,
   160                                      error->args[argi++].value_i);
   161                     msg += len;
   162                     maxlen -= len;
   163                     break;
   164                 case 'f':
   165                     len =
   166                         SDL_snprintf(msg, maxlen, tmp,
   167                                      error->args[argi++].value_f);
   168                     msg += len;
   169                     maxlen -= len;
   170                     break;
   171                 case 'p':
   172                     len =
   173                         SDL_snprintf(msg, maxlen, tmp,
   174                                      error->args[argi++].value_ptr);
   175                     msg += len;
   176                     maxlen -= len;
   177                     break;
   178                 case 's':
   179                     len =
   180                         SDL_snprintf(msg, maxlen, tmp,
   181                                      SDL_LookupString(error->args[argi++].
   182                                                       buf));
   183                     msg += len;
   184                     maxlen -= len;
   185                     break;
   186                 }
   187             } else {
   188                 *msg++ = *fmt++;
   189                 maxlen -= 1;
   190             }
   191         }
   192         *msg = 0;               /* NULL terminate the string */
   193     }
   194     return (errstr);
   195 }
   196 
   197 /* Available for backwards compatibility */
   198 const char *
   199 SDL_GetError(void)
   200 {
   201     static char errmsg[SDL_ERRBUFIZE];
   202 
   203     return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
   204 }
   205 
   206 void
   207 SDL_ClearError(void)
   208 {
   209     SDL_error *error;
   210 
   211     error = SDL_GetErrBuf();
   212     error->error = 0;
   213 }
   214 
   215 /* Very common errors go here */
   216 void
   217 SDL_Error(SDL_errorcode code)
   218 {
   219     switch (code) {
   220     case SDL_ENOMEM:
   221         SDL_SetError("Out of memory");
   222         break;
   223     case SDL_EFREAD:
   224         SDL_SetError("Error reading from datastream");
   225         break;
   226     case SDL_EFWRITE:
   227         SDL_SetError("Error writing to datastream");
   228         break;
   229     case SDL_EFSEEK:
   230         SDL_SetError("Error seeking in datastream");
   231         break;
   232     case SDL_UNSUPPORTED:
   233         SDL_SetError("That operation is not supported");
   234         break;
   235     default:
   236         SDL_SetError("Unknown SDL error");
   237         break;
   238     }
   239 }
   240 
   241 #ifdef TEST_ERROR
   242 int
   243 main(int argc, char *argv[])
   244 {
   245     char buffer[BUFSIZ + 1];
   246 
   247     SDL_SetError("Hi there!");
   248     printf("Error 1: %s\n", SDL_GetError());
   249     SDL_ClearError();
   250     SDL_memset(buffer, '1', BUFSIZ);
   251     buffer[BUFSIZ] = 0;
   252     SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
   253     printf("Error 2: %s\n", SDL_GetError());
   254     exit(0);
   255 }
   256 #endif
   257 
   258 /* vi: set ts=4 sw=4 expandtab: */