00001 /********************************************************************** 00002 * $Id: cpl_error_cpp-source.html,v 1.10 2002/04/16 13:11:47 warmerda Exp $ 00003 * 00004 * Name: cpl_error.cpp 00005 * Project: CPL - Common Portability Library 00006 * Purpose: Error handling functions. 00007 * Author: Daniel Morissette, danmo@videotron.ca 00008 * 00009 ********************************************************************** 00010 * Copyright (c) 1998, Daniel Morissette 00011 * 00012 * Permission is hereby granted, free of charge, to any person obtaining a 00013 * copy of this software and associated documentation files (the "Software"), 00014 * to deal in the Software without restriction, including without limitation 00015 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00016 * and/or sell copies of the Software, and to permit persons to whom the 00017 * Software is furnished to do so, subject to the following conditions: 00018 * 00019 * The above copyright notice and this permission notice shall be included 00020 * in all copies or substantial portions of the Software. 00021 * 00022 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00023 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00024 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00025 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00026 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00027 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00028 * DEALINGS IN THE SOFTWARE. 00029 ********************************************************************** 00030 * 00031 * $Log: cpl_error_cpp-source.html,v $ 00031 * Revision 1.10 2002/04/16 13:11:47 warmerda 00031 * updated 00031 * 00032 * Revision 1.21 2001/12/14 19:45:17 warmerda 00033 * Avoid use of errno in prototype. 00034 * 00035 * Revision 1.20 2001/11/27 17:01:06 warmerda 00036 * added timestamp to debug messages 00037 * 00038 * Revision 1.19 2001/11/15 16:11:08 warmerda 00039 * use vsnprintf() for debug calls if it is available 00040 * 00041 * Revision 1.18 2001/11/02 22:07:58 warmerda 00042 * added logging error handler 00043 * 00044 * Revision 1.17 2001/07/18 04:00:49 warmerda 00045 * added CPL_CVSID 00046 * 00047 * Revision 1.16 2001/02/15 16:30:57 warmerda 00048 * fixed initialization of fpLog 00049 * 00050 * Revision 1.15 2001/01/19 21:16:41 warmerda 00051 * expanded tabs 00052 * 00053 * Revision 1.14 2000/11/30 17:30:10 warmerda 00054 * added CPLGetLastErrorType 00055 * 00056 * Revision 1.13 2000/03/31 14:37:48 warmerda 00057 * only use vsnprintf where available 00058 * 00059 * Revision 1.12 2000/03/31 14:11:55 warmerda 00060 * added CPLErrorV 00061 * 00062 * Revision 1.11 2000/01/10 17:35:45 warmerda 00063 * added push down stack of error handlers 00064 * 00065 * Revision 1.10 1999/11/23 04:16:56 danmo 00066 * Fixed var. initialization that failed to compile as C 00067 * 00068 * Revision 1.9 1999/09/03 17:03:45 warmerda 00069 * Completed partial help line. 00070 * 00071 * Revision 1.8 1999/07/23 14:27:47 warmerda 00072 * CPLSetErrorHandler returns old handler 00073 * 00074 * Revision 1.7 1999/06/27 16:50:52 warmerda 00075 * added support for CPL_DEBUG and CPL_LOG variables 00076 * 00077 * Revision 1.6 1999/06/26 02:46:11 warmerda 00078 * Fixed initialization of debug messages. 00079 * 00080 * Revision 1.5 1999/05/20 14:59:05 warmerda 00081 * added CPLDebug() 00082 * 00083 * Revision 1.4 1999/05/20 02:54:38 warmerda 00084 * Added API documentation 00085 * 00086 * Revision 1.3 1998/12/15 19:02:27 warmerda 00087 * Avoid use of errno as a variable 00088 * 00089 * Revision 1.2 1998/12/06 02:52:52 warmerda 00090 * Implement assert support 00091 * 00092 * Revision 1.1 1998/12/03 18:26:02 warmerda 00093 * New 00094 * 00095 **********************************************************************/ 00096 00097 #include "cpl_error.h" 00098 #include "cpl_vsi.h" 00099 00100 #define TIMESTAMP_DEBUG 00101 #ifdef TIMESTAMP_DEBUG 00102 #include <time.h> 00103 #endif 00104 00105 CPL_CVSID("$Id: cpl_error_cpp-source.html,v 1.10 2002/04/16 13:11:47 warmerda Exp $"); 00106 00107 /* static buffer to store the last error message. We'll assume that error 00108 * messages cannot be longer than 2000 chars... which is quite reasonable 00109 * (that's 25 lines of 80 chars!!!) 00110 */ 00111 static char gszCPLLastErrMsg[2000] = ""; 00112 static int gnCPLLastErrNo = 0; 00113 static CPLErr geCPLLastErrType = CE_None; 00114 00115 static CPLErrorHandler gpfnCPLErrorHandler = CPLDefaultErrorHandler; 00116 00117 typedef struct errHandler 00118 { 00119 struct errHandler *psNext; 00120 CPLErrorHandler pfnHandler; 00121 } CPLErrorHandlerNode; 00122 00123 static CPLErrorHandlerNode * psHandlerStack = NULL; 00124 00125 /********************************************************************** 00126 * CPLError() 00127 **********************************************************************/ 00128 00161 void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...) 00162 { 00163 va_list args; 00164 00165 /* Expand the error message 00166 */ 00167 va_start(args, fmt); 00168 CPLErrorV( eErrClass, err_no, fmt, args ); 00169 va_end(args); 00170 } 00171 00172 /************************************************************************/ 00173 /* CPLErrorV() */ 00174 /************************************************************************/ 00175 00176 void CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args ) 00177 { 00178 /* Expand the error message 00179 */ 00180 #if defined(HAVE_VSNPRINTF) 00181 vsnprintf(gszCPLLastErrMsg, sizeof(gszCPLLastErrMsg), fmt, args); 00182 #else 00183 vsprintf(gszCPLLastErrMsg, fmt, args); 00184 #endif 00185 00186 /* If the user provided his own error handling function, then call 00187 * it, otherwise print the error to stderr and return. 00188 */ 00189 gnCPLLastErrNo = err_no; 00190 geCPLLastErrType = eErrClass; 00191 00192 if( gpfnCPLErrorHandler ) 00193 gpfnCPLErrorHandler(eErrClass, err_no, gszCPLLastErrMsg); 00194 00195 if( eErrClass == CE_Fatal ) 00196 abort(); 00197 } 00198 00199 /************************************************************************/ 00200 /* CPLDebug() */ 00201 /************************************************************************/ 00202 00224 void CPLDebug( const char * pszCategory, const char * pszFormat, ... ) 00225 00226 { 00227 char *pszMessage; 00228 va_list args; 00229 const char *pszDebug = getenv("CPL_DEBUG"); 00230 00231 #define ERROR_MAX 25000 00232 00233 /* -------------------------------------------------------------------- */ 00234 /* Does this message pass our current criteria? */ 00235 /* -------------------------------------------------------------------- */ 00236 if( pszDebug == NULL ) 00237 return; 00238 00239 if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") ) 00240 { 00241 int i, nLen = strlen(pszCategory); 00242 00243 for( i = 0; pszDebug[i] != '\0'; i++ ) 00244 { 00245 if( EQUALN(pszCategory,pszDebug+i,nLen) ) 00246 break; 00247 } 00248 00249 if( pszDebug[i] == '\0' ) 00250 return; 00251 } 00252 00253 /* -------------------------------------------------------------------- */ 00254 /* Allocate a block for the error. */ 00255 /* -------------------------------------------------------------------- */ 00256 pszMessage = (char *) VSIMalloc(ERROR_MAX); 00257 if( pszMessage == NULL ) 00258 return; 00259 00260 /* -------------------------------------------------------------------- */ 00261 /* Dal -- always log a timestamp as the first part of the line */ 00262 /* to ensure one is looking at what one should be looking at! */ 00263 /* -------------------------------------------------------------------- */ 00264 00265 #ifdef TIMESTAMP_DEBUG 00266 { 00267 time_t ltime; 00268 00269 time( <ime ); 00270 strcpy( pszMessage, ctime( <ime ) ); 00271 00272 // On windows anyway, ctime puts a \n at the end, but I'm not 00273 // convinced this is standard behaviour, so we'll get rid of it 00274 // carefully 00275 00276 if (pszMessage[strlen(pszMessage) -1 ] == '\n') 00277 { 00278 pszMessage[strlen(pszMessage) - 1] = 0; // blow it out 00279 } 00280 strcat( pszMessage, ": " ); 00281 } 00282 #else 00283 pszMessage[0] = '\0'; 00284 #endif 00285 00286 /* -------------------------------------------------------------------- */ 00287 /* Add the category. */ 00288 /* -------------------------------------------------------------------- */ 00289 strcat( pszMessage, pszCategory ); 00290 strcat( pszMessage, ": " ); 00291 00292 /* -------------------------------------------------------------------- */ 00293 /* Format the application provided portion of the debug message. */ 00294 /* -------------------------------------------------------------------- */ 00295 va_start(args, pszFormat); 00296 #if defined(HAVE_VSNPRINTF) 00297 vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage), 00298 pszFormat, args); 00299 #else 00300 vsprintf(pszMessage+strlen(pszMessage), pszFormat, args); 00301 #endif 00302 va_end(args); 00303 00304 /* -------------------------------------------------------------------- */ 00305 /* If the user provided his own error handling function, then call */ 00306 /* it, otherwise print the error to stderr and return. */ 00307 /* -------------------------------------------------------------------- */ 00308 if( gpfnCPLErrorHandler ) 00309 gpfnCPLErrorHandler(CE_Debug, CPLE_None, pszMessage); 00310 00311 VSIFree( pszMessage ); 00312 } 00313 00314 /********************************************************************** 00315 * CPLErrorReset() 00316 **********************************************************************/ 00317 00325 void CPLErrorReset() 00326 { 00327 gnCPLLastErrNo = CPLE_None; 00328 gszCPLLastErrMsg[0] = '\0'; 00329 geCPLLastErrType = CE_None; 00330 } 00331 00332 00333 /********************************************************************** 00334 * CPLGetLastErrorNo() 00335 **********************************************************************/ 00336 00346 int CPLGetLastErrorNo() 00347 { 00348 return gnCPLLastErrNo; 00349 } 00350 00351 /********************************************************************** 00352 * CPLGetLastErrorType() 00353 **********************************************************************/ 00354 00364 CPLErr CPLGetLastErrorType() 00365 { 00366 return geCPLLastErrType; 00367 } 00368 00369 /********************************************************************** 00370 * CPLGetLastErrorMsg() 00371 **********************************************************************/ 00372 00384 const char* CPLGetLastErrorMsg() 00385 { 00386 return gszCPLLastErrMsg; 00387 } 00388 00389 /************************************************************************/ 00390 /* CPLDefaultErrorHandler() */ 00391 /************************************************************************/ 00392 00393 void CPLDefaultErrorHandler( CPLErr eErrClass, int nError, 00394 const char * pszErrorMsg ) 00395 00396 { 00397 static int bLogInit = FALSE; 00398 static FILE * fpLog = stderr; 00399 00400 if( !bLogInit ) 00401 { 00402 bLogInit = TRUE; 00403 00404 fpLog = stderr; 00405 if( getenv( "CPL_LOG" ) != NULL ) 00406 { 00407 fpLog = fopen( getenv("CPL_LOG"), "wt" ); 00408 if( fpLog == NULL ) 00409 fpLog = stderr; 00410 } 00411 } 00412 00413 if( eErrClass == CE_Debug ) 00414 fprintf( fpLog, "%s\n", pszErrorMsg ); 00415 else if( eErrClass == CE_Warning ) 00416 fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg ); 00417 else 00418 fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg ); 00419 00420 fflush( fpLog ); 00421 } 00422 00423 /************************************************************************/ 00424 /* CPLQuietErrorHandler() */ 00425 /************************************************************************/ 00426 00427 void CPLQuietErrorHandler( CPLErr eErrClass , int nError, 00428 const char * pszErrorMsg ) 00429 00430 { 00431 if( eErrClass == CE_Debug ) 00432 CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg ); 00433 } 00434 00435 /************************************************************************/ 00436 /* CPLLoggingErrorHandler() */ 00437 /************************************************************************/ 00438 00439 void CPLLoggingErrorHandler( CPLErr eErrClass, int nError, 00440 const char * pszErrorMsg ) 00441 00442 { 00443 static int bLogInit = FALSE; 00444 static FILE * fpLog = stderr; 00445 00446 if( !bLogInit ) 00447 { 00448 const char *cpl_log = NULL; 00449 00450 bLogInit = TRUE; 00451 00452 if( getenv("CPL_LOG") != NULL ) 00453 cpl_log = getenv("CPL_LOG"); 00454 00455 fpLog = stderr; 00456 if( cpl_log != NULL && EQUAL(cpl_log,"OFF") ) 00457 { 00458 fpLog = NULL; 00459 } 00460 else if( cpl_log != NULL ) 00461 { 00462 char path[5000]; 00463 int i = 0; 00464 00465 strcpy( path, cpl_log ); 00466 00467 while( (fpLog = fopen( path, "rt" )) != NULL ) 00468 { 00469 fclose( fpLog ); 00470 00471 sprintf( path, "%s_%d", cpl_log, i++ ); 00472 } 00473 00474 fpLog = fopen( path, "wt" ); 00475 } 00476 } 00477 00478 if( fpLog == NULL ) 00479 return; 00480 00481 if( eErrClass == CE_Debug ) 00482 fprintf( fpLog, "%s\n", pszErrorMsg ); 00483 else if( eErrClass == CE_Warning ) 00484 fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg ); 00485 else 00486 fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg ); 00487 00488 fflush( fpLog ); 00489 } 00490 00491 /********************************************************************** 00492 * CPLSetErrorHandler() 00493 **********************************************************************/ 00494 00524 CPLErrorHandler CPLSetErrorHandler( CPLErrorHandler pfnErrorHandler ) 00525 { 00526 CPLErrorHandler pfnOldHandler = gpfnCPLErrorHandler; 00527 00528 gpfnCPLErrorHandler = pfnErrorHandler; 00529 00530 return pfnOldHandler; 00531 } 00532 00533 00534 00535 /************************************************************************/ 00536 /* CPLPushErrorHandler() */ 00537 /************************************************************************/ 00538 00550 void CPLPushErrorHandler( CPLErrorHandler pfnErrorHandler ) 00551 00552 { 00553 CPLErrorHandlerNode *psNode; 00554 00555 psNode = (CPLErrorHandlerNode *) VSIMalloc(sizeof(CPLErrorHandlerNode)); 00556 psNode->psNext = psHandlerStack; 00557 psNode->pfnHandler = gpfnCPLErrorHandler; 00558 00559 psHandlerStack = psNode; 00560 00561 CPLSetErrorHandler( pfnErrorHandler ); 00562 } 00563 00564 /************************************************************************/ 00565 /* CPLPopErrorHandler() */ 00566 /************************************************************************/ 00567 00575 void CPLPopErrorHandler() 00576 00577 { 00578 if( psHandlerStack != NULL ) 00579 { 00580 CPLErrorHandlerNode *psNode = psHandlerStack; 00581 00582 psHandlerStack = psNode->psNext; 00583 CPLSetErrorHandler( psNode->pfnHandler ); 00584 VSIFree( psNode ); 00585 } 00586 } 00587 00588 /************************************************************************/ 00589 /* _CPLAssert() */ 00590 /* */ 00591 /* This function is called only when an assertion fails. */ 00592 /************************************************************************/ 00593 00606 void _CPLAssert( const char * pszExpression, const char * pszFile, 00607 int iLine ) 00608 00609 { 00610 CPLError( CE_Fatal, CPLE_AssertionFailed, 00611 "Assertion `%s' failed\n" 00612 "in file `%s', line %d\n", 00613 pszExpression, pszFile, iLine ); 00614 } 00615