00001 /********************************************************************** 00002 * $Id: cpl_error_cpp-source.html,v 1.8 2001/07/05 13:24:08 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.8 2001/07/05 13:24:08 warmerda 00031 * *** empty log message *** 00031 * 00032 * Revision 1.16 2001/02/15 16:30:57 warmerda 00033 * fixed initialization of fpLog 00034 * 00035 * Revision 1.15 2001/01/19 21:16:41 warmerda 00036 * expanded tabs 00037 * 00038 * Revision 1.14 2000/11/30 17:30:10 warmerda 00039 * added CPLGetLastErrorType 00040 * 00041 * Revision 1.13 2000/03/31 14:37:48 warmerda 00042 * only use vsnprintf where available 00043 * 00044 * Revision 1.12 2000/03/31 14:11:55 warmerda 00045 * added CPLErrorV 00046 * 00047 * Revision 1.11 2000/01/10 17:35:45 warmerda 00048 * added push down stack of error handlers 00049 * 00050 * Revision 1.10 1999/11/23 04:16:56 danmo 00051 * Fixed var. initialization that failed to compile as C 00052 * 00053 * Revision 1.9 1999/09/03 17:03:45 warmerda 00054 * Completed partial help line. 00055 * 00056 * Revision 1.8 1999/07/23 14:27:47 warmerda 00057 * CPLSetErrorHandler returns old handler 00058 * 00059 * Revision 1.7 1999/06/27 16:50:52 warmerda 00060 * added support for CPL_DEBUG and CPL_LOG variables 00061 * 00062 * Revision 1.6 1999/06/26 02:46:11 warmerda 00063 * Fixed initialization of debug messages. 00064 * 00065 * Revision 1.5 1999/05/20 14:59:05 warmerda 00066 * added CPLDebug() 00067 * 00068 * Revision 1.4 1999/05/20 02:54:38 warmerda 00069 * Added API documentation 00070 * 00071 * Revision 1.3 1998/12/15 19:02:27 warmerda 00072 * Avoid use of errno as a variable 00073 * 00074 * Revision 1.2 1998/12/06 02:52:52 warmerda 00075 * Implement assert support 00076 * 00077 * Revision 1.1 1998/12/03 18:26:02 warmerda 00078 * New 00079 * 00080 **********************************************************************/ 00081 00082 #include "cpl_error.h" 00083 #include "cpl_vsi.h" 00084 00085 /* static buffer to store the last error message. We'll assume that error 00086 * messages cannot be longer than 2000 chars... which is quite reasonable 00087 * (that's 25 lines of 80 chars!!!) 00088 */ 00089 static char gszCPLLastErrMsg[2000] = ""; 00090 static int gnCPLLastErrNo = 0; 00091 static CPLErr geCPLLastErrType = CE_None; 00092 00093 static CPLErrorHandler gpfnCPLErrorHandler = CPLDefaultErrorHandler; 00094 00095 typedef struct errHandler 00096 { 00097 struct errHandler *psNext; 00098 CPLErrorHandler pfnHandler; 00099 } CPLErrorHandlerNode; 00100 00101 static CPLErrorHandlerNode * psHandlerStack = NULL; 00102 00103 /********************************************************************** 00104 * CPLError() 00105 **********************************************************************/ 00106 00139 void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...) 00140 { 00141 va_list args; 00142 00143 /* Expand the error message 00144 */ 00145 va_start(args, fmt); 00146 CPLErrorV( eErrClass, err_no, fmt, args ); 00147 va_end(args); 00148 } 00149 00150 /************************************************************************/ 00151 /* CPLErrorV() */ 00152 /************************************************************************/ 00153 00154 void CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args ) 00155 { 00156 /* Expand the error message 00157 */ 00158 #if defined(HAVE_VSNPRINTF) 00159 vsnprintf(gszCPLLastErrMsg, sizeof(gszCPLLastErrMsg), fmt, args); 00160 #else 00161 vsprintf(gszCPLLastErrMsg, fmt, args); 00162 #endif 00163 00164 /* If the user provided his own error handling function, then call 00165 * it, otherwise print the error to stderr and return. 00166 */ 00167 gnCPLLastErrNo = err_no; 00168 geCPLLastErrType = eErrClass; 00169 00170 if( gpfnCPLErrorHandler ) 00171 gpfnCPLErrorHandler(eErrClass, err_no, gszCPLLastErrMsg); 00172 00173 if( eErrClass == CE_Fatal ) 00174 abort(); 00175 } 00176 00177 /************************************************************************/ 00178 /* CPLDebug() */ 00179 /************************************************************************/ 00180 00202 void CPLDebug( const char * pszCategory, const char * pszFormat, ... ) 00203 00204 { 00205 char *pszMessage; 00206 va_list args; 00207 const char *pszDebug = getenv("CPL_DEBUG"); 00208 00209 /* -------------------------------------------------------------------- */ 00210 /* Does this message pass our current criteria? */ 00211 /* -------------------------------------------------------------------- */ 00212 if( pszDebug == NULL ) 00213 return; 00214 00215 if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") ) 00216 { 00217 int i, nLen = strlen(pszCategory); 00218 00219 for( i = 0; pszDebug[i] != '\0'; i++ ) 00220 { 00221 if( EQUALN(pszCategory,pszDebug+i,nLen) ) 00222 break; 00223 } 00224 00225 if( pszDebug[i] == '\0' ) 00226 return; 00227 } 00228 00229 /* -------------------------------------------------------------------- */ 00230 /* Format the error message */ 00231 /* -------------------------------------------------------------------- */ 00232 pszMessage = (char *) VSIMalloc(25000); 00233 if( pszMessage == NULL ) 00234 return; 00235 00236 strcpy( pszMessage, pszCategory ); 00237 strcat( pszMessage, ": " ); 00238 00239 va_start(args, pszFormat); 00240 vsprintf(pszMessage+strlen(pszMessage), pszFormat, args); 00241 va_end(args); 00242 00243 /* -------------------------------------------------------------------- */ 00244 /* If the user provided his own error handling function, then call */ 00245 /* it, otherwise print the error to stderr and return. */ 00246 /* -------------------------------------------------------------------- */ 00247 if( gpfnCPLErrorHandler ) 00248 gpfnCPLErrorHandler(CE_Debug, CPLE_None, pszMessage); 00249 00250 VSIFree( pszMessage ); 00251 } 00252 00253 /********************************************************************** 00254 * CPLErrorReset() 00255 **********************************************************************/ 00256 00264 void CPLErrorReset() 00265 { 00266 gnCPLLastErrNo = CPLE_None; 00267 gszCPLLastErrMsg[0] = '\0'; 00268 geCPLLastErrType = CE_None; 00269 } 00270 00271 00272 /********************************************************************** 00273 * CPLGetLastErrorNo() 00274 **********************************************************************/ 00275 00285 int CPLGetLastErrorNo() 00286 { 00287 return gnCPLLastErrNo; 00288 } 00289 00290 /********************************************************************** 00291 * CPLGetLastErrorType() 00292 **********************************************************************/ 00293 00303 CPLErr CPLGetLastErrorType() 00304 { 00305 return geCPLLastErrType; 00306 } 00307 00308 /********************************************************************** 00309 * CPLGetLastErrorMsg() 00310 **********************************************************************/ 00311 00323 const char* CPLGetLastErrorMsg() 00324 { 00325 return gszCPLLastErrMsg; 00326 } 00327 00328 /************************************************************************/ 00329 /* CPLDefaultErrorHandler() */ 00330 /************************************************************************/ 00331 00332 void CPLDefaultErrorHandler( CPLErr eErrClass, int nError, 00333 const char * pszErrorMsg ) 00334 00335 { 00336 static int bLogInit = FALSE; 00337 static FILE * fpLog = stderr; 00338 00339 if( !bLogInit ) 00340 { 00341 bLogInit = TRUE; 00342 00343 fpLog = stderr; 00344 if( getenv( "CPL_LOG" ) != NULL ) 00345 { 00346 fpLog = fopen( getenv("CPL_LOG"), "wt" ); 00347 if( fpLog == NULL ) 00348 fpLog = stderr; 00349 } 00350 } 00351 00352 if( eErrClass == CE_Debug ) 00353 fprintf( fpLog, "%s\n", pszErrorMsg ); 00354 else if( eErrClass == CE_Warning ) 00355 fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg ); 00356 else 00357 fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg ); 00358 00359 fflush( fpLog ); 00360 } 00361 00362 /************************************************************************/ 00363 /* CPLQuietErrorHandler() */ 00364 /************************************************************************/ 00365 00366 void CPLQuietErrorHandler( CPLErr eErrClass , int nError, 00367 const char * pszErrorMsg ) 00368 00369 { 00370 if( eErrClass == CE_Debug ) 00371 CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg ); 00372 } 00373 00374 /********************************************************************** 00375 * CPLSetErrorHandler() 00376 **********************************************************************/ 00377 00407 CPLErrorHandler CPLSetErrorHandler( CPLErrorHandler pfnErrorHandler ) 00408 { 00409 CPLErrorHandler pfnOldHandler = gpfnCPLErrorHandler; 00410 00411 gpfnCPLErrorHandler = pfnErrorHandler; 00412 00413 return pfnOldHandler; 00414 } 00415 00416 00417 00418 /************************************************************************/ 00419 /* CPLPushErrorHandler() */ 00420 /************************************************************************/ 00421 00433 void CPLPushErrorHandler( CPLErrorHandler pfnErrorHandler ) 00434 00435 { 00436 CPLErrorHandlerNode *psNode; 00437 00438 psNode = (CPLErrorHandlerNode *) VSIMalloc(sizeof(CPLErrorHandlerNode)); 00439 psNode->psNext = psHandlerStack; 00440 psNode->pfnHandler = gpfnCPLErrorHandler; 00441 00442 psHandlerStack = psNode; 00443 00444 CPLSetErrorHandler( pfnErrorHandler ); 00445 } 00446 00447 /************************************************************************/ 00448 /* CPLPopErrorHandler() */ 00449 /************************************************************************/ 00450 00458 void CPLPopErrorHandler() 00459 00460 { 00461 if( psHandlerStack != NULL ) 00462 { 00463 CPLErrorHandlerNode *psNode = psHandlerStack; 00464 00465 psHandlerStack = psNode->psNext; 00466 CPLSetErrorHandler( psNode->pfnHandler ); 00467 VSIFree( psNode ); 00468 } 00469 } 00470 00471 /************************************************************************/ 00472 /* _CPLAssert() */ 00473 /* */ 00474 /* This function is called only when an assertion fails. */ 00475 /************************************************************************/ 00476 00489 void _CPLAssert( const char * pszExpression, const char * pszFile, 00490 int iLine ) 00491 00492 { 00493 CPLError( CE_Fatal, CPLE_AssertionFailed, 00494 "Assertion `%s' failed\n" 00495 "in file `%s', line %d\n", 00496 pszExpression, pszFile, iLine ); 00497 } 00498