LCOV - code coverage report
Current view: directory - port - cpl_error.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 219 138 63.0 %
Date: 2013-03-30 Functions: 21 18 85.7 %

       1                 : /**********************************************************************
       2                 :  * $Id: cpl_error.cpp 25781 2013-03-22 20:57:00Z warmerdam $
       3                 :  *
       4                 :  * Name:     cpl_error.cpp
       5                 :  * Project:  CPL - Common Portability Library
       6                 :  * Purpose:  Error handling functions.
       7                 :  * Author:   Daniel Morissette, danmo@videotron.ca
       8                 :  *
       9                 :  **********************************************************************
      10                 :  * Copyright (c) 1998, Daniel Morissette
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  * 
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  * 
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      23                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "cpl_error.h"
      32                 : #include "cpl_vsi.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_multiproc.h"
      35                 : 
      36                 : #if defined(WIN32CE)
      37                 : #  include "cpl_wince.h"
      38                 : #  include <wce_stdlib.h>
      39                 : #endif
      40                 :  
      41                 : #define TIMESTAMP_DEBUG
      42                 : 
      43                 : CPL_CVSID("$Id: cpl_error.cpp 25781 2013-03-22 20:57:00Z warmerdam $");
      44                 : 
      45                 : static void *hErrorMutex = NULL;
      46                 : static void *pErrorHandlerUserData = NULL; 
      47                 : static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
      48                 : 
      49                 : #if !defined(HAVE_VSNPRINTF)
      50                 : #  define DEFAULT_LAST_ERR_MSG_SIZE 20000
      51                 : #else
      52                 : #  define DEFAULT_LAST_ERR_MSG_SIZE 500
      53                 : #endif
      54                 : 
      55                 : typedef struct errHandler
      56                 : {
      57                 :     struct errHandler   *psNext;
      58                 :     void                *pUserData;
      59                 :     CPLErrorHandler     pfnHandler;
      60                 : } CPLErrorHandlerNode;
      61                 : 
      62                 : typedef struct {
      63                 :     int     nLastErrNo;
      64                 :     CPLErr  eLastErrType;
      65                 :     CPLErrorHandlerNode *psHandlerStack;
      66                 :     int     nLastErrMsgMax;
      67                 :     int     nFailureIntoWarning;
      68                 :     char    szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
      69                 :     /* Do not add anything here. szLastErrMsg must be the last field. See CPLRealloc() below */
      70                 : } CPLErrorContext;
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                         CPLGetErrorContext()                         */
      74                 : /************************************************************************/
      75                 : 
      76         2176337 : static CPLErrorContext *CPLGetErrorContext()
      77                 : 
      78                 : {
      79                 :     CPLErrorContext *psCtx = 
      80         2176337 :         (CPLErrorContext *) CPLGetTLS( CTLS_ERRORCONTEXT );
      81                 : 
      82         2176337 :     if( psCtx == NULL )
      83                 :     {
      84             761 :         psCtx = (CPLErrorContext *) VSICalloc(sizeof(CPLErrorContext),1);
      85             761 :         if (psCtx == NULL) {
      86               0 :             CPLEmergencyError("Out of memory attempting to report error");
      87                 :         }
      88             761 :         psCtx->eLastErrType = CE_None;
      89             761 :         psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
      90             761 :         CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
      91                 :     }
      92                 : 
      93         2176337 :     return psCtx;
      94                 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                         CPLGetErrorHandlerUserData()                 */
      98                 : /************************************************************************/
      99                 : 
     100                 : /**
     101                 :  * Fetch the user data for the error context
     102                 :  *
     103                 :  * Fetches the user data for the current error context.  You can 
     104                 :  * set the user data for the error context when you add your handler by 
     105                 :  * issuing CPLSetErrorHandlerEx() and CPLPushErrorHandlerEx().  Note that 
     106                 :  * user data is primarily intended for providing context within error handlers
     107                 :  * themselves, but they could potentially be abused in other useful ways with the usual 
     108                 :  * caveat emptor understanding.
     109                 :  *
     110                 :  * @return the user data pointer for the error context
     111                 :  */
     112                 : 
     113               3 : void* CPL_STDCALL CPLGetErrorHandlerUserData(void)
     114                 : {
     115               3 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     116               3 :     return (void*) psCtx->psHandlerStack ? psCtx->psHandlerStack->pUserData : pErrorHandlerUserData;
     117                 : }
     118                 : 
     119                 : /**********************************************************************
     120                 :  *                          CPLError()
     121                 :  **********************************************************************/
     122                 : 
     123                 : /**
     124                 :  * Report an error.
     125                 :  *
     126                 :  * This function reports an error in a manner that can be hooked
     127                 :  * and reported appropriate by different applications.
     128                 :  *
     129                 :  * The effect of this function can be altered by applications by installing
     130                 :  * a custom error handling using CPLSetErrorHandler().
     131                 :  *
     132                 :  * The eErrClass argument can have the value CE_Warning indicating that the
     133                 :  * message is an informational warning, CE_Failure indicating that the
     134                 :  * action failed, but that normal recover mechanisms will be used or
     135                 :  * CE_Fatal meaning that a fatal error has occured, and that CPLError()
     136                 :  * should not return.  
     137                 :  *
     138                 :  * The default behaviour of CPLError() is to report errors to stderr,
     139                 :  * and to abort() after reporting a CE_Fatal error.  It is expected that
     140                 :  * some applications will want to supress error reporting, and will want to
     141                 :  * install a C++ exception, or longjmp() approach to no local fatal error
     142                 :  * recovery.
     143                 :  *
     144                 :  * Regardless of how application error handlers or the default error
     145                 :  * handler choose to handle an error, the error number, and message will
     146                 :  * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
     147                 :  *
     148                 :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
     149                 :  * @param err_no the error number (CPLE_*) from cpl_error.h.
     150                 :  * @param fmt a printf() style format string.  Any additional arguments
     151                 :  * will be treated as arguments to fill in this format in a manner
     152                 :  * similar to printf().
     153                 :  */
     154                 : 
     155            5443 : void    CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...)
     156                 : {
     157                 :     va_list args;
     158                 : 
     159                 :     /* Expand the error message 
     160                 :      */
     161            5443 :     va_start(args, fmt);
     162            5443 :     CPLErrorV( eErrClass, err_no, fmt, args );
     163            5443 :     va_end(args);
     164            5443 : }
     165                 : 
     166                 : /************************************************************************/
     167                 : /*                             CPLErrorV()                              */
     168                 : /************************************************************************/
     169                 : 
     170           18702 : void    CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
     171                 : {
     172           18702 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     173                 : 
     174           18702 :     if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
     175               0 :         eErrClass = CE_Warning;
     176                 : 
     177                 : /* -------------------------------------------------------------------- */
     178                 : /*      Expand the error message                                        */
     179                 : /* -------------------------------------------------------------------- */
     180                 : #if defined(HAVE_VSNPRINTF)
     181                 :     {
     182                 :         int nPR;
     183                 :         va_list wrk_args;
     184                 : 
     185                 : #ifdef va_copy
     186           18702 :         va_copy( wrk_args, args );
     187                 : #else
     188                 :         wrk_args = args;
     189                 : #endif
     190                 : 
     191                 : /* -------------------------------------------------------------------- */
     192                 : /*      If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages,        */
     193                 : /*      rather than just replacing the last error message.              */
     194                 : /* -------------------------------------------------------------------- */
     195           18702 :         int nPreviousSize = 0;
     196           18702 :         if ( psCtx->psHandlerStack != NULL &&
     197                 :              EQUAL(CPLGetConfigOption( "CPL_ACCUM_ERROR_MSG", "" ), "ON"))
     198                 :         {
     199               0 :             nPreviousSize = strlen(psCtx->szLastErrMsg);
     200               0 :             if (nPreviousSize)
     201                 :             {
     202               0 :                 if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
     203                 :                 {
     204               0 :                     psCtx->nLastErrMsgMax *= 3;
     205                 :                     psCtx = (CPLErrorContext *) 
     206               0 :                         CPLRealloc(psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE + psCtx->nLastErrMsgMax + 1);
     207               0 :                     CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
     208                 :                 }
     209               0 :                 psCtx->szLastErrMsg[nPreviousSize] = '\n';
     210               0 :                 psCtx->szLastErrMsg[nPreviousSize+1] = '0';
     211               0 :                 nPreviousSize ++;
     212                 :             }
     213                 :         }
     214                 : 
     215           37407 :         while( ((nPR = vsnprintf( psCtx->szLastErrMsg+nPreviousSize, 
     216                 :                                  psCtx->nLastErrMsgMax-nPreviousSize, fmt, wrk_args )) == -1
     217                 :                 || nPR >= psCtx->nLastErrMsgMax-nPreviousSize-1)
     218                 :                && psCtx->nLastErrMsgMax < 1000000 )
     219                 :         {
     220                 : #ifdef va_copy
     221               3 :             va_end( wrk_args );
     222               3 :             va_copy( wrk_args, args );
     223                 : #else
     224                 :             wrk_args = args;
     225                 : #endif
     226               3 :             psCtx->nLastErrMsgMax *= 3;
     227                 :             psCtx = (CPLErrorContext *) 
     228               3 :                 CPLRealloc(psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE + psCtx->nLastErrMsgMax + 1);
     229               3 :             CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
     230                 :         }
     231                 : 
     232           18702 :         va_end( wrk_args );
     233                 :     }
     234                 : #else
     235                 :     vsprintf( psCtx->szLastErrMsg, fmt, args);
     236                 : #endif
     237                 : 
     238                 : /* -------------------------------------------------------------------- */
     239                 : /*      If the user provided his own error handling function, then      */
     240                 : /*      call it, otherwise print the error to stderr and return.        */
     241                 : /* -------------------------------------------------------------------- */
     242           18702 :     psCtx->nLastErrNo = err_no;
     243           18702 :     psCtx->eLastErrType = eErrClass;
     244                 : 
     245           18702 :     if( CPLGetConfigOption("CPL_LOG_ERRORS",NULL) != NULL )
     246               0 :         CPLDebug( "CPLError", "%s", psCtx->szLastErrMsg );
     247                 : 
     248                 : /* -------------------------------------------------------------------- */
     249                 : /*      Invoke the current error handler.                               */
     250                 : /* -------------------------------------------------------------------- */
     251           18702 :     if( psCtx->psHandlerStack != NULL )
     252                 :     {
     253                 :         psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, 
     254           18388 :                                           psCtx->szLastErrMsg);
     255                 :     }
     256                 :     else
     257                 :     {
     258             314 :         CPLMutexHolderD( &hErrorMutex );
     259             314 :         if( pfnErrorHandler != NULL )
     260             314 :             pfnErrorHandler(eErrClass, err_no, psCtx->szLastErrMsg);
     261                 :     }
     262                 : 
     263           18702 :     if( eErrClass == CE_Fatal )
     264               0 :         abort();
     265           18702 : }
     266                 : 
     267                 : /************************************************************************/
     268                 : /*                         CPLEmergencyError()                          */
     269                 : /************************************************************************/
     270                 : 
     271                 : /**
     272                 :  * Fatal error when things are bad. 
     273                 :  *
     274                 :  * This function should be called in an emergency situation where
     275                 :  * it is unlikely that a regular error report would work.  This would 
     276                 :  * include in the case of heap exhaustion for even small allocations, 
     277                 :  * or any failure in the process of reporting an error (such as TLS 
     278                 :  * allocations). 
     279                 :  *
     280                 :  * This function should never return.  After the error message has been
     281                 :  * reported as best possible, the application will abort() similarly to how
     282                 :  * CPLError() aborts on CE_Fatal class errors.
     283                 :  *
     284                 :  * @param pszMessage the error message to report.
     285                 :  */
     286                 : 
     287               0 : void CPLEmergencyError( const char *pszMessage )
     288                 : {
     289               0 :     CPLErrorContext *psCtx = NULL;
     290                 :     static int bInEmergencyError = FALSE;
     291                 : 
     292                 :     // If we are already in emergency error then one of the 
     293                 :     // following failed, so avoid them the second time through.
     294               0 :     if( !bInEmergencyError )
     295                 :     {
     296               0 :         bInEmergencyError = TRUE;
     297               0 :         psCtx = (CPLErrorContext *) CPLGetTLS( CTLS_ERRORCONTEXT );
     298                 : 
     299               0 :         if( psCtx != NULL && psCtx->psHandlerStack != NULL )
     300                 :         {
     301                 :             psCtx->psHandlerStack->pfnHandler( CE_Fatal, CPLE_AppDefined, 
     302               0 :                                                pszMessage );
     303                 :         }
     304               0 :         else if( pfnErrorHandler != NULL )
     305                 :         {
     306               0 :             pfnErrorHandler( CE_Fatal, CPLE_AppDefined, pszMessage );
     307                 :         }
     308                 :     }
     309                 : 
     310                 :     // Ultimate fallback.
     311               0 :     fprintf( stderr, "FATAL: %s\n", pszMessage );
     312                 : 
     313               0 :     abort();
     314                 : }
     315                 : 
     316                 : /************************************************************************/
     317                 : /*                              CPLDebug()                              */
     318                 : /************************************************************************/
     319                 : 
     320                 : /**
     321                 :  * Display a debugging message.
     322                 :  *
     323                 :  * The category argument is used in conjunction with the CPL_DEBUG
     324                 :  * environment variable to establish if the message should be displayed.
     325                 :  * If the CPL_DEBUG environment variable is not set, no debug messages
     326                 :  * are emitted (use CPLError(CE_Warning,...) to ensure messages are displayed).
     327                 :  * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
     328                 :  * debug messages are shown.  Otherwise only messages whose category appears
     329                 :  * somewhere within the CPL_DEBUG value are displayed (as determinted by
     330                 :  * strstr()).
     331                 :  *
     332                 :  * Categories are usually an identifier for the subsystem producing the
     333                 :  * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
     334                 :  * for messages from the TIFF translator.  
     335                 :  *
     336                 :  * @param pszCategory name of the debugging message category.
     337                 :  * @param pszFormat printf() style format string for message to display.
     338                 :  *        Remaining arguments are assumed to be for format.
     339                 :  */ 
     340                 : 
     341          182669 : void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
     342                 : 
     343                 : {
     344          182669 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     345                 :     char        *pszMessage;
     346                 :     va_list     args;
     347          182669 :     const char  *pszDebug = CPLGetConfigOption("CPL_DEBUG",NULL);
     348                 : 
     349                 : #define ERROR_MAX 25000
     350                 : 
     351                 : /* -------------------------------------------------------------------- */
     352                 : /*      Does this message pass our current criteria?                    */
     353                 : /* -------------------------------------------------------------------- */
     354          182669 :     if( pszDebug == NULL )
     355          182197 :         return;
     356                 : 
     357             472 :     if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") )
     358                 :     {
     359               0 :         size_t  i, nLen = strlen(pszCategory);
     360                 : 
     361               0 :         for( i = 0; pszDebug[i] != '\0'; i++ )
     362                 :         {
     363               0 :             if( EQUALN(pszCategory,pszDebug+i,nLen) )
     364               0 :                 break;
     365                 :         }
     366                 : 
     367               0 :         if( pszDebug[i] == '\0' )
     368               0 :             return;
     369                 :     }
     370                 : 
     371                 : /* -------------------------------------------------------------------- */
     372                 : /*    Allocate a block for the error.                                   */
     373                 : /* -------------------------------------------------------------------- */
     374             472 :     pszMessage = (char *) VSIMalloc( ERROR_MAX );
     375             472 :     if( pszMessage == NULL )
     376               0 :         return;
     377                 :         
     378                 : /* -------------------------------------------------------------------- */
     379                 : /*      Dal -- always log a timestamp as the first part of the line     */
     380                 : /*      to ensure one is looking at what one should be looking at!      */
     381                 : /* -------------------------------------------------------------------- */
     382                 : 
     383             472 :     pszMessage[0] = '\0';
     384                 : #ifdef TIMESTAMP_DEBUG
     385             472 :     if( CPLGetConfigOption( "CPL_TIMESTAMP", NULL ) != NULL )
     386                 :     {
     387               0 :         strcpy( pszMessage, VSICTime( VSITime(NULL) ) );
     388                 :         
     389                 :         // On windows anyway, ctime puts a \n at the end, but I'm not 
     390                 :         // convinced this is standard behaviour, so we'll get rid of it
     391                 :         // carefully
     392                 : 
     393               0 :         if (pszMessage[strlen(pszMessage) -1 ] == '\n')
     394                 :         {
     395               0 :             pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
     396                 :         }
     397               0 :         strcat( pszMessage, ": " );
     398                 :     }
     399                 : #endif
     400                 :     //sprintf(pszMessage,"[%d] ", (int)getpid());
     401                 : 
     402                 : /* -------------------------------------------------------------------- */
     403                 : /*      Add the category.                                               */
     404                 : /* -------------------------------------------------------------------- */
     405             472 :     strcat( pszMessage, pszCategory );
     406             472 :     strcat( pszMessage, ": " );
     407                 :     
     408                 : /* -------------------------------------------------------------------- */
     409                 : /*      Format the application provided portion of the debug message.   */
     410                 : /* -------------------------------------------------------------------- */
     411             472 :     va_start(args, pszFormat);
     412                 : #if defined(HAVE_VSNPRINTF)
     413                 :     vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage), 
     414             472 :               pszFormat, args);
     415                 : #else
     416                 :     vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
     417                 : #endif
     418             472 :     va_end(args);
     419                 : 
     420                 : /* -------------------------------------------------------------------- */
     421                 : /*      Invoke the current error handler.                               */
     422                 : /* -------------------------------------------------------------------- */
     423             472 :     if( psCtx->psHandlerStack != NULL )
     424                 :     {
     425               4 :         psCtx->psHandlerStack->pfnHandler( CE_Debug, CPLE_None, pszMessage );
     426                 :     }
     427                 :     else
     428                 :     {
     429             468 :         CPLMutexHolderD( &hErrorMutex );
     430             468 :         if( pfnErrorHandler != NULL )
     431             468 :             pfnErrorHandler( CE_Debug, CPLE_None, pszMessage );
     432                 :     }
     433                 : 
     434             472 :     VSIFree( pszMessage );
     435                 : }
     436                 : 
     437                 : /**********************************************************************
     438                 :  *                          CPLErrorReset()
     439                 :  **********************************************************************/
     440                 : 
     441                 : /**
     442                 :  * Erase any traces of previous errors.
     443                 :  *
     444                 :  * This is normally used to ensure that an error which has been recovered
     445                 :  * from does not appear to be still in play with high level functions.
     446                 :  */
     447                 : 
     448          672157 : void CPL_STDCALL CPLErrorReset()
     449                 : {
     450          672157 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     451                 : 
     452          672157 :     psCtx->nLastErrNo = CPLE_None;
     453          672157 :     psCtx->szLastErrMsg[0] = '\0';
     454          672157 :     psCtx->eLastErrType = CE_None;
     455          672157 : }
     456                 : 
     457                 : 
     458                 : /**********************************************************************
     459                 :  *                          CPLGetLastErrorNo()
     460                 :  **********************************************************************/
     461                 : 
     462                 : /**
     463                 :  * Fetch the last error number.
     464                 :  *
     465                 :  * Fetches the last error number posted with CPLError(), that hasn't
     466                 :  * been cleared by CPLErrorReset().  This is the error number, not the error class.
     467                 :  *
     468                 :  * @return the error number of the last error to occur, or CPLE_None (0)
     469                 :  * if there are no posted errors.
     470                 :  */
     471                 : 
     472          862379 : int CPL_STDCALL CPLGetLastErrorNo()
     473                 : {
     474          862379 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     475                 : 
     476          862379 :     return psCtx->nLastErrNo;
     477                 : }
     478                 : 
     479                 : /**********************************************************************
     480                 :  *                          CPLGetLastErrorType()
     481                 :  **********************************************************************/
     482                 : 
     483                 : /**
     484                 :  * Fetch the last error type.
     485                 :  *
     486                 :  * Fetches the last error type posted with CPLError(), that hasn't
     487                 :  * been cleared by CPLErrorReset().  This is the error class, not the error number.
     488                 :  *
     489                 :  * @return the error type of the last error to occur, or CE_None (0)
     490                 :  * if there are no posted errors.
     491                 :  */
     492                 : 
     493          390231 : CPLErr CPL_STDCALL CPLGetLastErrorType()
     494                 : {
     495          390231 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     496                 : 
     497          390231 :     return psCtx->eLastErrType;
     498                 : }
     499                 : 
     500                 : /**********************************************************************
     501                 :  *                          CPLGetLastErrorMsg()
     502                 :  **********************************************************************/
     503                 : 
     504                 : /**
     505                 :  * Get the last error message.
     506                 :  *
     507                 :  * Fetches the last error message posted with CPLError(), that hasn't
     508                 :  * been cleared by CPLErrorReset().  The returned pointer is to an internal
     509                 :  * string that should not be altered or freed.
     510                 :  *
     511                 :  * @return the last error message, or NULL if there is no posted error
     512                 :  * message.
     513                 :  */
     514                 : 
     515             624 : const char* CPL_STDCALL CPLGetLastErrorMsg()
     516                 : {
     517             624 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     518                 : 
     519             624 :     return psCtx->szLastErrMsg;
     520                 : }
     521                 : 
     522                 : /************************************************************************/
     523                 : /*                       CPLDefaultErrorHandler()                       */
     524                 : /************************************************************************/
     525                 : 
     526             777 : void CPL_STDCALL CPLDefaultErrorHandler( CPLErr eErrClass, int nError, 
     527                 :                              const char * pszErrorMsg )
     528                 : 
     529                 : {
     530                 :     static int       bLogInit = FALSE;
     531             777 :     static FILE *    fpLog = stderr;
     532                 :     static int       nCount = 0;
     533                 :     static int       nMaxErrors = -1;
     534                 : 
     535             777 :     if (eErrClass != CE_Debug)
     536                 :     {
     537             305 :         if( nMaxErrors == -1 )
     538                 :         {
     539                 :             nMaxErrors = 
     540              99 :                 atoi(CPLGetConfigOption( "CPL_MAX_ERROR_REPORTS", "1000" ));
     541                 :         }
     542                 : 
     543             305 :         nCount++;
     544             305 :         if (nCount > nMaxErrors && nMaxErrors > 0 )
     545               0 :             return;
     546                 :     }
     547                 : 
     548             777 :     if( !bLogInit )
     549                 :     {
     550             101 :         bLogInit = TRUE;
     551                 : 
     552             101 :         fpLog = stderr;
     553             101 :         if( CPLGetConfigOption( "CPL_LOG", NULL ) != NULL )
     554                 :         {
     555               0 :             fpLog = fopen( CPLGetConfigOption("CPL_LOG",""), "wt" );
     556               0 :             if( fpLog == NULL )
     557               0 :                 fpLog = stderr;
     558                 :         }
     559                 :     }
     560                 : 
     561             777 :     if( eErrClass == CE_Debug )
     562             472 :         fprintf( fpLog, "%s\n", pszErrorMsg );
     563             305 :     else if( eErrClass == CE_Warning )
     564             156 :         fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
     565                 :     else
     566             149 :         fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
     567                 : 
     568             777 :     if (eErrClass != CE_Debug 
     569                 :         && nMaxErrors > 0 
     570                 :         && nCount == nMaxErrors )
     571                 :     {
     572                 :         fprintf( fpLog, 
     573                 :                  "More than %d errors or warnings have been reported. "
     574                 :                  "No more will be reported from now.\n", 
     575               0 :                  nMaxErrors );
     576                 :     }
     577                 : 
     578             777 :     fflush( fpLog );
     579                 : }
     580                 : 
     581                 : /************************************************************************/
     582                 : /*                        CPLQuietErrorHandler()                        */
     583                 : /************************************************************************/
     584                 : 
     585           18397 : void CPL_STDCALL CPLQuietErrorHandler( CPLErr eErrClass , int nError, 
     586                 :                            const char * pszErrorMsg )
     587                 : 
     588                 : {
     589           18397 :     if( eErrClass == CE_Debug )
     590               4 :         CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg );
     591           18397 : }
     592                 : 
     593                 : /************************************************************************/
     594                 : /*                       CPLLoggingErrorHandler()                       */
     595                 : /************************************************************************/
     596                 : 
     597               0 : void CPL_STDCALL CPLLoggingErrorHandler( CPLErr eErrClass, int nError, 
     598                 :                              const char * pszErrorMsg )
     599                 : 
     600                 : {
     601                 :     static int       bLogInit = FALSE;
     602               0 :     static FILE *    fpLog = stderr;
     603                 : 
     604               0 :     if( !bLogInit )
     605                 :     {
     606               0 :         const char *cpl_log = NULL;
     607                 : 
     608               0 :         CPLSetConfigOption( "CPL_TIMESTAMP", "ON" );
     609                 : 
     610               0 :         bLogInit = TRUE;
     611                 : 
     612               0 :         cpl_log = CPLGetConfigOption("CPL_LOG", NULL );
     613                 : 
     614               0 :         fpLog = stderr;
     615               0 :         if( cpl_log != NULL && EQUAL(cpl_log,"OFF") )
     616                 :         {
     617               0 :             fpLog = NULL;
     618                 :         }
     619               0 :         else if( cpl_log != NULL )
     620                 :         {
     621                 :             char*     pszPath;
     622               0 :             int       i = 0;
     623                 : 
     624               0 :             pszPath = (char*)CPLMalloc(strlen(cpl_log) + 20);
     625               0 :             strcpy(pszPath, cpl_log);
     626                 : 
     627               0 :             while( (fpLog = fopen( pszPath, "rt" )) != NULL ) 
     628                 :             {
     629               0 :                 fclose( fpLog );
     630                 : 
     631                 :                 /* generate sequenced log file names, inserting # before ext.*/
     632               0 :                 if (strrchr(cpl_log, '.') == NULL)
     633                 :                 {
     634                 :                     sprintf( pszPath, "%s_%d%s", cpl_log, i++,
     635               0 :                              ".log" );
     636                 :                 }
     637                 :                 else
     638                 :                 {
     639               0 :                     size_t pos = 0;
     640               0 :                     char *cpl_log_base = strdup(cpl_log);
     641               0 :                     pos = strcspn(cpl_log_base, ".");
     642               0 :                     if (pos > 0)
     643                 :                     {
     644               0 :                         cpl_log_base[pos] = '\0';
     645                 :                     }
     646                 :                     sprintf( pszPath, "%s_%d%s", cpl_log_base,
     647               0 :                              i++, ".log" );
     648               0 :                     free(cpl_log_base);
     649                 :                 }
     650                 :             }
     651                 : 
     652               0 :             fpLog = fopen( pszPath, "wt" );
     653               0 :             CPLFree(pszPath);
     654                 :         }
     655                 :     }
     656                 : 
     657               0 :     if( fpLog == NULL )
     658               0 :         return;
     659                 : 
     660               0 :     if( eErrClass == CE_Debug )
     661               0 :         fprintf( fpLog, "%s\n", pszErrorMsg );
     662               0 :     else if( eErrClass == CE_Warning )
     663               0 :         fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
     664                 :     else
     665               0 :         fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
     666                 : 
     667               0 :     fflush( fpLog );
     668                 : }
     669                 : 
     670                 : /**********************************************************************
     671                 :  *                      CPLTurnFailureIntoWarning()                   *
     672                 :  **********************************************************************/
     673                 : 
     674              40 : void CPLTurnFailureIntoWarning(int bOn )
     675                 : {
     676              40 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     677              40 :     psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
     678              40 :     if (psCtx->nFailureIntoWarning < 0)
     679                 :     {
     680               0 :         CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / CPLTurnFailureIntoWarning(FALSE)");
     681                 :     }
     682              40 : }
     683                 : 
     684                 : /**********************************************************************
     685                 :  *                          CPLSetErrorHandlerEx()                    *
     686                 :  **********************************************************************/
     687                 : 
     688                 : /**
     689                 :  * Install custom error handle with user's data. This method is 
     690                 :  * essentially CPLSetErrorHandler with an added pointer to pUserData.  
     691                 :  * The pUserData is not returned in the CPLErrorHandler, however, and 
     692                 :  * must be fetched via CPLGetLastErrorUserData
     693                 :  *
     694                 :  * @param pfnErrorHandlerNew new error handler function.
     695                 :  * @param pUserData User data to carry along with the error context.
     696                 :  * @return returns the previously installed error handler.
     697                 :  */ 
     698                 : 
     699                 : CPLErrorHandler CPL_STDCALL 
     700              34 : CPLSetErrorHandlerEx( CPLErrorHandler pfnErrorHandlerNew, 
     701                 :                       void* pUserData )
     702                 : {
     703              34 :     CPLErrorHandler     pfnOldHandler = pfnErrorHandler;
     704              34 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     705                 : 
     706              34 :     if( psCtx->psHandlerStack != NULL )
     707                 :     {
     708                 :         CPLDebug( "CPL", 
     709                 :                   "CPLSetErrorHandler() called with an error handler on\n"
     710               0 :                   "the local stack.  New error handler will not be used immediately.\n" );
     711                 :     }
     712                 : 
     713                 : 
     714                 :     {
     715              34 :         CPLMutexHolderD( &hErrorMutex );
     716                 : 
     717              34 :         pfnOldHandler = pfnErrorHandler;
     718                 :         
     719              34 :         if( pfnErrorHandler == NULL )
     720               0 :             pfnErrorHandler = CPLDefaultErrorHandler;
     721                 :         else
     722              34 :             pfnErrorHandler = pfnErrorHandlerNew;
     723                 :             
     724              34 :         pErrorHandlerUserData = pUserData;
     725                 :     }
     726                 : 
     727              34 :     return pfnOldHandler;
     728                 : }
     729                 : 
     730                 : 
     731                 : /**********************************************************************
     732                 :  *                          CPLSetErrorHandler()                      *
     733                 :  **********************************************************************/
     734                 : 
     735                 : /**
     736                 :  * Install custom error handler.
     737                 :  *
     738                 :  * Allow the library's user to specify his own error handler function.
     739                 :  * A valid error handler is a C function with the following prototype:
     740                 :  *
     741                 :  * <pre>
     742                 :  *     void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
     743                 :  * </pre>
     744                 :  *
     745                 :  * Pass NULL to come back to the default behavior.  The default behaviour
     746                 :  * (CPLDefaultErrorHandler()) is to write the message to stderr. 
     747                 :  *
     748                 :  * The msg will be a partially formatted error message not containing the
     749                 :  * "ERROR %d:" portion emitted by the default handler.  Message formatting
     750                 :  * is handled by CPLError() before calling the handler.  If the error
     751                 :  * handler function is passed a CE_Fatal class error and returns, then
     752                 :  * CPLError() will call abort(). Applications wanting to interrupt this
     753                 :  * fatal behaviour will have to use longjmp(), or a C++ exception to
     754                 :  * indirectly exit the function.
     755                 :  *
     756                 :  * Another standard error handler is CPLQuietErrorHandler() which doesn't
     757                 :  * make any attempt to report the passed error or warning messages but
     758                 :  * will process debug messages via CPLDefaultErrorHandler.
     759                 :  *
     760                 :  * Note that error handlers set with CPLSetErrorHandler() apply to all
     761                 :  * threads in an application, while error handlers set with CPLPushErrorHandler
     762                 :  * are thread-local.  However, any error handlers pushed with 
     763                 :  * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take 
     764                 :  * precidence over the global error handlers set with CPLSetErrorHandler(). 
     765                 :  * Generally speaking CPLSetErrorHandler() would be used to set a desired
     766                 :  * global error handler, while CPLPushErrorHandler() would be used to install
     767                 :  * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
     768                 :  * error reporting in a limited segment of code. 
     769                 :  *
     770                 :  * @param pfnErrorHandlerNew new error handler function.
     771                 :  * @return returns the previously installed error handler.
     772                 :  */ 
     773                 : CPLErrorHandler CPL_STDCALL 
     774              34 : CPLSetErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
     775                 : {
     776              34 :     return CPLSetErrorHandlerEx(pfnErrorHandlerNew, NULL);
     777                 : }
     778                 : 
     779                 : /************************************************************************/
     780                 : /*                        CPLPushErrorHandler()                         */
     781                 : /************************************************************************/
     782                 : 
     783                 : /**
     784                 :  * Push a new CPLError handler.
     785                 :  *
     786                 :  * This pushes a new error handler on the thread-local error handler
     787                 :  * stack.  This handler will be used until removed with CPLPopErrorHandler().
     788                 :  *
     789                 :  * The CPLSetErrorHandler() docs have further information on how 
     790                 :  * CPLError handlers work.
     791                 :  *
     792                 :  * @param pfnErrorHandlerNew new error handler function.
     793                 :  */
     794                 : 
     795           23522 : void CPL_STDCALL CPLPushErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
     796                 : 
     797                 : {
     798           23522 :     CPLPushErrorHandlerEx(pfnErrorHandlerNew, NULL);
     799           23522 : }
     800                 : 
     801                 : 
     802                 : /************************************************************************/
     803                 : /*                        CPLPushErrorHandlerEx()                       */
     804                 : /************************************************************************/
     805                 : 
     806                 : /**
     807                 :  * Push a new CPLError handler with user data on the error context.
     808                 :  *
     809                 :  * This pushes a new error handler on the thread-local error handler
     810                 :  * stack.  This handler will be used until removed with CPLPopErrorHandler(). 
     811                 :  * Obtain the user data back by using CPLGetErrorContext().
     812                 :  *
     813                 :  * The CPLSetErrorHandler() docs have further information on how 
     814                 :  * CPLError handlers work.
     815                 :  *
     816                 :  * @param pfnErrorHandlerNew new error handler function.
     817                 :  * @param pUserData User data to put on the error context. 
     818                 :  */
     819           24749 : void CPL_STDCALL CPLPushErrorHandlerEx( CPLErrorHandler pfnErrorHandlerNew, 
     820                 :                                         void* pUserData )
     821                 : 
     822                 : {
     823           24749 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     824                 :     CPLErrorHandlerNode         *psNode;
     825                 : 
     826           24749 :     psNode = (CPLErrorHandlerNode *) CPLMalloc(sizeof(CPLErrorHandlerNode));
     827           24749 :     psNode->psNext = psCtx->psHandlerStack;
     828           24749 :     psNode->pfnHandler = pfnErrorHandlerNew;
     829           24749 :     psNode->pUserData = pUserData;
     830           24749 :     psCtx->psHandlerStack = psNode;
     831           24749 : }
     832                 : 
     833                 : /************************************************************************/
     834                 : /*                         CPLPopErrorHandler()                         */
     835                 : /************************************************************************/
     836                 : 
     837                 : /**
     838                 :  * Pop error handler off stack.
     839                 :  *
     840                 :  * Discards the current error handler on the error handler stack, and restores 
     841                 :  * the one in use before the last CPLPushErrorHandler() call.  This method
     842                 :  * has no effect if there are no error handlers on the current threads error
     843                 :  * handler stack. 
     844                 :  */ 
     845                 : 
     846           24749 : void CPL_STDCALL CPLPopErrorHandler()
     847                 : 
     848                 : {
     849           24749 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     850                 : 
     851           24749 :     if( psCtx->psHandlerStack != NULL )
     852                 :     {
     853           24749 :         CPLErrorHandlerNode     *psNode = psCtx->psHandlerStack;
     854                 : 
     855           24749 :         psCtx->psHandlerStack = psNode->psNext;
     856           24749 :         VSIFree( psNode );
     857                 :     }
     858           24749 : }
     859                 : 
     860                 : /************************************************************************/
     861                 : /*                             _CPLAssert()                             */
     862                 : /*                                                                      */
     863                 : /*      This function is called only when an assertion fails.           */
     864                 : /************************************************************************/
     865                 : 
     866                 : /**
     867                 :  * Report failure of a logical assertion.
     868                 :  *
     869                 :  * Applications would normally use the CPLAssert() macro which expands
     870                 :  * into code calling _CPLAssert() only if the condition fails.  _CPLAssert()
     871                 :  * will generate a CE_Fatal error call to CPLError(), indicating the file
     872                 :  * name, and line number of the failed assertion, as well as containing
     873                 :  * the assertion itself.
     874                 :  *
     875                 :  * There is no reason for application code to call _CPLAssert() directly.
     876                 :  */
     877                 : 
     878               0 : void CPL_STDCALL _CPLAssert( const char * pszExpression, const char * pszFile,
     879                 :                  int iLine )
     880                 : 
     881                 : {
     882                 :     CPLError( CE_Fatal, CPLE_AssertionFailed,
     883                 :               "Assertion `%s' failed\n"
     884                 :               "in file `%s', line %d\n",
     885               0 :               pszExpression, pszFile, iLine );
     886               0 : }
     887                 : 
     888                 : 
     889                 : /************************************************************************/
     890                 : /*                       CPLCleanupErrorMutex()                         */
     891                 : /************************************************************************/
     892                 : 
     893             550 : void CPLCleanupErrorMutex()
     894                 : {
     895             550 :     if( hErrorMutex != NULL )
     896                 :     {
     897              92 :         CPLDestroyMutex(hErrorMutex);
     898              92 :         hErrorMutex = NULL;
     899                 :     }
     900             550 : }

Generated by: LCOV version 1.7