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