src/SDL_error.c
author Ozkan Sezer
Thu, 21 Nov 2019 11:50:50 +0300
changeset 13267 a8e016c00f2e
parent 13209 f872396dcc58
child 13422 fd6a12de91c7
permissions -rw-r--r--
ran gendynapi.pl after newly added SDL_string.c functions.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 #define SDL_ERRBUFIZE   1024
    30 
    31 /* Private functions */
    32 
    33 static const char *
    34 SDL_LookupString(const char *key)
    35 {
    36     /* FIXME: Add code to lookup key in language string hash-table */
    37     return key;
    38 }
    39 
    40 /* Public functions */
    41 
    42 static char *SDL_GetErrorMsg(char *errstr, int maxlen);
    43 
    44 int
    45 SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
    46 {
    47     va_list ap;
    48     SDL_error *error;
    49 
    50     /* Ignore call if invalid format pointer was passed */
    51     if (fmt == NULL) return -1;
    52 
    53     /* Copy in the key, mark error as valid */
    54     error = SDL_GetErrBuf();
    55     error->error = 1;
    56     SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
    57 
    58     va_start(ap, fmt);
    59     error->argc = 0;
    60     while (*fmt) {
    61         if (*fmt++ == '%') {
    62             while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
    63                 ++fmt;
    64             }
    65             switch (*fmt++) {
    66             case 0:            /* Malformed format string.. */
    67                 --fmt;
    68                 break;
    69             case 'l':
    70                 switch (*fmt++) {
    71                 case 0:        /* Malformed format string.. */
    72                     --fmt;
    73                     break;
    74                 case 'i': case 'd': case 'u': case 'x': case 'X':
    75                     error->args[error->argc++].value_l = va_arg(ap, long);
    76                     break;
    77                 }
    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                 if (*fmt == 'l') {
   223                     *spot++ = *fmt++;
   224                     *spot++ = *fmt++;
   225                     *spot++ = '\0';
   226                     switch (spot[-2]) {
   227                     case 'i': case 'd': case 'u': case 'x': case 'X':
   228                       len = SDL_snprintf(msg, maxlen, tmp,
   229                                          error->args[argi++].value_l);
   230                       if (len > 0) {
   231                           msg += len;
   232                           maxlen -= len;
   233                       }
   234                       break;
   235                     }
   236                     continue;
   237                 }
   238                 *spot++ = *fmt++;
   239                 *spot++ = '\0';
   240                 switch (spot[-2]) {
   241                 case '%':
   242                     *msg++ = '%';
   243                     maxlen -= 1;
   244                     break;
   245                 case 'c':
   246                 case 'i':
   247                 case 'd':
   248                 case 'u':
   249                 case 'o':
   250                 case 'x':
   251                 case 'X':
   252                     len =
   253                         SDL_snprintf(msg, maxlen, tmp,
   254                                      error->args[argi++].value_i);
   255                     if (len > 0) {
   256                         msg += len;
   257                         maxlen -= len;
   258                     }
   259                     break;
   260 
   261                 case 'f':
   262                     len =
   263                         SDL_snprintf(msg, maxlen, tmp,
   264                                      error->args[argi++].value_f);
   265                     if (len > 0) {
   266                         msg += len;
   267                         maxlen -= len;
   268                     }
   269                     break;
   270 
   271                 case 'p':
   272                     len =
   273                         SDL_snprintf(msg, maxlen, tmp,
   274                                      error->args[argi++].value_ptr);
   275                     if (len > 0) {
   276                         msg += len;
   277                         maxlen -= len;
   278                     }
   279                     break;
   280 
   281                 case 's':
   282                     len =
   283                         SDL_snprintf(msg, maxlen, tmp,
   284                                      SDL_LookupString(error->args[argi++].
   285                                                       buf));
   286                     if (len > 0) {
   287                         msg += len;
   288                         maxlen -= len;
   289                     }
   290                     break;
   291 
   292                 }
   293             } else {
   294                 *msg++ = *fmt++;
   295                 maxlen -= 1;
   296             }
   297         }
   298 
   299         /* slide back if we've overshot the end of our buffer. */
   300         if (maxlen < 0) {
   301             msg -= (-maxlen) + 1;
   302         }
   303 
   304         *msg = 0;               /* NULL terminate the string */
   305     }
   306     return (errstr);
   307 }
   308 
   309 /* vi: set ts=4 sw=4 expandtab: */