LCOV - code coverage report
Current view: top level - port - cpl_error.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 311 444 70.0 %
Date: 2024-11-21 22:18:42 Functions: 34 38 89.5 %

          Line data    Source code
       1             : 
       2             : /**********************************************************************
       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             :  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "cpl_error.h"
      17             : 
      18             : #include <cstdarg>
      19             : #include <cstdio>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : 
      23             : #include <algorithm>
      24             : 
      25             : #include "cpl_config.h"
      26             : #include "cpl_conv.h"
      27             : #include "cpl_multiproc.h"
      28             : #include "cpl_string.h"
      29             : #include "cpl_vsi.h"
      30             : #include "cpl_error_internal.h"
      31             : 
      32             : #if !defined(va_copy) && defined(__va_copy)
      33             : #define va_copy __va_copy
      34             : #endif
      35             : 
      36             : #define TIMESTAMP_DEBUG
      37             : // #define MEMORY_DEBUG
      38             : 
      39             : static CPLMutex *hErrorMutex = nullptr;
      40             : static void *pErrorHandlerUserData = nullptr;
      41             : static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
      42             : static bool gbCatchDebug = true;
      43             : 
      44             : constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
      45             : #if !defined(HAVE_VSNPRINTF)
      46             :     20000
      47             : #else
      48             :     500
      49             : #endif
      50             :     ;
      51             : 
      52             : typedef struct errHandler
      53             : {
      54             :     struct errHandler *psNext;
      55             :     void *pUserData;
      56             :     CPLErrorHandler pfnHandler;
      57             :     bool bCatchDebug;
      58             : } CPLErrorHandlerNode;
      59             : 
      60             : typedef struct
      61             : {
      62             :     CPLErrorNum nLastErrNo;
      63             :     CPLErr eLastErrType;
      64             :     CPLErrorHandlerNode *psHandlerStack;
      65             :     int nLastErrMsgMax;
      66             :     int nFailureIntoWarning;
      67             :     bool bProgressMode;
      68             :     bool bEmitNewlineBeforeNextDbgMsg;
      69             :     GUInt32 nErrorCounter;
      70             :     char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
      71             :     // Do not add anything here. szLastErrMsg must be the last field.
      72             :     // See CPLRealloc() below.
      73             : } CPLErrorContext;
      74             : 
      75             : constexpr CPLErrorContext sNoErrorContext = {0,     CE_None, nullptr, 0, 0,
      76             :                                              false, false,   0,       ""};
      77             : 
      78             : constexpr CPLErrorContext sWarningContext = {
      79             :     0, CE_Warning, nullptr, 0, 0, false, false, 0, "A warning was emitted"};
      80             : 
      81             : constexpr CPLErrorContext sFailureContext = {
      82             :     0, CE_Warning, nullptr, 0, 0, false, false, 0, "A failure was emitted"};
      83             : 
      84             : #define IS_PREFEFINED_ERROR_CTX(psCtxt)                                        \
      85             :     (psCtx == &sNoErrorContext || psCtx == &sWarningContext ||                 \
      86             :      psCtxt == &sFailureContext)
      87             : 
      88             : /************************************************************************/
      89             : /*                     CPLErrorContextGetString()                       */
      90             : /************************************************************************/
      91             : 
      92             : // Makes clang -fsanitize=undefined happy since it doesn't like
      93             : // dereferencing szLastErrMsg[i>=DEFAULT_LAST_ERR_MSG_SIZE]
      94             : 
      95      579321 : static char *CPLErrorContextGetString(CPLErrorContext *psCtxt)
      96             : {
      97      579321 :     return psCtxt->szLastErrMsg;
      98             : }
      99             : 
     100             : /************************************************************************/
     101             : /*                         CPLGetErrorContext()                         */
     102             : /************************************************************************/
     103             : 
     104    47087300 : static CPLErrorContext *CPLGetErrorContext()
     105             : 
     106             : {
     107    47087300 :     int bError = FALSE;
     108             :     CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
     109    47087300 :         CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
     110    47083200 :     if (bError)
     111           0 :         return nullptr;
     112             : 
     113    47083200 :     if (psCtx == nullptr)
     114             :     {
     115             :         psCtx = static_cast<CPLErrorContext *>(
     116        2880 :             VSICalloc(sizeof(CPLErrorContext), 1));
     117        2881 :         if (psCtx == nullptr)
     118             :         {
     119           0 :             fprintf(stderr, "Out of memory attempting to report error.\n");
     120           0 :             return nullptr;
     121             :         }
     122        2881 :         psCtx->eLastErrType = CE_None;
     123        2881 :         psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
     124        2881 :         CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
     125             :     }
     126             : 
     127    47083100 :     return psCtx;
     128             : }
     129             : 
     130             : /************************************************************************/
     131             : /*                         CPLGetErrorHandlerUserData()                 */
     132             : /************************************************************************/
     133             : 
     134             : /**
     135             :  * Fetch the user data for the error context
     136             :  *
     137             :  * Fetches the user data for the current error context.  You can
     138             :  * set the user data for the error context when you add your handler by
     139             :  * issuing CPLSetErrorHandlerEx() and CPLPushErrorHandlerEx().  Note that
     140             :  * user data is primarily intended for providing context within error handlers
     141             :  * themselves, but they could potentially be abused in other useful ways with
     142             :  * the usual caveat emptor understanding.
     143             :  *
     144             :  * @return the user data pointer for the error context
     145             :  */
     146             : 
     147     5909300 : void *CPL_STDCALL CPLGetErrorHandlerUserData(void)
     148             : {
     149             :     // get the current threadlocal or global error context user data
     150     5909300 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     151     5909300 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
     152           0 :         abort();
     153     5909300 :     return reinterpret_cast<void *>(psCtx->psHandlerStack
     154     5909300 :                                         ? psCtx->psHandlerStack->pUserData
     155     5909300 :                                         : pErrorHandlerUserData);
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                         CPLGetErrorHandler()                         */
     160             : /************************************************************************/
     161             : 
     162             : /**
     163             :  * Fetch the current error handler for the current error context.
     164             :  *
     165             :  * This will be the last error handler pushed in the thread-local error stack
     166             :  * with CPLPushErrorHandler()/CPLPushErrorHandlerEx(), or if the stack is
     167             :  * empty, the global error handler set with
     168             :  * CPLSetErrorHandler()/CPLSetErrorHandlerEx(), or the default global error
     169             :  * handler.
     170             :  *
     171             :  * @param[out] ppUserData Pointer to store the user data pointer. May be NULL
     172             :  * @since GDAL 3.7
     173             :  */
     174             : 
     175           0 : CPLErrorHandler CPLGetErrorHandler(void **ppUserData)
     176             : {
     177           0 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     178             : 
     179           0 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
     180             :     {
     181           0 :         fprintf(stderr, "CPLGetErrorHandler() failed.\n");
     182           0 :         if (ppUserData)
     183           0 :             *ppUserData = nullptr;
     184           0 :         return CPLDefaultErrorHandler;
     185             :     }
     186             : 
     187           0 :     if (psCtx->psHandlerStack != nullptr)
     188             :     {
     189           0 :         if (ppUserData)
     190           0 :             *ppUserData = psCtx->psHandlerStack->pUserData;
     191           0 :         return psCtx->psHandlerStack->pfnHandler;
     192             :     }
     193             : 
     194           0 :     CPLMutexHolderD(&hErrorMutex);
     195           0 :     if (ppUserData)
     196           0 :         *ppUserData = pErrorHandlerUserData;
     197           0 :     return pfnErrorHandler;
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                          ApplyErrorHandler()                         */
     202             : /************************************************************************/
     203             : 
     204       98164 : static void ApplyErrorHandler(CPLErrorContext *psCtx, CPLErr eErrClass,
     205             :                               CPLErrorNum err_no, const char *pszMessage)
     206             : {
     207       98164 :     bool bProcessed = false;
     208             : 
     209       98164 :     if (psCtx->psHandlerStack != nullptr)
     210             :     {
     211             :         // iterate through the threadlocal handler stack
     212       58707 :         if ((eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug)
     213             :         {
     214             :             // call the error handler
     215       58648 :             CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
     216       58648 :             psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
     217       58648 :             if (psNewCurNode != psCtx->psHandlerStack)
     218             :             {
     219           0 :                 fprintf(stderr, "ApplyErrorHandler() has detected that a "
     220             :                                 "previous error handler messed up with the "
     221             :                                 "error stack. Chaos guaranteed!\n");
     222             :             }
     223       58646 :             bProcessed = true;
     224             :         }
     225             :         else
     226             :         {
     227             :             // need to iterate to a parent handler for debug messages
     228          59 :             CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
     229          59 :             while (psNode != nullptr)
     230             :             {
     231          58 :                 if (psNode->bCatchDebug)
     232             :                 {
     233          58 :                     CPLErrorHandlerNode *psBackupCurNode =
     234             :                         psCtx->psHandlerStack;
     235          58 :                     psCtx->psHandlerStack = psNode;
     236          58 :                     CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
     237          58 :                     psNode->pfnHandler(eErrClass, err_no, pszMessage);
     238             :                     // cppcheck-suppress knownConditionTrueFalse
     239          58 :                     if (psNewCurNode != psCtx->psHandlerStack)
     240             :                     {
     241           0 :                         fprintf(stderr,
     242             :                                 "ApplyErrorHandler() has detected that a "
     243             :                                 "previous error handler messed up with the "
     244             :                                 "error stack. Chaos guaranteed!\n");
     245             :                     }
     246          58 :                     psCtx->psHandlerStack = psBackupCurNode;
     247          58 :                     bProcessed = true;
     248          58 :                     break;
     249             :                 }
     250           0 :                 psNode = psNode->psNext;
     251             :             }
     252             :         }
     253             :     }
     254             : 
     255       98162 :     if (!bProcessed)
     256             :     {
     257             :         // hit the global error handler
     258       78916 :         CPLMutexHolderD(&hErrorMutex);
     259       39458 :         if ((eErrClass != CE_Debug) || gbCatchDebug)
     260             :         {
     261       39456 :             if (pfnErrorHandler != nullptr)
     262             :             {
     263       39454 :                 pfnErrorHandler(eErrClass, err_no, pszMessage);
     264             :             }
     265             :         }
     266             :         else /* if( eErrClass == CE_Debug ) */
     267             :         {
     268             :             // for CPLDebug messages we propagate to the default error handler
     269           2 :             CPLDefaultErrorHandler(eErrClass, err_no, pszMessage);
     270             :         }
     271             :     }
     272       98162 : }
     273             : 
     274             : /**********************************************************************
     275             :  *                          CPLError()
     276             :  **********************************************************************/
     277             : 
     278             : /**
     279             :  * Report an error.
     280             :  *
     281             :  * This function reports an error in a manner that can be hooked
     282             :  * and reported appropriate by different applications.
     283             :  *
     284             :  * The effect of this function can be altered by applications by installing
     285             :  * a custom error handling using CPLSetErrorHandler().
     286             :  *
     287             :  * The eErrClass argument can have the value CE_Warning indicating that the
     288             :  * message is an informational warning, CE_Failure indicating that the
     289             :  * action failed, but that normal recover mechanisms will be used or
     290             :  * CE_Fatal meaning that a fatal error has occurred, and that CPLError()
     291             :  * should not return.
     292             :  *
     293             :  * The default behavior of CPLError() is to report errors to stderr,
     294             :  * and to abort() after reporting a CE_Fatal error.  It is expected that
     295             :  * some applications will want to suppress error reporting, and will want to
     296             :  * install a C++ exception, or longjmp() approach to no local fatal error
     297             :  * recovery.
     298             :  *
     299             :  * Regardless of how application error handlers or the default error
     300             :  * handler choose to handle an error, the error number, and message will
     301             :  * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
     302             :  *
     303             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
     304             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
     305             :  * @param fmt a printf() style format string.  Any additional arguments
     306             :  * will be treated as arguments to fill in this format in a manner
     307             :  * similar to printf().
     308             :  */
     309             : 
     310       96507 : void CPLError(CPLErr eErrClass, CPLErrorNum err_no,
     311             :               CPL_FORMAT_STRING(const char *fmt), ...)
     312             : {
     313             :     va_list args;
     314             : 
     315             :     // Expand the error message.
     316       96507 :     va_start(args, fmt);
     317       96507 :     CPLErrorV(eErrClass, err_no, fmt, args);
     318       96527 :     va_end(args);
     319       96527 : }
     320             : 
     321             : /************************************************************************/
     322             : /*                             CPLErrorV()                              */
     323             : /************************************************************************/
     324             : 
     325             : /** Same as CPLError() but with a va_list */
     326       97409 : void CPLErrorV(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
     327             :                va_list args)
     328             : {
     329       97409 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     330       97381 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
     331             :     {
     332           7 :         int bMemoryError = FALSE;
     333           7 :         if (eErrClass == CE_Warning)
     334             :         {
     335           0 :             CPLSetTLSWithFreeFuncEx(
     336             :                 CTLS_ERRORCONTEXT,
     337             :                 reinterpret_cast<void *>(
     338             :                     const_cast<CPLErrorContext *>(&sWarningContext)),
     339             :                 nullptr, &bMemoryError);
     340             :         }
     341           7 :         else if (eErrClass == CE_Failure)
     342             :         {
     343           0 :             CPLSetTLSWithFreeFuncEx(
     344             :                 CTLS_ERRORCONTEXT,
     345             :                 reinterpret_cast<void *>(
     346             :                     const_cast<CPLErrorContext *>(&sFailureContext)),
     347             :                 nullptr, &bMemoryError);
     348             :         }
     349             : 
     350             :         // TODO: Is it possible to move the entire szShortMessage under the if
     351             :         // pfnErrorHandler?
     352           7 :         char szShortMessage[80] = {};
     353           7 :         CPLvsnprintf(szShortMessage, sizeof(szShortMessage), fmt, args);
     354             : 
     355           0 :         CPLMutexHolderD(&hErrorMutex);
     356           0 :         if (pfnErrorHandler != nullptr)
     357           0 :             pfnErrorHandler(eErrClass, err_no, szShortMessage);
     358           0 :         return;
     359             :     }
     360             : 
     361       97374 :     if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
     362           2 :         eErrClass = CE_Warning;
     363             : 
     364             : /* -------------------------------------------------------------------- */
     365             : /*      Expand the error message                                        */
     366             : /* -------------------------------------------------------------------- */
     367             : #if defined(HAVE_VSNPRINTF)
     368             :     {
     369             :         va_list wrk_args;
     370             : 
     371             : #ifdef va_copy
     372       97374 :         va_copy(wrk_args, args);
     373             : #else
     374             :         wrk_args = args;
     375             : #endif
     376             : 
     377             :         /* --------------------------------------------------------------------
     378             :          */
     379             :         /*      If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages, */
     380             :         /*      rather than just replacing the last error message. */
     381             :         /* --------------------------------------------------------------------
     382             :          */
     383       97374 :         int nPreviousSize = 0;
     384      155958 :         if (psCtx->psHandlerStack != nullptr &&
     385       58503 :             EQUAL(CPLGetConfigOption("CPL_ACCUM_ERROR_MSG", ""), "ON"))
     386             :         {
     387           0 :             nPreviousSize = static_cast<int>(strlen(psCtx->szLastErrMsg));
     388           0 :             if (nPreviousSize)
     389             :             {
     390           0 :                 if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
     391             :                 {
     392           0 :                     psCtx->nLastErrMsgMax *= 3;
     393             :                     psCtx = static_cast<CPLErrorContext *>(
     394           0 :                         CPLRealloc(psCtx, sizeof(CPLErrorContext) -
     395             :                                               DEFAULT_LAST_ERR_MSG_SIZE +
     396           0 :                                               psCtx->nLastErrMsgMax + 1));
     397           0 :                     CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
     398             :                 }
     399           0 :                 char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
     400           0 :                 pszLastErrMsg[nPreviousSize] = '\n';
     401           0 :                 pszLastErrMsg[nPreviousSize + 1] = '\0';
     402           0 :                 nPreviousSize++;
     403             :             }
     404             :         }
     405             : 
     406       97455 :         int nPR = 0;
     407          13 :         while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
     408       97468 :                                     psCtx->nLastErrMsgMax - nPreviousSize, fmt,
     409       97365 :                                     wrk_args)) == -1 ||
     410       97454 :                 nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
     411          51 :                psCtx->nLastErrMsgMax < 1000000)
     412             :         {
     413             : #ifdef va_copy
     414          13 :             va_end(wrk_args);
     415          13 :             va_copy(wrk_args, args);
     416             : #else
     417             :             wrk_args = args;
     418             : #endif
     419          13 :             psCtx->nLastErrMsgMax *= 3;
     420          26 :             psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
     421             :                 psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
     422          13 :                            psCtx->nLastErrMsgMax + 1));
     423          13 :             CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
     424             :         }
     425             : 
     426       97390 :         va_end(wrk_args);
     427             :     }
     428             : #else
     429             :     // !HAVE_VSNPRINTF
     430             :     CPLvsnprintf(psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
     431             : #endif
     432             : 
     433             :     /* -------------------------------------------------------------------- */
     434             :     /*      Obfuscate any password in error message                         */
     435             :     /* -------------------------------------------------------------------- */
     436       97390 :     char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
     437       97390 :     if (pszPassword != nullptr)
     438             :     {
     439           0 :         char *pszIter = pszPassword + strlen("password=");
     440           0 :         while (*pszIter != ' ' && *pszIter != '\0')
     441             :         {
     442           0 :             *pszIter = 'X';
     443           0 :             pszIter++;
     444             :         }
     445             :     }
     446             : 
     447             :     /* -------------------------------------------------------------------- */
     448             :     /*      If the user provided an handling function, then                 */
     449             :     /*      call it, otherwise print the error to stderr and return.        */
     450             :     /* -------------------------------------------------------------------- */
     451       97390 :     psCtx->nLastErrNo = err_no;
     452       97390 :     psCtx->eLastErrType = eErrClass;
     453       97390 :     if (psCtx->nErrorCounter == ~(0U))
     454           0 :         psCtx->nErrorCounter = 0;
     455             :     else
     456       97390 :         psCtx->nErrorCounter++;
     457             : 
     458       97390 :     if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
     459           0 :         CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
     460             : 
     461             :     /* -------------------------------------------------------------------- */
     462             :     /*      Invoke the current error handler.                               */
     463             :     /* -------------------------------------------------------------------- */
     464       97433 :     ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
     465             : 
     466       97432 :     if (eErrClass == CE_Fatal)
     467           0 :         abort();
     468             : }
     469             : 
     470             : /************************************************************************/
     471             : /*                         CPLEmergencyError()                          */
     472             : /************************************************************************/
     473             : 
     474             : /**
     475             :  * Fatal error when things are bad.
     476             :  *
     477             :  * This function should be called in an emergency situation where
     478             :  * it is unlikely that a regular error report would work.  This would
     479             :  * include in the case of heap exhaustion for even small allocations,
     480             :  * or any failure in the process of reporting an error (such as TLS
     481             :  * allocations).
     482             :  *
     483             :  * This function should never return.  After the error message has been
     484             :  * reported as best possible, the application will abort() similarly to how
     485             :  * CPLError() aborts on CE_Fatal class errors.
     486             :  *
     487             :  * @param pszMessage the error message to report.
     488             :  */
     489             : 
     490           0 : void CPLEmergencyError(const char *pszMessage)
     491             : {
     492             :     static bool bInEmergencyError = false;
     493             : 
     494             :     // If we are already in emergency error then one of the
     495             :     // following failed, so avoid them the second time through.
     496           0 :     if (!bInEmergencyError)
     497             :     {
     498           0 :         bInEmergencyError = true;
     499             :         CPLErrorContext *psCtx =
     500           0 :             static_cast<CPLErrorContext *>(CPLGetTLS(CTLS_ERRORCONTEXT));
     501             : 
     502           0 :         ApplyErrorHandler(psCtx, CE_Fatal, CPLE_AppDefined, pszMessage);
     503             :     }
     504             : 
     505             :     // Ultimate fallback.
     506           0 :     fprintf(stderr, "FATAL: %s\n", pszMessage);
     507             : 
     508           0 :     abort();
     509             : }
     510             : 
     511             : /************************************************************************/
     512             : /*                    CPLGetProcessMemorySize()                         */
     513             : /************************************************************************/
     514             : 
     515             : #ifdef MEMORY_DEBUG
     516             : 
     517             : #ifdef __linux
     518             : static int CPLGetProcessMemorySize()
     519             : {
     520             :     FILE *fp = fopen("/proc/self/status", "r");
     521             :     if (fp == nullptr)
     522             :         return -1;
     523             :     int nRet = -1;
     524             :     char szLine[128] = {};
     525             :     while (fgets(szLine, sizeof(szLine), fp) != nullptr)
     526             :     {
     527             :         if (STARTS_WITH(szLine, "VmSize:"))
     528             :         {
     529             :             const char *pszPtr = szLine;
     530             :             while (!(*pszPtr == '\0' || (*pszPtr >= '0' && *pszPtr <= '9')))
     531             :                 pszPtr++;
     532             :             nRet = atoi(pszPtr);
     533             :             break;
     534             :         }
     535             :     }
     536             :     fclose(fp);
     537             :     return nRet;
     538             : }
     539             : #else
     540             : #error CPLGetProcessMemorySize() unimplemented for this OS
     541             : #endif
     542             : 
     543             : #endif  // def MEMORY_DEBUG
     544             : 
     545             : /************************************************************************/
     546             : /*                        CPLGettimeofday()                             */
     547             : /************************************************************************/
     548             : 
     549             : #if defined(_WIN32) && !defined(__CYGWIN__)
     550             : #include <sys/timeb.h>
     551             : 
     552             : namespace
     553             : {
     554             : struct CPLTimeVal
     555             : {
     556             :     time_t tv_sec; /* seconds */
     557             :     long tv_usec;  /* and microseconds */
     558             : };
     559             : }  // namespace
     560             : 
     561             : static int CPLGettimeofday(struct CPLTimeVal *tp, void * /* timezonep*/)
     562             : {
     563             :     struct _timeb theTime;
     564             : 
     565             :     _ftime(&theTime);
     566             :     tp->tv_sec = static_cast<time_t>(theTime.time);
     567             :     tp->tv_usec = theTime.millitm * 1000;
     568             :     return 0;
     569             : }
     570             : #else
     571             : #include <sys/time.h> /* for gettimeofday() */
     572             : #define CPLTimeVal timeval
     573             : #define CPLGettimeofday(t, u) gettimeofday(t, u)
     574             : #endif
     575             : 
     576             : #ifndef WITHOUT_CPLDEBUG
     577             : 
     578             : /************************************************************************/
     579             : /*                             CPLvDebug()                              */
     580             : /************************************************************************/
     581             : 
     582      621663 : static void CPLvDebug(const char *pszCategory,
     583             :                       CPL_FORMAT_STRING(const char *pszFormat), va_list args)
     584             : {
     585      621663 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     586      621629 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
     587           2 :         return;
     588      621627 :     const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
     589             : 
     590             :     /* -------------------------------------------------------------------- */
     591             :     /*      Does this message pass our current criteria?                    */
     592             :     /* -------------------------------------------------------------------- */
     593      621778 :     if (pszDebug == nullptr || EQUAL(pszDebug, "NO") ||
     594         814 :         EQUAL(pszDebug, "OFF") || EQUAL(pszDebug, "FALSE") ||
     595         795 :         EQUAL(pszDebug, "0"))
     596             :     {
     597      620984 :         return;
     598             :     }
     599             : 
     600         794 :     if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "YES") &&
     601         112 :         !EQUAL(pszDebug, "TRUE") && !EQUAL(pszDebug, "1") &&
     602         106 :         !EQUAL(pszDebug, ""))
     603             :     {
     604             :         // check if value of CPL_DEBUG contains the category
     605         105 :         const size_t nLen = strlen(pszCategory);
     606             : 
     607         105 :         size_t i = 0;
     608         759 :         for (i = 0; pszDebug[i] != '\0'; i++)
     609             :         {
     610         696 :             if (EQUALN(pszCategory, pszDebug + i, nLen))
     611          42 :                 break;
     612             :         }
     613             : 
     614         105 :         if (pszDebug[i] == '\0')
     615          63 :             return;
     616             :     }
     617             : 
     618             :     /* -------------------------------------------------------------------- */
     619             :     /*    Allocate a block for the error.                                   */
     620             :     /* -------------------------------------------------------------------- */
     621         731 :     const int ERROR_MAX = 25000;
     622         731 :     char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
     623         731 :     if (pszMessage == nullptr)
     624           0 :         return;
     625             : 
     626             :     /* -------------------------------------------------------------------- */
     627             :     /*      Dal -- always log a timestamp as the first part of the line     */
     628             :     /*      to ensure one is looking at what one should be looking at!      */
     629             :     /* -------------------------------------------------------------------- */
     630             : 
     631         731 :     pszMessage[0] = '\0';
     632             : #ifdef TIMESTAMP_DEBUG
     633         731 :     if (CPLTestBool(CPLGetConfigOption("CPL_TIMESTAMP", "NO")))
     634             :     {
     635             :         static struct CPLTimeVal tvStart;
     636           4 :         static const auto unused = CPLGettimeofday(&tvStart, nullptr);
     637           4 :         CPL_IGNORE_RET_VAL(unused);
     638             :         struct CPLTimeVal tv;
     639           4 :         CPLGettimeofday(&tv, nullptr);
     640           4 :         strcpy(pszMessage, "[");
     641           4 :         strcat(pszMessage, VSICTime(static_cast<unsigned long>(tv.tv_sec)));
     642             : 
     643             :         // On windows anyway, ctime puts a \n at the end, but I'm not
     644             :         // convinced this is standard behavior, so we'll get rid of it
     645             :         // carefully
     646             : 
     647           4 :         if (pszMessage[strlen(pszMessage) - 1] == '\n')
     648             :         {
     649           4 :             pszMessage[strlen(pszMessage) - 1] = 0;  // blow it out
     650             :         }
     651           4 :         CPLsnprintf(pszMessage + strlen(pszMessage),
     652           4 :                     ERROR_MAX - strlen(pszMessage),
     653           4 :                     "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
     654           4 :                     tv.tv_sec + tv.tv_usec * 1e-6 -
     655           4 :                         (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
     656             :     }
     657             : #endif
     658             : 
     659             : /* -------------------------------------------------------------------- */
     660             : /*      Add the process memory size.                                    */
     661             : /* -------------------------------------------------------------------- */
     662             : #ifdef MEMORY_DEBUG
     663             :     char szVmSize[32] = {};
     664             :     CPLsprintf(szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
     665             :     strcat(pszMessage, szVmSize);
     666             : #endif
     667             : 
     668             :     /* -------------------------------------------------------------------- */
     669             :     /*      Add the category.                                               */
     670             :     /* -------------------------------------------------------------------- */
     671         731 :     strcat(pszMessage, pszCategory);
     672         731 :     strcat(pszMessage, ": ");
     673             : 
     674             :     /* -------------------------------------------------------------------- */
     675             :     /*      Format the application provided portion of the debug message.   */
     676             :     /* -------------------------------------------------------------------- */
     677         731 :     CPLvsnprintf(pszMessage + strlen(pszMessage),
     678         731 :                  ERROR_MAX - strlen(pszMessage), pszFormat, args);
     679             : 
     680             :     /* -------------------------------------------------------------------- */
     681             :     /*      Obfuscate any password in error message                         */
     682             :     /* -------------------------------------------------------------------- */
     683             : 
     684         731 :     char *pszPassword = strstr(pszMessage, "password=");
     685         731 :     if (pszPassword != nullptr)
     686             :     {
     687           0 :         char *pszIter = pszPassword + strlen("password=");
     688           0 :         while (*pszIter != ' ' && *pszIter != '\0')
     689             :         {
     690           0 :             *pszIter = 'X';
     691           0 :             pszIter++;
     692             :         }
     693             :     }
     694             : 
     695             :     /* -------------------------------------------------------------------- */
     696             :     /*      Invoke the current error handler.                               */
     697             :     /* -------------------------------------------------------------------- */
     698         731 :     ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
     699             : 
     700         731 :     VSIFree(pszMessage);
     701             : }
     702             : 
     703             : #endif  // !WITHOUT_CPLDEBUG
     704             : 
     705             : /************************************************************************/
     706             : /*                              CPLDebug()                              */
     707             : /************************************************************************/
     708             : 
     709             : /**
     710             :  * Display a debugging message.
     711             :  *
     712             :  * The category argument is used in conjunction with the CPL_DEBUG
     713             :  * environment variable to establish if the message should be displayed.
     714             :  * If the CPL_DEBUG environment variable is not set, no debug messages
     715             :  * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
     716             :  * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
     717             :  * debug messages are shown.  Otherwise only messages whose category appears
     718             :  * somewhere within the CPL_DEBUG value are displayed (as determined by
     719             :  * strstr()).
     720             :  *
     721             :  * Categories are usually an identifier for the subsystem producing the
     722             :  * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
     723             :  * for messages from the TIFF translator.
     724             :  *
     725             :  * @param pszCategory name of the debugging message category.
     726             :  * @param pszFormat printf() style format string for message to display.
     727             :  *        Remaining arguments are assumed to be for format.
     728             :  */
     729             : 
     730             : #ifdef WITHOUT_CPLDEBUG
     731             : // Do not include CPLDebug.  Only available in custom builds.
     732             : #else
     733             : 
     734      621724 : void CPLDebug(const char *pszCategory, CPL_FORMAT_STRING(const char *pszFormat),
     735             :               ...)
     736             : 
     737             : {
     738             :     va_list args;
     739      621724 :     va_start(args, pszFormat);
     740      621724 :     CPLvDebug(pszCategory, pszFormat, args);
     741      621776 :     va_end(args);
     742      621776 : }
     743             : 
     744             : #endif  // WITHOUT_CPLDEBUG
     745             : 
     746             : /************************************************************************/
     747             : /*                         CPLDebugProgress()                           */
     748             : /************************************************************************/
     749             : 
     750             : /**
     751             :  * Display a debugging message indicating a progression.
     752             :  *
     753             :  * This is the same as CPLDebug(), except that when displaying on the terminal,
     754             :  * it will erase the previous debug progress message. This is for example
     755             :  * appropriate to display increasing percentages for a task.
     756             :  *
     757             :  * The category argument is used in conjunction with the CPL_DEBUG
     758             :  * environment variable to establish if the message should be displayed.
     759             :  * If the CPL_DEBUG environment variable is not set, no debug messages
     760             :  * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
     761             :  * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
     762             :  * debug messages are shown.  Otherwise only messages whose category appears
     763             :  * somewhere within the CPL_DEBUG value are displayed (as determined by
     764             :  * strstr()).
     765             :  *
     766             :  * Categories are usually an identifier for the subsystem producing the
     767             :  * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
     768             :  * for messages from the TIFF translator.
     769             :  *
     770             :  * @param pszCategory name of the debugging message category.
     771             :  * @param pszFormat printf() style format string for message to display.
     772             :  *        Remaining arguments are assumed to be for format.
     773             :  * @since 3.9
     774             :  */
     775             : 
     776             : #ifdef WITHOUT_CPLDEBUG
     777             : // Do not include CPLDebugProgress. Only available in custom builds.
     778             : #else
     779           2 : void CPLDebugProgress(const char *pszCategory,
     780             :                       CPL_FORMAT_STRING(const char *pszFormat), ...)
     781             : 
     782             : {
     783           2 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     784           2 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
     785           0 :         return;
     786             : 
     787           2 :     psCtx->bProgressMode = true;
     788             : 
     789             :     va_list args;
     790           2 :     va_start(args, pszFormat);
     791           2 :     CPLvDebug(pszCategory, pszFormat, args);
     792           2 :     va_end(args);
     793             : 
     794           2 :     psCtx->bProgressMode = false;
     795             : }
     796             : #endif  // !WITHOUT_CPLDEBUG
     797             : 
     798             : /**********************************************************************
     799             :  *                          CPLErrorReset()
     800             :  **********************************************************************/
     801             : 
     802             : /**
     803             :  * Erase any traces of previous errors.
     804             :  *
     805             :  * This is normally used to ensure that an error which has been recovered
     806             :  * from does not appear to be still in play with high level functions.
     807             :  */
     808             : 
     809     6613940 : void CPL_STDCALL CPLErrorReset()
     810             : {
     811     6613940 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     812     6613940 :     if (psCtx == nullptr)
     813           0 :         return;
     814     6613940 :     if (IS_PREFEFINED_ERROR_CTX(psCtx))
     815             :     {
     816           0 :         int bMemoryError = FALSE;
     817           0 :         CPLSetTLSWithFreeFuncEx(
     818             :             CTLS_ERRORCONTEXT,
     819             :             reinterpret_cast<void *>(
     820             :                 const_cast<CPLErrorContext *>(&sNoErrorContext)),
     821             :             nullptr, &bMemoryError);
     822           0 :         return;
     823             :     }
     824             : 
     825     6613940 :     psCtx->nLastErrNo = CPLE_None;
     826     6613940 :     psCtx->szLastErrMsg[0] = '\0';
     827     6613940 :     psCtx->eLastErrType = CE_None;
     828     6613940 :     psCtx->nErrorCounter = 0;
     829             : }
     830             : 
     831             : /**********************************************************************
     832             :  *                       CPLErrorSetState()
     833             :  **********************************************************************/
     834             : 
     835      579327 : static void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
     836             :                              const char *pszMsg, GUInt32 *pnErrorCounter)
     837             : {
     838      579327 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     839      579326 :     if (psCtx == nullptr)
     840           0 :         return;
     841      579326 :     if (IS_PREFEFINED_ERROR_CTX(psCtx))
     842             :     {
     843           1 :         int bMemoryError = FALSE;
     844           1 :         if (eErrClass == CE_None)
     845           0 :             CPLSetTLSWithFreeFuncEx(
     846             :                 CTLS_ERRORCONTEXT,
     847             :                 reinterpret_cast<void *>(
     848             :                     const_cast<CPLErrorContext *>(&sNoErrorContext)),
     849             :                 nullptr, &bMemoryError);
     850           1 :         else if (eErrClass == CE_Warning)
     851           0 :             CPLSetTLSWithFreeFuncEx(
     852             :                 CTLS_ERRORCONTEXT,
     853             :                 reinterpret_cast<void *>(
     854             :                     const_cast<CPLErrorContext *>(&sWarningContext)),
     855             :                 nullptr, &bMemoryError);
     856           1 :         else if (eErrClass == CE_Failure)
     857           0 :             CPLSetTLSWithFreeFuncEx(
     858             :                 CTLS_ERRORCONTEXT,
     859             :                 reinterpret_cast<void *>(
     860             :                     const_cast<CPLErrorContext *>(&sFailureContext)),
     861             :                 nullptr, &bMemoryError);
     862           0 :         return;
     863             :     }
     864             : 
     865      579325 :     psCtx->nLastErrNo = err_no;
     866     1158650 :     const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
     867      579325 :                                  strlen(pszMsg));
     868      579321 :     char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
     869      579321 :     memcpy(pszLastErrMsg, pszMsg, size);
     870      579321 :     pszLastErrMsg[size] = '\0';
     871      579321 :     psCtx->eLastErrType = eErrClass;
     872      579321 :     if (pnErrorCounter)
     873      100982 :         psCtx->nErrorCounter = *pnErrorCounter;
     874             : }
     875             : 
     876             : /**
     877             :  * Restore an error state, without emitting an error.
     878             :  *
     879             :  * Can be useful if a routine might call CPLErrorReset() and one wants to
     880             :  * preserve the previous error state.
     881             :  *
     882             :  * @since GDAL 2.0
     883             :  */
     884             : 
     885      478342 : void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
     886             :                               const char *pszMsg)
     887             : {
     888      478342 :     CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
     889      478342 : }
     890             : 
     891             : /**********************************************************************
     892             :  *                          CPLGetLastErrorNo()
     893             :  **********************************************************************/
     894             : 
     895             : /**
     896             :  * Fetch the last error number.
     897             :  *
     898             :  * Fetches the last error number posted with CPLError(), that hasn't
     899             :  * been cleared by CPLErrorReset().  This is the error number, not the error
     900             :  * class.
     901             :  *
     902             :  * @return the error number of the last error to occur, or CPLE_None (0)
     903             :  * if there are no posted errors.
     904             :  */
     905             : 
     906      823320 : CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
     907             : {
     908      823320 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     909      821850 :     if (psCtx == nullptr)
     910           0 :         return 0;
     911             : 
     912      821850 :     return psCtx->nLastErrNo;
     913             : }
     914             : 
     915             : /**********************************************************************
     916             :  *                          CPLGetLastErrorType()
     917             :  **********************************************************************/
     918             : 
     919             : /**
     920             :  * Fetch the last error type.
     921             :  *
     922             :  * Fetches the last error type posted with CPLError(), that hasn't
     923             :  * been cleared by CPLErrorReset().  This is the error class, not the error
     924             :  * number.
     925             :  *
     926             :  * @return the error type of the last error to occur, or CE_None (0)
     927             :  * if there are no posted errors.
     928             :  */
     929             : 
     930     9301070 : CPLErr CPL_STDCALL CPLGetLastErrorType()
     931             : {
     932     9301070 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     933     9301070 :     if (psCtx == nullptr)
     934           0 :         return CE_None;
     935             : 
     936     9301070 :     return psCtx->eLastErrType;
     937             : }
     938             : 
     939             : /**********************************************************************
     940             :  *                          CPLGetLastErrorMsg()
     941             :  **********************************************************************/
     942             : 
     943             : /**
     944             :  * Get the last error message.
     945             :  *
     946             :  * Fetches the last error message posted with CPLError(), that hasn't
     947             :  * been cleared by CPLErrorReset().  The returned pointer is to an internal
     948             :  * string that should not be altered or freed.
     949             :  *
     950             :  * @return the last error message, or an empty string ("") if there is no
     951             :  * posted error message.
     952             :  */
     953             : 
     954      338652 : const char *CPL_STDCALL CPLGetLastErrorMsg()
     955             : {
     956      338652 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     957      338653 :     if (psCtx == nullptr)
     958           0 :         return "";
     959             : 
     960      338653 :     return psCtx->szLastErrMsg;
     961             : }
     962             : 
     963             : /**********************************************************************
     964             :  *                          CPLGetErrorCounter()
     965             :  **********************************************************************/
     966             : 
     967             : /**
     968             :  * Get the error counter
     969             :  *
     970             :  * Fetches the number of errors emitted in the current error context,
     971             :  * since the last call to CPLErrorReset()
     972             :  *
     973             :  * @return the error counter.
     974             :  * @since GDAL 2.3
     975             :  */
     976             : 
     977    10494300 : GUInt32 CPL_STDCALL CPLGetErrorCounter()
     978             : {
     979    10494300 :     CPLErrorContext *psCtx = CPLGetErrorContext();
     980    10490300 :     if (psCtx == nullptr)
     981           0 :         return 0;
     982             : 
     983    10490300 :     return psCtx->nErrorCounter;
     984             : }
     985             : 
     986             : /************************************************************************/
     987             : /*                       CPLDefaultErrorHandler()                       */
     988             : /************************************************************************/
     989             : 
     990             : static FILE *fpLog = stderr;
     991             : static bool bLogInit = false;
     992             : 
     993           1 : static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
     994             : {
     995             :     FILE *f;
     996             : #ifdef _WIN32
     997             :     wchar_t *pwszFilename =
     998             :         CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
     999             :     wchar_t *pwszAccess =
    1000             :         CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
    1001             :     f = _wfopen(pwszFilename, pwszAccess);
    1002             :     VSIFree(pwszFilename);
    1003             :     VSIFree(pwszAccess);
    1004             : #else
    1005           1 :     f = fopen(pszFilename, pszAccess);
    1006             : #endif
    1007           1 :     return f;
    1008             : }
    1009             : 
    1010             : /** Default error handler. */
    1011       58432 : void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
    1012             :                                         const char *pszErrorMsg)
    1013             : 
    1014             : {
    1015             :     static int nCount = 0;
    1016             :     static int nMaxErrors = -1;
    1017             :     static const char *pszErrorSeparator = ":";
    1018             : 
    1019       58432 :     if (eErrClass != CE_Debug)
    1020             :     {
    1021       57820 :         if (nMaxErrors == -1)
    1022             :         {
    1023         212 :             nMaxErrors =
    1024         212 :                 atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
    1025             :             // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
    1026             :             // is considered as failing the job. This is rarely the intended
    1027             :             // behavior
    1028         212 :             pszErrorSeparator = CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
    1029             :         }
    1030             : 
    1031       57820 :         nCount++;
    1032       57820 :         if (nCount > nMaxErrors && nMaxErrors > 0)
    1033       54440 :             return;
    1034             :     }
    1035             : 
    1036        3992 :     if (!bLogInit)
    1037             :     {
    1038         225 :         bLogInit = true;
    1039             : 
    1040         225 :         fpLog = stderr;
    1041         225 :         const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
    1042         225 :         if (pszLog != nullptr)
    1043             :         {
    1044             :             const bool bAppend =
    1045           1 :                 CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
    1046           1 :             const char *pszAccess = bAppend ? "at" : "wt";
    1047           1 :             fpLog = CPLfopenUTF8(pszLog, pszAccess);
    1048           1 :             if (fpLog == nullptr)
    1049           0 :                 fpLog = stderr;
    1050             :         }
    1051             :     }
    1052             : 
    1053        3992 :     if (eErrClass == CE_Debug)
    1054             :     {
    1055             : #ifndef _WIN32
    1056         612 :         CPLErrorContext *psCtx = CPLGetErrorContext();
    1057         612 :         if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
    1058        1224 :             fpLog == stderr && CPLIsInteractive(stderr))
    1059             :         {
    1060           0 :             if (psCtx->bProgressMode)
    1061             :             {
    1062             :                 // Erase the content of the current line
    1063           0 :                 fprintf(stderr, "\r");
    1064           0 :                 fprintf(stderr, "%s", pszErrorMsg);
    1065           0 :                 fflush(stderr);
    1066           0 :                 psCtx->bEmitNewlineBeforeNextDbgMsg = true;
    1067             :             }
    1068             :             else
    1069             :             {
    1070           0 :                 if (psCtx->bEmitNewlineBeforeNextDbgMsg)
    1071             :                 {
    1072           0 :                     psCtx->bEmitNewlineBeforeNextDbgMsg = false;
    1073           0 :                     fprintf(fpLog, "\n");
    1074             :                 }
    1075           0 :                 fprintf(fpLog, "%s\n", pszErrorMsg);
    1076             :             }
    1077             :         }
    1078             :         else
    1079             : #endif
    1080             :         {
    1081         612 :             fprintf(fpLog, "%s\n", pszErrorMsg);
    1082             :         }
    1083             :     }
    1084        3380 :     else if (eErrClass == CE_Warning)
    1085        2574 :         fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
    1086             :     else
    1087         806 :         fprintf(fpLog, "ERROR %d%s %s\n", nError, pszErrorSeparator,
    1088             :                 pszErrorMsg);
    1089             : 
    1090        3992 :     if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
    1091             :     {
    1092           2 :         fprintf(fpLog,
    1093             :                 "More than %d errors or warnings have been reported. "
    1094             :                 "No more will be reported from now.\n",
    1095             :                 nMaxErrors);
    1096             :     }
    1097             : 
    1098        3992 :     fflush(fpLog);
    1099             : }
    1100             : 
    1101             : /************************************************************************/
    1102             : /*                        CPLQuietErrorHandler()                        */
    1103             : /************************************************************************/
    1104             : 
    1105             : /** Error handler that does not do anything, except for debug messages. */
    1106       37039 : void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
    1107             :                                       const char *pszErrorMsg)
    1108             : 
    1109             : {
    1110       37039 :     if (eErrClass == CE_Debug)
    1111           2 :         CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
    1112       37039 : }
    1113             : 
    1114             : /************************************************************************/
    1115             : /*                       CPLLoggingErrorHandler()                       */
    1116             : /************************************************************************/
    1117             : 
    1118             : /** Error handler that logs into the file defined by the CPL_LOG configuration
    1119             :  * option, or stderr otherwise.
    1120             :  */
    1121           0 : void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
    1122             :                                         const char *pszErrorMsg)
    1123             : 
    1124             : {
    1125           0 :     if (!bLogInit)
    1126             :     {
    1127           0 :         bLogInit = true;
    1128             : 
    1129           0 :         CPLSetConfigOption("CPL_TIMESTAMP", "ON");
    1130             : 
    1131           0 :         const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr);
    1132             : 
    1133           0 :         fpLog = stderr;
    1134           0 :         if (cpl_log != nullptr && EQUAL(cpl_log, "OFF"))
    1135             :         {
    1136           0 :             fpLog = nullptr;
    1137             :         }
    1138           0 :         else if (cpl_log != nullptr)
    1139             :         {
    1140           0 :             size_t nPathLen = strlen(cpl_log) + 20;
    1141           0 :             char *pszPath = static_cast<char *>(CPLMalloc(nPathLen));
    1142           0 :             strcpy(pszPath, cpl_log);
    1143             : 
    1144           0 :             int i = 0;
    1145           0 :             while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr)
    1146             :             {
    1147           0 :                 fclose(fpLog);
    1148             : 
    1149             :                 // Generate sequenced log file names, inserting # before ext.
    1150           0 :                 if (strrchr(cpl_log, '.') == nullptr)
    1151             :                 {
    1152           0 :                     snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
    1153             :                              ".log");
    1154             :                 }
    1155             :                 else
    1156             :                 {
    1157           0 :                     size_t pos = 0;
    1158           0 :                     char *cpl_log_base = CPLStrdup(cpl_log);
    1159           0 :                     pos = strcspn(cpl_log_base, ".");
    1160           0 :                     if (pos > 0)
    1161             :                     {
    1162           0 :                         cpl_log_base[pos] = '\0';
    1163             :                     }
    1164           0 :                     snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++,
    1165             :                              ".log");
    1166           0 :                     CPLFree(cpl_log_base);
    1167             :                 }
    1168             :             }
    1169             : 
    1170           0 :             fpLog = CPLfopenUTF8(pszPath, "wt");
    1171           0 :             CPLFree(pszPath);
    1172             :         }
    1173             :     }
    1174             : 
    1175           0 :     if (fpLog == nullptr)
    1176           0 :         return;
    1177             : 
    1178           0 :     if (eErrClass == CE_Debug)
    1179           0 :         fprintf(fpLog, "%s\n", pszErrorMsg);
    1180           0 :     else if (eErrClass == CE_Warning)
    1181           0 :         fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
    1182             :     else
    1183           0 :         fprintf(fpLog, "ERROR %d: %s\n", nError, pszErrorMsg);
    1184             : 
    1185           0 :     fflush(fpLog);
    1186             : }
    1187             : 
    1188             : /**********************************************************************
    1189             :  *                      CPLTurnFailureIntoWarning()                   *
    1190             :  **********************************************************************/
    1191             : 
    1192             : /** Whether failures should be turned into warnings.
    1193             :  */
    1194        1370 : void CPLTurnFailureIntoWarning(int bOn)
    1195             : {
    1196        1370 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1197        1370 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1198             :     {
    1199           0 :         fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
    1200           0 :         return;
    1201             :     }
    1202        1370 :     psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
    1203        1370 :     if (psCtx->nFailureIntoWarning < 0)
    1204             :     {
    1205           0 :         CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
    1206             :                         "CPLTurnFailureIntoWarning(FALSE)");
    1207             :     }
    1208             : }
    1209             : 
    1210             : /**********************************************************************
    1211             :  *                          CPLSetErrorHandlerEx()                    *
    1212             :  **********************************************************************/
    1213             : 
    1214             : /**
    1215             :  * Install custom error handle with user's data. This method is
    1216             :  * essentially CPLSetErrorHandler with an added pointer to pUserData.
    1217             :  * The pUserData is not returned in the CPLErrorHandler, however, and
    1218             :  * must be fetched via CPLGetErrorHandlerUserData.
    1219             :  *
    1220             :  * @param pfnErrorHandlerNew new error handler function.
    1221             :  * @param pUserData User data to carry along with the error context.
    1222             :  * @return returns the previously installed error handler.
    1223             :  */
    1224             : 
    1225             : CPLErrorHandler CPL_STDCALL
    1226          14 : CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew, void *pUserData)
    1227             : {
    1228          14 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1229          14 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1230             :     {
    1231           0 :         fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
    1232           0 :         return nullptr;
    1233             :     }
    1234             : 
    1235          14 :     if (psCtx->psHandlerStack != nullptr)
    1236             :     {
    1237           0 :         CPLDebug("CPL", "CPLSetErrorHandler() called with an error handler on "
    1238             :                         "the local stack.  New error handler will not be used "
    1239             :                         "immediately.");
    1240             :     }
    1241             : 
    1242          14 :     CPLErrorHandler pfnOldHandler = nullptr;
    1243             :     {
    1244          14 :         CPLMutexHolderD(&hErrorMutex);
    1245             : 
    1246          14 :         pfnOldHandler = pfnErrorHandler;
    1247             : 
    1248          14 :         pfnErrorHandler = pfnErrorHandlerNew;
    1249             : 
    1250          14 :         pErrorHandlerUserData = pUserData;
    1251             :     }
    1252             : 
    1253          14 :     return pfnOldHandler;
    1254             : }
    1255             : 
    1256             : /**********************************************************************
    1257             :  *                          CPLSetErrorHandler()                      *
    1258             :  **********************************************************************/
    1259             : 
    1260             : /**
    1261             :  * Install custom error handler.
    1262             :  *
    1263             :  * Allow the library's user to specify an error handler function.
    1264             :  * A valid error handler is a C function with the following prototype:
    1265             :  *
    1266             :  * <pre>
    1267             :  *     void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
    1268             :  * </pre>
    1269             :  *
    1270             :  * Pass NULL to come back to the default behavior.  The default behavior
    1271             :  * (CPLDefaultErrorHandler()) is to write the message to stderr.
    1272             :  *
    1273             :  * The msg will be a partially formatted error message not containing the
    1274             :  * "ERROR %d:" portion emitted by the default handler.  Message formatting
    1275             :  * is handled by CPLError() before calling the handler.  If the error
    1276             :  * handler function is passed a CE_Fatal class error and returns, then
    1277             :  * CPLError() will call abort(). Applications wanting to interrupt this
    1278             :  * fatal behavior will have to use longjmp(), or a C++ exception to
    1279             :  * indirectly exit the function.
    1280             :  *
    1281             :  * Another standard error handler is CPLQuietErrorHandler() which doesn't
    1282             :  * make any attempt to report the passed error or warning messages but
    1283             :  * will process debug messages via CPLDefaultErrorHandler.
    1284             :  *
    1285             :  * Note that error handlers set with CPLSetErrorHandler() apply to all
    1286             :  * threads in an application, while error handlers set with CPLPushErrorHandler
    1287             :  * are thread-local.  However, any error handlers pushed with
    1288             :  * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
    1289             :  * precedence over the global error handlers set with CPLSetErrorHandler().
    1290             :  * Generally speaking CPLSetErrorHandler() would be used to set a desired
    1291             :  * global error handler, while CPLPushErrorHandler() would be used to install
    1292             :  * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
    1293             :  * error reporting in a limited segment of code.
    1294             :  *
    1295             :  * @param pfnErrorHandlerNew new error handler function.
    1296             :  * @return returns the previously installed error handler.
    1297             :  */
    1298             : CPLErrorHandler CPL_STDCALL
    1299           8 : CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
    1300             : {
    1301           8 :     return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
    1302             : }
    1303             : 
    1304             : /************************************************************************/
    1305             : /*                        CPLPushErrorHandler()                         */
    1306             : /************************************************************************/
    1307             : 
    1308             : /**
    1309             :  * Push a new CPLError handler.
    1310             :  *
    1311             :  * This pushes a new error handler on the thread-local error handler
    1312             :  * stack.  This handler will be used until removed with CPLPopErrorHandler().
    1313             :  *
    1314             :  * The CPLSetErrorHandler() docs have further information on how
    1315             :  * CPLError handlers work.
    1316             :  *
    1317             :  * @param pfnErrorHandlerNew new error handler function.
    1318             :  */
    1319             : 
    1320      160711 : void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
    1321             : 
    1322             : {
    1323      160711 :     CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
    1324      160707 : }
    1325             : 
    1326             : /************************************************************************/
    1327             : /*                        CPLPushErrorHandlerEx()                       */
    1328             : /************************************************************************/
    1329             : 
    1330             : /**
    1331             :  * Push a new CPLError handler with user data on the error context.
    1332             :  *
    1333             :  * This pushes a new error handler on the thread-local error handler
    1334             :  * stack.  This handler will be used until removed with CPLPopErrorHandler().
    1335             :  * Obtain the user data back by using CPLGetErrorContext().
    1336             :  *
    1337             :  * The CPLSetErrorHandler() docs have further information on how
    1338             :  * CPLError handlers work.
    1339             :  *
    1340             :  * @param pfnErrorHandlerNew new error handler function.
    1341             :  * @param pUserData User data to put on the error context.
    1342             :  */
    1343     6130790 : void CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,
    1344             :                                        void *pUserData)
    1345             : 
    1346             : {
    1347     6130790 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1348             : 
    1349     6130750 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1350             :     {
    1351           8 :         fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
    1352           0 :         return;
    1353             :     }
    1354             : 
    1355             :     CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
    1356     6130740 :         CPLMalloc(sizeof(CPLErrorHandlerNode)));
    1357     6130770 :     psNode->psNext = psCtx->psHandlerStack;
    1358     6130770 :     psNode->pfnHandler = pfnErrorHandlerNew;
    1359     6130770 :     psNode->pUserData = pUserData;
    1360     6130770 :     psNode->bCatchDebug = true;
    1361     6130770 :     psCtx->psHandlerStack = psNode;
    1362             : }
    1363             : 
    1364             : /************************************************************************/
    1365             : /*                         CPLPopErrorHandler()                         */
    1366             : /************************************************************************/
    1367             : 
    1368             : /**
    1369             :  * Pop error handler off stack.
    1370             :  *
    1371             :  * Discards the current error handler on the error handler stack, and restores
    1372             :  * the one in use before the last CPLPushErrorHandler() call.  This method
    1373             :  * has no effect if there are no error handlers on the current threads error
    1374             :  * handler stack.
    1375             :  */
    1376             : 
    1377     6130770 : void CPL_STDCALL CPLPopErrorHandler()
    1378             : 
    1379             : {
    1380     6130770 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1381             : 
    1382     6130700 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1383             :     {
    1384          14 :         fprintf(stderr, "CPLPopErrorHandler() failed.\n");
    1385           0 :         return;
    1386             :     }
    1387             : 
    1388     6130690 :     if (psCtx->psHandlerStack != nullptr)
    1389             :     {
    1390     6130760 :         CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
    1391             : 
    1392     6130760 :         psCtx->psHandlerStack = psNode->psNext;
    1393     6130760 :         VSIFree(psNode);
    1394             :     }
    1395             : }
    1396             : 
    1397             : /************************************************************************/
    1398             : /*                         CPLCallPreviousHandler()                     */
    1399             : /************************************************************************/
    1400             : 
    1401             : /**
    1402             :  * Call the previously installed error handler in the error handler stack.
    1403             :  *
    1404             :  * Only to be used by a custom error handler that wants to forward events to
    1405             :  * the previous error handler.
    1406             :  *
    1407             :  * @since GDAL 3.8
    1408             :  */
    1409             : 
    1410       19655 : void CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
    1411             :                             const char *pszMsg)
    1412             : {
    1413       19655 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1414             : 
    1415       19655 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1416             :     {
    1417           0 :         fprintf(stderr, "CPLCallPreviousHandler() failed.\n");
    1418           0 :         return;
    1419             :     }
    1420             : 
    1421       19655 :     if (psCtx->psHandlerStack != nullptr)
    1422             :     {
    1423       19655 :         CPLErrorHandlerNode *psCurNode = psCtx->psHandlerStack;
    1424       19655 :         psCtx->psHandlerStack = psCurNode->psNext;
    1425       19655 :         if (psCtx->psHandlerStack)
    1426             :         {
    1427         663 :             CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
    1428         663 :             psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMsg);
    1429         663 :             if (psNewCurNode != psCtx->psHandlerStack)
    1430             :             {
    1431           0 :                 fprintf(stderr, "CPLCallPreviousHandler() has detected that a "
    1432             :                                 "previous error handler messed up with the "
    1433             :                                 "error stack. Chaos guaranteed!\n");
    1434             :             }
    1435             :         }
    1436             :         else
    1437       18992 :             CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
    1438       19655 :         psCtx->psHandlerStack = psCurNode;
    1439             :     }
    1440             :     else
    1441             :     {
    1442           0 :         CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
    1443             :     }
    1444             : }
    1445             : 
    1446             : /************************************************************************/
    1447             : /*                 CPLSetCurrentErrorHandlerCatchDebug()                */
    1448             : /************************************************************************/
    1449             : 
    1450             : /**
    1451             :  * Set if the current error handler should intercept debug messages, or if
    1452             :  * they should be processed by the previous handler.
    1453             :  *
    1454             :  * By default when installing a custom error handler, this one intercepts
    1455             :  * debug messages. In some cases, this might not be desirable and the user
    1456             :  * would prefer that the previous installed handler (or the default one if no
    1457             :  * previous installed handler exists in the stack) deal with it. In which
    1458             :  * case, this function should be called with bCatchDebug = FALSE.
    1459             :  *
    1460             :  * @param bCatchDebug FALSE if the current error handler should not intercept
    1461             :  * debug messages
    1462             :  * @since GDAL 2.1
    1463             :  */
    1464             : 
    1465       21757 : void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
    1466             : {
    1467       21757 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1468             : 
    1469       21735 :     if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
    1470             :     {
    1471          36 :         fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
    1472           0 :         return;
    1473             :     }
    1474             : 
    1475       21699 :     if (psCtx->psHandlerStack != nullptr)
    1476       21707 :         psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
    1477             :     else
    1478           0 :         gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
    1479             : }
    1480             : 
    1481             : /************************************************************************/
    1482             : /*                             _CPLAssert()                             */
    1483             : /*                                                                      */
    1484             : /*      This function is called only when an assertion fails.           */
    1485             : /************************************************************************/
    1486             : 
    1487             : /**
    1488             :  * Report failure of a logical assertion.
    1489             :  *
    1490             :  * Applications would normally use the CPLAssert() macro which expands
    1491             :  * into code calling _CPLAssert() only if the condition fails.  _CPLAssert()
    1492             :  * will generate a CE_Fatal error call to CPLError(), indicating the file
    1493             :  * name, and line number of the failed assertion, as well as containing
    1494             :  * the assertion itself.
    1495             :  *
    1496             :  * There is no reason for application code to call _CPLAssert() directly.
    1497             :  */
    1498             : 
    1499           0 : void CPL_STDCALL _CPLAssert(const char *pszExpression, const char *pszFile,
    1500             :                             int iLine)
    1501             : 
    1502             : {
    1503           0 :     CPLError(CE_Fatal, CPLE_AssertionFailed,
    1504             :              "Assertion `%s' failed "
    1505             :              "in file `%s', line %d",
    1506             :              pszExpression, pszFile, iLine);
    1507             : 
    1508             :     // Just to please compiler so it is aware the function does not return.
    1509           0 :     abort();
    1510             : }
    1511             : 
    1512             : /************************************************************************/
    1513             : /*                       CPLCleanupErrorMutex()                         */
    1514             : /************************************************************************/
    1515             : 
    1516        1371 : void CPLCleanupErrorMutex()
    1517             : {
    1518        1371 :     if (hErrorMutex != nullptr)
    1519             :     {
    1520         194 :         CPLDestroyMutex(hErrorMutex);
    1521         194 :         hErrorMutex = nullptr;
    1522             :     }
    1523        1371 :     if (fpLog != nullptr && fpLog != stderr)
    1524             :     {
    1525           1 :         fclose(fpLog);
    1526           1 :         fpLog = nullptr;
    1527           1 :         bLogInit = false;
    1528             :     }
    1529        1371 : }
    1530             : 
    1531        4825 : bool CPLIsDefaultErrorHandlerAndCatchDebug()
    1532             : {
    1533        4825 :     CPLErrorContext *psCtx = CPLGetErrorContext();
    1534        4825 :     return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
    1535        9650 :            gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
    1536             : }
    1537             : 
    1538             : /************************************************************************/
    1539             : /*                       CPLErrorHandlerAccumulator()                   */
    1540             : /************************************************************************/
    1541             : 
    1542         351 : static void CPL_STDCALL CPLErrorHandlerAccumulator(CPLErr eErr, CPLErrorNum no,
    1543             :                                                    const char *msg)
    1544             : {
    1545             :     std::vector<CPLErrorHandlerAccumulatorStruct> *paoErrors =
    1546             :         static_cast<std::vector<CPLErrorHandlerAccumulatorStruct> *>(
    1547         351 :             CPLGetErrorHandlerUserData());
    1548         351 :     paoErrors->push_back(CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
    1549         351 : }
    1550             : 
    1551       76781 : void CPLInstallErrorHandlerAccumulator(
    1552             :     std::vector<CPLErrorHandlerAccumulatorStruct> &aoErrors)
    1553             : {
    1554       76781 :     CPLPushErrorHandlerEx(CPLErrorHandlerAccumulator, &aoErrors);
    1555       76783 : }
    1556             : 
    1557       76793 : void CPLUninstallErrorHandlerAccumulator()
    1558             : {
    1559       76793 :     CPLPopErrorHandler();
    1560       76745 : }
    1561             : 
    1562             : /************************************************************************/
    1563             : /*               CPLErrorStateBackuper::CPLErrorStateBackuper()         */
    1564             : /************************************************************************/
    1565             : 
    1566      100988 : CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
    1567      100988 :     : m_nLastErrorNum(CPLGetLastErrorNo()),
    1568      201971 :       m_nLastErrorType(CPLGetLastErrorType()),
    1569             :       m_osLastErrorMsg(CPLGetLastErrorMsg()),
    1570      201971 :       m_nLastErrorCounter(CPLGetErrorCounter()),
    1571             :       m_poErrorHandlerPusher(
    1572             :           hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
    1573      100986 :                    : nullptr)
    1574             : {
    1575      100982 : }
    1576             : 
    1577             : /************************************************************************/
    1578             : /*               CPLErrorStateBackuper::~CPLErrorStateBackuper()        */
    1579             : /************************************************************************/
    1580             : 
    1581      100980 : CPLErrorStateBackuper::~CPLErrorStateBackuper()
    1582             : {
    1583      100986 :     CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
    1584             :                      m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
    1585      100982 : }

Generated by: LCOV version 1.14