LCOV - code coverage report
Current view: top level - port - cpl_error.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 334 466 71.7 %
Date: 2026-04-20 19:56:30 Functions: 37 41 90.2 %

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

Generated by: LCOV version 1.14