src/SDL_error.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 10 Feb 2006 06:48:43 +0000
changeset 1358 c71e05b4dc2e
parent 1338 604d73db6802
child 1361 19418e4422cb
permissions -rw-r--r--
More header massaging... works great on Windows. ;-)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 /* Simple error handling in SDL */
    24 
    25 #include "SDL_error.h"
    26 #include "SDL_error_c.h"
    27 #ifndef DISABLE_THREADS
    28 #include "SDL_thread_c.h"
    29 #endif
    30 
    31 #ifdef DISABLE_THREADS
    32 /* The default (non-thread-safe) global error variable */
    33 static SDL_error SDL_global_error;
    34 
    35 #define SDL_GetErrBuf()	(&SDL_global_error)
    36 #endif /* DISABLE_THREADS */
    37 
    38 #define SDL_ERRBUFIZE	1024
    39 
    40 /* Private functions */
    41 
    42 static void SDL_LookupString(const Uint8 *key, Uint16 *buf, int buflen)
    43 {
    44 	/* FIXME: Add code to lookup key in language string hash-table */
    45 
    46 	/* Key not found in language string hash-table */
    47 	while ( *key && (--buflen > 0) ) {
    48 		*buf++ = *key++;
    49 	}
    50 	*buf = 0;	/* NULL terminate string */
    51 }
    52 
    53 /* Public functions */
    54 
    55 void SDL_SetError (const char *fmt, ...)
    56 {
    57 	va_list ap;
    58 	SDL_error *error;
    59 
    60 	/* Copy in the key, mark error as valid */
    61 	error = SDL_GetErrBuf();
    62 	error->error = 1;
    63 	SDL_strncpy((char *)error->key, fmt, sizeof(error->key));
    64 	error->key[sizeof(error->key)-1] = '\0';
    65 
    66 	va_start(ap, fmt);
    67 	error->argc = 0;
    68 	while ( *fmt ) {
    69 		if ( *fmt++ == '%' ) {
    70 			switch (*fmt++) {
    71 			    case 0:  /* Malformed format string.. */
    72 				--fmt;
    73 				break;
    74 #if 0	/* What is a character anyway?  (UNICODE issues) */
    75 			    case 'c':
    76 				error->args[error->argc++].value_c =
    77 						va_arg(ap, unsigned char);
    78 				break;
    79 #endif
    80 			    case 'd':
    81 				error->args[error->argc++].value_i =
    82 							va_arg(ap, int);
    83 				break;
    84 			    case 'f':
    85 				error->args[error->argc++].value_f =
    86 							va_arg(ap, double);
    87 				break;
    88 			    case 'p':
    89 				error->args[error->argc++].value_ptr =
    90 							va_arg(ap, void *);
    91 				break;
    92 			    case 's':
    93 				{
    94 				  int index = error->argc;
    95 				  char *str = va_arg(ap, char *);
    96 				  if (str == NULL)
    97 				      str = "(null)";
    98 				  SDL_strncpy((char *)error->args[index].buf, str, ERR_MAX_STRLEN);
    99 				  error->args[index].buf[ERR_MAX_STRLEN-1] = 0;
   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 #ifdef DEBUG_ERROR
   115 	fprintf(stderr, "SDL_SetError: %s\n", SDL_GetError());
   116 #endif
   117 }
   118 
   119 /* Print out an integer value to a UNICODE buffer */
   120 static int PrintInt(Uint16 *str, unsigned int maxlen, int value)
   121 {
   122 	char tmp[128];
   123 	int len, i;
   124 
   125 	SDL_snprintf(tmp, SDL_arraysize(tmp), "%d", value);
   126 	len = 0;
   127 	if ( SDL_strlen(tmp) < maxlen ) {
   128 		for ( i=0; tmp[i]; ++i ) {
   129 			*str++ = tmp[i];
   130 			++len;
   131 		}
   132 	}
   133 	return(len);
   134 }
   135 /* Print out a double value to a UNICODE buffer */
   136 static int PrintDouble(Uint16 *str, unsigned int maxlen, double value)
   137 {
   138 	char tmp[128];
   139 	int len, i;
   140 
   141 	SDL_snprintf(tmp, SDL_arraysize(tmp), "%f", value);
   142 	len = 0;
   143 	if ( SDL_strlen(tmp) < maxlen ) {
   144 		for ( i=0; tmp[i]; ++i ) {
   145 			*str++ = tmp[i];
   146 			++len;
   147 		}
   148 	}
   149 	return(len);
   150 }
   151 /* Print out a pointer value to a UNICODE buffer */
   152 static int PrintPointer(Uint16 *str, unsigned int maxlen, void *value)
   153 {
   154 	char tmp[128];
   155 	int len, i;
   156 
   157 	SDL_snprintf(tmp, SDL_arraysize(tmp), "%p", value);
   158 	len = 0;
   159 	if ( SDL_strlen(tmp) < maxlen ) {
   160 		for ( i=0; tmp[i]; ++i ) {
   161 			*str++ = tmp[i];
   162 			++len;
   163 		}
   164 	}
   165 	return(len);
   166 }
   167 
   168 /* This function has a bit more overhead than most error functions
   169    so that it supports internationalization and thread-safe errors.
   170 */
   171 Uint16 *SDL_GetErrorMsgUNICODE(Uint16 *errstr, unsigned int maxlen)
   172 {
   173 	SDL_error *error;
   174 
   175 	/* Clear the error string */
   176 	*errstr = 0; --maxlen;
   177 
   178 	/* Get the thread-safe error, and print it out */
   179 	error = SDL_GetErrBuf();
   180 	if ( error->error ) {
   181 		Uint16 translated[ERR_MAX_STRLEN], *fmt, *msg;
   182 		int len;
   183 		int argi;
   184 
   185 		/* Print out the UNICODE error message */
   186 		SDL_LookupString(error->key, translated, sizeof(translated));
   187 		msg = errstr;
   188 		argi = 0;
   189 		for ( fmt=translated; *fmt && (maxlen > 0); ) {
   190 			if ( *fmt == '%' ) {
   191 				switch (fmt[1]) {
   192 				    case 'S':	/* Special SKIP operand */
   193 					argi += (fmt[2] - '0');
   194 					++fmt;
   195 					break;
   196 				    case '%':
   197 					*msg++ = '%';
   198 					maxlen -= 1;
   199 					break;
   200 #if 0	/* What is a character anyway?  (UNICODE issues) */
   201 				    case 'c':
   202                                         *msg++ = (unsigned char)
   203 					         error->args[argi++].value_c;
   204 					maxlen -= 1;
   205 					break;
   206 #endif
   207 				    case 'd':
   208 					len = PrintInt(msg, maxlen,
   209 						error->args[argi++].value_i);
   210 					msg += len;
   211 					maxlen -= len;
   212 					break;
   213 				    case 'f':
   214 					len = PrintDouble(msg, maxlen,
   215 						error->args[argi++].value_f);
   216 					msg += len;
   217 					maxlen -= len;
   218 					break;
   219 				    case 'p':
   220 					len = PrintPointer(msg, maxlen,
   221 						error->args[argi++].value_ptr);
   222 					msg += len;
   223 					maxlen -= len;
   224 					break;
   225 				    case 's': /* UNICODE string */
   226 					{ Uint16 buf[ERR_MAX_STRLEN], *str;
   227 					  SDL_LookupString(error->args[argi++].buf, buf, sizeof(buf));
   228 					  str = buf;
   229 					  while ( *str && (maxlen > 0) ) {
   230 						*msg++ = *str++;
   231 						maxlen -= 1;
   232 					  }
   233 					}
   234 					break;
   235 				}
   236 				fmt += 2;
   237 			} else {
   238 				*msg++ = *fmt++;
   239 				maxlen -= 1;
   240 			}
   241 		}
   242 		*msg = 0;	/* NULL terminate the string */
   243 	}
   244 	return(errstr);
   245 }
   246 
   247 Uint8 *SDL_GetErrorMsg(Uint8 *errstr, unsigned int maxlen)
   248 {
   249 	Uint16 *errstr16;
   250 	unsigned int i;
   251 
   252 	/* Allocate the UNICODE buffer */
   253 	errstr16 = (Uint16 *)SDL_malloc(maxlen * (sizeof *errstr16));
   254 	if ( ! errstr16 ) {
   255 		SDL_strncpy((char *)errstr, "Out of memory", maxlen);
   256 		errstr[maxlen-1] = '\0';
   257 		return(errstr);
   258 	}
   259 
   260 	/* Get the error message */
   261 	SDL_GetErrorMsgUNICODE(errstr16, maxlen);
   262 
   263 	/* Convert from UNICODE to Latin1 encoding */
   264 	for ( i=0; i<maxlen; ++i ) {
   265 		errstr[i] = (Uint8)errstr16[i];
   266 	}
   267 
   268 	/* Free UNICODE buffer (if necessary) */
   269 	SDL_free(errstr16);
   270 
   271 	return(errstr);
   272 }
   273 
   274 /* Available for backwards compatibility */
   275 char *SDL_GetError (void)
   276 {
   277 	static char errmsg[SDL_ERRBUFIZE];
   278 
   279 	return((char *)SDL_GetErrorMsg((unsigned char *)errmsg, SDL_ERRBUFIZE));
   280 }
   281 
   282 void SDL_ClearError(void)
   283 {
   284 	SDL_error *error;
   285 
   286 	error = SDL_GetErrBuf();
   287 	error->error = 0;
   288 }
   289 
   290 /* Very common errors go here */
   291 void SDL_Error(SDL_errorcode code)
   292 {
   293 	switch (code) {
   294 		case SDL_ENOMEM:
   295 			SDL_SetError("Out of memory");
   296 			break;
   297 		case SDL_EFREAD:
   298 			SDL_SetError("Error reading from datastream");
   299 			break;
   300 		case SDL_EFWRITE:
   301 			SDL_SetError("Error writing to datastream");
   302 			break;
   303 		case SDL_EFSEEK:
   304 			SDL_SetError("Error seeking in datastream");
   305 			break;
   306 		default:
   307 			SDL_SetError("Unknown SDL error");
   308 			break;
   309 	}
   310 }
   311 
   312 #ifdef TEST_ERROR
   313 int main(int argc, char *argv[])
   314 {
   315 	char buffer[BUFSIZ+1];
   316 
   317 	SDL_SetError("Hi there!");
   318 	printf("Error 1: %s\n", SDL_GetError());
   319 	SDL_ClearError();
   320 	SDL_memset(buffer, '1', BUFSIZ);
   321 	buffer[BUFSIZ] = 0;
   322 	SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
   323 	printf("Error 2: %s\n", SDL_GetError());
   324 	exit(0);
   325 }
   326 #endif