📄 cpl_error.cpp
字号:
/**********************************************************************
* $Id: cpl_error.cpp 10646 2007-01-18 02:38:10Z warmerdam $
*
* Name: cpl_error.cpp
* Project: CPL - Common Portability Library
* Purpose: Error handling functions.
* Author: Daniel Morissette, danmo@videotron.ca
*
**********************************************************************
* Copyright (c) 1998, Daniel Morissette
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_error.h"
#include "cpl_vsi.h"
#include "cpl_conv.h"
#include "cpl_multiproc.h"
#if defined(WIN32CE)
# include "cpl_wince.h"
# include <wce_stdlib.h>
#endif
#define TIMESTAMP_DEBUG
CPL_CVSID("$Id: cpl_error.cpp 10646 2007-01-18 02:38:10Z warmerdam $");
static void *hErrorMutex = NULL;
static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
#if !defined(HAVE_VSNPRINTF)
# define DEFAULT_LAST_ERR_MSG_SIZE 20000
#else
# define DEFAULT_LAST_ERR_MSG_SIZE 500
#endif
typedef struct errHandler
{
struct errHandler *psNext;
CPLErrorHandler pfnHandler;
} CPLErrorHandlerNode;
typedef struct {
int nLastErrNo;
CPLErr eLastErrType;
CPLErrorHandlerNode *psHandlerStack;
int nLastErrMsgMax;
char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
} CPLErrorContext;
/************************************************************************/
/* CPLGetErrorContext() */
/************************************************************************/
static CPLErrorContext *CPLGetErrorContext()
{
CPLErrorContext *psCtx =
(CPLErrorContext *) CPLGetTLS( CTLS_ERRORCONTEXT );
if( psCtx == NULL )
{
psCtx = (CPLErrorContext *) CPLCalloc(sizeof(CPLErrorContext),1);
psCtx->eLastErrType = CE_None;
psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
}
return psCtx;
}
/**********************************************************************
* CPLError()
**********************************************************************/
/**
* Report an error.
*
* This function reports an error in a manner that can be hooked
* and reported appropriate by different applications.
*
* The effect of this function can be altered by applications by installing
* a custom error handling using CPLSetErrorHandler().
*
* The eErrClass argument can have the value CE_Warning indicating that the
* message is an informational warning, CE_Failure indicating that the
* action failed, but that normal recover mechanisms will be used or
* CE_Fatal meaning that a fatal error has occured, and that CPLError()
* should not return.
*
* The default behaviour of CPLError() is to report errors to stderr,
* and to abort() after reporting a CE_Fatal error. It is expected that
* some applications will want to supress error reporting, and will want to
* install a C++ exception, or longjmp() approach to no local fatal error
* recovery.
*
* Regardless of how application error handlers or the default error
* handler choose to handle an error, the error number, and message will
* be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
*
* @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
* @param err_no the error number (CPLE_*) from cpl_error.h.
* @param fmt a printf() style format string. Any additional arguments
* will be treated as arguments to fill in this format in a manner
* similar to printf().
*/
void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...)
{
va_list args;
/* Expand the error message
*/
va_start(args, fmt);
CPLErrorV( eErrClass, err_no, fmt, args );
va_end(args);
}
/************************************************************************/
/* CPLErrorV() */
/************************************************************************/
void CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
{
CPLErrorContext *psCtx = CPLGetErrorContext();
/* -------------------------------------------------------------------- */
/* Expand the error message */
/* -------------------------------------------------------------------- */
#if defined(HAVE_VSNPRINTF)
{
int nPR;
va_list wrk_args;
#ifdef va_copy
va_copy( wrk_args, args );
#else
wrk_args = args;
#endif
while( ((nPR = vsnprintf( psCtx->szLastErrMsg,
psCtx->nLastErrMsgMax, fmt, wrk_args )) == -1
|| nPR >= psCtx->nLastErrMsgMax-1)
&& psCtx->nLastErrMsgMax < 1000000 )
{
#ifdef va_copy
va_end( wrk_args );
va_copy( wrk_args, args );
#else
wrk_args = args;
#endif
psCtx->nLastErrMsgMax *= 3;
psCtx = (CPLErrorContext *)
CPLRealloc(psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE + psCtx->nLastErrMsgMax + 1);
CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
}
va_end( wrk_args );
}
#else
vsprintf( psCtx->szLastErrMsg, fmt, args);
#endif
/* -------------------------------------------------------------------- */
/* If the user provided his own error handling function, then */
/* call it, otherwise print the error to stderr and return. */
/* -------------------------------------------------------------------- */
psCtx->nLastErrNo = err_no;
psCtx->eLastErrType = eErrClass;
if( CPLGetConfigOption("CPL_LOG_ERRORS",NULL) != NULL )
CPLDebug( "CPLError", "%s", psCtx->szLastErrMsg );
/* -------------------------------------------------------------------- */
/* Invoke the current error handler. */
/* -------------------------------------------------------------------- */
if( psCtx->psHandlerStack != NULL )
{
psCtx->psHandlerStack->pfnHandler(eErrClass, err_no,
psCtx->szLastErrMsg);
}
else
{
CPLMutexHolderD( &hErrorMutex );
if( pfnErrorHandler != NULL )
pfnErrorHandler(eErrClass, err_no, psCtx->szLastErrMsg);
}
if( eErrClass == CE_Fatal )
abort();
}
/************************************************************************/
/* CPLDebug() */
/************************************************************************/
/**
* Display a debugging message.
*
* The category argument is used in conjunction with the CPL_DEBUG
* environment variable to establish if the message should be displayed.
* If the CPL_DEBUG environment variable is not set, no debug messages
* are emitted (use CPLError(CE_Warning,...) to ensure messages are displayed).
* If CPL_DEBUG is set, but is an empty string or the word "ON" then all
* debug messages are shown. Otherwise only messages whose category appears
* somewhere within the CPL_DEBUG value are displayed (as determinted by
* strstr()).
*
* Categories are usually an identifier for the subsystem producing the
* error. For instance "GDAL" might be used for the GDAL core, and "TIFF"
* for messages from the TIFF translator.
*
* @param pszCategory name of the debugging message category.
* @param pszFormat printf() style format string for message to display.
* Remaining arguments are assumed to be for format.
*/
void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
{
CPLErrorContext *psCtx = CPLGetErrorContext();
char *pszMessage;
va_list args;
const char *pszDebug = CPLGetConfigOption("CPL_DEBUG",NULL);
#define ERROR_MAX 25000
/* -------------------------------------------------------------------- */
/* Does this message pass our current criteria? */
/* -------------------------------------------------------------------- */
if( pszDebug == NULL )
return;
if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") )
{
size_t i, nLen = strlen(pszCategory);
for( i = 0; pszDebug[i] != '\0'; i++ )
{
if( EQUALN(pszCategory,pszDebug+i,nLen) )
break;
}
if( pszDebug[i] == '\0' )
return;
}
/* -------------------------------------------------------------------- */
/* Allocate a block for the error. */
/* -------------------------------------------------------------------- */
pszMessage = (char *) VSIMalloc( ERROR_MAX );
if( pszMessage == NULL )
return;
/* -------------------------------------------------------------------- */
/* Dal -- always log a timestamp as the first part of the line */
/* to ensure one is looking at what one should be looking at! */
/* -------------------------------------------------------------------- */
pszMessage[0] = '\0';
#ifdef TIMESTAMP_DEBUG
if( CPLGetConfigOption( "CPL_TIMESTAMP", NULL ) != NULL )
{
strcpy( pszMessage, VSICTime( VSITime(NULL) ) );
// On windows anyway, ctime puts a \n at the end, but I'm not
// convinced this is standard behaviour, so we'll get rid of it
// carefully
if (pszMessage[strlen(pszMessage) -1 ] == '\n')
{
pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
}
strcat( pszMessage, ": " );
}
#endif
/* -------------------------------------------------------------------- */
/* Add the category. */
/* -------------------------------------------------------------------- */
strcat( pszMessage, pszCategory );
strcat( pszMessage, ": " );
/* -------------------------------------------------------------------- */
/* Format the application provided portion of the debug message. */
/* -------------------------------------------------------------------- */
va_start(args, pszFormat);
#if defined(HAVE_VSNPRINTF)
vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage),
pszFormat, args);
#else
vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
#endif
va_end(args);
/* -------------------------------------------------------------------- */
/* Invoke the current error handler. */
/* -------------------------------------------------------------------- */
if( psCtx->psHandlerStack != NULL )
{
psCtx->psHandlerStack->pfnHandler( CE_Debug, CPLE_None, pszMessage );
}
else
{
CPLMutexHolderD( &hErrorMutex );
if( pfnErrorHandler != NULL )
pfnErrorHandler( CE_Debug, CPLE_None, pszMessage );
}
VSIFree( pszMessage );
}
/**********************************************************************
* CPLErrorReset()
**********************************************************************/
/**
* Erase any traces of previous errors.
*
* This is normally used to ensure that an error which has been recovered
* from does not appear to be still in play with high level functions.
*/
void CPL_STDCALL CPLErrorReset()
{
CPLErrorContext *psCtx = CPLGetErrorContext();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -