LCOV - code coverage report
Current view: top level - port - cpl_conv.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 703 914 76.9 %
Date: 2024-11-21 22:18:42 Functions: 64 74 86.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Convenience functions.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_config.h"
      15             : 
      16             : #ifdef HAVE_USELOCALE
      17             : // For uselocale, define _XOPEN_SOURCE = 700
      18             : // but on Solaris, we don't have uselocale and we cannot have
      19             : // std=c++11 with _XOPEN_SOURCE != 600
      20             : #if defined(__sun__) && __cplusplus >= 201103L
      21             : #if _XOPEN_SOURCE != 600
      22             : #ifdef _XOPEN_SOURCE
      23             : #undef _XOPEN_SOURCE
      24             : #endif
      25             : #define _XOPEN_SOURCE 600
      26             : #endif
      27             : #else
      28             : #ifdef _XOPEN_SOURCE
      29             : #undef _XOPEN_SOURCE
      30             : #endif
      31             : #define _XOPEN_SOURCE 700
      32             : #endif
      33             : #endif
      34             : 
      35             : // For atoll (at least for NetBSD)
      36             : #ifndef _ISOC99_SOURCE
      37             : #define _ISOC99_SOURCE
      38             : #endif
      39             : 
      40             : #ifdef MSVC_USE_VLD
      41             : #include <vld.h>
      42             : #endif
      43             : 
      44             : #include "cpl_conv.h"
      45             : 
      46             : #include <algorithm>
      47             : #include <cctype>
      48             : #include <cerrno>
      49             : #include <climits>
      50             : #include <clocale>
      51             : #include <cmath>
      52             : #include <cstdlib>
      53             : #include <cstring>
      54             : #include <ctime>
      55             : #if HAVE_FCNTL_H
      56             : #include <fcntl.h>
      57             : #endif
      58             : #if HAVE_UNISTD_H
      59             : #include <unistd.h>
      60             : #endif
      61             : #if HAVE_XLOCALE_H
      62             : #include <xlocale.h>  // for LC_NUMERIC_MASK on MacOS
      63             : #endif
      64             : 
      65             : #ifdef _WIN32
      66             : #include <io.h>  // _isatty
      67             : #else
      68             : #include <unistd.h>  // isatty
      69             : #endif
      70             : 
      71             : #ifdef DEBUG_CONFIG_OPTIONS
      72             : #include <set>
      73             : #endif
      74             : #include <string>
      75             : 
      76             : #if __cplusplus >= 202002L
      77             : #include <bit>  // For std::endian
      78             : #endif
      79             : 
      80             : #include "cpl_config.h"
      81             : #include "cpl_multiproc.h"
      82             : #include "cpl_string.h"
      83             : #include "cpl_vsi.h"
      84             : #include "cpl_vsil_curl_priv.h"
      85             : 
      86             : #ifdef DEBUG
      87             : #define OGRAPISPY_ENABLED
      88             : #endif
      89             : #ifdef OGRAPISPY_ENABLED
      90             : // Keep in sync with ograpispy.cpp
      91             : void OGRAPISPYCPLSetConfigOption(const char *, const char *);
      92             : void OGRAPISPYCPLSetThreadLocalConfigOption(const char *, const char *);
      93             : #endif
      94             : 
      95             : // Uncomment to get list of options that have been fetched and set.
      96             : // #define DEBUG_CONFIG_OPTIONS
      97             : 
      98             : static CPLMutex *hConfigMutex = nullptr;
      99             : static volatile char **g_papszConfigOptions = nullptr;
     100             : static bool gbIgnoreEnvVariables =
     101             :     false;  // if true, only take into account configuration options set through
     102             :             // configuration file or
     103             :             // CPLSetConfigOption()/CPLSetThreadLocalConfigOption()
     104             : 
     105             : static std::vector<std::pair<CPLSetConfigOptionSubscriber, void *>>
     106             :     gSetConfigOptionSubscribers{};
     107             : 
     108             : // Used by CPLOpenShared() and friends.
     109             : static CPLMutex *hSharedFileMutex = nullptr;
     110             : static int nSharedFileCount = 0;
     111             : static CPLSharedFileInfo *pasSharedFileList = nullptr;
     112             : 
     113             : // Used by CPLsetlocale().
     114             : static CPLMutex *hSetLocaleMutex = nullptr;
     115             : 
     116             : // Note: ideally this should be added in CPLSharedFileInfo*
     117             : // but CPLSharedFileInfo is exposed in the API, hence that trick
     118             : // to hide this detail.
     119             : typedef struct
     120             : {
     121             :     GIntBig nPID;  // pid of opening thread.
     122             : } CPLSharedFileInfoExtra;
     123             : 
     124             : static volatile CPLSharedFileInfoExtra *pasSharedFileListExtra = nullptr;
     125             : 
     126             : /************************************************************************/
     127             : /*                             CPLCalloc()                              */
     128             : /************************************************************************/
     129             : 
     130             : /**
     131             :  * Safe version of calloc().
     132             :  *
     133             :  * This function is like the C library calloc(), but raises a CE_Fatal
     134             :  * error with CPLError() if it fails to allocate the desired memory.  It
     135             :  * should be used for small memory allocations that are unlikely to fail
     136             :  * and for which the application is unwilling to test for out of memory
     137             :  * conditions.  It uses VSICalloc() to get the memory, so any hooking of
     138             :  * VSICalloc() will apply to CPLCalloc() as well.  CPLFree() or VSIFree()
     139             :  * can be used free memory allocated by CPLCalloc().
     140             :  *
     141             :  * @param nCount number of objects to allocate.
     142             :  * @param nSize size (in bytes) of object to allocate.
     143             :  * @return pointer to newly allocated memory, only NULL if nSize * nCount is
     144             :  * NULL.
     145             :  */
     146             : 
     147     3183000 : void *CPLCalloc(size_t nCount, size_t nSize)
     148             : 
     149             : {
     150     3183000 :     if (nSize * nCount == 0)
     151        9130 :         return nullptr;
     152             : 
     153     3173870 :     void *pReturn = CPLMalloc(nCount * nSize);
     154     3173860 :     memset(pReturn, 0, nCount * nSize);
     155     3173860 :     return pReturn;
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                             CPLMalloc()                              */
     160             : /************************************************************************/
     161             : 
     162             : /**
     163             :  * Safe version of malloc().
     164             :  *
     165             :  * This function is like the C library malloc(), but raises a CE_Fatal
     166             :  * error with CPLError() if it fails to allocate the desired memory.  It
     167             :  * should be used for small memory allocations that are unlikely to fail
     168             :  * and for which the application is unwilling to test for out of memory
     169             :  * conditions.  It uses VSIMalloc() to get the memory, so any hooking of
     170             :  * VSIMalloc() will apply to CPLMalloc() as well.  CPLFree() or VSIFree()
     171             :  * can be used free memory allocated by CPLMalloc().
     172             :  *
     173             :  * @param nSize size (in bytes) of memory block to allocate.
     174             :  * @return pointer to newly allocated memory, only NULL if nSize is zero.
     175             :  */
     176             : 
     177    18567000 : void *CPLMalloc(size_t nSize)
     178             : 
     179             : {
     180    18567000 :     if (nSize == 0)
     181        5652 :         return nullptr;
     182             : 
     183    18561400 :     if ((nSize >> (8 * sizeof(nSize) - 1)) != 0)
     184             :     {
     185             :         // coverity[dead_error_begin]
     186           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     187             :                  "CPLMalloc(%ld): Silly size requested.",
     188             :                  static_cast<long>(nSize));
     189           0 :         return nullptr;
     190             :     }
     191             : 
     192    18561400 :     void *pReturn = VSIMalloc(nSize);
     193    18561300 :     if (pReturn == nullptr)
     194             :     {
     195           0 :         if (nSize < 2000)
     196             :         {
     197           0 :             CPLEmergencyError("CPLMalloc(): Out of memory allocating a small "
     198             :                               "number of bytes.");
     199             :         }
     200             : 
     201           0 :         CPLError(CE_Fatal, CPLE_OutOfMemory,
     202             :                  "CPLMalloc(): Out of memory allocating %ld bytes.",
     203             :                  static_cast<long>(nSize));
     204             :     }
     205             : 
     206    18561300 :     return pReturn;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                             CPLRealloc()                             */
     211             : /************************************************************************/
     212             : 
     213             : /**
     214             :  * Safe version of realloc().
     215             :  *
     216             :  * This function is like the C library realloc(), but raises a CE_Fatal
     217             :  * error with CPLError() if it fails to allocate the desired memory.  It
     218             :  * should be used for small memory allocations that are unlikely to fail
     219             :  * and for which the application is unwilling to test for out of memory
     220             :  * conditions.  It uses VSIRealloc() to get the memory, so any hooking of
     221             :  * VSIRealloc() will apply to CPLRealloc() as well.  CPLFree() or VSIFree()
     222             :  * can be used free memory allocated by CPLRealloc().
     223             :  *
     224             :  * It is also safe to pass NULL in as the existing memory block for
     225             :  * CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block.
     226             :  *
     227             :  * @param pData existing memory block which should be copied to the new block.
     228             :  * @param nNewSize new size (in bytes) of memory block to allocate.
     229             :  * @return pointer to allocated memory, only NULL if nNewSize is zero.
     230             :  */
     231             : 
     232     1807340 : void *CPLRealloc(void *pData, size_t nNewSize)
     233             : 
     234             : {
     235     1807340 :     if (nNewSize == 0)
     236             :     {
     237          45 :         VSIFree(pData);
     238          45 :         return nullptr;
     239             :     }
     240             : 
     241     1807300 :     if ((nNewSize >> (8 * sizeof(nNewSize) - 1)) != 0)
     242             :     {
     243             :         // coverity[dead_error_begin]
     244           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     245             :                  "CPLRealloc(%ld): Silly size requested.",
     246             :                  static_cast<long>(nNewSize));
     247           0 :         return nullptr;
     248             :     }
     249             : 
     250     1807300 :     void *pReturn = nullptr;
     251             : 
     252     1807300 :     if (pData == nullptr)
     253      847543 :         pReturn = VSIMalloc(nNewSize);
     254             :     else
     255      959754 :         pReturn = VSIRealloc(pData, nNewSize);
     256             : 
     257     1807280 :     if (pReturn == nullptr)
     258             :     {
     259           0 :         if (nNewSize < 2000)
     260             :         {
     261           0 :             char szSmallMsg[80] = {};
     262             : 
     263           0 :             snprintf(szSmallMsg, sizeof(szSmallMsg),
     264             :                      "CPLRealloc(): Out of memory allocating %ld bytes.",
     265             :                      static_cast<long>(nNewSize));
     266           0 :             CPLEmergencyError(szSmallMsg);
     267             :         }
     268             :         else
     269             :         {
     270           0 :             CPLError(CE_Fatal, CPLE_OutOfMemory,
     271             :                      "CPLRealloc(): Out of memory allocating %ld bytes.",
     272             :                      static_cast<long>(nNewSize));
     273             :         }
     274             :     }
     275             : 
     276     1807280 :     return pReturn;
     277             : }
     278             : 
     279             : /************************************************************************/
     280             : /*                             CPLStrdup()                              */
     281             : /************************************************************************/
     282             : 
     283             : /**
     284             :  * Safe version of strdup() function.
     285             :  *
     286             :  * This function is similar to the C library strdup() function, but if
     287             :  * the memory allocation fails it will issue a CE_Fatal error with
     288             :  * CPLError() instead of returning NULL. Memory
     289             :  * allocated with CPLStrdup() can be freed with CPLFree() or VSIFree().
     290             :  *
     291             :  * It is also safe to pass a NULL string into CPLStrdup().  CPLStrdup()
     292             :  * will allocate and return a zero length string (as opposed to a NULL
     293             :  * string).
     294             :  *
     295             :  * @param pszString input string to be duplicated.  May be NULL.
     296             :  * @return pointer to a newly allocated copy of the string.  Free with
     297             :  * CPLFree() or VSIFree().
     298             :  */
     299             : 
     300     7092030 : char *CPLStrdup(const char *pszString)
     301             : 
     302             : {
     303     7092030 :     if (pszString == nullptr)
     304      960535 :         pszString = "";
     305             : 
     306     7092030 :     const size_t nLen = strlen(pszString);
     307     7092030 :     char *pszReturn = static_cast<char *>(CPLMalloc(nLen + 1));
     308     7091980 :     memcpy(pszReturn, pszString, nLen + 1);
     309     7091980 :     return (pszReturn);
     310             : }
     311             : 
     312             : /************************************************************************/
     313             : /*                             CPLStrlwr()                              */
     314             : /************************************************************************/
     315             : 
     316             : /**
     317             :  * Convert each characters of the string to lower case.
     318             :  *
     319             :  * For example, "ABcdE" will be converted to "abcde".
     320             :  * Starting with GDAL 3.9, this function is no longer locale dependent.
     321             :  *
     322             :  * @param pszString input string to be converted.
     323             :  * @return pointer to the same string, pszString.
     324             :  */
     325             : 
     326          32 : char *CPLStrlwr(char *pszString)
     327             : 
     328             : {
     329          32 :     if (pszString == nullptr)
     330           0 :         return nullptr;
     331             : 
     332          32 :     char *pszTemp = pszString;
     333             : 
     334         140 :     while (*pszTemp)
     335             :     {
     336         108 :         *pszTemp =
     337         108 :             static_cast<char>(CPLTolower(static_cast<unsigned char>(*pszTemp)));
     338         108 :         pszTemp++;
     339             :     }
     340             : 
     341          32 :     return pszString;
     342             : }
     343             : 
     344             : /************************************************************************/
     345             : /*                              CPLFGets()                              */
     346             : /*                                                                      */
     347             : /*      Note: LF = \n = ASCII 10                                        */
     348             : /*            CR = \r = ASCII 13                                        */
     349             : /************************************************************************/
     350             : 
     351             : // ASCII characters.
     352             : constexpr char knLF = 10;
     353             : constexpr char knCR = 13;
     354             : 
     355             : /**
     356             :  * Reads in at most one less than nBufferSize characters from the fp
     357             :  * stream and stores them into the buffer pointed to by pszBuffer.
     358             :  * Reading stops after an EOF or a newline. If a newline is read, it
     359             :  * is _not_ stored into the buffer. A '\\0' is stored after the last
     360             :  * character in the buffer. All three types of newline terminators
     361             :  * recognized by the CPLFGets(): single '\\r' and '\\n' and '\\r\\n'
     362             :  * combination.
     363             :  *
     364             :  * @param pszBuffer pointer to the targeting character buffer.
     365             :  * @param nBufferSize maximum size of the string to read (not including
     366             :  * terminating '\\0').
     367             :  * @param fp file pointer to read from.
     368             :  * @return pointer to the pszBuffer containing a string read
     369             :  * from the file or NULL if the error or end of file was encountered.
     370             :  */
     371             : 
     372           0 : char *CPLFGets(char *pszBuffer, int nBufferSize, FILE *fp)
     373             : 
     374             : {
     375           0 :     if (nBufferSize == 0 || pszBuffer == nullptr || fp == nullptr)
     376           0 :         return nullptr;
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Let the OS level call read what it things is one line.  This    */
     380             :     /*      will include the newline.  On windows, if the file happens      */
     381             :     /*      to be in text mode, the CRLF will have been converted to        */
     382             :     /*      just the newline (LF).  If it is in binary mode it may well     */
     383             :     /*      have both.                                                      */
     384             :     /* -------------------------------------------------------------------- */
     385           0 :     const long nOriginalOffset = VSIFTell(fp);
     386           0 :     if (VSIFGets(pszBuffer, nBufferSize, fp) == nullptr)
     387           0 :         return nullptr;
     388             : 
     389           0 :     int nActuallyRead = static_cast<int>(strlen(pszBuffer));
     390           0 :     if (nActuallyRead == 0)
     391           0 :         return nullptr;
     392             : 
     393             :     /* -------------------------------------------------------------------- */
     394             :     /*      If we found \r and out buffer is full, it is possible there     */
     395             :     /*      is also a pending \n.  Check for it.                            */
     396             :     /* -------------------------------------------------------------------- */
     397           0 :     if (nBufferSize == nActuallyRead + 1 &&
     398           0 :         pszBuffer[nActuallyRead - 1] == knCR)
     399             :     {
     400           0 :         const int chCheck = fgetc(fp);
     401           0 :         if (chCheck != knLF)
     402             :         {
     403             :             // unget the character.
     404           0 :             if (VSIFSeek(fp, nOriginalOffset + nActuallyRead, SEEK_SET) == -1)
     405             :             {
     406           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     407             :                          "Unable to unget a character");
     408             :             }
     409             :         }
     410             :     }
     411             : 
     412             :     /* -------------------------------------------------------------------- */
     413             :     /*      Trim off \n, \r or \r\n if it appears at the end.  We don't     */
     414             :     /*      need to do any "seeking" since we want the newline eaten.       */
     415             :     /* -------------------------------------------------------------------- */
     416           0 :     if (nActuallyRead > 1 && pszBuffer[nActuallyRead - 1] == knLF &&
     417           0 :         pszBuffer[nActuallyRead - 2] == knCR)
     418             :     {
     419           0 :         pszBuffer[nActuallyRead - 2] = '\0';
     420             :     }
     421           0 :     else if (pszBuffer[nActuallyRead - 1] == knLF ||
     422           0 :              pszBuffer[nActuallyRead - 1] == knCR)
     423             :     {
     424           0 :         pszBuffer[nActuallyRead - 1] = '\0';
     425             :     }
     426             : 
     427             :     /* -------------------------------------------------------------------- */
     428             :     /*      Search within the string for a \r (MacOS convention             */
     429             :     /*      apparently), and if we find it we need to trim the string,      */
     430             :     /*      and seek back.                                                  */
     431             :     /* -------------------------------------------------------------------- */
     432           0 :     char *pszExtraNewline = strchr(pszBuffer, knCR);
     433             : 
     434           0 :     if (pszExtraNewline != nullptr)
     435             :     {
     436           0 :         nActuallyRead = static_cast<int>(pszExtraNewline - pszBuffer + 1);
     437             : 
     438           0 :         *pszExtraNewline = '\0';
     439           0 :         if (VSIFSeek(fp, nOriginalOffset + nActuallyRead - 1, SEEK_SET) != 0)
     440           0 :             return nullptr;
     441             : 
     442             :         // This hackery is necessary to try and find our correct
     443             :         // spot on win32 systems with text mode line translation going
     444             :         // on.  Sometimes the fseek back overshoots, but it doesn't
     445             :         // "realize it" till a character has been read. Try to read till
     446             :         // we get to the right spot and get our CR.
     447           0 :         int chCheck = fgetc(fp);
     448           0 :         while ((chCheck != knCR && chCheck != EOF) ||
     449           0 :                VSIFTell(fp) < nOriginalOffset + nActuallyRead)
     450             :         {
     451             :             static bool bWarned = false;
     452             : 
     453           0 :             if (!bWarned)
     454             :             {
     455           0 :                 bWarned = true;
     456           0 :                 CPLDebug("CPL",
     457             :                          "CPLFGets() correcting for DOS text mode translation "
     458             :                          "seek problem.");
     459             :             }
     460           0 :             chCheck = fgetc(fp);
     461             :         }
     462             :     }
     463             : 
     464           0 :     return pszBuffer;
     465             : }
     466             : 
     467             : /************************************************************************/
     468             : /*                         CPLReadLineBuffer()                          */
     469             : /*                                                                      */
     470             : /*      Fetch readline buffer, and ensure it is the desired size,       */
     471             : /*      reallocating if needed.  Manages TLS (thread local storage)     */
     472             : /*      issues for the buffer.                                          */
     473             : /*      We use a special trick to track the actual size of the buffer   */
     474             : /*      The first 4 bytes are reserved to store it as a int, hence the  */
     475             : /*      -4 / +4 hacks with the size and pointer.                        */
     476             : /************************************************************************/
     477     2359850 : static char *CPLReadLineBuffer(int nRequiredSize)
     478             : 
     479             : {
     480             : 
     481             :     /* -------------------------------------------------------------------- */
     482             :     /*      A required size of -1 means the buffer should be freed.         */
     483             :     /* -------------------------------------------------------------------- */
     484     2359850 :     if (nRequiredSize == -1)
     485             :     {
     486        2302 :         int bMemoryError = FALSE;
     487        2302 :         void *pRet = CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError);
     488        2302 :         if (pRet != nullptr)
     489             :         {
     490        2050 :             CPLFree(pRet);
     491        2050 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     492             :         }
     493        2302 :         return nullptr;
     494             :     }
     495             : 
     496             :     /* -------------------------------------------------------------------- */
     497             :     /*      If the buffer doesn't exist yet, create it.                     */
     498             :     /* -------------------------------------------------------------------- */
     499     2357540 :     int bMemoryError = FALSE;
     500             :     GUInt32 *pnAlloc =
     501     2357540 :         static_cast<GUInt32 *>(CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError));
     502     2357540 :     if (bMemoryError)
     503           0 :         return nullptr;
     504             : 
     505     2357540 :     if (pnAlloc == nullptr)
     506             :     {
     507        3213 :         pnAlloc = static_cast<GUInt32 *>(VSI_MALLOC_VERBOSE(200));
     508        3213 :         if (pnAlloc == nullptr)
     509           0 :             return nullptr;
     510        3213 :         *pnAlloc = 196;
     511        3213 :         CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
     512             :     }
     513             : 
     514             :     /* -------------------------------------------------------------------- */
     515             :     /*      If it is too small, grow it bigger.                             */
     516             :     /* -------------------------------------------------------------------- */
     517     2357540 :     if (static_cast<int>(*pnAlloc) - 1 < nRequiredSize)
     518             :     {
     519         649 :         const int nNewSize = nRequiredSize + 4 + 500;
     520         649 :         if (nNewSize <= 0)
     521             :         {
     522           0 :             VSIFree(pnAlloc);
     523           0 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     524           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     525             :                      "CPLReadLineBuffer(): Trying to allocate more than "
     526             :                      "2 GB.");
     527           0 :             return nullptr;
     528             :         }
     529             : 
     530             :         GUInt32 *pnAllocNew =
     531         649 :             static_cast<GUInt32 *>(VSI_REALLOC_VERBOSE(pnAlloc, nNewSize));
     532         649 :         if (pnAllocNew == nullptr)
     533             :         {
     534           0 :             VSIFree(pnAlloc);
     535           0 :             CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
     536           0 :             return nullptr;
     537             :         }
     538         649 :         pnAlloc = pnAllocNew;
     539             : 
     540         649 :         *pnAlloc = nNewSize - 4;
     541         649 :         CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
     542             :     }
     543             : 
     544     2357540 :     return reinterpret_cast<char *>(pnAlloc + 1);
     545             : }
     546             : 
     547             : /************************************************************************/
     548             : /*                            CPLReadLine()                             */
     549             : /************************************************************************/
     550             : 
     551             : /**
     552             :  * Simplified line reading from text file.
     553             :  *
     554             :  * Read a line of text from the given file handle, taking care
     555             :  * to capture CR and/or LF and strip off ... equivalent of
     556             :  * DKReadLine().  Pointer to an internal buffer is returned.
     557             :  * The application shouldn't free it, or depend on its value
     558             :  * past the next call to CPLReadLine().
     559             :  *
     560             :  * Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file
     561             :  * services should apply to CPLReadLine() as well.
     562             :  *
     563             :  * CPLReadLine() maintains an internal buffer, which will appear as a
     564             :  * single block memory leak in some circumstances.  CPLReadLine() may
     565             :  * be called with a NULL FILE * at any time to free this working buffer.
     566             :  *
     567             :  * @param fp file pointer opened with VSIFOpen().
     568             :  *
     569             :  * @return pointer to an internal buffer containing a line of text read
     570             :  * from the file or NULL if the end of file was encountered.
     571             :  */
     572             : 
     573           6 : const char *CPLReadLine(FILE *fp)
     574             : 
     575             : {
     576             :     /* -------------------------------------------------------------------- */
     577             :     /*      Cleanup case.                                                   */
     578             :     /* -------------------------------------------------------------------- */
     579           6 :     if (fp == nullptr)
     580             :     {
     581           6 :         CPLReadLineBuffer(-1);
     582           6 :         return nullptr;
     583             :     }
     584             : 
     585             :     /* -------------------------------------------------------------------- */
     586             :     /*      Loop reading chunks of the line till we get to the end of       */
     587             :     /*      the line.                                                       */
     588             :     /* -------------------------------------------------------------------- */
     589           0 :     size_t nBytesReadThisTime = 0;
     590           0 :     char *pszRLBuffer = nullptr;
     591           0 :     size_t nReadSoFar = 0;
     592             : 
     593           0 :     do
     594             :     {
     595             :         /* --------------------------------------------------------------------
     596             :          */
     597             :         /*      Grow the working buffer if we have it nearly full.  Fail out */
     598             :         /*      of read line if we can't reallocate it big enough (for */
     599             :         /*      instance for a _very large_ file with no newlines). */
     600             :         /* --------------------------------------------------------------------
     601             :          */
     602           0 :         if (nReadSoFar > 100 * 1024 * 1024)
     603             :             // It is dubious that we need to read a line longer than 100 MB.
     604           0 :             return nullptr;
     605           0 :         pszRLBuffer = CPLReadLineBuffer(static_cast<int>(nReadSoFar) + 129);
     606           0 :         if (pszRLBuffer == nullptr)
     607           0 :             return nullptr;
     608             : 
     609             :         /* --------------------------------------------------------------------
     610             :          */
     611             :         /*      Do the actual read. */
     612             :         /* --------------------------------------------------------------------
     613             :          */
     614           0 :         if (CPLFGets(pszRLBuffer + nReadSoFar, 128, fp) == nullptr &&
     615             :             nReadSoFar == 0)
     616           0 :             return nullptr;
     617             : 
     618           0 :         nBytesReadThisTime = strlen(pszRLBuffer + nReadSoFar);
     619           0 :         nReadSoFar += nBytesReadThisTime;
     620           0 :     } while (nBytesReadThisTime >= 127 && pszRLBuffer[nReadSoFar - 1] != knCR &&
     621           0 :              pszRLBuffer[nReadSoFar - 1] != knLF);
     622             : 
     623           0 :     return pszRLBuffer;
     624             : }
     625             : 
     626             : /************************************************************************/
     627             : /*                            CPLReadLineL()                            */
     628             : /************************************************************************/
     629             : 
     630             : /**
     631             :  * Simplified line reading from text file.
     632             :  *
     633             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     634             :  *
     635             :  * @param fp file pointer opened with VSIFOpenL().
     636             :  *
     637             :  * @return pointer to an internal buffer containing a line of text read
     638             :  * from the file or NULL if the end of file was encountered.
     639             :  */
     640             : 
     641      194451 : const char *CPLReadLineL(VSILFILE *fp)
     642             : {
     643      194451 :     return CPLReadLine2L(fp, -1, nullptr);
     644             : }
     645             : 
     646             : /************************************************************************/
     647             : /*                           CPLReadLine2L()                            */
     648             : /************************************************************************/
     649             : 
     650             : /**
     651             :  * Simplified line reading from text file.
     652             :  *
     653             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     654             :  *
     655             :  * @param fp file pointer opened with VSIFOpenL().
     656             :  * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
     657             :  * @param papszOptions NULL-terminated array of options. Unused for now.
     658             : 
     659             :  * @return pointer to an internal buffer containing a line of text read
     660             :  * from the file or NULL if the end of file was encountered or the maximum
     661             :  * number of characters allowed reached.
     662             :  *
     663             :  * @since GDAL 1.7.0
     664             :  */
     665             : 
     666     1254680 : const char *CPLReadLine2L(VSILFILE *fp, int nMaxCars,
     667             :                           CPL_UNUSED CSLConstList papszOptions)
     668             : 
     669             : {
     670             :     int nBufLength;
     671     2509360 :     return CPLReadLine3L(fp, nMaxCars, &nBufLength, papszOptions);
     672             : }
     673             : 
     674             : /************************************************************************/
     675             : /*                           CPLReadLine3L()                            */
     676             : /************************************************************************/
     677             : 
     678             : /**
     679             :  * Simplified line reading from text file.
     680             :  *
     681             :  * Similar to CPLReadLine(), but reading from a large file API handle.
     682             :  *
     683             :  * @param fp file pointer opened with VSIFOpenL().
     684             :  * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
     685             :  * @param papszOptions NULL-terminated array of options. Unused for now.
     686             :  * @param[out] pnBufLength size of output string (must be non-NULL)
     687             : 
     688             :  * @return pointer to an internal buffer containing a line of text read
     689             :  * from the file or NULL if the end of file was encountered or the maximum
     690             :  * number of characters allowed reached.
     691             :  *
     692             :  * @since GDAL 2.3.0
     693             :  */
     694     1317540 : const char *CPLReadLine3L(VSILFILE *fp, int nMaxCars, int *pnBufLength,
     695             :                           CPL_UNUSED CSLConstList papszOptions)
     696             : {
     697             :     /* -------------------------------------------------------------------- */
     698             :     /*      Cleanup case.                                                   */
     699             :     /* -------------------------------------------------------------------- */
     700     1317540 :     if (fp == nullptr)
     701             :     {
     702        2296 :         CPLReadLineBuffer(-1);
     703        2296 :         return nullptr;
     704             :     }
     705             : 
     706             :     /* -------------------------------------------------------------------- */
     707             :     /*      Loop reading chunks of the line till we get to the end of       */
     708             :     /*      the line.                                                       */
     709             :     /* -------------------------------------------------------------------- */
     710     1315240 :     char *pszRLBuffer = nullptr;
     711     1315240 :     const size_t nChunkSize = 40;
     712     1315240 :     char szChunk[nChunkSize] = {};
     713     1315240 :     size_t nChunkBytesRead = 0;
     714     1315240 :     size_t nChunkBytesConsumed = 0;
     715             : 
     716     1315240 :     *pnBufLength = 0;
     717     1315240 :     szChunk[0] = 0;
     718             : 
     719             :     while (true)
     720             :     {
     721             :         /* --------------------------------------------------------------------
     722             :          */
     723             :         /*      Read a chunk from the input file. */
     724             :         /* --------------------------------------------------------------------
     725             :          */
     726     2357540 :         if (*pnBufLength > INT_MAX - static_cast<int>(nChunkSize) - 1)
     727             :         {
     728           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     729             :                      "Too big line : more than 2 billion characters!.");
     730           0 :             CPLReadLineBuffer(-1);
     731           0 :             return nullptr;
     732             :         }
     733             : 
     734             :         pszRLBuffer =
     735     2357540 :             CPLReadLineBuffer(static_cast<int>(*pnBufLength + nChunkSize + 1));
     736     2357540 :         if (pszRLBuffer == nullptr)
     737           0 :             return nullptr;
     738             : 
     739     2357540 :         if (nChunkBytesRead == nChunkBytesConsumed + 1)
     740             :         {
     741             : 
     742             :             // case where one character is left over from last read.
     743     1042300 :             szChunk[0] = szChunk[nChunkBytesConsumed];
     744             : 
     745     1042300 :             nChunkBytesConsumed = 0;
     746     1042300 :             nChunkBytesRead = VSIFReadL(szChunk + 1, 1, nChunkSize - 1, fp) + 1;
     747             :         }
     748             :         else
     749             :         {
     750     1315240 :             nChunkBytesConsumed = 0;
     751             : 
     752             :             // fresh read.
     753     1315240 :             nChunkBytesRead = VSIFReadL(szChunk, 1, nChunkSize, fp);
     754     1315240 :             if (nChunkBytesRead == 0)
     755             :             {
     756       10987 :                 if (*pnBufLength == 0)
     757       10987 :                     return nullptr;
     758             : 
     759           0 :                 break;
     760             :             }
     761             :         }
     762             : 
     763             :         /* --------------------------------------------------------------------
     764             :          */
     765             :         /*      copy over characters watching for end-of-line. */
     766             :         /* --------------------------------------------------------------------
     767             :          */
     768     2346560 :         bool bBreak = false;
     769    62218000 :         while (nChunkBytesConsumed < nChunkBytesRead - 1 && !bBreak)
     770             :         {
     771    59871400 :             if ((szChunk[nChunkBytesConsumed] == knCR &&
     772      172272 :                  szChunk[nChunkBytesConsumed + 1] == knLF) ||
     773    59699400 :                 (szChunk[nChunkBytesConsumed] == knLF &&
     774     1120600 :                  szChunk[nChunkBytesConsumed + 1] == knCR))
     775             :             {
     776      171995 :                 nChunkBytesConsumed += 2;
     777      171995 :                 bBreak = true;
     778             :             }
     779    59699400 :             else if (szChunk[nChunkBytesConsumed] == knLF ||
     780    58578800 :                      szChunk[nChunkBytesConsumed] == knCR)
     781             :             {
     782     1120880 :                 nChunkBytesConsumed += 1;
     783     1120880 :                 bBreak = true;
     784             :             }
     785             :             else
     786             :             {
     787    58578500 :                 pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
     788    58578500 :                 if (nMaxCars >= 0 && *pnBufLength == nMaxCars)
     789             :                 {
     790           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     791             :                              "Maximum number of characters allowed reached.");
     792           0 :                     return nullptr;
     793             :                 }
     794             :             }
     795             :         }
     796             : 
     797     2346560 :         if (bBreak)
     798     1292870 :             break;
     799             : 
     800             :         /* --------------------------------------------------------------------
     801             :          */
     802             :         /*      If there is a remaining character and it is not a newline */
     803             :         /*      consume it.  If it is a newline, but we are clearly at the */
     804             :         /*      end of the file then consume it. */
     805             :         /* --------------------------------------------------------------------
     806             :          */
     807     1053690 :         if (nChunkBytesConsumed == nChunkBytesRead - 1 &&
     808             :             nChunkBytesRead < nChunkSize)
     809             :         {
     810       11383 :             if (szChunk[nChunkBytesConsumed] == knLF ||
     811        1633 :                 szChunk[nChunkBytesConsumed] == knCR)
     812             :             {
     813        9750 :                 nChunkBytesConsumed++;
     814        9750 :                 break;
     815             :             }
     816             : 
     817        1633 :             pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
     818        1633 :             break;
     819             :         }
     820     1042300 :     }
     821             : 
     822             :     /* -------------------------------------------------------------------- */
     823             :     /*      If we have left over bytes after breaking out, seek back to     */
     824             :     /*      ensure they remain to be read next time.                        */
     825             :     /* -------------------------------------------------------------------- */
     826     1304250 :     if (nChunkBytesConsumed < nChunkBytesRead)
     827             :     {
     828     1287370 :         const size_t nBytesToPush = nChunkBytesRead - nChunkBytesConsumed;
     829             : 
     830     1287370 :         if (VSIFSeekL(fp, VSIFTellL(fp) - nBytesToPush, SEEK_SET) != 0)
     831           0 :             return nullptr;
     832             :     }
     833             : 
     834     1304250 :     pszRLBuffer[*pnBufLength] = '\0';
     835             : 
     836     1304250 :     return pszRLBuffer;
     837             : }
     838             : 
     839             : /************************************************************************/
     840             : /*                            CPLScanString()                           */
     841             : /************************************************************************/
     842             : 
     843             : /**
     844             :  * Scan up to a maximum number of characters from a given string,
     845             :  * allocate a buffer for a new string and fill it with scanned characters.
     846             :  *
     847             :  * @param pszString String containing characters to be scanned. It may be
     848             :  * terminated with a null character.
     849             :  *
     850             :  * @param nMaxLength The maximum number of character to read. Less
     851             :  * characters will be read if a null character is encountered.
     852             :  *
     853             :  * @param bTrimSpaces If TRUE, trim ending spaces from the input string.
     854             :  * Character considered as empty using isspace(3) function.
     855             :  *
     856             :  * @param bNormalize If TRUE, replace ':' symbol with the '_'. It is needed if
     857             :  * resulting string will be used in CPL dictionaries.
     858             :  *
     859             :  * @return Pointer to the resulting string buffer. Caller responsible to free
     860             :  * this buffer with CPLFree().
     861             :  */
     862             : 
     863        5017 : char *CPLScanString(const char *pszString, int nMaxLength, int bTrimSpaces,
     864             :                     int bNormalize)
     865             : {
     866        5017 :     if (!pszString)
     867           0 :         return nullptr;
     868             : 
     869        5017 :     if (!nMaxLength)
     870           2 :         return CPLStrdup("");
     871             : 
     872        5015 :     char *pszBuffer = static_cast<char *>(CPLMalloc(nMaxLength + 1));
     873        5015 :     if (!pszBuffer)
     874           0 :         return nullptr;
     875             : 
     876        5015 :     strncpy(pszBuffer, pszString, nMaxLength);
     877        5015 :     pszBuffer[nMaxLength] = '\0';
     878             : 
     879        5015 :     if (bTrimSpaces)
     880             :     {
     881        5012 :         size_t i = strlen(pszBuffer);
     882        6136 :         while (i > 0)
     883             :         {
     884        6102 :             i--;
     885        6102 :             if (!isspace(static_cast<unsigned char>(pszBuffer[i])))
     886        4978 :                 break;
     887        1124 :             pszBuffer[i] = '\0';
     888             :         }
     889             :     }
     890             : 
     891        5015 :     if (bNormalize)
     892             :     {
     893        4894 :         size_t i = strlen(pszBuffer);
     894       37519 :         while (i > 0)
     895             :         {
     896       32625 :             i--;
     897       32625 :             if (pszBuffer[i] == ':')
     898           0 :                 pszBuffer[i] = '_';
     899             :         }
     900             :     }
     901             : 
     902        5015 :     return pszBuffer;
     903             : }
     904             : 
     905             : /************************************************************************/
     906             : /*                             CPLScanLong()                            */
     907             : /************************************************************************/
     908             : 
     909             : /**
     910             :  * Scan up to a maximum number of characters from a string and convert
     911             :  * the result to a long.
     912             :  *
     913             :  * @param pszString String containing characters to be scanned. It may be
     914             :  * terminated with a null character.
     915             :  *
     916             :  * @param nMaxLength The maximum number of character to consider as part
     917             :  * of the number. Less characters will be considered if a null character
     918             :  * is encountered.
     919             :  *
     920             :  * @return Long value, converted from its ASCII form.
     921             :  */
     922             : 
     923        1358 : long CPLScanLong(const char *pszString, int nMaxLength)
     924             : {
     925        1358 :     CPLAssert(nMaxLength >= 0);
     926        1358 :     if (pszString == nullptr)
     927           0 :         return 0;
     928        1358 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     929        2716 :     const std::string osValue(pszString, nLength);
     930        1358 :     return atol(osValue.c_str());
     931             : }
     932             : 
     933             : /************************************************************************/
     934             : /*                            CPLScanULong()                            */
     935             : /************************************************************************/
     936             : 
     937             : /**
     938             :  * Scan up to a maximum number of characters from a string and convert
     939             :  * the result to a unsigned long.
     940             :  *
     941             :  * @param pszString String containing characters to be scanned. It may be
     942             :  * terminated with a null character.
     943             :  *
     944             :  * @param nMaxLength The maximum number of character to consider as part
     945             :  * of the number. Less characters will be considered if a null character
     946             :  * is encountered.
     947             :  *
     948             :  * @return Unsigned long value, converted from its ASCII form.
     949             :  */
     950             : 
     951           0 : unsigned long CPLScanULong(const char *pszString, int nMaxLength)
     952             : {
     953           0 :     CPLAssert(nMaxLength >= 0);
     954           0 :     if (pszString == nullptr)
     955           0 :         return 0;
     956           0 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     957           0 :     const std::string osValue(pszString, nLength);
     958           0 :     return strtoul(osValue.c_str(), nullptr, 10);
     959             : }
     960             : 
     961             : /************************************************************************/
     962             : /*                           CPLScanUIntBig()                           */
     963             : /************************************************************************/
     964             : 
     965             : /**
     966             :  * Extract big integer from string.
     967             :  *
     968             :  * Scan up to a maximum number of characters from a string and convert
     969             :  * the result to a GUIntBig.
     970             :  *
     971             :  * @param pszString String containing characters to be scanned. It may be
     972             :  * terminated with a null character.
     973             :  *
     974             :  * @param nMaxLength The maximum number of character to consider as part
     975             :  * of the number. Less characters will be considered if a null character
     976             :  * is encountered.
     977             :  *
     978             :  * @return GUIntBig value, converted from its ASCII form.
     979             :  */
     980             : 
     981       20417 : GUIntBig CPLScanUIntBig(const char *pszString, int nMaxLength)
     982             : {
     983       20417 :     CPLAssert(nMaxLength >= 0);
     984       20417 :     if (pszString == nullptr)
     985           0 :         return 0;
     986       20417 :     const size_t nLength = CPLStrnlen(pszString, nMaxLength);
     987       40834 :     const std::string osValue(pszString, nLength);
     988             : 
     989             :     /* -------------------------------------------------------------------- */
     990             :     /*      Fetch out the result                                            */
     991             :     /* -------------------------------------------------------------------- */
     992       20417 :     return strtoull(osValue.c_str(), nullptr, 10);
     993             : }
     994             : 
     995             : /************************************************************************/
     996             : /*                           CPLAtoGIntBig()                            */
     997             : /************************************************************************/
     998             : 
     999             : /**
    1000             :  * Convert a string to a 64 bit signed integer.
    1001             :  *
    1002             :  * @param pszString String containing 64 bit signed integer.
    1003             :  * @return 64 bit signed integer.
    1004             :  * @since GDAL 2.0
    1005             :  */
    1006             : 
    1007      103866 : GIntBig CPLAtoGIntBig(const char *pszString)
    1008             : {
    1009      103866 :     return atoll(pszString);
    1010             : }
    1011             : 
    1012             : #if defined(__MINGW32__) || defined(__sun__)
    1013             : 
    1014             : // mingw atoll() doesn't return ERANGE in case of overflow
    1015             : static int CPLAtoGIntBigExHasOverflow(const char *pszString, GIntBig nVal)
    1016             : {
    1017             :     if (strlen(pszString) <= 18)
    1018             :         return FALSE;
    1019             :     while (*pszString == ' ')
    1020             :         pszString++;
    1021             :     if (*pszString == '+')
    1022             :         pszString++;
    1023             :     char szBuffer[32] = {};
    1024             : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
    1025             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1026             : #pragma GCC diagnostic push
    1027             : #pragma GCC diagnostic ignored "-Wformat"
    1028             : #endif
    1029             :     snprintf(szBuffer, sizeof(szBuffer), CPL_FRMT_GIB, nVal);
    1030             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1031             : #pragma GCC diagnostic pop
    1032             : #endif
    1033             :     return strcmp(szBuffer, pszString) != 0;
    1034             : }
    1035             : 
    1036             : #endif
    1037             : 
    1038             : /************************************************************************/
    1039             : /*                          CPLAtoGIntBigEx()                           */
    1040             : /************************************************************************/
    1041             : 
    1042             : /**
    1043             :  * Convert a string to a 64 bit signed integer.
    1044             :  *
    1045             :  * @param pszString String containing 64 bit signed integer.
    1046             :  * @param bWarn Issue a warning if an overflow occurs during conversion
    1047             :  * @param pbOverflow Pointer to an integer to store if an overflow occurred, or
    1048             :  *        NULL
    1049             :  * @return 64 bit signed integer.
    1050             :  * @since GDAL 2.0
    1051             :  */
    1052             : 
    1053       99672 : GIntBig CPLAtoGIntBigEx(const char *pszString, int bWarn, int *pbOverflow)
    1054             : {
    1055       99672 :     errno = 0;
    1056       99672 :     GIntBig nVal = strtoll(pszString, nullptr, 10);
    1057       99672 :     if (errno == ERANGE
    1058             : #if defined(__MINGW32__) || defined(__sun__)
    1059             :         || CPLAtoGIntBigExHasOverflow(pszString, nVal)
    1060             : #endif
    1061             :     )
    1062             :     {
    1063           4 :         if (pbOverflow)
    1064           2 :             *pbOverflow = TRUE;
    1065           4 :         if (bWarn)
    1066             :         {
    1067           2 :             CPLError(CE_Warning, CPLE_AppDefined,
    1068             :                      "64 bit integer overflow when converting %s", pszString);
    1069             :         }
    1070           4 :         while (*pszString == ' ')
    1071           0 :             pszString++;
    1072           4 :         return (*pszString == '-') ? GINTBIG_MIN : GINTBIG_MAX;
    1073             :     }
    1074       99668 :     else if (pbOverflow)
    1075             :     {
    1076        3874 :         *pbOverflow = FALSE;
    1077             :     }
    1078       99668 :     return nVal;
    1079             : }
    1080             : 
    1081             : /************************************************************************/
    1082             : /*                           CPLScanPointer()                           */
    1083             : /************************************************************************/
    1084             : 
    1085             : /**
    1086             :  * Extract pointer from string.
    1087             :  *
    1088             :  * Scan up to a maximum number of characters from a string and convert
    1089             :  * the result to a pointer.
    1090             :  *
    1091             :  * @param pszString String containing characters to be scanned. It may be
    1092             :  * terminated with a null character.
    1093             :  *
    1094             :  * @param nMaxLength The maximum number of character to consider as part
    1095             :  * of the number. Less characters will be considered if a null character
    1096             :  * is encountered.
    1097             :  *
    1098             :  * @return pointer value, converted from its ASCII form.
    1099             :  */
    1100             : 
    1101         955 : void *CPLScanPointer(const char *pszString, int nMaxLength)
    1102             : {
    1103         955 :     char szTemp[128] = {};
    1104             : 
    1105             :     /* -------------------------------------------------------------------- */
    1106             :     /*      Compute string into local buffer, and terminate it.             */
    1107             :     /* -------------------------------------------------------------------- */
    1108         955 :     if (nMaxLength > static_cast<int>(sizeof(szTemp)) - 1)
    1109           0 :         nMaxLength = sizeof(szTemp) - 1;
    1110             : 
    1111         955 :     strncpy(szTemp, pszString, nMaxLength);
    1112         955 :     szTemp[nMaxLength] = '\0';
    1113             : 
    1114             :     /* -------------------------------------------------------------------- */
    1115             :     /*      On MSVC we have to scanf pointer values without the 0x          */
    1116             :     /*      prefix.                                                         */
    1117             :     /* -------------------------------------------------------------------- */
    1118         955 :     if (STARTS_WITH_CI(szTemp, "0x"))
    1119             :     {
    1120         929 :         void *pResult = nullptr;
    1121             : 
    1122             : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
    1123             :         // cppcheck-suppress invalidscanf
    1124             :         sscanf(szTemp + 2, "%p", &pResult);
    1125             : #else
    1126             :         // cppcheck-suppress invalidscanf
    1127         929 :         sscanf(szTemp, "%p", &pResult);
    1128             : 
    1129             :         // Solaris actually behaves like MSVCRT.
    1130         929 :         if (pResult == nullptr)
    1131             :         {
    1132             :             // cppcheck-suppress invalidscanf
    1133           0 :             sscanf(szTemp + 2, "%p", &pResult);
    1134             :         }
    1135             : #endif
    1136         929 :         return pResult;
    1137             :     }
    1138             : 
    1139             : #if SIZEOF_VOIDP == 8
    1140          26 :     return reinterpret_cast<void *>(CPLScanUIntBig(szTemp, nMaxLength));
    1141             : #else
    1142             :     return reinterpret_cast<void *>(CPLScanULong(szTemp, nMaxLength));
    1143             : #endif
    1144             : }
    1145             : 
    1146             : /************************************************************************/
    1147             : /*                             CPLScanDouble()                          */
    1148             : /************************************************************************/
    1149             : 
    1150             : /**
    1151             :  * Extract double from string.
    1152             :  *
    1153             :  * Scan up to a maximum number of characters from a string and convert the
    1154             :  * result to a double. This function uses CPLAtof() to convert string to
    1155             :  * double value, so it uses a comma as a decimal delimiter.
    1156             :  *
    1157             :  * @param pszString String containing characters to be scanned. It may be
    1158             :  * terminated with a null character.
    1159             :  *
    1160             :  * @param nMaxLength The maximum number of character to consider as part
    1161             :  * of the number. Less characters will be considered if a null character
    1162             :  * is encountered.
    1163             :  *
    1164             :  * @return Double value, converted from its ASCII form.
    1165             :  */
    1166             : 
    1167         317 : double CPLScanDouble(const char *pszString, int nMaxLength)
    1168             : {
    1169         317 :     char szValue[32] = {};
    1170         317 :     char *pszValue = nullptr;
    1171             : 
    1172         317 :     if (nMaxLength + 1 < static_cast<int>(sizeof(szValue)))
    1173         317 :         pszValue = szValue;
    1174             :     else
    1175           0 :         pszValue = static_cast<char *>(CPLMalloc(nMaxLength + 1));
    1176             : 
    1177             :     /* -------------------------------------------------------------------- */
    1178             :     /*      Compute string into local buffer, and terminate it.             */
    1179             :     /* -------------------------------------------------------------------- */
    1180         317 :     strncpy(pszValue, pszString, nMaxLength);
    1181         317 :     pszValue[nMaxLength] = '\0';
    1182             : 
    1183             :     /* -------------------------------------------------------------------- */
    1184             :     /*      Make a pass through converting 'D's to 'E's.                    */
    1185             :     /* -------------------------------------------------------------------- */
    1186        6436 :     for (int i = 0; i < nMaxLength; i++)
    1187        6119 :         if (pszValue[i] == 'd' || pszValue[i] == 'D')
    1188          45 :             pszValue[i] = 'E';
    1189             : 
    1190             :     /* -------------------------------------------------------------------- */
    1191             :     /*      The conversion itself.                                          */
    1192             :     /* -------------------------------------------------------------------- */
    1193         317 :     const double dfValue = CPLAtof(pszValue);
    1194             : 
    1195         317 :     if (pszValue != szValue)
    1196           0 :         CPLFree(pszValue);
    1197         317 :     return dfValue;
    1198             : }
    1199             : 
    1200             : /************************************************************************/
    1201             : /*                      CPLPrintString()                                */
    1202             : /************************************************************************/
    1203             : 
    1204             : /**
    1205             :  * Copy the string pointed to by pszSrc, NOT including the terminating
    1206             :  * `\\0' character, to the array pointed to by pszDest.
    1207             :  *
    1208             :  * @param pszDest Pointer to the destination string buffer. Should be
    1209             :  * large enough to hold the resulting string.
    1210             :  *
    1211             :  * @param pszSrc Pointer to the source buffer.
    1212             :  *
    1213             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1214             :  * is greater than nMaxLen, it will be truncated.
    1215             :  *
    1216             :  * @return Number of characters printed.
    1217             :  */
    1218             : 
    1219        8770 : int CPLPrintString(char *pszDest, const char *pszSrc, int nMaxLen)
    1220             : {
    1221        8770 :     if (!pszDest)
    1222           0 :         return 0;
    1223             : 
    1224        8770 :     if (!pszSrc)
    1225             :     {
    1226           0 :         *pszDest = '\0';
    1227           0 :         return 1;
    1228             :     }
    1229             : 
    1230        8770 :     int nChars = 0;
    1231        8770 :     char *pszTemp = pszDest;
    1232             : 
    1233      128873 :     while (nChars < nMaxLen && *pszSrc)
    1234             :     {
    1235      120103 :         *pszTemp++ = *pszSrc++;
    1236      120103 :         nChars++;
    1237             :     }
    1238             : 
    1239        8770 :     return nChars;
    1240             : }
    1241             : 
    1242             : /************************************************************************/
    1243             : /*                         CPLPrintStringFill()                         */
    1244             : /************************************************************************/
    1245             : 
    1246             : /**
    1247             :  * Copy the string pointed to by pszSrc, NOT including the terminating
    1248             :  * `\\0' character, to the array pointed to by pszDest. Remainder of the
    1249             :  * destination string will be filled with space characters. This is only
    1250             :  * difference from the PrintString().
    1251             :  *
    1252             :  * @param pszDest Pointer to the destination string buffer. Should be
    1253             :  * large enough to hold the resulting string.
    1254             :  *
    1255             :  * @param pszSrc Pointer to the source buffer.
    1256             :  *
    1257             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1258             :  * is greater than nMaxLen, it will be truncated.
    1259             :  *
    1260             :  * @return Number of characters printed.
    1261             :  */
    1262             : 
    1263         203 : int CPLPrintStringFill(char *pszDest, const char *pszSrc, int nMaxLen)
    1264             : {
    1265         203 :     if (!pszDest)
    1266           0 :         return 0;
    1267             : 
    1268         203 :     if (!pszSrc)
    1269             :     {
    1270           0 :         memset(pszDest, ' ', nMaxLen);
    1271           0 :         return nMaxLen;
    1272             :     }
    1273             : 
    1274         203 :     char *pszTemp = pszDest;
    1275        1219 :     while (nMaxLen && *pszSrc)
    1276             :     {
    1277        1016 :         *pszTemp++ = *pszSrc++;
    1278        1016 :         nMaxLen--;
    1279             :     }
    1280             : 
    1281         203 :     if (nMaxLen)
    1282          69 :         memset(pszTemp, ' ', nMaxLen);
    1283             : 
    1284         203 :     return nMaxLen;
    1285             : }
    1286             : 
    1287             : /************************************************************************/
    1288             : /*                          CPLPrintInt32()                             */
    1289             : /************************************************************************/
    1290             : 
    1291             : /**
    1292             :  * Print GInt32 value into specified string buffer. This string will not
    1293             :  * be NULL-terminated.
    1294             :  *
    1295             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1296             :  * large enough to hold the resulting string. Note, that the string will
    1297             :  * not be NULL-terminated, so user should do this himself, if needed.
    1298             :  *
    1299             :  * @param iValue Numerical value to print.
    1300             :  *
    1301             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1302             :  * is greater than nMaxLen, it will be truncated.
    1303             :  *
    1304             :  * @return Number of characters printed.
    1305             :  */
    1306             : 
    1307           9 : int CPLPrintInt32(char *pszBuffer, GInt32 iValue, int nMaxLen)
    1308             : {
    1309           9 :     if (!pszBuffer)
    1310           0 :         return 0;
    1311             : 
    1312           9 :     if (nMaxLen >= 64)
    1313           0 :         nMaxLen = 63;
    1314             : 
    1315           9 :     char szTemp[64] = {};
    1316             : 
    1317             : #if UINT_MAX == 65535
    1318             :     snprintf(szTemp, sizeof(szTemp), "%*ld", nMaxLen, iValue);
    1319             : #else
    1320           9 :     snprintf(szTemp, sizeof(szTemp), "%*d", nMaxLen, iValue);
    1321             : #endif
    1322             : 
    1323           9 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1324             : }
    1325             : 
    1326             : /************************************************************************/
    1327             : /*                          CPLPrintUIntBig()                           */
    1328             : /************************************************************************/
    1329             : 
    1330             : /**
    1331             :  * Print GUIntBig value into specified string buffer. This string will not
    1332             :  * be NULL-terminated.
    1333             :  *
    1334             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1335             :  * large enough to hold the resulting string. Note, that the string will
    1336             :  * not be NULL-terminated, so user should do this himself, if needed.
    1337             :  *
    1338             :  * @param iValue Numerical value to print.
    1339             :  *
    1340             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1341             :  * is greater than nMaxLen, it will be truncated.
    1342             :  *
    1343             :  * @return Number of characters printed.
    1344             :  */
    1345             : 
    1346          26 : int CPLPrintUIntBig(char *pszBuffer, GUIntBig iValue, int nMaxLen)
    1347             : {
    1348          26 :     if (!pszBuffer)
    1349           0 :         return 0;
    1350             : 
    1351          26 :     if (nMaxLen >= 64)
    1352           0 :         nMaxLen = 63;
    1353             : 
    1354          26 :     char szTemp[64] = {};
    1355             : 
    1356             : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
    1357             : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
    1358             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1359             : #pragma GCC diagnostic push
    1360             : #pragma GCC diagnostic ignored "-Wformat"
    1361             : #pragma GCC diagnostic ignored "-Wformat-extra-args"
    1362             : #endif
    1363             :     snprintf(szTemp, sizeof(szTemp), "%*I64u", nMaxLen, iValue);
    1364             : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
    1365             : #pragma GCC diagnostic pop
    1366             : #endif
    1367             : #else
    1368          26 :     snprintf(szTemp, sizeof(szTemp), "%*llu", nMaxLen, iValue);
    1369             : #endif
    1370             : 
    1371          26 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1372             : }
    1373             : 
    1374             : /************************************************************************/
    1375             : /*                          CPLPrintPointer()                           */
    1376             : /************************************************************************/
    1377             : 
    1378             : /**
    1379             :  * Print pointer value into specified string buffer. This string will not
    1380             :  * be NULL-terminated.
    1381             :  *
    1382             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1383             :  * large enough to hold the resulting string. Note, that the string will
    1384             :  * not be NULL-terminated, so user should do this himself, if needed.
    1385             :  *
    1386             :  * @param pValue Pointer to ASCII encode.
    1387             :  *
    1388             :  * @param nMaxLen Maximum length of the resulting string. If string length
    1389             :  * is greater than nMaxLen, it will be truncated.
    1390             :  *
    1391             :  * @return Number of characters printed.
    1392             :  */
    1393             : 
    1394        8708 : int CPLPrintPointer(char *pszBuffer, void *pValue, int nMaxLen)
    1395             : {
    1396        8708 :     if (!pszBuffer)
    1397           0 :         return 0;
    1398             : 
    1399        8708 :     if (nMaxLen >= 64)
    1400        7758 :         nMaxLen = 63;
    1401             : 
    1402        8708 :     char szTemp[64] = {};
    1403             : 
    1404        8708 :     snprintf(szTemp, sizeof(szTemp), "%p", pValue);
    1405             : 
    1406             :     // On windows, and possibly some other platforms the sprintf("%p")
    1407             :     // does not prefix things with 0x so it is hard to know later if the
    1408             :     // value is hex encoded.  Fix this up here.
    1409             : 
    1410        8708 :     if (!STARTS_WITH_CI(szTemp, "0x"))
    1411           0 :         snprintf(szTemp, sizeof(szTemp), "0x%p", pValue);
    1412             : 
    1413        8708 :     return CPLPrintString(pszBuffer, szTemp, nMaxLen);
    1414             : }
    1415             : 
    1416             : /************************************************************************/
    1417             : /*                          CPLPrintDouble()                            */
    1418             : /************************************************************************/
    1419             : 
    1420             : /**
    1421             :  * Print double value into specified string buffer. Exponential character
    1422             :  * flag 'E' (or 'e') will be replaced with 'D', as in Fortran. Resulting
    1423             :  * string will not to be NULL-terminated.
    1424             :  *
    1425             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1426             :  * large enough to hold the resulting string. Note, that the string will
    1427             :  * not be NULL-terminated, so user should do this himself, if needed.
    1428             :  *
    1429             :  * @param pszFormat Format specifier (for example, "%16.9E").
    1430             :  *
    1431             :  * @param dfValue Numerical value to print.
    1432             :  *
    1433             :  * @param pszLocale Unused.
    1434             :  *
    1435             :  * @return Number of characters printed.
    1436             :  */
    1437             : 
    1438           0 : int CPLPrintDouble(char *pszBuffer, const char *pszFormat, double dfValue,
    1439             :                    CPL_UNUSED const char *pszLocale)
    1440             : {
    1441           0 :     if (!pszBuffer)
    1442           0 :         return 0;
    1443             : 
    1444           0 :     const int knDoubleBufferSize = 64;
    1445           0 :     char szTemp[knDoubleBufferSize] = {};
    1446             : 
    1447           0 :     CPLsnprintf(szTemp, knDoubleBufferSize, pszFormat, dfValue);
    1448           0 :     szTemp[knDoubleBufferSize - 1] = '\0';
    1449             : 
    1450           0 :     for (int i = 0; szTemp[i] != '\0'; i++)
    1451             :     {
    1452           0 :         if (szTemp[i] == 'E' || szTemp[i] == 'e')
    1453           0 :             szTemp[i] = 'D';
    1454             :     }
    1455             : 
    1456           0 :     return CPLPrintString(pszBuffer, szTemp, 64);
    1457             : }
    1458             : 
    1459             : /************************************************************************/
    1460             : /*                            CPLPrintTime()                            */
    1461             : /************************************************************************/
    1462             : 
    1463             : /**
    1464             :  * Print specified time value accordingly to the format options and
    1465             :  * specified locale name. This function does following:
    1466             :  *
    1467             :  *  - if locale parameter is not NULL, the current locale setting will be
    1468             :  *  stored and replaced with the specified one;
    1469             :  *  - format time value with the strftime(3) function;
    1470             :  *  - restore back current locale, if was saved.
    1471             :  *
    1472             :  * @param pszBuffer Pointer to the destination string buffer. Should be
    1473             :  * large enough to hold the resulting string. Note, that the string will
    1474             :  * not be NULL-terminated, so user should do this himself, if needed.
    1475             :  *
    1476             :  * @param nMaxLen Maximum length of the resulting string. If string length is
    1477             :  * greater than nMaxLen, it will be truncated.
    1478             :  *
    1479             :  * @param pszFormat Controls the output format. Options are the same as
    1480             :  * for strftime(3) function.
    1481             :  *
    1482             :  * @param poBrokenTime Pointer to the broken-down time structure. May be
    1483             :  * requested with the VSIGMTime() and VSILocalTime() functions.
    1484             :  *
    1485             :  * @param pszLocale Pointer to a character string containing locale name
    1486             :  * ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
    1487             :  * manipulate with locale settings and current process locale will be used for
    1488             :  * printing. Be aware that it may be unsuitable to use current locale for
    1489             :  * printing time, because all names will be printed in your native language,
    1490             :  * as well as time format settings also may be adjusted differently from the
    1491             :  * C/POSIX defaults. To solve these problems this option was introduced.
    1492             :  *
    1493             :  * @return Number of characters printed.
    1494             :  */
    1495             : 
    1496          30 : int CPLPrintTime(char *pszBuffer, int nMaxLen, const char *pszFormat,
    1497             :                  const struct tm *poBrokenTime, const char *pszLocale)
    1498             : {
    1499             :     char *pszTemp =
    1500          30 :         static_cast<char *>(CPLMalloc((nMaxLen + 1) * sizeof(char)));
    1501             : 
    1502          30 :     if (pszLocale && EQUAL(pszLocale, "C") &&
    1503          30 :         strcmp(pszFormat, "%a, %d %b %Y %H:%M:%S GMT") == 0)
    1504             :     {
    1505             :         // Particular case when formatting RFC822 datetime, to avoid locale
    1506             :         // change
    1507             :         static const char *const aszMonthStr[] = {"Jan", "Feb", "Mar", "Apr",
    1508             :                                                   "May", "Jun", "Jul", "Aug",
    1509             :                                                   "Sep", "Oct", "Nov", "Dec"};
    1510             :         static const char *const aszDayOfWeek[] = {"Sun", "Mon", "Tue", "Wed",
    1511             :                                                    "Thu", "Fri", "Sat"};
    1512          60 :         snprintf(pszTemp, nMaxLen + 1, "%s, %02d %s %04d %02d:%02d:%02d GMT",
    1513          30 :                  aszDayOfWeek[std::max(0, std::min(6, poBrokenTime->tm_wday))],
    1514          30 :                  poBrokenTime->tm_mday,
    1515          30 :                  aszMonthStr[std::max(0, std::min(11, poBrokenTime->tm_mon))],
    1516          30 :                  poBrokenTime->tm_year + 1900, poBrokenTime->tm_hour,
    1517          60 :                  poBrokenTime->tm_min, poBrokenTime->tm_sec);
    1518             :     }
    1519             :     else
    1520             :     {
    1521             : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
    1522             :         char *pszCurLocale = NULL;
    1523             : 
    1524             :         if (pszLocale || EQUAL(pszLocale, ""))
    1525             :         {
    1526             :             // Save the current locale.
    1527             :             pszCurLocale = CPLsetlocale(LC_ALL, NULL);
    1528             :             // Set locale to the specified value.
    1529             :             CPLsetlocale(LC_ALL, pszLocale);
    1530             :         }
    1531             : #else
    1532             :         (void)pszLocale;
    1533             : #endif
    1534             : 
    1535           0 :         if (!strftime(pszTemp, nMaxLen + 1, pszFormat, poBrokenTime))
    1536           0 :             memset(pszTemp, 0, nMaxLen + 1);
    1537             : 
    1538             : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
    1539             :         // Restore stored locale back.
    1540             :         if (pszCurLocale)
    1541             :             CPLsetlocale(LC_ALL, pszCurLocale);
    1542             : #endif
    1543             :     }
    1544             : 
    1545          30 :     const int nChars = CPLPrintString(pszBuffer, pszTemp, nMaxLen);
    1546             : 
    1547          30 :     CPLFree(pszTemp);
    1548             : 
    1549          30 :     return nChars;
    1550             : }
    1551             : 
    1552             : /************************************************************************/
    1553             : /*                       CPLVerifyConfiguration()                       */
    1554             : /************************************************************************/
    1555             : 
    1556           0 : void CPLVerifyConfiguration()
    1557             : 
    1558             : {
    1559             :     /* -------------------------------------------------------------------- */
    1560             :     /*      Verify data types.                                              */
    1561             :     /* -------------------------------------------------------------------- */
    1562             :     static_assert(sizeof(short) == 2);   // We unfortunately rely on this
    1563             :     static_assert(sizeof(int) == 4);     // We unfortunately rely on this
    1564             :     static_assert(sizeof(float) == 4);   // We unfortunately rely on this
    1565             :     static_assert(sizeof(double) == 8);  // We unfortunately rely on this
    1566             :     static_assert(sizeof(GInt64) == 8);
    1567             :     static_assert(sizeof(GInt32) == 4);
    1568             :     static_assert(sizeof(GInt16) == 2);
    1569             :     static_assert(sizeof(GByte) == 1);
    1570             : 
    1571             :     /* -------------------------------------------------------------------- */
    1572             :     /*      Verify byte order                                               */
    1573             :     /* -------------------------------------------------------------------- */
    1574             : #ifdef CPL_LSB
    1575             : #if __cplusplus >= 202002L
    1576             :     static_assert(std::endian::native == std::endian::little);
    1577             : #elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
    1578             :     static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
    1579             : #endif
    1580             : #elif defined(CPL_MSB)
    1581             : #if __cplusplus >= 202002L
    1582             :     static_assert(std::endian::native == std::endian::big);
    1583             : #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
    1584             :     static_assert(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
    1585             : #endif
    1586             : #else
    1587             : #error "CPL_LSB or CPL_MSB must be defined"
    1588             : #endif
    1589           0 : }
    1590             : 
    1591             : #ifdef DEBUG_CONFIG_OPTIONS
    1592             : 
    1593             : static CPLMutex *hRegisterConfigurationOptionMutex = nullptr;
    1594             : static std::set<CPLString> *paoGetKeys = nullptr;
    1595             : static std::set<CPLString> *paoSetKeys = nullptr;
    1596             : 
    1597             : /************************************************************************/
    1598             : /*                      CPLShowAccessedOptions()                        */
    1599             : /************************************************************************/
    1600             : 
    1601             : static void CPLShowAccessedOptions()
    1602             : {
    1603             :     std::set<CPLString>::iterator aoIter;
    1604             : 
    1605             :     printf("Configuration options accessed in reading : "); /*ok*/
    1606             :     aoIter = paoGetKeys->begin();
    1607             :     while (aoIter != paoGetKeys->end())
    1608             :     {
    1609             :         printf("%s, ", (*aoIter).c_str()); /*ok*/
    1610             :         ++aoIter;
    1611             :     }
    1612             :     printf("\n"); /*ok*/
    1613             : 
    1614             :     printf("Configuration options accessed in writing : "); /*ok*/
    1615             :     aoIter = paoSetKeys->begin();
    1616             :     while (aoIter != paoSetKeys->end())
    1617             :     {
    1618             :         printf("%s, ", (*aoIter).c_str()); /*ok*/
    1619             :         ++aoIter;
    1620             :     }
    1621             :     printf("\n"); /*ok*/
    1622             : 
    1623             :     delete paoGetKeys;
    1624             :     delete paoSetKeys;
    1625             :     paoGetKeys = nullptr;
    1626             :     paoSetKeys = nullptr;
    1627             : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                       CPLAccessConfigOption()                        */
    1631             : /************************************************************************/
    1632             : 
    1633             : static void CPLAccessConfigOption(const char *pszKey, bool bGet)
    1634             : {
    1635             :     CPLMutexHolderD(&hRegisterConfigurationOptionMutex);
    1636             :     if (paoGetKeys == nullptr)
    1637             :     {
    1638             :         paoGetKeys = new std::set<CPLString>;
    1639             :         paoSetKeys = new std::set<CPLString>;
    1640             :         atexit(CPLShowAccessedOptions);
    1641             :     }
    1642             :     if (bGet)
    1643             :         paoGetKeys->insert(pszKey);
    1644             :     else
    1645             :         paoSetKeys->insert(pszKey);
    1646             : }
    1647             : #endif
    1648             : 
    1649             : /************************************************************************/
    1650             : /*                         CPLGetConfigOption()                         */
    1651             : /************************************************************************/
    1652             : 
    1653             : /**
    1654             :  * Get the value of a configuration option.
    1655             :  *
    1656             :  * The value is the value of a (key, value) option set with
    1657             :  * CPLSetConfigOption(), or CPLSetThreadLocalConfigOption() of the same
    1658             :  * thread. If the given option was no defined with
    1659             :  * CPLSetConfigOption(), it tries to find it in environment variables.
    1660             :  *
    1661             :  * Note: the string returned by CPLGetConfigOption() might be short-lived, and
    1662             :  * in particular it will become invalid after a call to CPLSetConfigOption()
    1663             :  * with the same key.
    1664             :  *
    1665             :  * To override temporary a potentially existing option with a new value, you
    1666             :  * can use the following snippet :
    1667             :  * <pre>
    1668             :  *     // backup old value
    1669             :  *     const char* pszOldValTmp = CPLGetConfigOption(pszKey, NULL);
    1670             :  *     char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
    1671             :  *     // override with new value
    1672             :  *     CPLSetConfigOption(pszKey, pszNewVal);
    1673             :  *     // do something useful
    1674             :  *     // restore old value
    1675             :  *     CPLSetConfigOption(pszKey, pszOldVal);
    1676             :  *     CPLFree(pszOldVal);
    1677             :  * </pre>
    1678             :  *
    1679             :  * @param pszKey the key of the option to retrieve
    1680             :  * @param pszDefault a default value if the key does not match existing defined
    1681             :  *     options (may be NULL)
    1682             :  * @return the value associated to the key, or the default value if not found
    1683             :  *
    1684             :  * @see CPLSetConfigOption(), http://trac.osgeo.org/gdal/wiki/ConfigOptions
    1685             :  */
    1686     4751910 : const char *CPL_STDCALL CPLGetConfigOption(const char *pszKey,
    1687             :                                            const char *pszDefault)
    1688             : 
    1689             : {
    1690     4751910 :     const char *pszResult = CPLGetThreadLocalConfigOption(pszKey, nullptr);
    1691             : 
    1692     4751040 :     if (pszResult == nullptr)
    1693             :     {
    1694     4713980 :         pszResult = CPLGetGlobalConfigOption(pszKey, nullptr);
    1695             :     }
    1696             : 
    1697     4752660 :     if (gbIgnoreEnvVariables)
    1698             :     {
    1699           6 :         const char *pszEnvVar = getenv(pszKey);
    1700           6 :         if (pszEnvVar != nullptr)
    1701             :         {
    1702           1 :             CPLDebug("CPL",
    1703             :                      "Ignoring environment variable %s=%s because of "
    1704             :                      "ignore-env-vars=yes setting in configuration file",
    1705             :                      pszKey, pszEnvVar);
    1706             :         }
    1707             :     }
    1708     4752650 :     else if (pszResult == nullptr)
    1709             :     {
    1710     4708120 :         pszResult = getenv(pszKey);
    1711             :     }
    1712             : 
    1713     4752620 :     if (pszResult == nullptr)
    1714     4699590 :         return pszDefault;
    1715             : 
    1716       53032 :     return pszResult;
    1717             : }
    1718             : 
    1719             : /************************************************************************/
    1720             : /*                         CPLGetConfigOptions()                        */
    1721             : /************************************************************************/
    1722             : 
    1723             : /**
    1724             :  * Return the list of configuration options as KEY=VALUE pairs.
    1725             :  *
    1726             :  * The list is the one set through the CPLSetConfigOption() API.
    1727             :  *
    1728             :  * Options that through environment variables or with
    1729             :  * CPLSetThreadLocalConfigOption() will *not* be listed.
    1730             :  *
    1731             :  * @return a copy of the list, to be freed with CSLDestroy().
    1732             :  * @since GDAL 2.2
    1733             :  */
    1734           7 : char **CPLGetConfigOptions(void)
    1735             : {
    1736          14 :     CPLMutexHolderD(&hConfigMutex);
    1737          14 :     return CSLDuplicate(const_cast<char **>(g_papszConfigOptions));
    1738             : }
    1739             : 
    1740             : /************************************************************************/
    1741             : /*                         CPLSetConfigOptions()                        */
    1742             : /************************************************************************/
    1743             : 
    1744             : /**
    1745             :  * Replace the full list of configuration options with the passed list of
    1746             :  * KEY=VALUE pairs.
    1747             :  *
    1748             :  * This has the same effect of clearing the existing list, and setting
    1749             :  * individually each pair with the CPLSetConfigOption() API.
    1750             :  *
    1751             :  * This does not affect options set through environment variables or with
    1752             :  * CPLSetThreadLocalConfigOption().
    1753             :  *
    1754             :  * The passed list is copied by the function.
    1755             :  *
    1756             :  * @param papszConfigOptions the new list (or NULL).
    1757             :  *
    1758             :  * @since GDAL 2.2
    1759             :  */
    1760          87 : void CPLSetConfigOptions(const char *const *papszConfigOptions)
    1761             : {
    1762          87 :     CPLMutexHolderD(&hConfigMutex);
    1763          87 :     CSLDestroy(const_cast<char **>(g_papszConfigOptions));
    1764          87 :     g_papszConfigOptions = const_cast<volatile char **>(
    1765          87 :         CSLDuplicate(const_cast<char **>(papszConfigOptions)));
    1766          87 : }
    1767             : 
    1768             : /************************************************************************/
    1769             : /*                   CPLGetThreadLocalConfigOption()                    */
    1770             : /************************************************************************/
    1771             : 
    1772             : /** Same as CPLGetConfigOption() but only with options set with
    1773             :  * CPLSetThreadLocalConfigOption() */
    1774     4777050 : const char *CPL_STDCALL CPLGetThreadLocalConfigOption(const char *pszKey,
    1775             :                                                       const char *pszDefault)
    1776             : 
    1777             : {
    1778             : #ifdef DEBUG_CONFIG_OPTIONS
    1779             :     CPLAccessConfigOption(pszKey, TRUE);
    1780             : #endif
    1781             : 
    1782     4777050 :     const char *pszResult = nullptr;
    1783             : 
    1784     4777050 :     int bMemoryError = FALSE;
    1785             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    1786     4777050 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    1787     4776750 :     if (papszTLConfigOptions != nullptr)
    1788     4353300 :         pszResult = CSLFetchNameValue(papszTLConfigOptions, pszKey);
    1789             : 
    1790     4776590 :     if (pszResult == nullptr)
    1791     4738950 :         return pszDefault;
    1792             : 
    1793       37643 :     return pszResult;
    1794             : }
    1795             : 
    1796             : /************************************************************************/
    1797             : /*                   CPLGetGlobalConfigOption()                         */
    1798             : /************************************************************************/
    1799             : 
    1800             : /** Same as CPLGetConfigOption() but excludes environment variables and
    1801             :  *  options set with CPLSetThreadLocalConfigOption().
    1802             :  *  This function should generally not be used by applications, which should
    1803             :  *  use CPLGetConfigOption() instead.
    1804             :  *  @since 3.8 */
    1805     4716330 : const char *CPL_STDCALL CPLGetGlobalConfigOption(const char *pszKey,
    1806             :                                                  const char *pszDefault)
    1807             : {
    1808             : #ifdef DEBUG_CONFIG_OPTIONS
    1809             :     CPLAccessConfigOption(pszKey, TRUE);
    1810             : #endif
    1811             : 
    1812     9433790 :     CPLMutexHolderD(&hConfigMutex);
    1813             : 
    1814             :     const char *pszResult =
    1815     4717460 :         CSLFetchNameValue(const_cast<char **>(g_papszConfigOptions), pszKey);
    1816             : 
    1817     4717460 :     if (pszResult == nullptr)
    1818     4709790 :         return pszDefault;
    1819             : 
    1820        7663 :     return pszResult;
    1821             : }
    1822             : 
    1823             : /************************************************************************/
    1824             : /*                    CPLSubscribeToSetConfigOption()                   */
    1825             : /************************************************************************/
    1826             : 
    1827             : /**
    1828             :  * Install a callback that will be notified of calls to CPLSetConfigOption()/
    1829             :  * CPLSetThreadLocalConfigOption()
    1830             :  *
    1831             :  * @param pfnCallback Callback. Must not be NULL
    1832             :  * @param pUserData Callback user data. May be NULL.
    1833             :  * @return subscriber ID that can be used with CPLUnsubscribeToSetConfigOption()
    1834             :  * @since GDAL 3.7
    1835             :  */
    1836             : 
    1837        1164 : int CPLSubscribeToSetConfigOption(CPLSetConfigOptionSubscriber pfnCallback,
    1838             :                                   void *pUserData)
    1839             : {
    1840        2328 :     CPLMutexHolderD(&hConfigMutex);
    1841        1169 :     for (int nId = 0;
    1842        1169 :          nId < static_cast<int>(gSetConfigOptionSubscribers.size()); ++nId)
    1843             :     {
    1844           6 :         if (!gSetConfigOptionSubscribers[nId].first)
    1845             :         {
    1846           1 :             gSetConfigOptionSubscribers[nId].first = pfnCallback;
    1847           1 :             gSetConfigOptionSubscribers[nId].second = pUserData;
    1848           1 :             return nId;
    1849             :         }
    1850             :     }
    1851        1163 :     int nId = static_cast<int>(gSetConfigOptionSubscribers.size());
    1852        1163 :     gSetConfigOptionSubscribers.push_back(
    1853        1163 :         std::pair<CPLSetConfigOptionSubscriber, void *>(pfnCallback,
    1854             :                                                         pUserData));
    1855        1163 :     return nId;
    1856             : }
    1857             : 
    1858             : /************************************************************************/
    1859             : /*                  CPLUnsubscribeToSetConfigOption()                   */
    1860             : /************************************************************************/
    1861             : 
    1862             : /**
    1863             :  * Remove a subscriber installed with CPLSubscribeToSetConfigOption()
    1864             :  *
    1865             :  * @param nId Subscriber id returned by CPLSubscribeToSetConfigOption()
    1866             :  * @since GDAL 3.7
    1867             :  */
    1868             : 
    1869           4 : void CPLUnsubscribeToSetConfigOption(int nId)
    1870             : {
    1871           8 :     CPLMutexHolderD(&hConfigMutex);
    1872           4 :     if (nId == static_cast<int>(gSetConfigOptionSubscribers.size()) - 1)
    1873             :     {
    1874           3 :         gSetConfigOptionSubscribers.resize(gSetConfigOptionSubscribers.size() -
    1875             :                                            1);
    1876             :     }
    1877           2 :     else if (nId >= 0 &&
    1878           1 :              nId < static_cast<int>(gSetConfigOptionSubscribers.size()))
    1879             :     {
    1880           1 :         gSetConfigOptionSubscribers[nId].first = nullptr;
    1881             :     }
    1882           4 : }
    1883             : 
    1884             : /************************************************************************/
    1885             : /*                  NotifyOtherComponentsConfigOptionChanged()          */
    1886             : /************************************************************************/
    1887             : 
    1888       60588 : static void NotifyOtherComponentsConfigOptionChanged(const char *pszKey,
    1889             :                                                      const char *pszValue,
    1890             :                                                      bool bThreadLocal)
    1891             : {
    1892             :     // Hack
    1893       60588 :     if (STARTS_WITH_CI(pszKey, "AWS_"))
    1894        2312 :         VSICurlAuthParametersChanged();
    1895             : 
    1896       60588 :     if (!gSetConfigOptionSubscribers.empty())
    1897             :     {
    1898      119856 :         for (const auto &iter : gSetConfigOptionSubscribers)
    1899             :         {
    1900       59992 :             if (iter.first)
    1901       60110 :                 iter.first(pszKey, pszValue, bThreadLocal, iter.second);
    1902             :         }
    1903             :     }
    1904       60394 : }
    1905             : 
    1906             : /************************************************************************/
    1907             : /*                         CPLSetConfigOption()                         */
    1908             : /************************************************************************/
    1909             : 
    1910             : /**
    1911             :  * Set a configuration option for GDAL/OGR use.
    1912             :  *
    1913             :  * Those options are defined as a (key, value) couple. The value corresponding
    1914             :  * to a key can be got later with the CPLGetConfigOption() method.
    1915             :  *
    1916             :  * This mechanism is similar to environment variables, but options set with
    1917             :  * CPLSetConfigOption() overrides, for CPLGetConfigOption() point of view,
    1918             :  * values defined in the environment.
    1919             :  *
    1920             :  * If CPLSetConfigOption() is called several times with the same key, the
    1921             :  * value provided during the last call will be used.
    1922             :  *
    1923             :  * Options can also be passed on the command line of most GDAL utilities
    1924             :  * with the with '--config KEY VALUE'. For example,
    1925             :  * ogrinfo --config CPL_DEBUG ON ~/data/test/point.shp
    1926             :  *
    1927             :  * This function can also be used to clear a setting by passing NULL as the
    1928             :  * value (note: passing NULL will not unset an existing environment variable;
    1929             :  * it will just unset a value previously set by CPLSetConfigOption()).
    1930             :  *
    1931             :  * @param pszKey the key of the option
    1932             :  * @param pszValue the value of the option, or NULL to clear a setting.
    1933             :  *
    1934             :  * @see http://trac.osgeo.org/gdal/wiki/ConfigOptions
    1935             :  */
    1936        4708 : void CPL_STDCALL CPLSetConfigOption(const char *pszKey, const char *pszValue)
    1937             : 
    1938             : {
    1939             : #ifdef DEBUG_CONFIG_OPTIONS
    1940             :     CPLAccessConfigOption(pszKey, FALSE);
    1941             : #endif
    1942        9416 :     CPLMutexHolderD(&hConfigMutex);
    1943             : 
    1944             : #ifdef OGRAPISPY_ENABLED
    1945        4708 :     OGRAPISPYCPLSetConfigOption(pszKey, pszValue);
    1946             : #endif
    1947             : 
    1948        4708 :     g_papszConfigOptions = const_cast<volatile char **>(CSLSetNameValue(
    1949             :         const_cast<char **>(g_papszConfigOptions), pszKey, pszValue));
    1950             : 
    1951        4708 :     NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
    1952             :                                              /*bTheadLocal=*/false);
    1953        4708 : }
    1954             : 
    1955             : /************************************************************************/
    1956             : /*                   CPLSetThreadLocalTLSFreeFunc()                     */
    1957             : /************************************************************************/
    1958             : 
    1959             : /* non-stdcall wrapper function for CSLDestroy() (#5590) */
    1960           6 : static void CPLSetThreadLocalTLSFreeFunc(void *pData)
    1961             : {
    1962           6 :     CSLDestroy(reinterpret_cast<char **>(pData));
    1963           6 : }
    1964             : 
    1965             : /************************************************************************/
    1966             : /*                   CPLSetThreadLocalConfigOption()                    */
    1967             : /************************************************************************/
    1968             : 
    1969             : /**
    1970             :  * Set a configuration option for GDAL/OGR use.
    1971             :  *
    1972             :  * Those options are defined as a (key, value) couple. The value corresponding
    1973             :  * to a key can be got later with the CPLGetConfigOption() method.
    1974             :  *
    1975             :  * This function sets the configuration option that only applies in the
    1976             :  * current thread, as opposed to CPLSetConfigOption() which sets an option
    1977             :  * that applies on all threads. CPLSetThreadLocalConfigOption() will override
    1978             :  * the effect of CPLSetConfigOption) for the current thread.
    1979             :  *
    1980             :  * This function can also be used to clear a setting by passing NULL as the
    1981             :  * value (note: passing NULL will not unset an existing environment variable or
    1982             :  * a value set through CPLSetConfigOption();
    1983             :  * it will just unset a value previously set by
    1984             :  * CPLSetThreadLocalConfigOption()).
    1985             :  *
    1986             :  * @param pszKey the key of the option
    1987             :  * @param pszValue the value of the option, or NULL to clear a setting.
    1988             :  */
    1989             : 
    1990       55985 : void CPL_STDCALL CPLSetThreadLocalConfigOption(const char *pszKey,
    1991             :                                                const char *pszValue)
    1992             : 
    1993             : {
    1994             : #ifdef DEBUG_CONFIG_OPTIONS
    1995             :     CPLAccessConfigOption(pszKey, FALSE);
    1996             : #endif
    1997             : 
    1998             : #ifdef OGRAPISPY_ENABLED
    1999       55985 :     OGRAPISPYCPLSetThreadLocalConfigOption(pszKey, pszValue);
    2000             : #endif
    2001             : 
    2002       55945 :     int bMemoryError = FALSE;
    2003             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2004       55945 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2005       55911 :     if (bMemoryError)
    2006           0 :         return;
    2007             : 
    2008             :     papszTLConfigOptions =
    2009       55911 :         CSLSetNameValue(papszTLConfigOptions, pszKey, pszValue);
    2010             : 
    2011       55829 :     CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
    2012             :                           CPLSetThreadLocalTLSFreeFunc);
    2013             : 
    2014       55835 :     NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
    2015             :                                              /*bTheadLocal=*/true);
    2016             : }
    2017             : 
    2018             : /************************************************************************/
    2019             : /*                   CPLGetThreadLocalConfigOptions()                   */
    2020             : /************************************************************************/
    2021             : 
    2022             : /**
    2023             :  * Return the list of thread local configuration options as KEY=VALUE pairs.
    2024             :  *
    2025             :  * Options that through environment variables or with
    2026             :  * CPLSetConfigOption() will *not* be listed.
    2027             :  *
    2028             :  * @return a copy of the list, to be freed with CSLDestroy().
    2029             :  * @since GDAL 2.2
    2030             :  */
    2031      747822 : char **CPLGetThreadLocalConfigOptions(void)
    2032             : {
    2033      747822 :     int bMemoryError = FALSE;
    2034             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2035      747822 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2036      744202 :     if (bMemoryError)
    2037           0 :         return nullptr;
    2038      744202 :     return CSLDuplicate(papszTLConfigOptions);
    2039             : }
    2040             : 
    2041             : /************************************************************************/
    2042             : /*                   CPLSetThreadLocalConfigOptions()                   */
    2043             : /************************************************************************/
    2044             : 
    2045             : /**
    2046             :  * Replace the full list of thread local configuration options with the
    2047             :  * passed list of KEY=VALUE pairs.
    2048             :  *
    2049             :  * This has the same effect of clearing the existing list, and setting
    2050             :  * individually each pair with the CPLSetThreadLocalConfigOption() API.
    2051             :  *
    2052             :  * This does not affect options set through environment variables or with
    2053             :  * CPLSetConfigOption().
    2054             :  *
    2055             :  * The passed list is copied by the function.
    2056             :  *
    2057             :  * @param papszConfigOptions the new list (or NULL).
    2058             :  *
    2059             :  * @since GDAL 2.2
    2060             :  */
    2061     1487350 : void CPLSetThreadLocalConfigOptions(const char *const *papszConfigOptions)
    2062             : {
    2063     1487350 :     int bMemoryError = FALSE;
    2064             :     char **papszTLConfigOptions = reinterpret_cast<char **>(
    2065     1487350 :         CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2066     1483420 :     if (bMemoryError)
    2067           0 :         return;
    2068     1483420 :     CSLDestroy(papszTLConfigOptions);
    2069             :     papszTLConfigOptions =
    2070     1480580 :         CSLDuplicate(const_cast<char **>(papszConfigOptions));
    2071     1483320 :     CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
    2072             :                           CPLSetThreadLocalTLSFreeFunc);
    2073             : }
    2074             : 
    2075             : /************************************************************************/
    2076             : /*                           CPLFreeConfig()                            */
    2077             : /************************************************************************/
    2078             : 
    2079        1370 : void CPL_STDCALL CPLFreeConfig()
    2080             : 
    2081             : {
    2082             :     {
    2083        2740 :         CPLMutexHolderD(&hConfigMutex);
    2084             : 
    2085        1370 :         CSLDestroy(const_cast<char **>(g_papszConfigOptions));
    2086        1370 :         g_papszConfigOptions = nullptr;
    2087             : 
    2088        1370 :         int bMemoryError = FALSE;
    2089             :         char **papszTLConfigOptions = reinterpret_cast<char **>(
    2090        1370 :             CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    2091        1370 :         if (papszTLConfigOptions != nullptr)
    2092             :         {
    2093         222 :             CSLDestroy(papszTLConfigOptions);
    2094         222 :             CPLSetTLS(CTLS_CONFIGOPTIONS, nullptr, FALSE);
    2095             :         }
    2096             :     }
    2097        1370 :     CPLDestroyMutex(hConfigMutex);
    2098        1370 :     hConfigMutex = nullptr;
    2099        1370 : }
    2100             : 
    2101             : /************************************************************************/
    2102             : /*                    CPLLoadConfigOptionsFromFile()                    */
    2103             : /************************************************************************/
    2104             : 
    2105             : /** Load configuration from a given configuration file.
    2106             : 
    2107             : A configuration file is a text file in a .ini style format, that lists
    2108             : configuration options and their values.
    2109             : Lines starting with # are comment lines.
    2110             : 
    2111             : Example:
    2112             : \verbatim
    2113             : [configoptions]
    2114             : # set BAR as the value of configuration option FOO
    2115             : FOO=BAR
    2116             : \endverbatim
    2117             : 
    2118             : Starting with GDAL 3.5, a configuration file can also contain credentials
    2119             : (or more generally options related to a virtual file system) for a given path
    2120             : prefix, that can also be set with VSISetPathSpecificOption(). Credentials should
    2121             : be put under a [credentials] section, and for each path prefix, under a relative
    2122             : subsection whose name starts with "[." (e.g. "[.some_arbitrary_name]"), and
    2123             : whose first key is "path".
    2124             : 
    2125             : Example:
    2126             : \verbatim
    2127             : [credentials]
    2128             : 
    2129             : [.private_bucket]
    2130             : path=/vsis3/my_private_bucket
    2131             : AWS_SECRET_ACCESS_KEY=...
    2132             : AWS_ACCESS_KEY_ID=...
    2133             : 
    2134             : [.sentinel_s2_l1c]
    2135             : path=/vsis3/sentinel-s2-l1c
    2136             : AWS_REQUEST_PAYER=requester
    2137             : \endverbatim
    2138             : 
    2139             : Starting with GDAL 3.6, a leading [directives] section might be added with
    2140             : a "ignore-env-vars=yes" setting to indicate that, starting with that point,
    2141             : all environment variables should be ignored, and only configuration options
    2142             : defined in the [configoptions] sections or through the CPLSetConfigOption() /
    2143             : CPLSetThreadLocalConfigOption() functions should be taken into account.
    2144             : 
    2145             : This function is typically called by CPLLoadConfigOptionsFromPredefinedFiles()
    2146             : 
    2147             : @param pszFilename File where to load configuration from.
    2148             : @param bOverrideEnvVars Whether configuration options from the configuration
    2149             :                         file should override environment variables.
    2150             : @since GDAL 3.3
    2151             :  */
    2152        2600 : void CPLLoadConfigOptionsFromFile(const char *pszFilename, int bOverrideEnvVars)
    2153             : {
    2154        2600 :     VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
    2155        2600 :     if (fp == nullptr)
    2156        2591 :         return;
    2157           9 :     CPLDebug("CPL", "Loading configuration from %s", pszFilename);
    2158             :     const char *pszLine;
    2159             :     enum class Section
    2160             :     {
    2161             :         NONE,
    2162             :         GENERAL,
    2163             :         CONFIG_OPTIONS,
    2164             :         CREDENTIALS,
    2165             :     };
    2166           9 :     Section eCurrentSection = Section::NONE;
    2167           9 :     bool bInSubsection = false;
    2168          18 :     std::string osPath;
    2169           9 :     int nSectionCounter = 0;
    2170             : 
    2171          56 :     const auto IsSpaceOnly = [](const char *pszStr)
    2172             :     {
    2173          56 :         for (; *pszStr; ++pszStr)
    2174             :         {
    2175          47 :             if (!isspace(static_cast<unsigned char>(*pszStr)))
    2176          41 :                 return false;
    2177             :         }
    2178           9 :         return true;
    2179             :     };
    2180             : 
    2181          59 :     while ((pszLine = CPLReadLine2L(fp, -1, nullptr)) != nullptr)
    2182             :     {
    2183          50 :         if (IsSpaceOnly(pszLine))
    2184             :         {
    2185             :             // Blank line
    2186             :         }
    2187          41 :         else if (pszLine[0] == '#')
    2188             :         {
    2189             :             // Comment line
    2190             :         }
    2191          35 :         else if (strcmp(pszLine, "[configoptions]") == 0)
    2192             :         {
    2193           6 :             nSectionCounter++;
    2194           6 :             eCurrentSection = Section::CONFIG_OPTIONS;
    2195             :         }
    2196          29 :         else if (strcmp(pszLine, "[credentials]") == 0)
    2197             :         {
    2198           4 :             nSectionCounter++;
    2199           4 :             eCurrentSection = Section::CREDENTIALS;
    2200           4 :             bInSubsection = false;
    2201           4 :             osPath.clear();
    2202             :         }
    2203          25 :         else if (strcmp(pszLine, "[directives]") == 0)
    2204             :         {
    2205           2 :             nSectionCounter++;
    2206           2 :             if (nSectionCounter != 1)
    2207             :             {
    2208           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2209             :                          "The [directives] section should be the first one in "
    2210             :                          "the file, otherwise some its settings might not be "
    2211             :                          "used correctly.");
    2212             :             }
    2213           2 :             eCurrentSection = Section::GENERAL;
    2214             :         }
    2215          23 :         else if (eCurrentSection == Section::GENERAL)
    2216             :         {
    2217           2 :             char *pszKey = nullptr;
    2218           2 :             const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2219           2 :             if (pszKey && pszValue)
    2220             :             {
    2221           2 :                 if (strcmp(pszKey, "ignore-env-vars") == 0)
    2222             :                 {
    2223           2 :                     gbIgnoreEnvVariables = CPLTestBool(pszValue);
    2224             :                 }
    2225             :                 else
    2226             :                 {
    2227           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    2228             :                              "Ignoring %s line in [directives] section",
    2229             :                              pszLine);
    2230             :                 }
    2231             :             }
    2232           2 :             CPLFree(pszKey);
    2233             :         }
    2234          21 :         else if (eCurrentSection == Section::CREDENTIALS)
    2235             :         {
    2236          15 :             if (strncmp(pszLine, "[.", 2) == 0)
    2237             :             {
    2238           4 :                 bInSubsection = true;
    2239           4 :                 osPath.clear();
    2240             :             }
    2241          11 :             else if (bInSubsection)
    2242             :             {
    2243          10 :                 char *pszKey = nullptr;
    2244          10 :                 const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2245          10 :                 if (pszKey && pszValue)
    2246             :                 {
    2247          10 :                     if (strcmp(pszKey, "path") == 0)
    2248             :                     {
    2249           4 :                         if (!osPath.empty())
    2250             :                         {
    2251           1 :                             CPLError(
    2252             :                                 CE_Warning, CPLE_AppDefined,
    2253             :                                 "Duplicated 'path' key in the same subsection. "
    2254             :                                 "Ignoring %s=%s",
    2255             :                                 pszKey, pszValue);
    2256             :                         }
    2257             :                         else
    2258             :                         {
    2259           3 :                             osPath = pszValue;
    2260             :                         }
    2261             :                     }
    2262           6 :                     else if (osPath.empty())
    2263             :                     {
    2264           1 :                         CPLError(CE_Warning, CPLE_AppDefined,
    2265             :                                  "First entry in a credentials subsection "
    2266             :                                  "should be 'path'.");
    2267             :                     }
    2268             :                     else
    2269             :                     {
    2270           5 :                         VSISetPathSpecificOption(osPath.c_str(), pszKey,
    2271             :                                                  pszValue);
    2272             :                     }
    2273             :                 }
    2274          10 :                 CPLFree(pszKey);
    2275             :             }
    2276           1 :             else if (pszLine[0] == '[')
    2277             :             {
    2278           0 :                 eCurrentSection = Section::NONE;
    2279             :             }
    2280             :             else
    2281             :             {
    2282           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2283             :                          "Ignoring content in [credential] section that is not "
    2284             :                          "in a [.xxxxx] subsection");
    2285             :             }
    2286             :         }
    2287           6 :         else if (pszLine[0] == '[')
    2288             :         {
    2289           0 :             eCurrentSection = Section::NONE;
    2290             :         }
    2291           6 :         else if (eCurrentSection == Section::CONFIG_OPTIONS)
    2292             :         {
    2293           6 :             char *pszKey = nullptr;
    2294           6 :             const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    2295           6 :             if (pszKey && pszValue)
    2296             :             {
    2297          11 :                 if (bOverrideEnvVars || gbIgnoreEnvVariables ||
    2298           5 :                     getenv(pszKey) == nullptr)
    2299             :                 {
    2300           5 :                     CPLDebugOnly("CPL", "Setting configuration option %s=%s",
    2301             :                                  pszKey, pszValue);
    2302           5 :                     CPLSetConfigOption(pszKey, pszValue);
    2303             :                 }
    2304             :                 else
    2305             :                 {
    2306           1 :                     CPLDebug("CPL",
    2307             :                              "Ignoring configuration option %s=%s from "
    2308             :                              "configuration file as it is already set "
    2309             :                              "as an environment variable",
    2310             :                              pszKey, pszValue);
    2311             :                 }
    2312             :             }
    2313           6 :             CPLFree(pszKey);
    2314             :         }
    2315             :     }
    2316           9 :     VSIFCloseL(fp);
    2317             : }
    2318             : 
    2319             : /************************************************************************/
    2320             : /*                CPLLoadConfigOptionsFromPredefinedFiles()             */
    2321             : /************************************************************************/
    2322             : 
    2323             : /** Load configuration from a set of predefined files.
    2324             :  *
    2325             :  * If the environment variable (or configuration option) GDAL_CONFIG_FILE is
    2326             :  * set, then CPLLoadConfigOptionsFromFile() will be called with the value of
    2327             :  * this configuration option as the file location.
    2328             :  *
    2329             :  * Otherwise, for Unix builds, CPLLoadConfigOptionsFromFile() will be called
    2330             :  * with ${sysconfdir}/gdal/gdalrc first where ${sysconfdir} evaluates
    2331             :  * to ${prefix}/etc, unless the --sysconfdir switch of configure has been
    2332             :  * invoked.
    2333             :  *
    2334             :  * Then CPLLoadConfigOptionsFromFile() will be called with $(HOME)/.gdal/gdalrc
    2335             :  * on Unix builds (potentially overriding what was loaded with the sysconfdir)
    2336             :  * or $(USERPROFILE)/.gdal/gdalrc on Windows builds.
    2337             :  *
    2338             :  * CPLLoadConfigOptionsFromFile() will be called with bOverrideEnvVars = false,
    2339             :  * that is the value of environment variables previously set will be used
    2340             :  * instead of the value set in the configuration files (unless the configuration
    2341             :  * file contains a leading [directives] section with a "ignore-env-vars=yes"
    2342             :  * setting).
    2343             :  *
    2344             :  * This function is automatically called by GDALDriverManager() constructor
    2345             :  *
    2346             :  * @since GDAL 3.3
    2347             :  */
    2348        1297 : void CPLLoadConfigOptionsFromPredefinedFiles()
    2349             : {
    2350        1297 :     const char *pszFile = CPLGetConfigOption("GDAL_CONFIG_FILE", nullptr);
    2351        1297 :     if (pszFile != nullptr)
    2352             :     {
    2353           2 :         CPLLoadConfigOptionsFromFile(pszFile, false);
    2354             :     }
    2355             :     else
    2356             :     {
    2357             : #ifdef SYSCONFDIR
    2358        1295 :         pszFile = CPLFormFilename(CPLFormFilename(SYSCONFDIR, "gdal", nullptr),
    2359             :                                   "gdalrc", nullptr);
    2360        1295 :         CPLLoadConfigOptionsFromFile(pszFile, false);
    2361             : #endif
    2362             : 
    2363             : #ifdef _WIN32
    2364             :         const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
    2365             : #else
    2366        1295 :         const char *pszHome = CPLGetConfigOption("HOME", nullptr);
    2367             : #endif
    2368        1295 :         if (pszHome != nullptr)
    2369             :         {
    2370        1295 :             pszFile = CPLFormFilename(
    2371             :                 CPLFormFilename(pszHome, ".gdal", nullptr), "gdalrc", nullptr);
    2372        1295 :             CPLLoadConfigOptionsFromFile(pszFile, false);
    2373             :         }
    2374             :     }
    2375        1297 : }
    2376             : 
    2377             : /************************************************************************/
    2378             : /*                              CPLStat()                               */
    2379             : /************************************************************************/
    2380             : 
    2381             : /** Same as VSIStat() except it works on "C:" as if it were "C:\". */
    2382             : 
    2383          66 : int CPLStat(const char *pszPath, VSIStatBuf *psStatBuf)
    2384             : 
    2385             : {
    2386          66 :     if (strlen(pszPath) == 2 && pszPath[1] == ':')
    2387             :     {
    2388           0 :         char szAltPath[4] = {pszPath[0], pszPath[1], '\\', '\0'};
    2389           0 :         return VSIStat(szAltPath, psStatBuf);
    2390             :     }
    2391             : 
    2392          66 :     return VSIStat(pszPath, psStatBuf);
    2393             : }
    2394             : 
    2395             : /************************************************************************/
    2396             : /*                            proj_strtod()                             */
    2397             : /************************************************************************/
    2398          20 : static double proj_strtod(char *nptr, char **endptr)
    2399             : 
    2400             : {
    2401          20 :     char c = '\0';
    2402          20 :     char *cp = nptr;
    2403             : 
    2404             :     // Scan for characters which cause problems with VC++ strtod().
    2405          92 :     while ((c = *cp) != '\0')
    2406             :     {
    2407          78 :         if (c == 'd' || c == 'D')
    2408             :         {
    2409             :             // Found one, so NUL it out, call strtod(),
    2410             :             // then restore it and return.
    2411           6 :             *cp = '\0';
    2412           6 :             const double result = CPLStrtod(nptr, endptr);
    2413           6 :             *cp = c;
    2414           6 :             return result;
    2415             :         }
    2416          72 :         ++cp;
    2417             :     }
    2418             : 
    2419             :     // No offending characters, just handle normally.
    2420             : 
    2421          14 :     return CPLStrtod(nptr, endptr);
    2422             : }
    2423             : 
    2424             : /************************************************************************/
    2425             : /*                            CPLDMSToDec()                             */
    2426             : /************************************************************************/
    2427             : 
    2428             : static const char *sym = "NnEeSsWw";
    2429             : constexpr double vm[] = {1.0, 0.0166666666667, 0.00027777778};
    2430             : 
    2431             : /** CPLDMSToDec */
    2432           8 : double CPLDMSToDec(const char *is)
    2433             : 
    2434             : {
    2435             :     // Copy string into work space.
    2436           8 :     while (isspace(static_cast<unsigned char>(*is)))
    2437           0 :         ++is;
    2438             : 
    2439           8 :     const char *p = is;
    2440           8 :     char work[64] = {};
    2441           8 :     char *s = work;
    2442           8 :     int n = sizeof(work);
    2443          68 :     for (; isgraph(*p) && --n;)
    2444          60 :         *s++ = *p++;
    2445           8 :     *s = '\0';
    2446             :     // It is possible that a really odd input (like lots of leading
    2447             :     // zeros) could be truncated in copying into work.  But...
    2448           8 :     s = work;
    2449           8 :     int sign = *s;
    2450             : 
    2451           8 :     if (sign == '+' || sign == '-')
    2452           0 :         s++;
    2453             :     else
    2454           8 :         sign = '+';
    2455             : 
    2456           8 :     int nl = 0;
    2457           8 :     double v = 0.0;
    2458          28 :     for (; nl < 3; nl = n + 1)
    2459             :     {
    2460          20 :         if (!(isdigit(static_cast<unsigned char>(*s)) || *s == '.'))
    2461           0 :             break;
    2462          20 :         const double tv = proj_strtod(s, &s);
    2463          20 :         if (tv == HUGE_VAL)
    2464           0 :             return tv;
    2465          20 :         switch (*s)
    2466             :         {
    2467           6 :             case 'D':
    2468             :             case 'd':
    2469           6 :                 n = 0;
    2470           6 :                 break;
    2471           6 :             case '\'':
    2472           6 :                 n = 1;
    2473           6 :                 break;
    2474           6 :             case '"':
    2475           6 :                 n = 2;
    2476           6 :                 break;
    2477           0 :             case 'r':
    2478             :             case 'R':
    2479           0 :                 if (nl)
    2480             :                 {
    2481           0 :                     return 0.0;
    2482             :                 }
    2483           0 :                 ++s;
    2484           0 :                 v = tv;
    2485           0 :                 goto skip;
    2486           2 :             default:
    2487           2 :                 v += tv * vm[nl];
    2488           2 :             skip:
    2489           2 :                 n = 4;
    2490           2 :                 continue;
    2491             :         }
    2492          18 :         if (n < nl)
    2493             :         {
    2494           0 :             return 0.0;
    2495             :         }
    2496          18 :         v += tv * vm[n];
    2497          18 :         ++s;
    2498             :     }
    2499             :     // Postfix sign.
    2500           8 :     if (*s && ((p = strchr(sym, *s))) != nullptr)
    2501             :     {
    2502           2 :         sign = (p - sym) >= 4 ? '-' : '+';
    2503           2 :         ++s;
    2504             :     }
    2505           8 :     if (sign == '-')
    2506           1 :         v = -v;
    2507             : 
    2508           8 :     return v;
    2509             : }
    2510             : 
    2511             : /************************************************************************/
    2512             : /*                            CPLDecToDMS()                             */
    2513             : /************************************************************************/
    2514             : 
    2515             : /** Translate a decimal degrees value to a DMS string with hemisphere. */
    2516             : 
    2517         500 : const char *CPLDecToDMS(double dfAngle, const char *pszAxis, int nPrecision)
    2518             : 
    2519             : {
    2520         500 :     VALIDATE_POINTER1(pszAxis, "CPLDecToDMS", "");
    2521             : 
    2522         500 :     if (std::isnan(dfAngle))
    2523           0 :         return "Invalid angle";
    2524             : 
    2525         500 :     const double dfEpsilon = (0.5 / 3600.0) * pow(0.1, nPrecision);
    2526         500 :     const double dfABSAngle = std::abs(dfAngle) + dfEpsilon;
    2527         500 :     if (dfABSAngle > 361.0)
    2528             :     {
    2529           0 :         return "Invalid angle";
    2530             :     }
    2531             : 
    2532         500 :     const int nDegrees = static_cast<int>(dfABSAngle);
    2533         500 :     const int nMinutes = static_cast<int>((dfABSAngle - nDegrees) * 60);
    2534         500 :     double dfSeconds = dfABSAngle * 3600 - nDegrees * 3600 - nMinutes * 60;
    2535             : 
    2536         500 :     if (dfSeconds > dfEpsilon * 3600.0)
    2537         494 :         dfSeconds -= dfEpsilon * 3600.0;
    2538             : 
    2539         500 :     const char *pszHemisphere = nullptr;
    2540         500 :     if (EQUAL(pszAxis, "Long") && dfAngle < 0.0)
    2541         218 :         pszHemisphere = "W";
    2542         282 :     else if (EQUAL(pszAxis, "Long"))
    2543          32 :         pszHemisphere = "E";
    2544         250 :     else if (dfAngle < 0.0)
    2545          17 :         pszHemisphere = "S";
    2546             :     else
    2547         233 :         pszHemisphere = "N";
    2548             : 
    2549         500 :     char szFormat[30] = {};
    2550         500 :     CPLsnprintf(szFormat, sizeof(szFormat), "%%3dd%%2d\'%%%d.%df\"%s",
    2551             :                 nPrecision + 3, nPrecision, pszHemisphere);
    2552             : 
    2553             :     static CPL_THREADLOCAL char szBuffer[50] = {};
    2554         500 :     CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, nDegrees, nMinutes,
    2555             :                 dfSeconds);
    2556             : 
    2557         500 :     return szBuffer;
    2558             : }
    2559             : 
    2560             : /************************************************************************/
    2561             : /*                         CPLPackedDMSToDec()                          */
    2562             : /************************************************************************/
    2563             : 
    2564             : /**
    2565             :  * Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
    2566             :  *
    2567             :  * This function converts a packed DMS angle to seconds. The standard
    2568             :  * packed DMS format is:
    2569             :  *
    2570             :  *  degrees * 1000000 + minutes * 1000 + seconds
    2571             :  *
    2572             :  * Example:     angle = 120025045.25 yields
    2573             :  *              deg = 120
    2574             :  *              min = 25
    2575             :  *              sec = 45.25
    2576             :  *
    2577             :  * The algorithm used for the conversion is as follows:
    2578             :  *
    2579             :  * 1.  The absolute value of the angle is used.
    2580             :  *
    2581             :  * 2.  The degrees are separated out:
    2582             :  *     deg = angle/1000000                    (fractional portion truncated)
    2583             :  *
    2584             :  * 3.  The minutes are separated out:
    2585             :  *     min = (angle - deg * 1000000) / 1000   (fractional portion truncated)
    2586             :  *
    2587             :  * 4.  The seconds are then computed:
    2588             :  *     sec = angle - deg * 1000000 - min * 1000
    2589             :  *
    2590             :  * 5.  The total angle in seconds is computed:
    2591             :  *     sec = deg * 3600.0 + min * 60.0 + sec
    2592             :  *
    2593             :  * 6.  The sign of sec is set to that of the input angle.
    2594             :  *
    2595             :  * Packed DMS values used by the USGS GCTP package and probably by other
    2596             :  * software.
    2597             :  *
    2598             :  * NOTE: This code does not validate input value. If you give the wrong
    2599             :  * value, you will get the wrong result.
    2600             :  *
    2601             :  * @param dfPacked Angle in packed DMS format.
    2602             :  *
    2603             :  * @return Angle in decimal degrees.
    2604             :  *
    2605             :  */
    2606             : 
    2607          34 : double CPLPackedDMSToDec(double dfPacked)
    2608             : {
    2609          34 :     const double dfSign = dfPacked < 0.0 ? -1 : 1;
    2610             : 
    2611          34 :     double dfSeconds = std::abs(dfPacked);
    2612          34 :     double dfDegrees = floor(dfSeconds / 1000000.0);
    2613          34 :     dfSeconds -= dfDegrees * 1000000.0;
    2614          34 :     const double dfMinutes = floor(dfSeconds / 1000.0);
    2615          34 :     dfSeconds -= dfMinutes * 1000.0;
    2616          34 :     dfSeconds = dfSign * (dfDegrees * 3600.0 + dfMinutes * 60.0 + dfSeconds);
    2617          34 :     dfDegrees = dfSeconds / 3600.0;
    2618             : 
    2619          34 :     return dfDegrees;
    2620             : }
    2621             : 
    2622             : /************************************************************************/
    2623             : /*                         CPLDecToPackedDMS()                          */
    2624             : /************************************************************************/
    2625             : /**
    2626             :  * Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
    2627             :  *
    2628             :  * This function converts a value, specified in decimal degrees into
    2629             :  * packed DMS angle. The standard packed DMS format is:
    2630             :  *
    2631             :  *  degrees * 1000000 + minutes * 1000 + seconds
    2632             :  *
    2633             :  * See also CPLPackedDMSToDec().
    2634             :  *
    2635             :  * @param dfDec Angle in decimal degrees.
    2636             :  *
    2637             :  * @return Angle in packed DMS format.
    2638             :  *
    2639             :  */
    2640             : 
    2641           8 : double CPLDecToPackedDMS(double dfDec)
    2642             : {
    2643           8 :     const double dfSign = dfDec < 0.0 ? -1 : 1;
    2644             : 
    2645           8 :     dfDec = std::abs(dfDec);
    2646           8 :     const double dfDegrees = floor(dfDec);
    2647           8 :     const double dfMinutes = floor((dfDec - dfDegrees) * 60.0);
    2648           8 :     const double dfSeconds = (dfDec - dfDegrees) * 3600.0 - dfMinutes * 60.0;
    2649             : 
    2650           8 :     return dfSign * (dfDegrees * 1000000.0 + dfMinutes * 1000.0 + dfSeconds);
    2651             : }
    2652             : 
    2653             : /************************************************************************/
    2654             : /*                         CPLStringToComplex()                         */
    2655             : /************************************************************************/
    2656             : 
    2657             : /** Fetch the real and imaginary part of a serialized complex number */
    2658        2148 : void CPL_DLL CPLStringToComplex(const char *pszString, double *pdfReal,
    2659             :                                 double *pdfImag)
    2660             : 
    2661             : {
    2662        2148 :     while (*pszString == ' ')
    2663           0 :         pszString++;
    2664             : 
    2665        2148 :     *pdfReal = CPLAtof(pszString);
    2666        2148 :     *pdfImag = 0.0;
    2667             : 
    2668        2148 :     int iPlus = -1;
    2669        2148 :     int iImagEnd = -1;
    2670             : 
    2671        4546 :     for (int i = 0; i < 100 && pszString[i] != '\0' && pszString[i] != ' '; i++)
    2672             :     {
    2673        2398 :         if (pszString[i] == '+' && i > 0)
    2674           0 :             iPlus = i;
    2675        2398 :         if (pszString[i] == '-' && i > 0)
    2676           0 :             iPlus = i;
    2677        2398 :         if (pszString[i] == 'i')
    2678           2 :             iImagEnd = i;
    2679             :     }
    2680             : 
    2681        2148 :     if (iPlus > -1 && iImagEnd > -1 && iPlus < iImagEnd)
    2682             :     {
    2683           0 :         *pdfImag = CPLAtof(pszString + iPlus);
    2684             :     }
    2685             : 
    2686        2148 :     return;
    2687             : }
    2688             : 
    2689             : /************************************************************************/
    2690             : /*                           CPLOpenShared()                            */
    2691             : /************************************************************************/
    2692             : 
    2693             : /**
    2694             :  * Open a shared file handle.
    2695             :  *
    2696             :  * Some operating systems have limits on the number of file handles that can
    2697             :  * be open at one time.  This function attempts to maintain a registry of
    2698             :  * already open file handles, and reuse existing ones if the same file
    2699             :  * is requested by another part of the application.
    2700             :  *
    2701             :  * Note that access is only shared for access types "r", "rb", "r+" and
    2702             :  * "rb+".  All others will just result in direct VSIOpen() calls.  Keep in
    2703             :  * mind that a file is only reused if the file name is exactly the same.
    2704             :  * Different names referring to the same file will result in different
    2705             :  * handles.
    2706             :  *
    2707             :  * The VSIFOpen() or VSIFOpenL() function is used to actually open the file,
    2708             :  * when an existing file handle can't be shared.
    2709             :  *
    2710             :  * @param pszFilename the name of the file to open.
    2711             :  * @param pszAccess the normal fopen()/VSIFOpen() style access string.
    2712             :  * @param bLargeIn If TRUE VSIFOpenL() (for large files) will be used instead of
    2713             :  * VSIFOpen().
    2714             :  *
    2715             :  * @return a file handle or NULL if opening fails.
    2716             :  */
    2717             : 
    2718          35 : FILE *CPLOpenShared(const char *pszFilename, const char *pszAccess,
    2719             :                     int bLargeIn)
    2720             : 
    2721             : {
    2722          35 :     const bool bLarge = CPL_TO_BOOL(bLargeIn);
    2723          70 :     CPLMutexHolderD(&hSharedFileMutex);
    2724          35 :     const GIntBig nPID = CPLGetPID();
    2725             : 
    2726             :     /* -------------------------------------------------------------------- */
    2727             :     /*      Is there an existing file we can use?                           */
    2728             :     /* -------------------------------------------------------------------- */
    2729          35 :     const bool bReuse = EQUAL(pszAccess, "rb") || EQUAL(pszAccess, "rb+");
    2730             : 
    2731          39 :     for (int i = 0; bReuse && i < nSharedFileCount; i++)
    2732             :     {
    2733          20 :         if (strcmp(pasSharedFileList[i].pszFilename, pszFilename) == 0 &&
    2734           4 :             !bLarge == !pasSharedFileList[i].bLarge &&
    2735          16 :             EQUAL(pasSharedFileList[i].pszAccess, pszAccess) &&
    2736           4 :             nPID == pasSharedFileListExtra[i].nPID)
    2737             :         {
    2738           4 :             pasSharedFileList[i].nRefCount++;
    2739           4 :             return pasSharedFileList[i].fp;
    2740             :         }
    2741             :     }
    2742             : 
    2743             :     /* -------------------------------------------------------------------- */
    2744             :     /*      Open the file.                                                  */
    2745             :     /* -------------------------------------------------------------------- */
    2746             :     FILE *fp = bLarge
    2747          31 :                    ? reinterpret_cast<FILE *>(VSIFOpenL(pszFilename, pszAccess))
    2748           0 :                    : VSIFOpen(pszFilename, pszAccess);
    2749             : 
    2750          31 :     if (fp == nullptr)
    2751           8 :         return nullptr;
    2752             : 
    2753             :     /* -------------------------------------------------------------------- */
    2754             :     /*      Add an entry to the list.                                       */
    2755             :     /* -------------------------------------------------------------------- */
    2756          23 :     nSharedFileCount++;
    2757             : 
    2758          23 :     pasSharedFileList = static_cast<CPLSharedFileInfo *>(
    2759          46 :         CPLRealloc(const_cast<CPLSharedFileInfo *>(pasSharedFileList),
    2760          23 :                    sizeof(CPLSharedFileInfo) * nSharedFileCount));
    2761          23 :     pasSharedFileListExtra = static_cast<CPLSharedFileInfoExtra *>(
    2762          46 :         CPLRealloc(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra),
    2763          23 :                    sizeof(CPLSharedFileInfoExtra) * nSharedFileCount));
    2764             : 
    2765          23 :     pasSharedFileList[nSharedFileCount - 1].fp = fp;
    2766          23 :     pasSharedFileList[nSharedFileCount - 1].nRefCount = 1;
    2767          23 :     pasSharedFileList[nSharedFileCount - 1].bLarge = bLarge;
    2768          46 :     pasSharedFileList[nSharedFileCount - 1].pszFilename =
    2769          23 :         CPLStrdup(pszFilename);
    2770          23 :     pasSharedFileList[nSharedFileCount - 1].pszAccess = CPLStrdup(pszAccess);
    2771          23 :     pasSharedFileListExtra[nSharedFileCount - 1].nPID = nPID;
    2772             : 
    2773          23 :     return fp;
    2774             : }
    2775             : 
    2776             : /************************************************************************/
    2777             : /*                           CPLCloseShared()                           */
    2778             : /************************************************************************/
    2779             : 
    2780             : /**
    2781             :  * Close shared file.
    2782             :  *
    2783             :  * Dereferences the indicated file handle, and closes it if the reference
    2784             :  * count has dropped to zero.  A CPLError() is issued if the file is not
    2785             :  * in the shared file list.
    2786             :  *
    2787             :  * @param fp file handle from CPLOpenShared() to deaccess.
    2788             :  */
    2789             : 
    2790          27 : void CPLCloseShared(FILE *fp)
    2791             : 
    2792             : {
    2793          27 :     CPLMutexHolderD(&hSharedFileMutex);
    2794             : 
    2795             :     /* -------------------------------------------------------------------- */
    2796             :     /*      Search for matching information.                                */
    2797             :     /* -------------------------------------------------------------------- */
    2798          27 :     int i = 0;
    2799          29 :     for (; i < nSharedFileCount && fp != pasSharedFileList[i].fp; i++)
    2800             :     {
    2801             :     }
    2802             : 
    2803          27 :     if (i == nSharedFileCount)
    2804             :     {
    2805           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2806             :                  "Unable to find file handle %p in CPLCloseShared().", fp);
    2807           0 :         return;
    2808             :     }
    2809             : 
    2810             :     /* -------------------------------------------------------------------- */
    2811             :     /*      Dereference and return if there are still some references.      */
    2812             :     /* -------------------------------------------------------------------- */
    2813          27 :     if (--pasSharedFileList[i].nRefCount > 0)
    2814           4 :         return;
    2815             : 
    2816             :     /* -------------------------------------------------------------------- */
    2817             :     /*      Close the file, and remove the information.                     */
    2818             :     /* -------------------------------------------------------------------- */
    2819          23 :     if (pasSharedFileList[i].bLarge)
    2820             :     {
    2821          23 :         if (VSIFCloseL(reinterpret_cast<VSILFILE *>(pasSharedFileList[i].fp)) !=
    2822             :             0)
    2823             :         {
    2824           0 :             CPLError(CE_Failure, CPLE_FileIO, "Error while closing %s",
    2825           0 :                      pasSharedFileList[i].pszFilename);
    2826             :         }
    2827             :     }
    2828             :     else
    2829             :     {
    2830           0 :         VSIFClose(pasSharedFileList[i].fp);
    2831             :     }
    2832             : 
    2833          23 :     CPLFree(pasSharedFileList[i].pszFilename);
    2834          23 :     CPLFree(pasSharedFileList[i].pszAccess);
    2835             : 
    2836          23 :     nSharedFileCount--;
    2837          23 :     memmove(
    2838          23 :         const_cast<CPLSharedFileInfo *>(pasSharedFileList + i),
    2839          23 :         const_cast<CPLSharedFileInfo *>(pasSharedFileList + nSharedFileCount),
    2840             :         sizeof(CPLSharedFileInfo));
    2841          23 :     memmove(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra + i),
    2842          23 :             const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra +
    2843          23 :                                                  nSharedFileCount),
    2844             :             sizeof(CPLSharedFileInfoExtra));
    2845             : 
    2846          23 :     if (nSharedFileCount == 0)
    2847             :     {
    2848          20 :         CPLFree(const_cast<CPLSharedFileInfo *>(pasSharedFileList));
    2849          20 :         pasSharedFileList = nullptr;
    2850          20 :         CPLFree(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra));
    2851          20 :         pasSharedFileListExtra = nullptr;
    2852             :     }
    2853             : }
    2854             : 
    2855             : /************************************************************************/
    2856             : /*                   CPLCleanupSharedFileMutex()                        */
    2857             : /************************************************************************/
    2858             : 
    2859         933 : void CPLCleanupSharedFileMutex()
    2860             : {
    2861         933 :     if (hSharedFileMutex != nullptr)
    2862             :     {
    2863           0 :         CPLDestroyMutex(hSharedFileMutex);
    2864           0 :         hSharedFileMutex = nullptr;
    2865             :     }
    2866         933 : }
    2867             : 
    2868             : /************************************************************************/
    2869             : /*                          CPLGetSharedList()                          */
    2870             : /************************************************************************/
    2871             : 
    2872             : /**
    2873             :  * Fetch list of open shared files.
    2874             :  *
    2875             :  * @param pnCount place to put the count of entries.
    2876             :  *
    2877             :  * @return the pointer to the first in the array of shared file info
    2878             :  * structures.
    2879             :  */
    2880             : 
    2881           0 : CPLSharedFileInfo *CPLGetSharedList(int *pnCount)
    2882             : 
    2883             : {
    2884           0 :     if (pnCount != nullptr)
    2885           0 :         *pnCount = nSharedFileCount;
    2886             : 
    2887           0 :     return const_cast<CPLSharedFileInfo *>(pasSharedFileList);
    2888             : }
    2889             : 
    2890             : /************************************************************************/
    2891             : /*                         CPLDumpSharedList()                          */
    2892             : /************************************************************************/
    2893             : 
    2894             : /**
    2895             :  * Report open shared files.
    2896             :  *
    2897             :  * Dumps all open shared files to the indicated file handle.  If the
    2898             :  * file handle is NULL information is sent via the CPLDebug() call.
    2899             :  *
    2900             :  * @param fp File handle to write to.
    2901             :  */
    2902             : 
    2903         103 : void CPLDumpSharedList(FILE *fp)
    2904             : 
    2905             : {
    2906         103 :     if (nSharedFileCount > 0)
    2907             :     {
    2908           0 :         if (fp == nullptr)
    2909           0 :             CPLDebug("CPL", "%d Shared files open.", nSharedFileCount);
    2910             :         else
    2911           0 :             fprintf(fp, "%d Shared files open.", nSharedFileCount);
    2912             :     }
    2913             : 
    2914         103 :     for (int i = 0; i < nSharedFileCount; i++)
    2915             :     {
    2916           0 :         if (fp == nullptr)
    2917           0 :             CPLDebug("CPL", "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
    2918           0 :                      pasSharedFileList[i].bLarge,
    2919           0 :                      pasSharedFileList[i].pszAccess,
    2920           0 :                      pasSharedFileList[i].pszFilename);
    2921             :         else
    2922           0 :             fprintf(fp, "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
    2923           0 :                     pasSharedFileList[i].bLarge, pasSharedFileList[i].pszAccess,
    2924           0 :                     pasSharedFileList[i].pszFilename);
    2925             :     }
    2926         103 : }
    2927             : 
    2928             : /************************************************************************/
    2929             : /*                           CPLUnlinkTree()                            */
    2930             : /************************************************************************/
    2931             : 
    2932             : /** Recursively unlink a directory.
    2933             :  *
    2934             :  * @return 0 on successful completion, -1 if function fails.
    2935             :  */
    2936             : 
    2937          52 : int CPLUnlinkTree(const char *pszPath)
    2938             : 
    2939             : {
    2940             :     /* -------------------------------------------------------------------- */
    2941             :     /*      First, ensure there is such a file.                             */
    2942             :     /* -------------------------------------------------------------------- */
    2943             :     VSIStatBufL sStatBuf;
    2944             : 
    2945          52 :     if (VSIStatL(pszPath, &sStatBuf) != 0)
    2946             :     {
    2947           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    2948             :                  "It seems no file system object called '%s' exists.", pszPath);
    2949             : 
    2950           2 :         return -1;
    2951             :     }
    2952             : 
    2953             :     /* -------------------------------------------------------------------- */
    2954             :     /*      If it is a simple file, just delete it.                         */
    2955             :     /* -------------------------------------------------------------------- */
    2956          50 :     if (VSI_ISREG(sStatBuf.st_mode))
    2957             :     {
    2958          34 :         if (VSIUnlink(pszPath) != 0)
    2959             :         {
    2960           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
    2961             :                      pszPath);
    2962             : 
    2963           0 :             return -1;
    2964             :         }
    2965             : 
    2966          34 :         return 0;
    2967             :     }
    2968             : 
    2969             :     /* -------------------------------------------------------------------- */
    2970             :     /*      If it is a directory recurse then unlink the directory.         */
    2971             :     /* -------------------------------------------------------------------- */
    2972          16 :     else if (VSI_ISDIR(sStatBuf.st_mode))
    2973             :     {
    2974          16 :         char **papszItems = VSIReadDir(pszPath);
    2975             : 
    2976          32 :         for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
    2977             :         {
    2978          16 :             if (papszItems[i][0] == '\0' || EQUAL(papszItems[i], ".") ||
    2979          16 :                 EQUAL(papszItems[i], ".."))
    2980           0 :                 continue;
    2981             : 
    2982             :             const std::string osSubPath =
    2983          16 :                 CPLFormFilename(pszPath, papszItems[i], nullptr);
    2984             : 
    2985          16 :             const int nErr = CPLUnlinkTree(osSubPath.c_str());
    2986             : 
    2987          16 :             if (nErr != 0)
    2988             :             {
    2989           0 :                 CSLDestroy(papszItems);
    2990           0 :                 return nErr;
    2991             :             }
    2992             :         }
    2993             : 
    2994          16 :         CSLDestroy(papszItems);
    2995             : 
    2996          16 :         if (VSIRmdir(pszPath) != 0)
    2997             :         {
    2998           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
    2999             :                      pszPath);
    3000             : 
    3001           0 :             return -1;
    3002             :         }
    3003             : 
    3004          16 :         return 0;
    3005             :     }
    3006             : 
    3007             :     /* -------------------------------------------------------------------- */
    3008             :     /*      otherwise report an error.                                      */
    3009             :     /* -------------------------------------------------------------------- */
    3010           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    3011             :              "Failed to unlink %s.\nUnrecognised filesystem object.", pszPath);
    3012           0 :     return 1000;
    3013             : }
    3014             : 
    3015             : /************************************************************************/
    3016             : /*                            CPLCopyFile()                             */
    3017             : /************************************************************************/
    3018             : 
    3019             : /** Copy a file */
    3020        2210 : int CPLCopyFile(const char *pszNewPath, const char *pszOldPath)
    3021             : 
    3022             : {
    3023        2210 :     return VSICopyFile(pszOldPath, pszNewPath, nullptr,
    3024             :                        static_cast<vsi_l_offset>(-1), nullptr, nullptr,
    3025        2210 :                        nullptr);
    3026             : }
    3027             : 
    3028             : /************************************************************************/
    3029             : /*                            CPLCopyTree()                             */
    3030             : /************************************************************************/
    3031             : 
    3032             : /** Recursively copy a tree */
    3033           4 : int CPLCopyTree(const char *pszNewPath, const char *pszOldPath)
    3034             : 
    3035             : {
    3036             :     VSIStatBufL sStatBuf;
    3037           4 :     if (VSIStatL(pszNewPath, &sStatBuf) == 0)
    3038             :     {
    3039           1 :         CPLError(
    3040             :             CE_Failure, CPLE_AppDefined,
    3041             :             "It seems that a file system object called '%s' already exists.",
    3042             :             pszNewPath);
    3043             : 
    3044           1 :         return -1;
    3045             :     }
    3046             : 
    3047           3 :     if (VSIStatL(pszOldPath, &sStatBuf) != 0)
    3048             :     {
    3049           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    3050             :                  "It seems no file system object called '%s' exists.",
    3051             :                  pszOldPath);
    3052             : 
    3053           1 :         return -1;
    3054             :     }
    3055             : 
    3056           2 :     if (VSI_ISDIR(sStatBuf.st_mode))
    3057             :     {
    3058           1 :         if (VSIMkdir(pszNewPath, 0755) != 0)
    3059             :         {
    3060           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    3061             :                      "Cannot create directory '%s'.", pszNewPath);
    3062             : 
    3063           0 :             return -1;
    3064             :         }
    3065             : 
    3066           1 :         char **papszItems = VSIReadDir(pszOldPath);
    3067             : 
    3068           4 :         for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
    3069             :         {
    3070           3 :             if (EQUAL(papszItems[i], ".") || EQUAL(papszItems[i], ".."))
    3071           2 :                 continue;
    3072             : 
    3073             :             const std::string osNewSubPath =
    3074           1 :                 CPLFormFilename(pszNewPath, papszItems[i], nullptr);
    3075             :             const std::string osOldSubPath =
    3076           1 :                 CPLFormFilename(pszOldPath, papszItems[i], nullptr);
    3077             : 
    3078             :             const int nErr =
    3079           1 :                 CPLCopyTree(osNewSubPath.c_str(), osOldSubPath.c_str());
    3080             : 
    3081           1 :             if (nErr != 0)
    3082             :             {
    3083           0 :                 CSLDestroy(papszItems);
    3084           0 :                 return nErr;
    3085             :             }
    3086             :         }
    3087           1 :         CSLDestroy(papszItems);
    3088             : 
    3089           1 :         return 0;
    3090             :     }
    3091           1 :     else if (VSI_ISREG(sStatBuf.st_mode))
    3092             :     {
    3093           1 :         return CPLCopyFile(pszNewPath, pszOldPath);
    3094             :     }
    3095             :     else
    3096             :     {
    3097           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3098             :                  "Unrecognized filesystem object : '%s'.", pszOldPath);
    3099           0 :         return -1;
    3100             :     }
    3101             : }
    3102             : 
    3103             : /************************************************************************/
    3104             : /*                            CPLMoveFile()                             */
    3105             : /************************************************************************/
    3106             : 
    3107             : /** Move a file */
    3108         184 : int CPLMoveFile(const char *pszNewPath, const char *pszOldPath)
    3109             : 
    3110             : {
    3111         184 :     if (VSIRename(pszOldPath, pszNewPath) == 0)
    3112         181 :         return 0;
    3113             : 
    3114           3 :     const int nRet = CPLCopyFile(pszNewPath, pszOldPath);
    3115             : 
    3116           3 :     if (nRet == 0)
    3117           3 :         VSIUnlink(pszOldPath);
    3118           3 :     return nRet;
    3119             : }
    3120             : 
    3121             : /************************************************************************/
    3122             : /*                             CPLSymlink()                             */
    3123             : /************************************************************************/
    3124             : 
    3125             : /** Create a symbolic link */
    3126             : #ifdef _WIN32
    3127             : int CPLSymlink(const char *, const char *, CSLConstList)
    3128             : {
    3129             :     return -1;
    3130             : }
    3131             : #else
    3132           0 : int CPLSymlink(const char *pszOldPath, const char *pszNewPath,
    3133             :                CSLConstList /* papszOptions */)
    3134             : {
    3135           0 :     return symlink(pszOldPath, pszNewPath);
    3136             : }
    3137             : #endif
    3138             : 
    3139             : /************************************************************************/
    3140             : /* ==================================================================== */
    3141             : /*                              CPLLocaleC                              */
    3142             : /* ==================================================================== */
    3143             : /************************************************************************/
    3144             : 
    3145             : //! @cond Doxygen_Suppress
    3146             : /************************************************************************/
    3147             : /*                             CPLLocaleC()                             */
    3148             : /************************************************************************/
    3149             : 
    3150         127 : CPLLocaleC::CPLLocaleC() : pszOldLocale(nullptr)
    3151             : {
    3152         127 :     if (CPLTestBool(CPLGetConfigOption("GDAL_DISABLE_CPLLOCALEC", "NO")))
    3153           0 :         return;
    3154             : 
    3155         127 :     pszOldLocale = CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr));
    3156         127 :     if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
    3157           0 :         CPLsetlocale(LC_NUMERIC, "C") == nullptr)
    3158             :     {
    3159         127 :         CPLFree(pszOldLocale);
    3160         127 :         pszOldLocale = nullptr;
    3161             :     }
    3162             : }
    3163             : 
    3164             : /************************************************************************/
    3165             : /*                            ~CPLLocaleC()                             */
    3166             : /************************************************************************/
    3167             : 
    3168           0 : CPLLocaleC::~CPLLocaleC()
    3169             : 
    3170             : {
    3171         127 :     if (pszOldLocale == nullptr)
    3172         127 :         return;
    3173             : 
    3174           0 :     CPLsetlocale(LC_NUMERIC, pszOldLocale);
    3175           0 :     CPLFree(pszOldLocale);
    3176         127 : }
    3177             : 
    3178             : /************************************************************************/
    3179             : /*                        CPLThreadLocaleCPrivate                       */
    3180             : /************************************************************************/
    3181             : 
    3182             : #ifdef HAVE_USELOCALE
    3183             : 
    3184             : class CPLThreadLocaleCPrivate
    3185             : {
    3186             :     locale_t nNewLocale;
    3187             :     locale_t nOldLocale;
    3188             : 
    3189             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3190             : 
    3191             :   public:
    3192             :     CPLThreadLocaleCPrivate();
    3193             :     ~CPLThreadLocaleCPrivate();
    3194             : };
    3195             : 
    3196           0 : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3197           0 :     : nNewLocale(newlocale(LC_NUMERIC_MASK, "C", nullptr)),
    3198           0 :       nOldLocale(uselocale(nNewLocale))
    3199             : {
    3200           0 : }
    3201             : 
    3202           0 : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3203             : {
    3204           0 :     uselocale(nOldLocale);
    3205           0 :     freelocale(nNewLocale);
    3206           0 : }
    3207             : 
    3208             : #elif defined(_MSC_VER)
    3209             : 
    3210             : class CPLThreadLocaleCPrivate
    3211             : {
    3212             :     int nOldValConfigThreadLocale;
    3213             :     char *pszOldLocale;
    3214             : 
    3215             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3216             : 
    3217             :   public:
    3218             :     CPLThreadLocaleCPrivate();
    3219             :     ~CPLThreadLocaleCPrivate();
    3220             : };
    3221             : 
    3222             : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3223             : {
    3224             :     nOldValConfigThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    3225             :     pszOldLocale = setlocale(LC_NUMERIC, "C");
    3226             :     if (pszOldLocale)
    3227             :         pszOldLocale = CPLStrdup(pszOldLocale);
    3228             : }
    3229             : 
    3230             : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3231             : {
    3232             :     if (pszOldLocale != nullptr)
    3233             :     {
    3234             :         setlocale(LC_NUMERIC, pszOldLocale);
    3235             :         CPLFree(pszOldLocale);
    3236             :     }
    3237             :     _configthreadlocale(nOldValConfigThreadLocale);
    3238             : }
    3239             : 
    3240             : #else
    3241             : 
    3242             : class CPLThreadLocaleCPrivate
    3243             : {
    3244             :     char *pszOldLocale;
    3245             : 
    3246             :     CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
    3247             : 
    3248             :   public:
    3249             :     CPLThreadLocaleCPrivate();
    3250             :     ~CPLThreadLocaleCPrivate();
    3251             : };
    3252             : 
    3253             : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
    3254             :     : pszOldLocale(CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr)))
    3255             : {
    3256             :     if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
    3257             :         CPLsetlocale(LC_NUMERIC, "C") == nullptr)
    3258             :     {
    3259             :         CPLFree(pszOldLocale);
    3260             :         pszOldLocale = nullptr;
    3261             :     }
    3262             : }
    3263             : 
    3264             : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
    3265             : {
    3266             :     if (pszOldLocale != nullptr)
    3267             :     {
    3268             :         CPLsetlocale(LC_NUMERIC, pszOldLocale);
    3269             :         CPLFree(pszOldLocale);
    3270             :     }
    3271             : }
    3272             : 
    3273             : #endif
    3274             : 
    3275             : /************************************************************************/
    3276             : /*                        CPLThreadLocaleC()                            */
    3277             : /************************************************************************/
    3278             : 
    3279           0 : CPLThreadLocaleC::CPLThreadLocaleC() : m_private(new CPLThreadLocaleCPrivate)
    3280             : {
    3281           0 : }
    3282             : 
    3283             : /************************************************************************/
    3284             : /*                       ~CPLThreadLocaleC()                            */
    3285             : /************************************************************************/
    3286             : 
    3287           0 : CPLThreadLocaleC::~CPLThreadLocaleC()
    3288             : 
    3289             : {
    3290           0 :     delete m_private;
    3291           0 : }
    3292             : 
    3293             : //! @endcond
    3294             : 
    3295             : /************************************************************************/
    3296             : /*                          CPLsetlocale()                              */
    3297             : /************************************************************************/
    3298             : 
    3299             : /**
    3300             :  * Prevents parallel executions of setlocale().
    3301             :  *
    3302             :  * Calling setlocale() concurrently from two or more threads is a
    3303             :  * potential data race. A mutex is used to provide a critical region so
    3304             :  * that only one thread at a time can be executing setlocale().
    3305             :  *
    3306             :  * The return should not be freed, and copied quickly as it may be invalidated
    3307             :  * by a following next call to CPLsetlocale().
    3308             :  *
    3309             :  * @param category See your compiler's documentation on setlocale.
    3310             :  * @param locale See your compiler's documentation on setlocale.
    3311             :  *
    3312             :  * @return See your compiler's documentation on setlocale.
    3313             :  */
    3314         129 : char *CPLsetlocale(int category, const char *locale)
    3315             : {
    3316         258 :     CPLMutexHolder oHolder(&hSetLocaleMutex);
    3317         129 :     char *pszRet = setlocale(category, locale);
    3318         129 :     if (pszRet == nullptr)
    3319           0 :         return pszRet;
    3320             : 
    3321             :     // Make it thread-locale storage.
    3322         129 :     return const_cast<char *>(CPLSPrintf("%s", pszRet));
    3323             : }
    3324             : 
    3325             : /************************************************************************/
    3326             : /*                       CPLCleanupSetlocaleMutex()                     */
    3327             : /************************************************************************/
    3328             : 
    3329         933 : void CPLCleanupSetlocaleMutex(void)
    3330             : {
    3331         933 :     if (hSetLocaleMutex != nullptr)
    3332           5 :         CPLDestroyMutex(hSetLocaleMutex);
    3333         933 :     hSetLocaleMutex = nullptr;
    3334         933 : }
    3335             : 
    3336             : /************************************************************************/
    3337             : /*                            IsPowerOfTwo()                            */
    3338             : /************************************************************************/
    3339             : 
    3340         134 : int CPLIsPowerOfTwo(unsigned int i)
    3341             : {
    3342         134 :     if (i == 0)
    3343           0 :         return FALSE;
    3344         134 :     return (i & (i - 1)) == 0 ? TRUE : FALSE;
    3345             : }
    3346             : 
    3347             : /************************************************************************/
    3348             : /*                          CPLCheckForFile()                           */
    3349             : /************************************************************************/
    3350             : 
    3351             : /**
    3352             :  * Check for file existence.
    3353             :  *
    3354             :  * The function checks if a named file exists in the filesystem, hopefully
    3355             :  * in an efficient fashion if a sibling file list is available.   It exists
    3356             :  * primarily to do faster file checking for functions like GDAL open methods
    3357             :  * that get a list of files from the target directory.
    3358             :  *
    3359             :  * If the sibling file list exists (is not NULL) it is assumed to be a list
    3360             :  * of files in the same directory as the target file, and it will be checked
    3361             :  * (case insensitively) for a match.  If a match is found, pszFilename is
    3362             :  * updated with the correct case and TRUE is returned.
    3363             :  *
    3364             :  * If papszSiblingFiles is NULL, a VSIStatL() is used to test for the files
    3365             :  * existence, and no case insensitive testing is done.
    3366             :  *
    3367             :  * @param pszFilename name of file to check for - filename case updated in
    3368             :  * some cases.
    3369             :  * @param papszSiblingFiles a list of files in the same directory as
    3370             :  * pszFilename if available, or NULL. This list should have no path components.
    3371             :  *
    3372             :  * @return TRUE if a match is found, or FALSE if not.
    3373             :  */
    3374             : 
    3375      151853 : int CPLCheckForFile(char *pszFilename, char **papszSiblingFiles)
    3376             : 
    3377             : {
    3378             :     /* -------------------------------------------------------------------- */
    3379             :     /*      Fallback case if we don't have a sibling file list.             */
    3380             :     /* -------------------------------------------------------------------- */
    3381      151853 :     if (papszSiblingFiles == nullptr)
    3382             :     {
    3383             :         VSIStatBufL sStatBuf;
    3384             : 
    3385       10844 :         return VSIStatExL(pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
    3386             :     }
    3387             : 
    3388             :     /* -------------------------------------------------------------------- */
    3389             :     /*      We have sibling files, compare the non-path filename portion    */
    3390             :     /*      of pszFilename too all entries.                                 */
    3391             :     /* -------------------------------------------------------------------- */
    3392      282018 :     const CPLString osFileOnly = CPLGetFilename(pszFilename);
    3393             : 
    3394    13303900 :     for (int i = 0; papszSiblingFiles[i] != nullptr; i++)
    3395             :     {
    3396    13163100 :         if (EQUAL(papszSiblingFiles[i], osFileOnly))
    3397             :         {
    3398         314 :             strcpy(pszFilename + strlen(pszFilename) - osFileOnly.size(),
    3399         157 :                    papszSiblingFiles[i]);
    3400         157 :             return TRUE;
    3401             :         }
    3402             :     }
    3403             : 
    3404      140852 :     return FALSE;
    3405             : }
    3406             : 
    3407             : /************************************************************************/
    3408             : /*      Stub implementation of zip services if we don't have libz.      */
    3409             : /************************************************************************/
    3410             : 
    3411             : #if !defined(HAVE_LIBZ)
    3412             : 
    3413             : void *CPLCreateZip(const char *, char **)
    3414             : 
    3415             : {
    3416             :     CPLError(CE_Failure, CPLE_NotSupported,
    3417             :              "This GDAL/OGR build does not include zlib and zip services.");
    3418             :     return nullptr;
    3419             : }
    3420             : 
    3421             : CPLErr CPLCreateFileInZip(void *, const char *, char **)
    3422             : {
    3423             :     return CE_Failure;
    3424             : }
    3425             : 
    3426             : CPLErr CPLWriteFileInZip(void *, const void *, int)
    3427             : {
    3428             :     return CE_Failure;
    3429             : }
    3430             : 
    3431             : CPLErr CPLCloseFileInZip(void *)
    3432             : {
    3433             :     return CE_Failure;
    3434             : }
    3435             : 
    3436             : CPLErr CPLCloseZip(void *)
    3437             : {
    3438             :     return CE_Failure;
    3439             : }
    3440             : 
    3441             : void *CPLZLibDeflate(const void *, size_t, int, void *, size_t,
    3442             :                      size_t *pnOutBytes)
    3443             : {
    3444             :     if (pnOutBytes != nullptr)
    3445             :         *pnOutBytes = 0;
    3446             :     return nullptr;
    3447             : }
    3448             : 
    3449             : void *CPLZLibInflate(const void *, size_t, void *, size_t, size_t *pnOutBytes)
    3450             : {
    3451             :     if (pnOutBytes != nullptr)
    3452             :         *pnOutBytes = 0;
    3453             :     return nullptr;
    3454             : }
    3455             : 
    3456             : #endif /* !defined(HAVE_LIBZ) */
    3457             : 
    3458             : /************************************************************************/
    3459             : /* ==================================================================== */
    3460             : /*                          CPLConfigOptionSetter                       */
    3461             : /* ==================================================================== */
    3462             : /************************************************************************/
    3463             : 
    3464             : //! @cond Doxygen_Suppress
    3465             : /************************************************************************/
    3466             : /*                         CPLConfigOptionSetter()                      */
    3467             : /************************************************************************/
    3468             : 
    3469       22757 : CPLConfigOptionSetter::CPLConfigOptionSetter(const char *pszKey,
    3470             :                                              const char *pszValue,
    3471       22757 :                                              bool bSetOnlyIfUndefined)
    3472       22757 :     : m_pszKey(CPLStrdup(pszKey)), m_pszOldValue(nullptr),
    3473       22738 :       m_bRestoreOldValue(false)
    3474             : {
    3475       22738 :     const char *pszOldValue = CPLGetThreadLocalConfigOption(pszKey, nullptr);
    3476       36359 :     if ((bSetOnlyIfUndefined &&
    3477       31866 :          CPLGetConfigOption(pszKey, nullptr) == nullptr) ||
    3478        9162 :         !bSetOnlyIfUndefined)
    3479             :     {
    3480       22748 :         m_bRestoreOldValue = true;
    3481       22748 :         if (pszOldValue)
    3482         643 :             m_pszOldValue = CPLStrdup(pszOldValue);
    3483       22748 :         CPLSetThreadLocalConfigOption(pszKey, pszValue);
    3484             :     }
    3485       22650 : }
    3486             : 
    3487             : /************************************************************************/
    3488             : /*                        ~CPLConfigOptionSetter()                      */
    3489             : /************************************************************************/
    3490             : 
    3491       45403 : CPLConfigOptionSetter::~CPLConfigOptionSetter()
    3492             : {
    3493       22749 :     if (m_bRestoreOldValue)
    3494             :     {
    3495       22740 :         CPLSetThreadLocalConfigOption(m_pszKey, m_pszOldValue);
    3496       22643 :         CPLFree(m_pszOldValue);
    3497             :     }
    3498       22635 :     CPLFree(m_pszKey);
    3499       22654 : }
    3500             : 
    3501             : //! @endcond
    3502             : 
    3503             : /************************************************************************/
    3504             : /*                          CPLIsInteractive()                          */
    3505             : /************************************************************************/
    3506             : 
    3507             : /** Returns whether the provided file refers to a terminal.
    3508             :  *
    3509             :  * This function is a wrapper of the ``isatty()`` POSIX function.
    3510             :  *
    3511             :  * @param f File to test. Typically stdin, stdout or stderr
    3512             :  * @return true if it is an open file referring to a terminal.
    3513             :  * @since GDAL 3.11
    3514             :  */
    3515         639 : bool CPLIsInteractive(FILE *f)
    3516             : {
    3517             : #ifndef _WIN32
    3518         639 :     return isatty(static_cast<int>(fileno(f)));
    3519             : #else
    3520             :     return _isatty(_fileno(f));
    3521             : #endif
    3522             : }

Generated by: LCOV version 1.14