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