src/SDL_error.c
author Ryan C. Gordon
Tue, 07 Apr 2020 14:03:13 -0400
changeset 13704 25edf3df6e51
parent 13696 ea20a7434b98
child 13772 6a1ff60e03fb
permissions -rw-r--r--
emscripten: support KaiOS's Left Soft Key and Right Soft Key (thanks, pelya!).

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