• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 17307945987

28 Aug 2025 09:07PM UTC coverage: 71.112% (+0.004%) from 71.108%
17307945987

Pull #12980

github

web-flow
Merge 78d404760 into c75bec111
Pull Request #12980: Add OCI connection pool to GeoRaster driver

579657 of 815135 relevant lines covered (71.11%)

291944.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.34
/port/cpl_conv.cpp
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
#if defined(HAVE_USELOCALE) && !defined(__FreeBSD__)
17
// For uselocale, define _XOPEN_SOURCE = 700
18
// and OpenBSD with libcxx 19.1.7 requires 800 for vasprintf
19
// (cf https://github.com/OSGeo/gdal/issues/12619)
20
// (not sure if the following is still up to date...) but on Solaris, we don't
21
// have uselocale and we cannot have std=c++11 with _XOPEN_SOURCE != 600
22
#if defined(__sun__) && __cplusplus >= 201103L
23
#if _XOPEN_SOURCE != 600
24
#ifdef _XOPEN_SOURCE
25
#undef _XOPEN_SOURCE
26
#endif
27
#define _XOPEN_SOURCE 600
28
#endif
29
#else
30
#ifdef _XOPEN_SOURCE
31
#undef _XOPEN_SOURCE
32
#endif
33
#define _XOPEN_SOURCE 800
34
#endif
35
#endif
36

37
// For atoll (at least for NetBSD)
38
#ifndef _ISOC99_SOURCE
39
#define _ISOC99_SOURCE
40
#endif
41

42
#ifdef MSVC_USE_VLD
43
#include <vld.h>
44
#endif
45

46
#include "cpl_conv.h"
47

48
#include <algorithm>
49
#include <atomic>
50
#include <cctype>
51
#include <cerrno>
52
#include <climits>
53
#include <clocale>
54
#include <cmath>
55
#include <cstdlib>
56
#include <cstring>
57
#include <ctime>
58
#include <mutex>
59
#include <set>
60

61
#if HAVE_UNISTD_H
62
#include <unistd.h>
63
#endif
64
#if HAVE_XLOCALE_H
65
#include <xlocale.h>  // for LC_NUMERIC_MASK on MacOS
66
#endif
67

68
#include <sys/types.h>  // open
69

70
#if defined(__FreeBSD__)
71
#include <sys/user.h>  // must be after sys/types.h
72
#include <sys/sysctl.h>
73
#endif
74

75
#include <sys/stat.h>  // open
76
#include <fcntl.h>     // open, fcntl
77

78
#ifdef _WIN32
79
#include <io.h>  // _isatty, _wopen
80
#else
81
#include <unistd.h>  // isatty, fcntl
82
#if HAVE_GETRLIMIT
83
#include <sys/resource.h>  // getrlimit
84
#include <sys/time.h>      // getrlimit
85
#endif
86
#endif
87

88
#include <string>
89

90
#if __cplusplus >= 202002L
91
#include <bit>  // For std::endian
92
#endif
93

94
#include "cpl_config.h"
95
#include "cpl_multiproc.h"
96
#include "cpl_string.h"
97
#include "cpl_vsi.h"
98
#include "cpl_vsil_curl_priv.h"
99
#include "cpl_known_config_options.h"
100

101
#ifdef DEBUG
102
#define OGRAPISPY_ENABLED
103
#endif
104
#ifdef OGRAPISPY_ENABLED
105
// Keep in sync with ograpispy.cpp
106
void OGRAPISPYCPLSetConfigOption(const char *, const char *);
107
void OGRAPISPYCPLSetThreadLocalConfigOption(const char *, const char *);
108
#endif
109

110
// Uncomment to get list of options that have been fetched and set.
111
// #define DEBUG_CONFIG_OPTIONS
112

113
static CPLMutex *hConfigMutex = nullptr;
114
static volatile char **g_papszConfigOptions = nullptr;
115
static bool gbIgnoreEnvVariables =
116
    false;  // if true, only take into account configuration options set through
117
            // configuration file or
118
            // CPLSetConfigOption()/CPLSetThreadLocalConfigOption()
119

120
static std::vector<std::pair<CPLSetConfigOptionSubscriber, void *>>
121
    gSetConfigOptionSubscribers{};
122

123
// Used by CPLOpenShared() and friends.
124
static CPLMutex *hSharedFileMutex = nullptr;
125
static int nSharedFileCount = 0;
126
static CPLSharedFileInfo *pasSharedFileList = nullptr;
127

128
// Used by CPLsetlocale().
129
static CPLMutex *hSetLocaleMutex = nullptr;
130

131
// Note: ideally this should be added in CPLSharedFileInfo*
132
// but CPLSharedFileInfo is exposed in the API, hence that trick
133
// to hide this detail.
134
typedef struct
135
{
136
    GIntBig nPID;  // pid of opening thread.
137
} CPLSharedFileInfoExtra;
138

139
static volatile CPLSharedFileInfoExtra *pasSharedFileListExtra = nullptr;
140

141
/************************************************************************/
142
/*                             CPLCalloc()                              */
143
/************************************************************************/
144

145
/**
146
 * Safe version of calloc().
147
 *
148
 * This function is like the C library calloc(), but raises a CE_Fatal
149
 * error with CPLError() if it fails to allocate the desired memory.  It
150
 * should be used for small memory allocations that are unlikely to fail
151
 * and for which the application is unwilling to test for out of memory
152
 * conditions.  It uses VSICalloc() to get the memory, so any hooking of
153
 * VSICalloc() will apply to CPLCalloc() as well.  CPLFree() or VSIFree()
154
 * can be used free memory allocated by CPLCalloc().
155
 *
156
 * @param nCount number of objects to allocate.
157
 * @param nSize size (in bytes) of object to allocate.
158
 * @return pointer to newly allocated memory, only NULL if nSize * nCount is
159
 * NULL.
160
 */
161

162
void *CPLCalloc(size_t nCount, size_t nSize)
3,510,300✔
163

164
{
165
    if (nSize * nCount == 0)
3,510,300✔
166
        return nullptr;
9,016✔
167

168
    void *pReturn = CPLMalloc(nCount * nSize);
3,501,290✔
169
    memset(pReturn, 0, nCount * nSize);
3,501,270✔
170
    return pReturn;
3,501,270✔
171
}
172

173
/************************************************************************/
174
/*                             CPLMalloc()                              */
175
/************************************************************************/
176

177
/**
178
 * Safe version of malloc().
179
 *
180
 * This function is like the C library malloc(), but raises a CE_Fatal
181
 * error with CPLError() if it fails to allocate the desired memory.  It
182
 * should be used for small memory allocations that are unlikely to fail
183
 * and for which the application is unwilling to test for out of memory
184
 * conditions.  It uses VSIMalloc() to get the memory, so any hooking of
185
 * VSIMalloc() will apply to CPLMalloc() as well.  CPLFree() or VSIFree()
186
 * can be used free memory allocated by CPLMalloc().
187
 *
188
 * @param nSize size (in bytes) of memory block to allocate.
189
 * @return pointer to newly allocated memory, only NULL if nSize is zero.
190
 */
191

192
void *CPLMalloc(size_t nSize)
20,125,700✔
193

194
{
195
    if (nSize == 0)
20,125,700✔
196
        return nullptr;
5,489✔
197

198
    if ((nSize >> (8 * sizeof(nSize) - 1)) != 0)
20,120,200✔
199
    {
200
        // coverity[dead_error_begin]
201
        CPLError(CE_Failure, CPLE_AppDefined,
×
202
                 "CPLMalloc(%ld): Silly size requested.",
203
                 static_cast<long>(nSize));
204
        return nullptr;
×
205
    }
206

207
    void *pReturn = VSIMalloc(nSize);
20,120,200✔
208
    if (pReturn == nullptr)
20,120,200✔
209
    {
210
        if (nSize < 2000)
×
211
        {
212
            CPLEmergencyError("CPLMalloc(): Out of memory allocating a small "
×
213
                              "number of bytes.");
214
        }
215

216
        CPLError(CE_Fatal, CPLE_OutOfMemory,
×
217
                 "CPLMalloc(): Out of memory allocating %ld bytes.",
218
                 static_cast<long>(nSize));
219
    }
220

221
    return pReturn;
20,120,100✔
222
}
223

224
/************************************************************************/
225
/*                             CPLRealloc()                             */
226
/************************************************************************/
227

228
/**
229
 * Safe version of realloc().
230
 *
231
 * This function is like the C library realloc(), but raises a CE_Fatal
232
 * error with CPLError() if it fails to allocate the desired memory.  It
233
 * should be used for small memory allocations that are unlikely to fail
234
 * and for which the application is unwilling to test for out of memory
235
 * conditions.  It uses VSIRealloc() to get the memory, so any hooking of
236
 * VSIRealloc() will apply to CPLRealloc() as well.  CPLFree() or VSIFree()
237
 * can be used free memory allocated by CPLRealloc().
238
 *
239
 * It is also safe to pass NULL in as the existing memory block for
240
 * CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block.
241
 *
242
 * @param pData existing memory block which should be copied to the new block.
243
 * @param nNewSize new size (in bytes) of memory block to allocate.
244
 * @return pointer to allocated memory, only NULL if nNewSize is zero.
245
 */
246

247
void *CPLRealloc(void *pData, size_t nNewSize)
3,036,900✔
248

249
{
250
    if (nNewSize == 0)
3,036,900✔
251
    {
252
        VSIFree(pData);
45✔
253
        return nullptr;
45✔
254
    }
255

256
    if ((nNewSize >> (8 * sizeof(nNewSize) - 1)) != 0)
3,036,850✔
257
    {
258
        // coverity[dead_error_begin]
259
        CPLError(CE_Failure, CPLE_AppDefined,
×
260
                 "CPLRealloc(%ld): Silly size requested.",
261
                 static_cast<long>(nNewSize));
262
        return nullptr;
×
263
    }
264

265
    void *pReturn = nullptr;
3,036,850✔
266

267
    if (pData == nullptr)
3,036,850✔
268
        pReturn = VSIMalloc(nNewSize);
1,966,010✔
269
    else
270
        pReturn = VSIRealloc(pData, nNewSize);
1,070,840✔
271

272
    if (pReturn == nullptr)
3,016,820✔
273
    {
274
        if (nNewSize < 2000)
×
275
        {
276
            char szSmallMsg[80] = {};
×
277

278
            snprintf(szSmallMsg, sizeof(szSmallMsg),
×
279
                     "CPLRealloc(): Out of memory allocating %ld bytes.",
280
                     static_cast<long>(nNewSize));
281
            CPLEmergencyError(szSmallMsg);
×
282
        }
283
        else
284
        {
285
            CPLError(CE_Fatal, CPLE_OutOfMemory,
×
286
                     "CPLRealloc(): Out of memory allocating %ld bytes.",
287
                     static_cast<long>(nNewSize));
288
        }
289
    }
290

291
    return pReturn;
3,028,460✔
292
}
293

294
/************************************************************************/
295
/*                             CPLStrdup()                              */
296
/************************************************************************/
297

298
/**
299
 * Safe version of strdup() function.
300
 *
301
 * This function is similar to the C library strdup() function, but if
302
 * the memory allocation fails it will issue a CE_Fatal error with
303
 * CPLError() instead of returning NULL. Memory
304
 * allocated with CPLStrdup() can be freed with CPLFree() or VSIFree().
305
 *
306
 * It is also safe to pass a NULL string into CPLStrdup().  CPLStrdup()
307
 * will allocate and return a zero length string (as opposed to a NULL
308
 * string).
309
 *
310
 * @param pszString input string to be duplicated.  May be NULL.
311
 * @return pointer to a newly allocated copy of the string.  Free with
312
 * CPLFree() or VSIFree().
313
 */
314

315
char *CPLStrdup(const char *pszString)
8,066,340✔
316

317
{
318
    if (pszString == nullptr)
8,066,340✔
319
        pszString = "";
1,134,590✔
320

321
    const size_t nLen = strlen(pszString);
8,066,340✔
322
    char *pszReturn = static_cast<char *>(CPLMalloc(nLen + 1));
8,066,340✔
323
    memcpy(pszReturn, pszString, nLen + 1);
8,066,270✔
324
    return (pszReturn);
8,066,270✔
325
}
326

327
/************************************************************************/
328
/*                             CPLStrlwr()                              */
329
/************************************************************************/
330

331
/**
332
 * Convert each characters of the string to lower case.
333
 *
334
 * For example, "ABcdE" will be converted to "abcde".
335
 * Starting with GDAL 3.9, this function is no longer locale dependent.
336
 *
337
 * @param pszString input string to be converted.
338
 * @return pointer to the same string, pszString.
339
 */
340

341
char *CPLStrlwr(char *pszString)
3✔
342

343
{
344
    if (pszString == nullptr)
3✔
345
        return nullptr;
×
346

347
    char *pszTemp = pszString;
3✔
348

349
    while (*pszTemp)
24✔
350
    {
351
        *pszTemp =
21✔
352
            static_cast<char>(CPLTolower(static_cast<unsigned char>(*pszTemp)));
21✔
353
        pszTemp++;
21✔
354
    }
355

356
    return pszString;
3✔
357
}
358

359
/************************************************************************/
360
/*                              CPLFGets()                              */
361
/*                                                                      */
362
/*      Note: LF = \n = ASCII 10                                        */
363
/*            CR = \r = ASCII 13                                        */
364
/************************************************************************/
365

366
// ASCII characters.
367
constexpr char knLF = 10;
368
constexpr char knCR = 13;
369

370
/**
371
 * Reads in at most one less than nBufferSize characters from the fp
372
 * stream and stores them into the buffer pointed to by pszBuffer.
373
 * Reading stops after an EOF or a newline. If a newline is read, it
374
 * is _not_ stored into the buffer. A '\\0' is stored after the last
375
 * character in the buffer. All three types of newline terminators
376
 * recognized by the CPLFGets(): single '\\r' and '\\n' and '\\r\\n'
377
 * combination.
378
 *
379
 * @param pszBuffer pointer to the targeting character buffer.
380
 * @param nBufferSize maximum size of the string to read (not including
381
 * terminating '\\0').
382
 * @param fp file pointer to read from.
383
 * @return pointer to the pszBuffer containing a string read
384
 * from the file or NULL if the error or end of file was encountered.
385
 */
386

387
char *CPLFGets(char *pszBuffer, int nBufferSize, FILE *fp)
×
388

389
{
390
    if (nBufferSize == 0 || pszBuffer == nullptr || fp == nullptr)
×
391
        return nullptr;
×
392

393
    /* -------------------------------------------------------------------- */
394
    /*      Let the OS level call read what it things is one line.  This    */
395
    /*      will include the newline.  On windows, if the file happens      */
396
    /*      to be in text mode, the CRLF will have been converted to        */
397
    /*      just the newline (LF).  If it is in binary mode it may well     */
398
    /*      have both.                                                      */
399
    /* -------------------------------------------------------------------- */
400
    const long nOriginalOffset = VSIFTell(fp);
×
401
    if (VSIFGets(pszBuffer, nBufferSize, fp) == nullptr)
×
402
        return nullptr;
×
403

404
    int nActuallyRead = static_cast<int>(strlen(pszBuffer));
×
405
    if (nActuallyRead == 0)
×
406
        return nullptr;
×
407

408
    /* -------------------------------------------------------------------- */
409
    /*      If we found \r and out buffer is full, it is possible there     */
410
    /*      is also a pending \n.  Check for it.                            */
411
    /* -------------------------------------------------------------------- */
412
    if (nBufferSize == nActuallyRead + 1 &&
×
413
        pszBuffer[nActuallyRead - 1] == knCR)
×
414
    {
415
        const int chCheck = fgetc(fp);
×
416
        if (chCheck != knLF)
×
417
        {
418
            // unget the character.
419
            if (VSIFSeek(fp, nOriginalOffset + nActuallyRead, SEEK_SET) == -1)
×
420
            {
421
                CPLError(CE_Failure, CPLE_FileIO,
×
422
                         "Unable to unget a character");
423
            }
424
        }
425
    }
426

427
    /* -------------------------------------------------------------------- */
428
    /*      Trim off \n, \r or \r\n if it appears at the end.  We don't     */
429
    /*      need to do any "seeking" since we want the newline eaten.       */
430
    /* -------------------------------------------------------------------- */
431
    if (nActuallyRead > 1 && pszBuffer[nActuallyRead - 1] == knLF &&
×
432
        pszBuffer[nActuallyRead - 2] == knCR)
×
433
    {
434
        pszBuffer[nActuallyRead - 2] = '\0';
×
435
    }
436
    else if (pszBuffer[nActuallyRead - 1] == knLF ||
×
437
             pszBuffer[nActuallyRead - 1] == knCR)
×
438
    {
439
        pszBuffer[nActuallyRead - 1] = '\0';
×
440
    }
441

442
    /* -------------------------------------------------------------------- */
443
    /*      Search within the string for a \r (MacOS convention             */
444
    /*      apparently), and if we find it we need to trim the string,      */
445
    /*      and seek back.                                                  */
446
    /* -------------------------------------------------------------------- */
447
    char *pszExtraNewline = strchr(pszBuffer, knCR);
×
448

449
    if (pszExtraNewline != nullptr)
×
450
    {
451
        nActuallyRead = static_cast<int>(pszExtraNewline - pszBuffer + 1);
×
452

453
        *pszExtraNewline = '\0';
×
454
        if (VSIFSeek(fp, nOriginalOffset + nActuallyRead - 1, SEEK_SET) != 0)
×
455
            return nullptr;
×
456

457
        // This hackery is necessary to try and find our correct
458
        // spot on win32 systems with text mode line translation going
459
        // on.  Sometimes the fseek back overshoots, but it doesn't
460
        // "realize it" till a character has been read. Try to read till
461
        // we get to the right spot and get our CR.
462
        int chCheck = fgetc(fp);
×
463
        while ((chCheck != knCR && chCheck != EOF) ||
×
464
               VSIFTell(fp) < nOriginalOffset + nActuallyRead)
×
465
        {
466
            static bool bWarned = false;
467

468
            if (!bWarned)
×
469
            {
470
                bWarned = true;
×
471
                CPLDebug("CPL",
×
472
                         "CPLFGets() correcting for DOS text mode translation "
473
                         "seek problem.");
474
            }
475
            chCheck = fgetc(fp);
×
476
        }
477
    }
478

479
    return pszBuffer;
×
480
}
481

482
/************************************************************************/
483
/*                         CPLReadLineBuffer()                          */
484
/*                                                                      */
485
/*      Fetch readline buffer, and ensure it is the desired size,       */
486
/*      reallocating if needed.  Manages TLS (thread local storage)     */
487
/*      issues for the buffer.                                          */
488
/*      We use a special trick to track the actual size of the buffer   */
489
/*      The first 4 bytes are reserved to store it as a int, hence the  */
490
/*      -4 / +4 hacks with the size and pointer.                        */
491
/************************************************************************/
492
static char *CPLReadLineBuffer(int nRequiredSize)
2,774,840✔
493

494
{
495

496
    /* -------------------------------------------------------------------- */
497
    /*      A required size of -1 means the buffer should be freed.         */
498
    /* -------------------------------------------------------------------- */
499
    if (nRequiredSize == -1)
2,774,840✔
500
    {
501
        int bMemoryError = FALSE;
2,389✔
502
        void *pRet = CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError);
2,389✔
503
        if (pRet != nullptr)
2,389✔
504
        {
505
            CPLFree(pRet);
2,137✔
506
            CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
2,137✔
507
        }
508
        return nullptr;
2,389✔
509
    }
510

511
    /* -------------------------------------------------------------------- */
512
    /*      If the buffer doesn't exist yet, create it.                     */
513
    /* -------------------------------------------------------------------- */
514
    int bMemoryError = FALSE;
2,772,450✔
515
    GUInt32 *pnAlloc =
516
        static_cast<GUInt32 *>(CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError));
2,772,450✔
517
    if (bMemoryError)
2,772,450✔
518
        return nullptr;
×
519

520
    if (pnAlloc == nullptr)
2,772,450✔
521
    {
522
        pnAlloc = static_cast<GUInt32 *>(VSI_MALLOC_VERBOSE(200));
3,730✔
523
        if (pnAlloc == nullptr)
3,730✔
524
            return nullptr;
×
525
        *pnAlloc = 196;
3,730✔
526
        CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
3,730✔
527
    }
528

529
    /* -------------------------------------------------------------------- */
530
    /*      If it is too small, grow it bigger.                             */
531
    /* -------------------------------------------------------------------- */
532
    if (static_cast<int>(*pnAlloc) - 1 < nRequiredSize)
2,772,450✔
533
    {
534
        const int nNewSize = nRequiredSize + 4 + 500;
2,803✔
535
        if (nNewSize <= 0)
2,803✔
536
        {
537
            VSIFree(pnAlloc);
×
538
            CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
×
539
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
540
                     "CPLReadLineBuffer(): Trying to allocate more than "
541
                     "2 GB.");
542
            return nullptr;
×
543
        }
544

545
        GUInt32 *pnAllocNew =
546
            static_cast<GUInt32 *>(VSI_REALLOC_VERBOSE(pnAlloc, nNewSize));
2,803✔
547
        if (pnAllocNew == nullptr)
2,803✔
548
        {
549
            VSIFree(pnAlloc);
×
550
            CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
×
551
            return nullptr;
×
552
        }
553
        pnAlloc = pnAllocNew;
2,803✔
554

555
        *pnAlloc = nNewSize - 4;
2,803✔
556
        CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
2,803✔
557
    }
558

559
    return reinterpret_cast<char *>(pnAlloc + 1);
2,772,450✔
560
}
561

562
/************************************************************************/
563
/*                            CPLReadLine()                             */
564
/************************************************************************/
565

566
/**
567
 * Simplified line reading from text file.
568
 *
569
 * Read a line of text from the given file handle, taking care
570
 * to capture CR and/or LF and strip off ... equivalent of
571
 * DKReadLine().  Pointer to an internal buffer is returned.
572
 * The application shouldn't free it, or depend on its value
573
 * past the next call to CPLReadLine().
574
 *
575
 * Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file
576
 * services should apply to CPLReadLine() as well.
577
 *
578
 * CPLReadLine() maintains an internal buffer, which will appear as a
579
 * single block memory leak in some circumstances.  CPLReadLine() may
580
 * be called with a NULL FILE * at any time to free this working buffer.
581
 *
582
 * @param fp file pointer opened with VSIFOpen().
583
 *
584
 * @return pointer to an internal buffer containing a line of text read
585
 * from the file or NULL if the end of file was encountered.
586
 */
587

588
const char *CPLReadLine(FILE *fp)
5✔
589

590
{
591
    /* -------------------------------------------------------------------- */
592
    /*      Cleanup case.                                                   */
593
    /* -------------------------------------------------------------------- */
594
    if (fp == nullptr)
5✔
595
    {
596
        CPLReadLineBuffer(-1);
5✔
597
        return nullptr;
5✔
598
    }
599

600
    /* -------------------------------------------------------------------- */
601
    /*      Loop reading chunks of the line till we get to the end of       */
602
    /*      the line.                                                       */
603
    /* -------------------------------------------------------------------- */
604
    size_t nBytesReadThisTime = 0;
×
605
    char *pszRLBuffer = nullptr;
×
606
    size_t nReadSoFar = 0;
×
607

608
    do
×
609
    {
610
        /* --------------------------------------------------------------------
611
         */
612
        /*      Grow the working buffer if we have it nearly full.  Fail out */
613
        /*      of read line if we can't reallocate it big enough (for */
614
        /*      instance for a _very large_ file with no newlines). */
615
        /* --------------------------------------------------------------------
616
         */
617
        if (nReadSoFar > 100 * 1024 * 1024)
×
618
            // It is dubious that we need to read a line longer than 100 MB.
619
            return nullptr;
×
620
        pszRLBuffer = CPLReadLineBuffer(static_cast<int>(nReadSoFar) + 129);
×
621
        if (pszRLBuffer == nullptr)
×
622
            return nullptr;
×
623

624
        /* --------------------------------------------------------------------
625
         */
626
        /*      Do the actual read. */
627
        /* --------------------------------------------------------------------
628
         */
629
        if (CPLFGets(pszRLBuffer + nReadSoFar, 128, fp) == nullptr &&
×
630
            nReadSoFar == 0)
631
            return nullptr;
×
632

633
        nBytesReadThisTime = strlen(pszRLBuffer + nReadSoFar);
×
634
        nReadSoFar += nBytesReadThisTime;
×
635
    } while (nBytesReadThisTime >= 127 && pszRLBuffer[nReadSoFar - 1] != knCR &&
×
636
             pszRLBuffer[nReadSoFar - 1] != knLF);
×
637

638
    return pszRLBuffer;
×
639
}
640

641
/************************************************************************/
642
/*                            CPLReadLineL()                            */
643
/************************************************************************/
644

645
/**
646
 * Simplified line reading from text file.
647
 *
648
 * Similar to CPLReadLine(), but reading from a large file API handle.
649
 *
650
 * @param fp file pointer opened with VSIFOpenL().
651
 *
652
 * @return pointer to an internal buffer containing a line of text read
653
 * from the file or NULL if the end of file was encountered.
654
 */
655

656
const char *CPLReadLineL(VSILFILE *fp)
197,414✔
657
{
658
    return CPLReadLine2L(fp, -1, nullptr);
197,414✔
659
}
660

661
/************************************************************************/
662
/*                           CPLReadLine2L()                            */
663
/************************************************************************/
664

665
/**
666
 * Simplified line reading from text file.
667
 *
668
 * Similar to CPLReadLine(), but reading from a large file API handle.
669
 *
670
 * @param fp file pointer opened with VSIFOpenL().
671
 * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
672
 * @param papszOptions NULL-terminated array of options. Unused for now.
673

674
 * @return pointer to an internal buffer containing a line of text read
675
 * from the file or NULL if the end of file was encountered or the maximum
676
 * number of characters allowed reached.
677
 *
678
 * @since GDAL 1.7.0
679
 */
680

681
const char *CPLReadLine2L(VSILFILE *fp, int nMaxCars,
1,357,210✔
682
                          CPL_UNUSED CSLConstList papszOptions)
683

684
{
685
    int nBufLength;
686
    return CPLReadLine3L(fp, nMaxCars, &nBufLength, papszOptions);
2,714,420✔
687
}
688

689
/************************************************************************/
690
/*                           CPLReadLine3L()                            */
691
/************************************************************************/
692

693
/**
694
 * Simplified line reading from text file.
695
 *
696
 * Similar to CPLReadLine(), but reading from a large file API handle.
697
 *
698
 * @param fp file pointer opened with VSIFOpenL().
699
 * @param nMaxCars  maximum number of characters allowed, or -1 for no limit.
700
 * @param papszOptions NULL-terminated array of options. Unused for now.
701
 * @param[out] pnBufLength size of output string (must be non-NULL)
702

703
 * @return pointer to an internal buffer containing a line of text read
704
 * from the file or NULL if the end of file was encountered or the maximum
705
 * number of characters allowed reached.
706
 *
707
 * @since GDAL 2.3.0
708
 */
709
const char *CPLReadLine3L(VSILFILE *fp, int nMaxCars, int *pnBufLength,
1,421,340✔
710
                          CPL_UNUSED CSLConstList papszOptions)
711
{
712
    /* -------------------------------------------------------------------- */
713
    /*      Cleanup case.                                                   */
714
    /* -------------------------------------------------------------------- */
715
    if (fp == nullptr)
1,421,340✔
716
    {
717
        CPLReadLineBuffer(-1);
2,384✔
718
        return nullptr;
2,384✔
719
    }
720

721
    /* -------------------------------------------------------------------- */
722
    /*      Loop reading chunks of the line till we get to the end of       */
723
    /*      the line.                                                       */
724
    /* -------------------------------------------------------------------- */
725
    char *pszRLBuffer = nullptr;
1,418,950✔
726
    const size_t nChunkSize = 40;
1,418,950✔
727
    char szChunk[nChunkSize] = {};
1,418,950✔
728
    size_t nChunkBytesRead = 0;
1,418,950✔
729
    size_t nChunkBytesConsumed = 0;
1,418,950✔
730

731
    *pnBufLength = 0;
1,418,950✔
732
    szChunk[0] = 0;
1,418,950✔
733

734
    while (true)
735
    {
736
        /* --------------------------------------------------------------------
737
         */
738
        /*      Read a chunk from the input file. */
739
        /* --------------------------------------------------------------------
740
         */
741
        if (*pnBufLength > INT_MAX - static_cast<int>(nChunkSize) - 1)
2,772,450✔
742
        {
743
            CPLError(CE_Failure, CPLE_AppDefined,
×
744
                     "Too big line : more than 2 billion characters!.");
745
            CPLReadLineBuffer(-1);
×
746
            return nullptr;
×
747
        }
748

749
        pszRLBuffer =
750
            CPLReadLineBuffer(static_cast<int>(*pnBufLength + nChunkSize + 1));
2,772,450✔
751
        if (pszRLBuffer == nullptr)
2,772,450✔
752
            return nullptr;
×
753

754
        if (nChunkBytesRead == nChunkBytesConsumed + 1)
2,772,450✔
755
        {
756

757
            // case where one character is left over from last read.
758
            szChunk[0] = szChunk[nChunkBytesConsumed];
1,353,500✔
759

760
            nChunkBytesConsumed = 0;
1,353,500✔
761
            nChunkBytesRead = VSIFReadL(szChunk + 1, 1, nChunkSize - 1, fp) + 1;
1,353,500✔
762
        }
763
        else
764
        {
765
            nChunkBytesConsumed = 0;
1,418,950✔
766

767
            // fresh read.
768
            nChunkBytesRead = VSIFReadL(szChunk, 1, nChunkSize, fp);
1,418,950✔
769
            if (nChunkBytesRead == 0)
1,418,950✔
770
            {
771
                if (*pnBufLength == 0)
11,579✔
772
                    return nullptr;
11,579✔
773

774
                break;
×
775
            }
776
        }
777

778
        /* --------------------------------------------------------------------
779
         */
780
        /*      copy over characters watching for end-of-line. */
781
        /* --------------------------------------------------------------------
782
         */
783
        bool bBreak = false;
2,760,870✔
784
        while (nChunkBytesConsumed < nChunkBytesRead - 1 && !bBreak)
75,622,100✔
785
        {
786
            if ((szChunk[nChunkBytesConsumed] == knCR &&
72,861,200✔
787
                 szChunk[nChunkBytesConsumed + 1] == knLF) ||
172,691✔
788
                (szChunk[nChunkBytesConsumed] == knLF &&
72,688,800✔
789
                 szChunk[nChunkBytesConsumed + 1] == knCR))
1,222,660✔
790
            {
791
                nChunkBytesConsumed += 2;
172,414✔
792
                bBreak = true;
172,414✔
793
            }
794
            else if (szChunk[nChunkBytesConsumed] == knLF ||
72,688,800✔
795
                     szChunk[nChunkBytesConsumed] == knCR)
71,466,200✔
796
            {
797
                nChunkBytesConsumed += 1;
1,222,930✔
798
                bBreak = true;
1,222,930✔
799
            }
800
            else
801
            {
802
                pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
71,465,900✔
803
                if (nMaxCars >= 0 && *pnBufLength == nMaxCars)
71,465,900✔
804
                {
805
                    CPLError(CE_Failure, CPLE_AppDefined,
1✔
806
                             "Maximum number of characters allowed reached.");
807
                    return nullptr;
1✔
808
                }
809
            }
810
        }
811

812
        if (bBreak)
2,760,870✔
813
            break;
1,395,350✔
814

815
        /* --------------------------------------------------------------------
816
         */
817
        /*      If there is a remaining character and it is not a newline */
818
        /*      consume it.  If it is a newline, but we are clearly at the */
819
        /*      end of the file then consume it. */
820
        /* --------------------------------------------------------------------
821
         */
822
        if (nChunkBytesConsumed == nChunkBytesRead - 1 &&
1,365,520✔
823
            nChunkBytesRead < nChunkSize)
824
        {
825
            if (szChunk[nChunkBytesConsumed] == knLF ||
12,023✔
826
                szChunk[nChunkBytesConsumed] == knCR)
1,810✔
827
            {
828
                nChunkBytesConsumed++;
10,213✔
829
                break;
10,213✔
830
            }
831

832
            pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
1,810✔
833
            break;
1,810✔
834
        }
835
    }
1,353,500✔
836

837
    /* -------------------------------------------------------------------- */
838
    /*      If we have left over bytes after breaking out, seek back to     */
839
    /*      ensure they remain to be read next time.                        */
840
    /* -------------------------------------------------------------------- */
841
    if (nChunkBytesConsumed < nChunkBytesRead)
1,407,370✔
842
    {
843
        const size_t nBytesToPush = nChunkBytesRead - nChunkBytesConsumed;
1,389,820✔
844

845
        if (VSIFSeekL(fp, VSIFTellL(fp) - nBytesToPush, SEEK_SET) != 0)
1,389,820✔
846
            return nullptr;
×
847
    }
848

849
    pszRLBuffer[*pnBufLength] = '\0';
1,407,370✔
850

851
    return pszRLBuffer;
1,407,370✔
852
}
853

854
/************************************************************************/
855
/*                            CPLScanString()                           */
856
/************************************************************************/
857

858
/**
859
 * Scan up to a maximum number of characters from a given string,
860
 * allocate a buffer for a new string and fill it with scanned characters.
861
 *
862
 * @param pszString String containing characters to be scanned. It may be
863
 * terminated with a null character.
864
 *
865
 * @param nMaxLength The maximum number of character to read. Less
866
 * characters will be read if a null character is encountered.
867
 *
868
 * @param bTrimSpaces If TRUE, trim ending spaces from the input string.
869
 * Character considered as empty using isspace(3) function.
870
 *
871
 * @param bNormalize If TRUE, replace ':' symbol with the '_'. It is needed if
872
 * resulting string will be used in CPL dictionaries.
873
 *
874
 * @return Pointer to the resulting string buffer. Caller responsible to free
875
 * this buffer with CPLFree().
876
 */
877

878
char *CPLScanString(const char *pszString, int nMaxLength, int bTrimSpaces,
5,220✔
879
                    int bNormalize)
880
{
881
    if (!pszString)
5,220✔
882
        return nullptr;
×
883

884
    if (!nMaxLength)
5,220✔
885
        return CPLStrdup("");
2✔
886

887
    char *pszBuffer = static_cast<char *>(CPLMalloc(nMaxLength + 1));
5,218✔
888
    if (!pszBuffer)
5,218✔
889
        return nullptr;
×
890

891
    strncpy(pszBuffer, pszString, nMaxLength);
5,218✔
892
    pszBuffer[nMaxLength] = '\0';
5,218✔
893

894
    if (bTrimSpaces)
5,218✔
895
    {
896
        size_t i = strlen(pszBuffer);
5,218✔
897
        while (i > 0)
6,342✔
898
        {
899
            i--;
6,308✔
900
            if (!isspace(static_cast<unsigned char>(pszBuffer[i])))
6,308✔
901
                break;
5,184✔
902
            pszBuffer[i] = '\0';
1,124✔
903
        }
904
    }
905

906
    if (bNormalize)
5,218✔
907
    {
908
        size_t i = strlen(pszBuffer);
5,100✔
909
        while (i > 0)
38,870✔
910
        {
911
            i--;
33,770✔
912
            if (pszBuffer[i] == ':')
33,770✔
913
                pszBuffer[i] = '_';
×
914
        }
915
    }
916

917
    return pszBuffer;
5,218✔
918
}
919

920
/************************************************************************/
921
/*                             CPLScanLong()                            */
922
/************************************************************************/
923

924
/**
925
 * Scan up to a maximum number of characters from a string and convert
926
 * the result to a long.
927
 *
928
 * @param pszString String containing characters to be scanned. It may be
929
 * terminated with a null character.
930
 *
931
 * @param nMaxLength The maximum number of character to consider as part
932
 * of the number. Less characters will be considered if a null character
933
 * is encountered.
934
 *
935
 * @return Long value, converted from its ASCII form.
936
 */
937

938
long CPLScanLong(const char *pszString, int nMaxLength)
573✔
939
{
940
    CPLAssert(nMaxLength >= 0);
573✔
941
    if (pszString == nullptr)
573✔
942
        return 0;
×
943
    const size_t nLength = CPLStrnlen(pszString, nMaxLength);
573✔
944
    const std::string osValue(pszString, nLength);
1,146✔
945
    return atol(osValue.c_str());
573✔
946
}
947

948
/************************************************************************/
949
/*                            CPLScanULong()                            */
950
/************************************************************************/
951

952
/**
953
 * Scan up to a maximum number of characters from a string and convert
954
 * the result to a unsigned long.
955
 *
956
 * @param pszString String containing characters to be scanned. It may be
957
 * terminated with a null character.
958
 *
959
 * @param nMaxLength The maximum number of character to consider as part
960
 * of the number. Less characters will be considered if a null character
961
 * is encountered.
962
 *
963
 * @return Unsigned long value, converted from its ASCII form.
964
 */
965

966
unsigned long CPLScanULong(const char *pszString, int nMaxLength)
×
967
{
968
    CPLAssert(nMaxLength >= 0);
×
969
    if (pszString == nullptr)
×
970
        return 0;
×
971
    const size_t nLength = CPLStrnlen(pszString, nMaxLength);
×
972
    const std::string osValue(pszString, nLength);
×
973
    return strtoul(osValue.c_str(), nullptr, 10);
×
974
}
975

976
/************************************************************************/
977
/*                           CPLScanUIntBig()                           */
978
/************************************************************************/
979

980
/**
981
 * Extract big integer from string.
982
 *
983
 * Scan up to a maximum number of characters from a string and convert
984
 * the result to a GUIntBig.
985
 *
986
 * @param pszString String containing characters to be scanned. It may be
987
 * terminated with a null character.
988
 *
989
 * @param nMaxLength The maximum number of character to consider as part
990
 * of the number. Less characters will be considered if a null character
991
 * is encountered.
992
 *
993
 * @return GUIntBig value, converted from its ASCII form.
994
 */
995

996
GUIntBig CPLScanUIntBig(const char *pszString, int nMaxLength)
16,132✔
997
{
998
    CPLAssert(nMaxLength >= 0);
16,132✔
999
    if (pszString == nullptr)
16,132✔
1000
        return 0;
×
1001
    const size_t nLength = CPLStrnlen(pszString, nMaxLength);
16,132✔
1002
    const std::string osValue(pszString, nLength);
32,264✔
1003

1004
    /* -------------------------------------------------------------------- */
1005
    /*      Fetch out the result                                            */
1006
    /* -------------------------------------------------------------------- */
1007
    return strtoull(osValue.c_str(), nullptr, 10);
16,132✔
1008
}
1009

1010
/************************************************************************/
1011
/*                           CPLAtoGIntBig()                            */
1012
/************************************************************************/
1013

1014
/**
1015
 * Convert a string to a 64 bit signed integer.
1016
 *
1017
 * @param pszString String containing 64 bit signed integer.
1018
 * @return 64 bit signed integer.
1019
 * @since GDAL 2.0
1020
 */
1021

1022
GIntBig CPLAtoGIntBig(const char *pszString)
112,574✔
1023
{
1024
    return atoll(pszString);
112,574✔
1025
}
1026

1027
#if defined(__MINGW32__) || defined(__sun__)
1028

1029
// mingw atoll() doesn't return ERANGE in case of overflow
1030
static int CPLAtoGIntBigExHasOverflow(const char *pszString, GIntBig nVal)
1031
{
1032
    if (strlen(pszString) <= 18)
1033
        return FALSE;
1034
    while (*pszString == ' ')
1035
        pszString++;
1036
    if (*pszString == '+')
1037
        pszString++;
1038
    char szBuffer[32] = {};
1039
/* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
1040
#ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1041
#pragma GCC diagnostic push
1042
#pragma GCC diagnostic ignored "-Wformat"
1043
#endif
1044
    snprintf(szBuffer, sizeof(szBuffer), CPL_FRMT_GIB, nVal);
1045
#ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1046
#pragma GCC diagnostic pop
1047
#endif
1048
    return strcmp(szBuffer, pszString) != 0;
1049
}
1050

1051
#endif
1052

1053
/************************************************************************/
1054
/*                          CPLAtoGIntBigEx()                           */
1055
/************************************************************************/
1056

1057
/**
1058
 * Convert a string to a 64 bit signed integer.
1059
 *
1060
 * @param pszString String containing 64 bit signed integer.
1061
 * @param bWarn Issue a warning if an overflow occurs during conversion
1062
 * @param pbOverflow Pointer to an integer to store if an overflow occurred, or
1063
 *        NULL
1064
 * @return 64 bit signed integer.
1065
 * @since GDAL 2.0
1066
 */
1067

1068
GIntBig CPLAtoGIntBigEx(const char *pszString, int bWarn, int *pbOverflow)
104,224✔
1069
{
1070
    errno = 0;
104,224✔
1071
    GIntBig nVal = strtoll(pszString, nullptr, 10);
104,224✔
1072
    if (errno == ERANGE
104,224✔
1073
#if defined(__MINGW32__) || defined(__sun__)
1074
        || CPLAtoGIntBigExHasOverflow(pszString, nVal)
1075
#endif
1076
    )
1077
    {
1078
        if (pbOverflow)
4✔
1079
            *pbOverflow = TRUE;
2✔
1080
        if (bWarn)
4✔
1081
        {
1082
            CPLError(CE_Warning, CPLE_AppDefined,
2✔
1083
                     "64 bit integer overflow when converting %s", pszString);
1084
        }
1085
        while (*pszString == ' ')
4✔
1086
            pszString++;
×
1087
        return (*pszString == '-') ? GINTBIG_MIN : GINTBIG_MAX;
4✔
1088
    }
1089
    else if (pbOverflow)
104,220✔
1090
    {
1091
        *pbOverflow = FALSE;
3,874✔
1092
    }
1093
    return nVal;
104,220✔
1094
}
1095

1096
/************************************************************************/
1097
/*                           CPLScanPointer()                           */
1098
/************************************************************************/
1099

1100
/**
1101
 * Extract pointer from string.
1102
 *
1103
 * Scan up to a maximum number of characters from a string and convert
1104
 * the result to a pointer.
1105
 *
1106
 * @param pszString String containing characters to be scanned. It may be
1107
 * terminated with a null character.
1108
 *
1109
 * @param nMaxLength The maximum number of character to consider as part
1110
 * of the number. Less characters will be considered if a null character
1111
 * is encountered.
1112
 *
1113
 * @return pointer value, converted from its ASCII form.
1114
 */
1115

1116
void *CPLScanPointer(const char *pszString, int nMaxLength)
2,408✔
1117
{
1118
    char szTemp[128] = {};
2,408✔
1119

1120
    /* -------------------------------------------------------------------- */
1121
    /*      Compute string into local buffer, and terminate it.             */
1122
    /* -------------------------------------------------------------------- */
1123
    if (nMaxLength > static_cast<int>(sizeof(szTemp)) - 1)
2,408✔
1124
        nMaxLength = sizeof(szTemp) - 1;
×
1125

1126
    strncpy(szTemp, pszString, nMaxLength);
2,408✔
1127
    szTemp[nMaxLength] = '\0';
2,408✔
1128

1129
    /* -------------------------------------------------------------------- */
1130
    /*      On MSVC we have to scanf pointer values without the 0x          */
1131
    /*      prefix.                                                         */
1132
    /* -------------------------------------------------------------------- */
1133
    if (STARTS_WITH_CI(szTemp, "0x"))
2,408✔
1134
    {
1135
        void *pResult = nullptr;
2,416✔
1136

1137
#if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
1138
        // cppcheck-suppress invalidscanf
1139
        sscanf(szTemp + 2, "%p", &pResult);
1140
#else
1141
        // cppcheck-suppress invalidscanf
1142
        sscanf(szTemp, "%p", &pResult);
2,416✔
1143

1144
        // Solaris actually behaves like MSVCRT.
1145
        if (pResult == nullptr)
2,416✔
1146
        {
1147
            // cppcheck-suppress invalidscanf
1148
            sscanf(szTemp + 2, "%p", &pResult);
×
1149
        }
1150
#endif
1151
        return pResult;
2,416✔
1152
    }
1153

1154
#if SIZEOF_VOIDP == 8
1155
    return reinterpret_cast<void *>(CPLScanUIntBig(szTemp, nMaxLength));
×
1156
#else
1157
    return reinterpret_cast<void *>(CPLScanULong(szTemp, nMaxLength));
1158
#endif
1159
}
1160

1161
/************************************************************************/
1162
/*                             CPLScanDouble()                          */
1163
/************************************************************************/
1164

1165
/**
1166
 * Extract double from string.
1167
 *
1168
 * Scan up to a maximum number of characters from a string and convert the
1169
 * result to a double. This function uses CPLAtof() to convert string to
1170
 * double value, so it uses a comma as a decimal delimiter.
1171
 *
1172
 * @param pszString String containing characters to be scanned. It may be
1173
 * terminated with a null character.
1174
 *
1175
 * @param nMaxLength The maximum number of character to consider as part
1176
 * of the number. Less characters will be considered if a null character
1177
 * is encountered.
1178
 *
1179
 * @return Double value, converted from its ASCII form.
1180
 */
1181

1182
double CPLScanDouble(const char *pszString, int nMaxLength)
317✔
1183
{
1184
    char szValue[32] = {};
317✔
1185
    char *pszValue = nullptr;
317✔
1186

1187
    if (nMaxLength + 1 < static_cast<int>(sizeof(szValue)))
317✔
1188
        pszValue = szValue;
317✔
1189
    else
1190
        pszValue = static_cast<char *>(CPLMalloc(nMaxLength + 1));
×
1191

1192
    /* -------------------------------------------------------------------- */
1193
    /*      Compute string into local buffer, and terminate it.             */
1194
    /* -------------------------------------------------------------------- */
1195
    strncpy(pszValue, pszString, nMaxLength);
317✔
1196
    pszValue[nMaxLength] = '\0';
317✔
1197

1198
    /* -------------------------------------------------------------------- */
1199
    /*      Make a pass through converting 'D's to 'E's.                    */
1200
    /* -------------------------------------------------------------------- */
1201
    for (int i = 0; i < nMaxLength; i++)
6,436✔
1202
        if (pszValue[i] == 'd' || pszValue[i] == 'D')
6,119✔
1203
            pszValue[i] = 'E';
45✔
1204

1205
    /* -------------------------------------------------------------------- */
1206
    /*      The conversion itself.                                          */
1207
    /* -------------------------------------------------------------------- */
1208
    const double dfValue = CPLAtof(pszValue);
317✔
1209

1210
    if (pszValue != szValue)
317✔
1211
        CPLFree(pszValue);
×
1212
    return dfValue;
317✔
1213
}
1214

1215
/************************************************************************/
1216
/*                      CPLPrintString()                                */
1217
/************************************************************************/
1218

1219
/**
1220
 * Copy the string pointed to by pszSrc, NOT including the terminating
1221
 * `\\0' character, to the array pointed to by pszDest.
1222
 *
1223
 * @param pszDest Pointer to the destination string buffer. Should be
1224
 * large enough to hold the resulting string.
1225
 *
1226
 * @param pszSrc Pointer to the source buffer.
1227
 *
1228
 * @param nMaxLen Maximum length of the resulting string. If string length
1229
 * is greater than nMaxLen, it will be truncated.
1230
 *
1231
 * @return Number of characters printed.
1232
 */
1233

1234
int CPLPrintString(char *pszDest, const char *pszSrc, int nMaxLen)
12,915✔
1235
{
1236
    if (!pszDest)
12,915✔
1237
        return 0;
×
1238

1239
    if (!pszSrc)
12,915✔
1240
    {
1241
        *pszDest = '\0';
×
1242
        return 1;
×
1243
    }
1244

1245
    int nChars = 0;
12,915✔
1246
    char *pszTemp = pszDest;
12,915✔
1247

1248
    while (nChars < nMaxLen && *pszSrc)
193,445✔
1249
    {
1250
        *pszTemp++ = *pszSrc++;
180,530✔
1251
        nChars++;
180,530✔
1252
    }
1253

1254
    return nChars;
12,915✔
1255
}
1256

1257
/************************************************************************/
1258
/*                         CPLPrintStringFill()                         */
1259
/************************************************************************/
1260

1261
/**
1262
 * Copy the string pointed to by pszSrc, NOT including the terminating
1263
 * `\\0' character, to the array pointed to by pszDest. Remainder of the
1264
 * destination string will be filled with space characters. This is only
1265
 * difference from the PrintString().
1266
 *
1267
 * @param pszDest Pointer to the destination string buffer. Should be
1268
 * large enough to hold the resulting string.
1269
 *
1270
 * @param pszSrc Pointer to the source buffer.
1271
 *
1272
 * @param nMaxLen Maximum length of the resulting string. If string length
1273
 * is greater than nMaxLen, it will be truncated.
1274
 *
1275
 * @return Number of characters printed.
1276
 */
1277

1278
int CPLPrintStringFill(char *pszDest, const char *pszSrc, int nMaxLen)
209✔
1279
{
1280
    if (!pszDest)
209✔
1281
        return 0;
×
1282

1283
    if (!pszSrc)
209✔
1284
    {
1285
        memset(pszDest, ' ', nMaxLen);
×
1286
        return nMaxLen;
×
1287
    }
1288

1289
    char *pszTemp = pszDest;
209✔
1290
    while (nMaxLen && *pszSrc)
1,257✔
1291
    {
1292
        *pszTemp++ = *pszSrc++;
1,048✔
1293
        nMaxLen--;
1,048✔
1294
    }
1295

1296
    if (nMaxLen)
209✔
1297
        memset(pszTemp, ' ', nMaxLen);
71✔
1298

1299
    return nMaxLen;
209✔
1300
}
1301

1302
/************************************************************************/
1303
/*                          CPLPrintInt32()                             */
1304
/************************************************************************/
1305

1306
/**
1307
 * Print GInt32 value into specified string buffer. This string will not
1308
 * be NULL-terminated.
1309
 *
1310
 * @param pszBuffer Pointer to the destination string buffer. Should be
1311
 * large enough to hold the resulting string. Note, that the string will
1312
 * not be NULL-terminated, so user should do this himself, if needed.
1313
 *
1314
 * @param iValue Numerical value to print.
1315
 *
1316
 * @param nMaxLen Maximum length of the resulting string. If string length
1317
 * is greater than nMaxLen, it will be truncated.
1318
 *
1319
 * @return Number of characters printed.
1320
 */
1321

1322
int CPLPrintInt32(char *pszBuffer, GInt32 iValue, int nMaxLen)
9✔
1323
{
1324
    if (!pszBuffer)
9✔
1325
        return 0;
×
1326

1327
    if (nMaxLen >= 64)
9✔
1328
        nMaxLen = 63;
×
1329

1330
    char szTemp[64] = {};
9✔
1331

1332
#if UINT_MAX == 65535
1333
    snprintf(szTemp, sizeof(szTemp), "%*ld", nMaxLen, iValue);
1334
#else
1335
    snprintf(szTemp, sizeof(szTemp), "%*d", nMaxLen, iValue);
9✔
1336
#endif
1337

1338
    return CPLPrintString(pszBuffer, szTemp, nMaxLen);
9✔
1339
}
1340

1341
/************************************************************************/
1342
/*                          CPLPrintUIntBig()                           */
1343
/************************************************************************/
1344

1345
/**
1346
 * Print GUIntBig value into specified string buffer. This string will not
1347
 * be NULL-terminated.
1348
 *
1349
 * @param pszBuffer Pointer to the destination string buffer. Should be
1350
 * large enough to hold the resulting string. Note, that the string will
1351
 * not be NULL-terminated, so user should do this himself, if needed.
1352
 *
1353
 * @param iValue Numerical value to print.
1354
 *
1355
 * @param nMaxLen Maximum length of the resulting string. If string length
1356
 * is greater than nMaxLen, it will be truncated.
1357
 *
1358
 * @return Number of characters printed.
1359
 */
1360

1361
int CPLPrintUIntBig(char *pszBuffer, GUIntBig iValue, int nMaxLen)
24✔
1362
{
1363
    if (!pszBuffer)
24✔
1364
        return 0;
×
1365

1366
    if (nMaxLen >= 64)
24✔
1367
        nMaxLen = 63;
×
1368

1369
    char szTemp[64] = {};
24✔
1370

1371
#if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
1372
/* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
1373
#ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1374
#pragma GCC diagnostic push
1375
#pragma GCC diagnostic ignored "-Wformat"
1376
#pragma GCC diagnostic ignored "-Wformat-extra-args"
1377
#endif
1378
    snprintf(szTemp, sizeof(szTemp), "%*I64u", nMaxLen, iValue);
1379
#ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1380
#pragma GCC diagnostic pop
1381
#endif
1382
#else
1383
    snprintf(szTemp, sizeof(szTemp), "%*llu", nMaxLen, iValue);
24✔
1384
#endif
1385

1386
    return CPLPrintString(pszBuffer, szTemp, nMaxLen);
24✔
1387
}
1388

1389
/************************************************************************/
1390
/*                          CPLPrintPointer()                           */
1391
/************************************************************************/
1392

1393
/**
1394
 * Print pointer value into specified string buffer. This string will not
1395
 * be NULL-terminated.
1396
 *
1397
 * @param pszBuffer Pointer to the destination string buffer. Should be
1398
 * large enough to hold the resulting string. Note, that the string will
1399
 * not be NULL-terminated, so user should do this himself, if needed.
1400
 *
1401
 * @param pValue Pointer to ASCII encode.
1402
 *
1403
 * @param nMaxLen Maximum length of the resulting string. If string length
1404
 * is greater than nMaxLen, it will be truncated.
1405
 *
1406
 * @return Number of characters printed.
1407
 */
1408

1409
int CPLPrintPointer(char *pszBuffer, void *pValue, int nMaxLen)
12,854✔
1410
{
1411
    if (!pszBuffer)
12,854✔
1412
        return 0;
×
1413

1414
    if (nMaxLen >= 64)
12,854✔
1415
        nMaxLen = 63;
10,440✔
1416

1417
    char szTemp[64] = {};
12,854✔
1418

1419
    snprintf(szTemp, sizeof(szTemp), "%p", pValue);
12,854✔
1420

1421
    // On windows, and possibly some other platforms the sprintf("%p")
1422
    // does not prefix things with 0x so it is hard to know later if the
1423
    // value is hex encoded.  Fix this up here.
1424

1425
    if (!STARTS_WITH_CI(szTemp, "0x"))
12,854✔
1426
        snprintf(szTemp, sizeof(szTemp), "0x%p", pValue);
×
1427

1428
    return CPLPrintString(pszBuffer, szTemp, nMaxLen);
12,854✔
1429
}
1430

1431
/************************************************************************/
1432
/*                          CPLPrintDouble()                            */
1433
/************************************************************************/
1434

1435
/**
1436
 * Print double value into specified string buffer. Exponential character
1437
 * flag 'E' (or 'e') will be replaced with 'D', as in Fortran. Resulting
1438
 * string will not to be NULL-terminated.
1439
 *
1440
 * @param pszBuffer Pointer to the destination string buffer. Should be
1441
 * large enough to hold the resulting string. Note, that the string will
1442
 * not be NULL-terminated, so user should do this himself, if needed.
1443
 *
1444
 * @param pszFormat Format specifier (for example, "%16.9E").
1445
 *
1446
 * @param dfValue Numerical value to print.
1447
 *
1448
 * @param pszLocale Unused.
1449
 *
1450
 * @return Number of characters printed.
1451
 */
1452

1453
int CPLPrintDouble(char *pszBuffer, const char *pszFormat, double dfValue,
×
1454
                   CPL_UNUSED const char *pszLocale)
1455
{
1456
    if (!pszBuffer)
×
1457
        return 0;
×
1458

1459
    const int knDoubleBufferSize = 64;
×
1460
    char szTemp[knDoubleBufferSize] = {};
×
1461

1462
    CPLsnprintf(szTemp, knDoubleBufferSize, pszFormat, dfValue);
×
1463
    szTemp[knDoubleBufferSize - 1] = '\0';
×
1464

1465
    for (int i = 0; szTemp[i] != '\0'; i++)
×
1466
    {
1467
        if (szTemp[i] == 'E' || szTemp[i] == 'e')
×
1468
            szTemp[i] = 'D';
×
1469
    }
1470

1471
    return CPLPrintString(pszBuffer, szTemp, 64);
×
1472
}
1473

1474
/************************************************************************/
1475
/*                            CPLPrintTime()                            */
1476
/************************************************************************/
1477

1478
/**
1479
 * Print specified time value accordingly to the format options and
1480
 * specified locale name. This function does following:
1481
 *
1482
 *  - if locale parameter is not NULL, the current locale setting will be
1483
 *  stored and replaced with the specified one;
1484
 *  - format time value with the strftime(3) function;
1485
 *  - restore back current locale, if was saved.
1486
 *
1487
 * @param pszBuffer Pointer to the destination string buffer. Should be
1488
 * large enough to hold the resulting string. Note, that the string will
1489
 * not be NULL-terminated, so user should do this himself, if needed.
1490
 *
1491
 * @param nMaxLen Maximum length of the resulting string. If string length is
1492
 * greater than nMaxLen, it will be truncated.
1493
 *
1494
 * @param pszFormat Controls the output format. Options are the same as
1495
 * for strftime(3) function.
1496
 *
1497
 * @param poBrokenTime Pointer to the broken-down time structure. May be
1498
 * requested with the VSIGMTime() and VSILocalTime() functions.
1499
 *
1500
 * @param pszLocale Pointer to a character string containing locale name
1501
 * ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
1502
 * manipulate with locale settings and current process locale will be used for
1503
 * printing. Be aware that it may be unsuitable to use current locale for
1504
 * printing time, because all names will be printed in your native language,
1505
 * as well as time format settings also may be adjusted differently from the
1506
 * C/POSIX defaults. To solve these problems this option was introduced.
1507
 *
1508
 * @return Number of characters printed.
1509
 */
1510

1511
int CPLPrintTime(char *pszBuffer, int nMaxLen, const char *pszFormat,
34✔
1512
                 const struct tm *poBrokenTime, const char *pszLocale)
1513
{
1514
    char *pszTemp =
1515
        static_cast<char *>(CPLMalloc((nMaxLen + 1) * sizeof(char)));
34✔
1516

1517
    if (pszLocale && EQUAL(pszLocale, "C") &&
34✔
1518
        strcmp(pszFormat, "%a, %d %b %Y %H:%M:%S GMT") == 0)
34✔
1519
    {
1520
        // Particular case when formatting RFC822 datetime, to avoid locale
1521
        // change
1522
        static const char *const aszMonthStr[] = {"Jan", "Feb", "Mar", "Apr",
1523
                                                  "May", "Jun", "Jul", "Aug",
1524
                                                  "Sep", "Oct", "Nov", "Dec"};
1525
        static const char *const aszDayOfWeek[] = {"Sun", "Mon", "Tue", "Wed",
1526
                                                   "Thu", "Fri", "Sat"};
1527
        snprintf(pszTemp, nMaxLen + 1, "%s, %02d %s %04d %02d:%02d:%02d GMT",
68✔
1528
                 aszDayOfWeek[std::max(0, std::min(6, poBrokenTime->tm_wday))],
34✔
1529
                 poBrokenTime->tm_mday,
34✔
1530
                 aszMonthStr[std::max(0, std::min(11, poBrokenTime->tm_mon))],
34✔
1531
                 poBrokenTime->tm_year + 1900, poBrokenTime->tm_hour,
34✔
1532
                 poBrokenTime->tm_min, poBrokenTime->tm_sec);
68✔
1533
    }
1534
    else
1535
    {
1536
#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1537
        char *pszCurLocale = NULL;
1538

1539
        if (pszLocale || EQUAL(pszLocale, ""))
1540
        {
1541
            // Save the current locale.
1542
            pszCurLocale = CPLsetlocale(LC_ALL, NULL);
1543
            // Set locale to the specified value.
1544
            CPLsetlocale(LC_ALL, pszLocale);
1545
        }
1546
#else
1547
        (void)pszLocale;
1548
#endif
1549

1550
        if (!strftime(pszTemp, nMaxLen + 1, pszFormat, poBrokenTime))
×
1551
            memset(pszTemp, 0, nMaxLen + 1);
×
1552

1553
#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1554
        // Restore stored locale back.
1555
        if (pszCurLocale)
1556
            CPLsetlocale(LC_ALL, pszCurLocale);
1557
#endif
1558
    }
1559

1560
    const int nChars = CPLPrintString(pszBuffer, pszTemp, nMaxLen);
34✔
1561

1562
    CPLFree(pszTemp);
34✔
1563

1564
    return nChars;
34✔
1565
}
1566

1567
/************************************************************************/
1568
/*                       CPLVerifyConfiguration()                       */
1569
/************************************************************************/
1570

1571
void CPLVerifyConfiguration()
×
1572

1573
{
1574
    /* -------------------------------------------------------------------- */
1575
    /*      Verify data types.                                              */
1576
    /* -------------------------------------------------------------------- */
1577
    static_assert(sizeof(short) == 2);   // We unfortunately rely on this
1578
    static_assert(sizeof(int) == 4);     // We unfortunately rely on this
1579
    static_assert(sizeof(float) == 4);   // We unfortunately rely on this
1580
    static_assert(sizeof(double) == 8);  // We unfortunately rely on this
1581
    static_assert(sizeof(GInt64) == 8);
1582
    static_assert(sizeof(GInt32) == 4);
1583
    static_assert(sizeof(GInt16) == 2);
1584
    static_assert(sizeof(GByte) == 1);
1585

1586
    /* -------------------------------------------------------------------- */
1587
    /*      Verify byte order                                               */
1588
    /* -------------------------------------------------------------------- */
1589
#ifdef CPL_LSB
1590
#if __cplusplus >= 202002L
1591
    static_assert(std::endian::native == std::endian::little);
1592
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
1593
    static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
1594
#endif
1595
#elif defined(CPL_MSB)
1596
#if __cplusplus >= 202002L
1597
    static_assert(std::endian::native == std::endian::big);
1598
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
1599
    static_assert(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
1600
#endif
1601
#else
1602
#error "CPL_LSB or CPL_MSB must be defined"
1603
#endif
1604
}
×
1605

1606
#ifdef DEBUG_CONFIG_OPTIONS
1607

1608
static CPLMutex *hRegisterConfigurationOptionMutex = nullptr;
1609
static std::set<CPLString> *paoGetKeys = nullptr;
1610
static std::set<CPLString> *paoSetKeys = nullptr;
1611

1612
/************************************************************************/
1613
/*                      CPLShowAccessedOptions()                        */
1614
/************************************************************************/
1615

1616
static void CPLShowAccessedOptions()
1617
{
1618
    std::set<CPLString>::iterator aoIter;
1619

1620
    printf("Configuration options accessed in reading : "); /*ok*/
1621
    aoIter = paoGetKeys->begin();
1622
    while (aoIter != paoGetKeys->end())
1623
    {
1624
        printf("%s, ", (*aoIter).c_str()); /*ok*/
1625
        ++aoIter;
1626
    }
1627
    printf("\n"); /*ok*/
1628

1629
    printf("Configuration options accessed in writing : "); /*ok*/
1630
    aoIter = paoSetKeys->begin();
1631
    while (aoIter != paoSetKeys->end())
1632
    {
1633
        printf("%s, ", (*aoIter).c_str()); /*ok*/
1634
        ++aoIter;
1635
    }
1636
    printf("\n"); /*ok*/
1637

1638
    delete paoGetKeys;
1639
    delete paoSetKeys;
1640
    paoGetKeys = nullptr;
1641
    paoSetKeys = nullptr;
1642
}
1643

1644
/************************************************************************/
1645
/*                       CPLAccessConfigOption()                        */
1646
/************************************************************************/
1647

1648
static void CPLAccessConfigOption(const char *pszKey, bool bGet)
1649
{
1650
    CPLMutexHolderD(&hRegisterConfigurationOptionMutex);
1651
    if (paoGetKeys == nullptr)
1652
    {
1653
        paoGetKeys = new std::set<CPLString>;
1654
        paoSetKeys = new std::set<CPLString>;
1655
        atexit(CPLShowAccessedOptions);
1656
    }
1657
    if (bGet)
1658
        paoGetKeys->insert(pszKey);
1659
    else
1660
        paoSetKeys->insert(pszKey);
1661
}
1662
#endif
1663

1664
/************************************************************************/
1665
/*                         CPLGetConfigOption()                         */
1666
/************************************************************************/
1667

1668
/**
1669
 * Get the value of a configuration option.
1670
 *
1671
 * The value is the value of a (key, value) option set with
1672
 * CPLSetConfigOption(), or CPLSetThreadLocalConfigOption() of the same
1673
 * thread. If the given option was no defined with
1674
 * CPLSetConfigOption(), it tries to find it in environment variables.
1675
 *
1676
 * Note: the string returned by CPLGetConfigOption() might be short-lived, and
1677
 * in particular it will become invalid after a call to CPLSetConfigOption()
1678
 * with the same key.
1679
 *
1680
 * To override temporary a potentially existing option with a new value, you
1681
 * can use the following snippet :
1682
 * \code{.cpp}
1683
 *     // backup old value
1684
 *     const char* pszOldValTmp = CPLGetConfigOption(pszKey, NULL);
1685
 *     char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
1686
 *     // override with new value
1687
 *     CPLSetConfigOption(pszKey, pszNewVal);
1688
 *     // do something useful
1689
 *     // restore old value
1690
 *     CPLSetConfigOption(pszKey, pszOldVal);
1691
 *     CPLFree(pszOldVal);
1692
 * \endcode
1693
 *
1694
 * @param pszKey the key of the option to retrieve
1695
 * @param pszDefault a default value if the key does not match existing defined
1696
 *     options (may be NULL)
1697
 * @return the value associated to the key, or the default value if not found
1698
 *
1699
 * @see CPLSetConfigOption(), https://gdal.org/user/configoptions.html
1700
 */
1701
const char *CPL_STDCALL CPLGetConfigOption(const char *pszKey,
6,792,180✔
1702
                                           const char *pszDefault)
1703

1704
{
1705
    const char *pszResult = CPLGetThreadLocalConfigOption(pszKey, nullptr);
6,792,180✔
1706

1707
    if (pszResult == nullptr)
6,791,240✔
1708
    {
1709
        pszResult = CPLGetGlobalConfigOption(pszKey, nullptr);
6,750,430✔
1710
    }
1711

1712
    if (gbIgnoreEnvVariables)
6,793,190✔
1713
    {
1714
        const char *pszEnvVar = getenv(pszKey);
6✔
1715
        if (pszEnvVar != nullptr)
6✔
1716
        {
1717
            CPLDebug("CPL",
1✔
1718
                     "Ignoring environment variable %s=%s because of "
1719
                     "ignore-env-vars=yes setting in configuration file",
1720
                     pszKey, pszEnvVar);
1721
        }
1722
    }
1723
    else if (pszResult == nullptr)
6,793,180✔
1724
    {
1725
        pszResult = getenv(pszKey);
6,742,970✔
1726
    }
1727

1728
    if (pszResult == nullptr)
6,793,240✔
1729
        return pszDefault;
6,731,210✔
1730

1731
    return pszResult;
62,028✔
1732
}
1733

1734
/************************************************************************/
1735
/*                         CPLGetConfigOptions()                        */
1736
/************************************************************************/
1737

1738
/**
1739
 * Return the list of configuration options as KEY=VALUE pairs.
1740
 *
1741
 * The list is the one set through the CPLSetConfigOption() API.
1742
 *
1743
 * Options that through environment variables or with
1744
 * CPLSetThreadLocalConfigOption() will *not* be listed.
1745
 *
1746
 * @return a copy of the list, to be freed with CSLDestroy().
1747
 * @since GDAL 2.2
1748
 */
1749
char **CPLGetConfigOptions(void)
45✔
1750
{
1751
    CPLMutexHolderD(&hConfigMutex);
90✔
1752
    return CSLDuplicate(const_cast<char **>(g_papszConfigOptions));
90✔
1753
}
1754

1755
/************************************************************************/
1756
/*                         CPLSetConfigOptions()                        */
1757
/************************************************************************/
1758

1759
/**
1760
 * Replace the full list of configuration options with the passed list of
1761
 * KEY=VALUE pairs.
1762
 *
1763
 * This has the same effect of clearing the existing list, and setting
1764
 * individually each pair with the CPLSetConfigOption() API.
1765
 *
1766
 * This does not affect options set through environment variables or with
1767
 * CPLSetThreadLocalConfigOption().
1768
 *
1769
 * The passed list is copied by the function.
1770
 *
1771
 * @param papszConfigOptions the new list (or NULL).
1772
 *
1773
 * @since GDAL 2.2
1774
 */
1775
void CPLSetConfigOptions(const char *const *papszConfigOptions)
98✔
1776
{
1777
    CPLMutexHolderD(&hConfigMutex);
98✔
1778
    CSLDestroy(const_cast<char **>(g_papszConfigOptions));
98✔
1779
    g_papszConfigOptions = const_cast<volatile char **>(
98✔
1780
        CSLDuplicate(const_cast<char **>(papszConfigOptions)));
98✔
1781
}
98✔
1782

1783
/************************************************************************/
1784
/*                   CPLGetThreadLocalConfigOption()                    */
1785
/************************************************************************/
1786

1787
/** Same as CPLGetConfigOption() but only with options set with
1788
 * CPLSetThreadLocalConfigOption() */
1789
const char *CPL_STDCALL CPLGetThreadLocalConfigOption(const char *pszKey,
6,821,110✔
1790
                                                      const char *pszDefault)
1791

1792
{
1793
#ifdef DEBUG_CONFIG_OPTIONS
1794
    CPLAccessConfigOption(pszKey, TRUE);
1795
#endif
1796

1797
    const char *pszResult = nullptr;
6,821,110✔
1798

1799
    int bMemoryError = FALSE;
6,821,110✔
1800
    char **papszTLConfigOptions = reinterpret_cast<char **>(
1801
        CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
6,821,110✔
1802
    if (papszTLConfigOptions != nullptr)
6,820,320✔
1803
        pszResult = CSLFetchNameValue(papszTLConfigOptions, pszKey);
6,389,680✔
1804

1805
    if (pszResult == nullptr)
6,820,470✔
1806
        return pszDefault;
6,778,740✔
1807

1808
    return pszResult;
41,735✔
1809
}
1810

1811
/************************************************************************/
1812
/*                   CPLGetGlobalConfigOption()                         */
1813
/************************************************************************/
1814

1815
/** Same as CPLGetConfigOption() but excludes environment variables and
1816
 *  options set with CPLSetThreadLocalConfigOption().
1817
 *  This function should generally not be used by applications, which should
1818
 *  use CPLGetConfigOption() instead.
1819
 *  @since 3.8 */
1820
const char *CPL_STDCALL CPLGetGlobalConfigOption(const char *pszKey,
6,752,580✔
1821
                                                 const char *pszDefault)
1822
{
1823
#ifdef DEBUG_CONFIG_OPTIONS
1824
    CPLAccessConfigOption(pszKey, TRUE);
1825
#endif
1826

1827
    CPLMutexHolderD(&hConfigMutex);
13,506,900✔
1828

1829
    const char *pszResult =
1830
        CSLFetchNameValue(const_cast<char **>(g_papszConfigOptions), pszKey);
6,754,300✔
1831

1832
    if (pszResult == nullptr)
6,754,300✔
1833
        return pszDefault;
6,744,690✔
1834

1835
    return pszResult;
9,607✔
1836
}
1837

1838
/************************************************************************/
1839
/*                    CPLSubscribeToSetConfigOption()                   */
1840
/************************************************************************/
1841

1842
/**
1843
 * Install a callback that will be notified of calls to CPLSetConfigOption()/
1844
 * CPLSetThreadLocalConfigOption()
1845
 *
1846
 * @param pfnCallback Callback. Must not be NULL
1847
 * @param pUserData Callback user data. May be NULL.
1848
 * @return subscriber ID that can be used with CPLUnsubscribeToSetConfigOption()
1849
 * @since GDAL 3.7
1850
 */
1851

1852
int CPLSubscribeToSetConfigOption(CPLSetConfigOptionSubscriber pfnCallback,
1,287✔
1853
                                  void *pUserData)
1854
{
1855
    CPLMutexHolderD(&hConfigMutex);
2,574✔
1856
    for (int nId = 0;
1,292✔
1857
         nId < static_cast<int>(gSetConfigOptionSubscribers.size()); ++nId)
1,292✔
1858
    {
1859
        if (!gSetConfigOptionSubscribers[nId].first)
6✔
1860
        {
1861
            gSetConfigOptionSubscribers[nId].first = pfnCallback;
1✔
1862
            gSetConfigOptionSubscribers[nId].second = pUserData;
1✔
1863
            return nId;
1✔
1864
        }
1865
    }
1866
    int nId = static_cast<int>(gSetConfigOptionSubscribers.size());
1,286✔
1867
    gSetConfigOptionSubscribers.push_back(
1,286✔
1868
        std::pair<CPLSetConfigOptionSubscriber, void *>(pfnCallback,
1,286✔
1869
                                                        pUserData));
1870
    return nId;
1,286✔
1871
}
1872

1873
/************************************************************************/
1874
/*                  CPLUnsubscribeToSetConfigOption()                   */
1875
/************************************************************************/
1876

1877
/**
1878
 * Remove a subscriber installed with CPLSubscribeToSetConfigOption()
1879
 *
1880
 * @param nId Subscriber id returned by CPLSubscribeToSetConfigOption()
1881
 * @since GDAL 3.7
1882
 */
1883

1884
void CPLUnsubscribeToSetConfigOption(int nId)
4✔
1885
{
1886
    CPLMutexHolderD(&hConfigMutex);
8✔
1887
    if (nId == static_cast<int>(gSetConfigOptionSubscribers.size()) - 1)
4✔
1888
    {
1889
        gSetConfigOptionSubscribers.resize(gSetConfigOptionSubscribers.size() -
3✔
1890
                                           1);
1891
    }
1892
    else if (nId >= 0 &&
2✔
1893
             nId < static_cast<int>(gSetConfigOptionSubscribers.size()))
1✔
1894
    {
1895
        gSetConfigOptionSubscribers[nId].first = nullptr;
1✔
1896
    }
1897
}
4✔
1898

1899
/************************************************************************/
1900
/*                  NotifyOtherComponentsConfigOptionChanged()          */
1901
/************************************************************************/
1902

1903
static void NotifyOtherComponentsConfigOptionChanged(const char *pszKey,
68,940✔
1904
                                                     const char *pszValue,
1905
                                                     bool bThreadLocal)
1906
{
1907
    // When changing authentication parameters of virtual file systems,
1908
    // partially invalidate cached state about file availability.
1909
    if (STARTS_WITH_CI(pszKey, "AWS_") || STARTS_WITH_CI(pszKey, "GS_") ||
68,940✔
1910
        STARTS_WITH_CI(pszKey, "GOOGLE_") ||
66,222✔
1911
        STARTS_WITH_CI(pszKey, "GDAL_HTTP_HEADER_FILE") ||
66,182✔
1912
        STARTS_WITH_CI(pszKey, "AZURE_") ||
66,155✔
1913
        (STARTS_WITH_CI(pszKey, "SWIFT_") && !EQUAL(pszKey, "SWIFT_MAX_KEYS")))
65,919✔
1914
    {
1915
        VSICurlAuthParametersChanged();
3,125✔
1916
    }
1917

1918
    if (!gSetConfigOptionSubscribers.empty())
68,882✔
1919
    {
1920
        for (const auto &iter : gSetConfigOptionSubscribers)
136,223✔
1921
        {
1922
            if (iter.first)
68,204✔
1923
                iter.first(pszKey, pszValue, bThreadLocal, iter.second);
68,248✔
1924
        }
1925
    }
1926
}
68,771✔
1927

1928
/************************************************************************/
1929
/*                       CPLIsDebugEnabled()                            */
1930
/************************************************************************/
1931

1932
static int gnDebug = -1;
1933

1934
/** Returns whether CPL_DEBUG is enabled.
1935
 *
1936
 * @since 3.11
1937
 */
1938
bool CPLIsDebugEnabled()
75,006✔
1939
{
1940
    if (gnDebug < 0)
75,006✔
1941
    {
1942
        // Check that apszKnownConfigOptions is correctly sorted with
1943
        // STRCASECMP() criterion.
1944
        for (size_t i = 1; i < CPL_ARRAYSIZE(apszKnownConfigOptions); ++i)
500,966✔
1945
        {
1946
            if (STRCASECMP(apszKnownConfigOptions[i - 1],
500,503✔
1947
                           apszKnownConfigOptions[i]) >= 0)
1948
            {
1949
                CPLError(CE_Failure, CPLE_AppDefined,
×
1950
                         "ERROR: apszKnownConfigOptions[] isn't correctly "
1951
                         "sorted: %s >= %s",
1952
                         apszKnownConfigOptions[i - 1],
×
1953
                         apszKnownConfigOptions[i]);
×
1954
            }
1955
        }
1956
        gnDebug = CPLTestBool(CPLGetConfigOption("CPL_DEBUG", "OFF"));
463✔
1957
    }
1958

1959
    return gnDebug != 0;
74,966✔
1960
}
1961

1962
/************************************************************************/
1963
/*                       CPLDeclareKnownConfigOption()                  */
1964
/************************************************************************/
1965

1966
static std::mutex goMutexDeclaredKnownConfigOptions;
1967
static std::set<CPLString> goSetKnownConfigOptions;
1968

1969
/** Declare that the specified configuration option is known.
1970
 *
1971
 * This is useful to avoid a warning to be emitted on unknown configuration
1972
 * options when CPL_DEBUG is enabled.
1973
 *
1974
 * @param pszKey Name of the configuration option to declare.
1975
 * @param pszDefinition Unused for now. Must be set to nullptr.
1976
 * @since 3.11
1977
 */
1978
void CPLDeclareKnownConfigOption(const char *pszKey,
1✔
1979
                                 [[maybe_unused]] const char *pszDefinition)
1980
{
1981
    std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
1✔
1982
    goSetKnownConfigOptions.insert(CPLString(pszKey).toupper());
1✔
1983
}
1✔
1984

1985
/************************************************************************/
1986
/*                       CPLGetKnownConfigOptions()                     */
1987
/************************************************************************/
1988

1989
/** Return the list of known configuration options.
1990
 *
1991
 * Must be freed with CSLDestroy().
1992
 * @since 3.11
1993
 */
1994
char **CPLGetKnownConfigOptions()
4✔
1995
{
1996
    std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
8✔
1997
    CPLStringList aosList;
8✔
1998
    for (const char *pszKey : apszKnownConfigOptions)
4,332✔
1999
        aosList.AddString(pszKey);
4,328✔
2000
    for (const auto &osKey : goSetKnownConfigOptions)
5✔
2001
        aosList.AddString(osKey);
1✔
2002
    return aosList.StealList();
8✔
2003
}
2004

2005
/************************************************************************/
2006
/*           CPLSetConfigOptionDetectUnknownConfigOption()              */
2007
/************************************************************************/
2008

2009
static void CPLSetConfigOptionDetectUnknownConfigOption(const char *pszKey,
69,043✔
2010
                                                        const char *pszValue)
2011
{
2012
    if (EQUAL(pszKey, "CPL_DEBUG"))
69,043✔
2013
    {
2014
        gnDebug = pszValue ? CPLTestBool(pszValue) : false;
112✔
2015
    }
2016
    else if (CPLIsDebugEnabled())
68,931✔
2017
    {
2018
        if (!std::binary_search(std::begin(apszKnownConfigOptions),
261✔
2019
                                std::end(apszKnownConfigOptions), pszKey,
2020
                                [](const char *a, const char *b)
2,904✔
2021
                                { return STRCASECMP(a, b) < 0; }))
2,904✔
2022
        {
2023
            bool bFound;
2024
            {
2025
                std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
4✔
2026
                bFound = cpl::contains(goSetKnownConfigOptions,
8✔
2027
                                       CPLString(pszKey).toupper());
4✔
2028
            }
2029
            if (!bFound)
4✔
2030
            {
2031
                const char *pszOldValue = CPLGetConfigOption(pszKey, nullptr);
2✔
2032
                if (!((!pszValue && !pszOldValue) ||
2✔
2033
                      (pszValue && pszOldValue &&
1✔
2034
                       EQUAL(pszValue, pszOldValue))))
×
2035
                {
2036
                    CPLError(CE_Warning, CPLE_AppDefined,
2✔
2037
                             "Unknown configuration option '%s'.", pszKey);
2038
                }
2039
            }
2040
        }
2041
    }
2042
}
68,948✔
2043

2044
/************************************************************************/
2045
/*                         CPLSetConfigOption()                         */
2046
/************************************************************************/
2047

2048
/**
2049
 * Set a configuration option for GDAL/OGR use.
2050
 *
2051
 * Those options are defined as a (key, value) couple. The value corresponding
2052
 * to a key can be got later with the CPLGetConfigOption() method.
2053
 *
2054
 * This mechanism is similar to environment variables, but options set with
2055
 * CPLSetConfigOption() overrides, for CPLGetConfigOption() point of view,
2056
 * values defined in the environment.
2057
 *
2058
 * If CPLSetConfigOption() is called several times with the same key, the
2059
 * value provided during the last call will be used.
2060
 *
2061
 * Options can also be passed on the command line of most GDAL utilities
2062
 * with '\--config KEY VALUE' (or '\--config KEY=VALUE' since GDAL 3.10).
2063
 * For example, ogrinfo \--config CPL_DEBUG ON ~/data/test/point.shp
2064
 *
2065
 * This function can also be used to clear a setting by passing NULL as the
2066
 * value (note: passing NULL will not unset an existing environment variable;
2067
 * it will just unset a value previously set by CPLSetConfigOption()).
2068
 *
2069
 * Starting with GDAL 3.11, if CPL_DEBUG is enabled prior to this call, and
2070
 * CPLSetConfigOption() is called with a key that is neither a known
2071
 * configuration option of GDAL itself, or one that has been declared with
2072
 * CPLDeclareKnownConfigOption(), a warning will be emitted.
2073
 *
2074
 * @param pszKey the key of the option
2075
 * @param pszValue the value of the option, or NULL to clear a setting.
2076
 *
2077
 * @see https://gdal.org/user/configoptions.html
2078
 */
2079
void CPL_STDCALL CPLSetConfigOption(const char *pszKey, const char *pszValue)
5,052✔
2080

2081
{
2082
#ifdef DEBUG_CONFIG_OPTIONS
2083
    CPLAccessConfigOption(pszKey, FALSE);
2084
#endif
2085
    CPLMutexHolderD(&hConfigMutex);
10,104✔
2086

2087
#ifdef OGRAPISPY_ENABLED
2088
    OGRAPISPYCPLSetConfigOption(pszKey, pszValue);
5,052✔
2089
#endif
2090

2091
    CPLSetConfigOptionDetectUnknownConfigOption(pszKey, pszValue);
5,052✔
2092

2093
    g_papszConfigOptions = const_cast<volatile char **>(CSLSetNameValue(
5,052✔
2094
        const_cast<char **>(g_papszConfigOptions), pszKey, pszValue));
2095

2096
    NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
5,052✔
2097
                                             /*bTheadLocal=*/false);
2098
}
5,052✔
2099

2100
/************************************************************************/
2101
/*                   CPLSetThreadLocalTLSFreeFunc()                     */
2102
/************************************************************************/
2103

2104
/* non-stdcall wrapper function for CSLDestroy() (#5590) */
2105
static void CPLSetThreadLocalTLSFreeFunc(void *pData)
21✔
2106
{
2107
    CSLDestroy(reinterpret_cast<char **>(pData));
21✔
2108
}
21✔
2109

2110
/************************************************************************/
2111
/*                   CPLSetThreadLocalConfigOption()                    */
2112
/************************************************************************/
2113

2114
/**
2115
 * Set a configuration option for GDAL/OGR use.
2116
 *
2117
 * Those options are defined as a (key, value) couple. The value corresponding
2118
 * to a key can be got later with the CPLGetConfigOption() method.
2119
 *
2120
 * This function sets the configuration option that only applies in the
2121
 * current thread, as opposed to CPLSetConfigOption() which sets an option
2122
 * that applies on all threads. CPLSetThreadLocalConfigOption() will override
2123
 * the effect of CPLSetConfigOption) for the current thread.
2124
 *
2125
 * This function can also be used to clear a setting by passing NULL as the
2126
 * value (note: passing NULL will not unset an existing environment variable or
2127
 * a value set through CPLSetConfigOption();
2128
 * it will just unset a value previously set by
2129
 * CPLSetThreadLocalConfigOption()).
2130
 *
2131
 * @param pszKey the key of the option
2132
 * @param pszValue the value of the option, or NULL to clear a setting.
2133
 */
2134

2135
void CPL_STDCALL CPLSetThreadLocalConfigOption(const char *pszKey,
63,885✔
2136
                                               const char *pszValue)
2137

2138
{
2139
#ifdef DEBUG_CONFIG_OPTIONS
2140
    CPLAccessConfigOption(pszKey, FALSE);
2141
#endif
2142

2143
#ifdef OGRAPISPY_ENABLED
2144
    OGRAPISPYCPLSetThreadLocalConfigOption(pszKey, pszValue);
63,885✔
2145
#endif
2146

2147
    int bMemoryError = FALSE;
63,966✔
2148
    char **papszTLConfigOptions = reinterpret_cast<char **>(
2149
        CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
63,966✔
2150
    if (bMemoryError)
63,944✔
2151
        return;
×
2152

2153
    CPLSetConfigOptionDetectUnknownConfigOption(pszKey, pszValue);
63,944✔
2154

2155
    papszTLConfigOptions =
2156
        CSLSetNameValue(papszTLConfigOptions, pszKey, pszValue);
63,929✔
2157

2158
    CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
63,854✔
2159
                          CPLSetThreadLocalTLSFreeFunc);
2160

2161
    NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
63,806✔
2162
                                             /*bTheadLocal=*/true);
2163
}
2164

2165
/************************************************************************/
2166
/*                   CPLGetThreadLocalConfigOptions()                   */
2167
/************************************************************************/
2168

2169
/**
2170
 * Return the list of thread local configuration options as KEY=VALUE pairs.
2171
 *
2172
 * Options that through environment variables or with
2173
 * CPLSetConfigOption() will *not* be listed.
2174
 *
2175
 * @return a copy of the list, to be freed with CSLDestroy().
2176
 * @since GDAL 2.2
2177
 */
2178
char **CPLGetThreadLocalConfigOptions(void)
739,394✔
2179
{
2180
    int bMemoryError = FALSE;
739,394✔
2181
    char **papszTLConfigOptions = reinterpret_cast<char **>(
2182
        CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
739,394✔
2183
    if (bMemoryError)
726,788✔
2184
        return nullptr;
×
2185
    return CSLDuplicate(papszTLConfigOptions);
726,788✔
2186
}
2187

2188
/************************************************************************/
2189
/*                   CPLSetThreadLocalConfigOptions()                   */
2190
/************************************************************************/
2191

2192
/**
2193
 * Replace the full list of thread local configuration options with the
2194
 * passed list of KEY=VALUE pairs.
2195
 *
2196
 * This has the same effect of clearing the existing list, and setting
2197
 * individually each pair with the CPLSetThreadLocalConfigOption() API.
2198
 *
2199
 * This does not affect options set through environment variables or with
2200
 * CPLSetConfigOption().
2201
 *
2202
 * The passed list is copied by the function.
2203
 *
2204
 * @param papszConfigOptions the new list (or NULL).
2205
 *
2206
 * @since GDAL 2.2
2207
 */
2208
void CPLSetThreadLocalConfigOptions(const char *const *papszConfigOptions)
1,454,800✔
2209
{
2210
    int bMemoryError = FALSE;
1,454,800✔
2211
    char **papszTLConfigOptions = reinterpret_cast<char **>(
2212
        CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
1,454,800✔
2213
    if (bMemoryError)
1,450,340✔
2214
        return;
×
2215
    CSLDestroy(papszTLConfigOptions);
1,450,340✔
2216
    papszTLConfigOptions =
2217
        CSLDuplicate(const_cast<char **>(papszConfigOptions));
1,441,020✔
2218
    CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
1,446,240✔
2219
                          CPLSetThreadLocalTLSFreeFunc);
2220
}
2221

2222
/************************************************************************/
2223
/*                           CPLFreeConfig()                            */
2224
/************************************************************************/
2225

2226
void CPL_STDCALL CPLFreeConfig()
1,550✔
2227

2228
{
2229
    {
2230
        CPLMutexHolderD(&hConfigMutex);
3,100✔
2231

2232
        CSLDestroy(const_cast<char **>(g_papszConfigOptions));
1,550✔
2233
        g_papszConfigOptions = nullptr;
1,550✔
2234

2235
        int bMemoryError = FALSE;
1,550✔
2236
        char **papszTLConfigOptions = reinterpret_cast<char **>(
2237
            CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
1,550✔
2238
        if (papszTLConfigOptions != nullptr)
1,550✔
2239
        {
2240
            CSLDestroy(papszTLConfigOptions);
204✔
2241
            CPLSetTLS(CTLS_CONFIGOPTIONS, nullptr, FALSE);
204✔
2242
        }
2243
    }
2244
    CPLDestroyMutex(hConfigMutex);
1,550✔
2245
    hConfigMutex = nullptr;
1,550✔
2246
}
1,550✔
2247

2248
/************************************************************************/
2249
/*                    CPLLoadConfigOptionsFromFile()                    */
2250
/************************************************************************/
2251

2252
/** Load configuration from a given configuration file.
2253

2254
A configuration file is a text file in a .ini style format, that lists
2255
configuration options and their values.
2256
Lines starting with # are comment lines.
2257

2258
Example:
2259
\verbatim
2260
[configoptions]
2261
# set BAR as the value of configuration option FOO
2262
FOO=BAR
2263
\endverbatim
2264

2265
Starting with GDAL 3.5, a configuration file can also contain credentials
2266
(or more generally options related to a virtual file system) for a given path
2267
prefix, that can also be set with VSISetPathSpecificOption(). Credentials should
2268
be put under a [credentials] section, and for each path prefix, under a relative
2269
subsection whose name starts with "[." (e.g. "[.some_arbitrary_name]"), and
2270
whose first key is "path".
2271

2272
Example:
2273
\verbatim
2274
[credentials]
2275

2276
[.private_bucket]
2277
path=/vsis3/my_private_bucket
2278
AWS_SECRET_ACCESS_KEY=...
2279
AWS_ACCESS_KEY_ID=...
2280

2281
[.sentinel_s2_l1c]
2282
path=/vsis3/sentinel-s2-l1c
2283
AWS_REQUEST_PAYER=requester
2284
\endverbatim
2285

2286
Starting with GDAL 3.6, a leading [directives] section might be added with
2287
a "ignore-env-vars=yes" setting to indicate that, starting with that point,
2288
all environment variables should be ignored, and only configuration options
2289
defined in the [configoptions] sections or through the CPLSetConfigOption() /
2290
CPLSetThreadLocalConfigOption() functions should be taken into account.
2291

2292
This function is typically called by CPLLoadConfigOptionsFromPredefinedFiles()
2293

2294
@param pszFilename File where to load configuration from.
2295
@param bOverrideEnvVars Whether configuration options from the configuration
2296
                        file should override environment variables.
2297
@since GDAL 3.3
2298
 */
2299
void CPLLoadConfigOptionsFromFile(const char *pszFilename, int bOverrideEnvVars)
3,494✔
2300
{
2301
    VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
3,494✔
2302
    if (fp == nullptr)
3,494✔
2303
        return;
3,485✔
2304
    CPLDebug("CPL", "Loading configuration from %s", pszFilename);
9✔
2305
    const char *pszLine;
2306
    enum class Section
2307
    {
2308
        NONE,
2309
        GENERAL,
2310
        CONFIG_OPTIONS,
2311
        CREDENTIALS,
2312
    };
2313
    Section eCurrentSection = Section::NONE;
9✔
2314
    bool bInSubsection = false;
9✔
2315
    std::string osPath;
18✔
2316
    int nSectionCounter = 0;
9✔
2317

2318
    const auto IsSpaceOnly = [](const char *pszStr)
56✔
2319
    {
2320
        for (; *pszStr; ++pszStr)
56✔
2321
        {
2322
            if (!isspace(static_cast<unsigned char>(*pszStr)))
47✔
2323
                return false;
41✔
2324
        }
2325
        return true;
9✔
2326
    };
2327

2328
    while ((pszLine = CPLReadLine2L(fp, -1, nullptr)) != nullptr)
59✔
2329
    {
2330
        if (IsSpaceOnly(pszLine))
50✔
2331
        {
2332
            // Blank line
2333
        }
2334
        else if (pszLine[0] == '#')
41✔
2335
        {
2336
            // Comment line
2337
        }
2338
        else if (strcmp(pszLine, "[configoptions]") == 0)
35✔
2339
        {
2340
            nSectionCounter++;
6✔
2341
            eCurrentSection = Section::CONFIG_OPTIONS;
6✔
2342
        }
2343
        else if (strcmp(pszLine, "[credentials]") == 0)
29✔
2344
        {
2345
            nSectionCounter++;
4✔
2346
            eCurrentSection = Section::CREDENTIALS;
4✔
2347
            bInSubsection = false;
4✔
2348
            osPath.clear();
4✔
2349
        }
2350
        else if (strcmp(pszLine, "[directives]") == 0)
25✔
2351
        {
2352
            nSectionCounter++;
2✔
2353
            if (nSectionCounter != 1)
2✔
2354
            {
2355
                CPLError(CE_Warning, CPLE_AppDefined,
×
2356
                         "The [directives] section should be the first one in "
2357
                         "the file, otherwise some its settings might not be "
2358
                         "used correctly.");
2359
            }
2360
            eCurrentSection = Section::GENERAL;
2✔
2361
        }
2362
        else if (eCurrentSection == Section::GENERAL)
23✔
2363
        {
2364
            char *pszKey = nullptr;
2✔
2365
            const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
2✔
2366
            if (pszKey && pszValue)
2✔
2367
            {
2368
                if (strcmp(pszKey, "ignore-env-vars") == 0)
2✔
2369
                {
2370
                    gbIgnoreEnvVariables = CPLTestBool(pszValue);
2✔
2371
                }
2372
                else
2373
                {
2374
                    CPLError(CE_Warning, CPLE_AppDefined,
×
2375
                             "Ignoring %s line in [directives] section",
2376
                             pszLine);
2377
                }
2378
            }
2379
            CPLFree(pszKey);
2✔
2380
        }
2381
        else if (eCurrentSection == Section::CREDENTIALS)
21✔
2382
        {
2383
            if (strncmp(pszLine, "[.", 2) == 0)
15✔
2384
            {
2385
                bInSubsection = true;
4✔
2386
                osPath.clear();
4✔
2387
            }
2388
            else if (bInSubsection)
11✔
2389
            {
2390
                char *pszKey = nullptr;
10✔
2391
                const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
10✔
2392
                if (pszKey && pszValue)
10✔
2393
                {
2394
                    if (strcmp(pszKey, "path") == 0)
10✔
2395
                    {
2396
                        if (!osPath.empty())
4✔
2397
                        {
2398
                            CPLError(
1✔
2399
                                CE_Warning, CPLE_AppDefined,
2400
                                "Duplicated 'path' key in the same subsection. "
2401
                                "Ignoring %s=%s",
2402
                                pszKey, pszValue);
2403
                        }
2404
                        else
2405
                        {
2406
                            osPath = pszValue;
3✔
2407
                        }
2408
                    }
2409
                    else if (osPath.empty())
6✔
2410
                    {
2411
                        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2412
                                 "First entry in a credentials subsection "
2413
                                 "should be 'path'.");
2414
                    }
2415
                    else
2416
                    {
2417
                        VSISetPathSpecificOption(osPath.c_str(), pszKey,
5✔
2418
                                                 pszValue);
2419
                    }
2420
                }
2421
                CPLFree(pszKey);
10✔
2422
            }
2423
            else if (pszLine[0] == '[')
1✔
2424
            {
2425
                eCurrentSection = Section::NONE;
×
2426
            }
2427
            else
2428
            {
2429
                CPLError(CE_Warning, CPLE_AppDefined,
1✔
2430
                         "Ignoring content in [credential] section that is not "
2431
                         "in a [.xxxxx] subsection");
2432
            }
2433
        }
2434
        else if (pszLine[0] == '[')
6✔
2435
        {
2436
            eCurrentSection = Section::NONE;
×
2437
        }
2438
        else if (eCurrentSection == Section::CONFIG_OPTIONS)
6✔
2439
        {
2440
            char *pszKey = nullptr;
6✔
2441
            const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
6✔
2442
            if (pszKey && pszValue)
6✔
2443
            {
2444
                if (bOverrideEnvVars || gbIgnoreEnvVariables ||
11✔
2445
                    getenv(pszKey) == nullptr)
5✔
2446
                {
2447
                    CPLDebugOnly("CPL", "Setting configuration option %s=%s",
5✔
2448
                                 pszKey, pszValue);
2449
                    CPLSetConfigOption(pszKey, pszValue);
5✔
2450
                }
2451
                else
2452
                {
2453
                    CPLDebug("CPL",
1✔
2454
                             "Ignoring configuration option %s=%s from "
2455
                             "configuration file as it is already set "
2456
                             "as an environment variable",
2457
                             pszKey, pszValue);
2458
                }
2459
            }
2460
            CPLFree(pszKey);
6✔
2461
        }
2462
    }
2463
    VSIFCloseL(fp);
9✔
2464
}
2465

2466
/************************************************************************/
2467
/*                CPLLoadConfigOptionsFromPredefinedFiles()             */
2468
/************************************************************************/
2469

2470
/** Load configuration from a set of predefined files.
2471
 *
2472
 * If the environment variable (or configuration option) GDAL_CONFIG_FILE is
2473
 * set, then CPLLoadConfigOptionsFromFile() will be called with the value of
2474
 * this configuration option as the file location.
2475
 *
2476
 * Otherwise, for Unix builds, CPLLoadConfigOptionsFromFile() will be called
2477
 * with ${sysconfdir}/gdal/gdalrc first where ${sysconfdir} evaluates
2478
 * to ${prefix}/etc, unless the \--sysconfdir switch of configure has been
2479
 * invoked.
2480
 *
2481
 * Then CPLLoadConfigOptionsFromFile() will be called with ${HOME}/.gdal/gdalrc
2482
 * on Unix builds (potentially overriding what was loaded with the sysconfdir)
2483
 * or ${USERPROFILE}/.gdal/gdalrc on Windows builds.
2484
 *
2485
 * CPLLoadConfigOptionsFromFile() will be called with bOverrideEnvVars = false,
2486
 * that is the value of environment variables previously set will be used
2487
 * instead of the value set in the configuration files (unless the configuration
2488
 * file contains a leading [directives] section with a "ignore-env-vars=yes"
2489
 * setting).
2490
 *
2491
 * This function is automatically called by GDALDriverManager() constructor
2492
 *
2493
 * @since GDAL 3.3
2494
 */
2495
void CPLLoadConfigOptionsFromPredefinedFiles()
1,744✔
2496
{
2497
    const char *pszFile = CPLGetConfigOption("GDAL_CONFIG_FILE", nullptr);
1,744✔
2498
    if (pszFile != nullptr)
1,744✔
2499
    {
2500
        CPLLoadConfigOptionsFromFile(pszFile, false);
2✔
2501
    }
2502
    else
2503
    {
2504
#ifdef SYSCONFDIR
2505
        CPLLoadConfigOptionsFromFile(
1,742✔
2506
            CPLFormFilenameSafe(
3,484✔
2507
                CPLFormFilenameSafe(SYSCONFDIR, "gdal", nullptr).c_str(),
3,484✔
2508
                "gdalrc", nullptr)
2509
                .c_str(),
2510
            false);
2511
#endif
2512

2513
#ifdef _WIN32
2514
        const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
2515
#else
2516
        const char *pszHome = CPLGetConfigOption("HOME", nullptr);
1,742✔
2517
#endif
2518
        if (pszHome != nullptr)
1,742✔
2519
        {
2520
            CPLLoadConfigOptionsFromFile(
1,742✔
2521
                CPLFormFilenameSafe(
3,484✔
2522
                    CPLFormFilenameSafe(pszHome, ".gdal", nullptr).c_str(),
3,484✔
2523
                    "gdalrc", nullptr)
2524
                    .c_str(),
2525
                false);
2526
        }
2527
    }
2528
}
1,744✔
2529

2530
/************************************************************************/
2531
/*                              CPLStat()                               */
2532
/************************************************************************/
2533

2534
/** Same as VSIStat() except it works on "C:" as if it were "C:\". */
2535

2536
int CPLStat(const char *pszPath, VSIStatBuf *psStatBuf)
×
2537

2538
{
2539
    if (strlen(pszPath) == 2 && pszPath[1] == ':')
×
2540
    {
2541
        char szAltPath[4] = {pszPath[0], pszPath[1], '\\', '\0'};
×
2542
        return VSIStat(szAltPath, psStatBuf);
×
2543
    }
2544

2545
    return VSIStat(pszPath, psStatBuf);
×
2546
}
2547

2548
/************************************************************************/
2549
/*                            proj_strtod()                             */
2550
/************************************************************************/
2551
static double proj_strtod(char *nptr, char **endptr)
18✔
2552

2553
{
2554
    char c = '\0';
18✔
2555
    char *cp = nptr;
18✔
2556

2557
    // Scan for characters which cause problems with VC++ strtod().
2558
    while ((c = *cp) != '\0')
84✔
2559
    {
2560
        if (c == 'd' || c == 'D')
72✔
2561
        {
2562
            // Found one, so NUL it out, call strtod(),
2563
            // then restore it and return.
2564
            *cp = '\0';
6✔
2565
            const double result = CPLStrtod(nptr, endptr);
6✔
2566
            *cp = c;
6✔
2567
            return result;
6✔
2568
        }
2569
        ++cp;
66✔
2570
    }
2571

2572
    // No offending characters, just handle normally.
2573

2574
    return CPLStrtod(nptr, endptr);
12✔
2575
}
2576

2577
/************************************************************************/
2578
/*                            CPLDMSToDec()                             */
2579
/************************************************************************/
2580

2581
static const char *sym = "NnEeSsWw";
2582
constexpr double vm[] = {1.0, 0.0166666666667, 0.00027777778};
2583

2584
/** CPLDMSToDec */
2585
double CPLDMSToDec(const char *is)
6✔
2586

2587
{
2588
    // Copy string into work space.
2589
    while (isspace(static_cast<unsigned char>(*is)))
6✔
2590
        ++is;
×
2591

2592
    const char *p = is;
6✔
2593
    char work[64] = {};
6✔
2594
    char *s = work;
6✔
2595
    int n = sizeof(work);
6✔
2596
    for (; isgraph(*p) && --n;)
60✔
2597
        *s++ = *p++;
54✔
2598
    *s = '\0';
6✔
2599
    // It is possible that a really odd input (like lots of leading
2600
    // zeros) could be truncated in copying into work.  But...
2601
    s = work;
6✔
2602
    int sign = *s;
6✔
2603

2604
    if (sign == '+' || sign == '-')
6✔
2605
        s++;
×
2606
    else
2607
        sign = '+';
6✔
2608

2609
    int nl = 0;
6✔
2610
    double v = 0.0;
6✔
2611
    for (; nl < 3; nl = n + 1)
24✔
2612
    {
2613
        if (!(isdigit(static_cast<unsigned char>(*s)) || *s == '.'))
18✔
2614
            break;
×
2615
        const double tv = proj_strtod(s, &s);
18✔
2616
        if (tv == HUGE_VAL)
18✔
2617
            return tv;
×
2618
        switch (*s)
18✔
2619
        {
2620
            case 'D':
6✔
2621
            case 'd':
2622
                n = 0;
6✔
2623
                break;
6✔
2624
            case '\'':
6✔
2625
                n = 1;
6✔
2626
                break;
6✔
2627
            case '"':
6✔
2628
                n = 2;
6✔
2629
                break;
6✔
2630
            case 'r':
×
2631
            case 'R':
2632
                if (nl)
×
2633
                {
2634
                    return 0.0;
×
2635
                }
2636
                ++s;
×
2637
                v = tv;
×
2638
                goto skip;
×
2639
            default:
×
2640
                v += tv * vm[nl];
×
2641
            skip:
×
2642
                n = 4;
×
2643
                continue;
×
2644
        }
2645
        if (n < nl)
18✔
2646
        {
2647
            return 0.0;
×
2648
        }
2649
        v += tv * vm[n];
18✔
2650
        ++s;
18✔
2651
    }
2652
    // Postfix sign.
2653
    if (*s && ((p = strchr(sym, *s))) != nullptr)
6✔
2654
    {
2655
        sign = (p - sym) >= 4 ? '-' : '+';
×
2656
        ++s;
×
2657
    }
2658
    if (sign == '-')
6✔
2659
        v = -v;
×
2660

2661
    return v;
6✔
2662
}
2663

2664
/************************************************************************/
2665
/*                            CPLDecToDMS()                             */
2666
/************************************************************************/
2667

2668
/** Translate a decimal degrees value to a DMS string with hemisphere. */
2669

2670
const char *CPLDecToDMS(double dfAngle, const char *pszAxis, int nPrecision)
590✔
2671

2672
{
2673
    VALIDATE_POINTER1(pszAxis, "CPLDecToDMS", "");
590✔
2674

2675
    if (std::isnan(dfAngle))
590✔
2676
        return "Invalid angle";
×
2677

2678
    const double dfEpsilon = (0.5 / 3600.0) * pow(0.1, nPrecision);
590✔
2679
    const double dfABSAngle = std::abs(dfAngle) + dfEpsilon;
590✔
2680
    if (dfABSAngle > 361.0)
590✔
2681
    {
2682
        return "Invalid angle";
×
2683
    }
2684

2685
    const int nDegrees = static_cast<int>(dfABSAngle);
590✔
2686
    const int nMinutes = static_cast<int>((dfABSAngle - nDegrees) * 60);
590✔
2687
    double dfSeconds = dfABSAngle * 3600 - nDegrees * 3600 - nMinutes * 60;
590✔
2688

2689
    if (dfSeconds > dfEpsilon * 3600.0)
590✔
2690
        dfSeconds -= dfEpsilon * 3600.0;
584✔
2691

2692
    const char *pszHemisphere = nullptr;
590✔
2693
    if (EQUAL(pszAxis, "Long") && dfAngle < 0.0)
590✔
2694
        pszHemisphere = "W";
258✔
2695
    else if (EQUAL(pszAxis, "Long"))
332✔
2696
        pszHemisphere = "E";
37✔
2697
    else if (dfAngle < 0.0)
295✔
2698
        pszHemisphere = "S";
22✔
2699
    else
2700
        pszHemisphere = "N";
273✔
2701

2702
    char szFormat[30] = {};
590✔
2703
    CPLsnprintf(szFormat, sizeof(szFormat), "%%3dd%%2d\'%%%d.%df\"%s",
590✔
2704
                nPrecision + 3, nPrecision, pszHemisphere);
2705

2706
    static CPL_THREADLOCAL char szBuffer[50] = {};
2707
    CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, nDegrees, nMinutes,
590✔
2708
                dfSeconds);
2709

2710
    return szBuffer;
590✔
2711
}
2712

2713
/************************************************************************/
2714
/*                         CPLPackedDMSToDec()                          */
2715
/************************************************************************/
2716

2717
/**
2718
 * Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
2719
 *
2720
 * This function converts a packed DMS angle to seconds. The standard
2721
 * packed DMS format is:
2722
 *
2723
 *  degrees * 1000000 + minutes * 1000 + seconds
2724
 *
2725
 * Example:     angle = 120025045.25 yields
2726
 *              deg = 120
2727
 *              min = 25
2728
 *              sec = 45.25
2729
 *
2730
 * The algorithm used for the conversion is as follows:
2731
 *
2732
 * 1.  The absolute value of the angle is used.
2733
 *
2734
 * 2.  The degrees are separated out:
2735
 *     deg = angle/1000000                    (fractional portion truncated)
2736
 *
2737
 * 3.  The minutes are separated out:
2738
 *     min = (angle - deg * 1000000) / 1000   (fractional portion truncated)
2739
 *
2740
 * 4.  The seconds are then computed:
2741
 *     sec = angle - deg * 1000000 - min * 1000
2742
 *
2743
 * 5.  The total angle in seconds is computed:
2744
 *     sec = deg * 3600.0 + min * 60.0 + sec
2745
 *
2746
 * 6.  The sign of sec is set to that of the input angle.
2747
 *
2748
 * Packed DMS values used by the USGS GCTP package and probably by other
2749
 * software.
2750
 *
2751
 * NOTE: This code does not validate input value. If you give the wrong
2752
 * value, you will get the wrong result.
2753
 *
2754
 * @param dfPacked Angle in packed DMS format.
2755
 *
2756
 * @return Angle in decimal degrees.
2757
 *
2758
 */
2759

2760
double CPLPackedDMSToDec(double dfPacked)
36✔
2761
{
2762
    const double dfSign = dfPacked < 0.0 ? -1 : 1;
36✔
2763

2764
    double dfSeconds = std::abs(dfPacked);
36✔
2765
    double dfDegrees = floor(dfSeconds / 1000000.0);
36✔
2766
    dfSeconds -= dfDegrees * 1000000.0;
36✔
2767
    const double dfMinutes = floor(dfSeconds / 1000.0);
36✔
2768
    dfSeconds -= dfMinutes * 1000.0;
36✔
2769
    dfSeconds = dfSign * (dfDegrees * 3600.0 + dfMinutes * 60.0 + dfSeconds);
36✔
2770
    dfDegrees = dfSeconds / 3600.0;
36✔
2771

2772
    return dfDegrees;
36✔
2773
}
2774

2775
/************************************************************************/
2776
/*                         CPLDecToPackedDMS()                          */
2777
/************************************************************************/
2778
/**
2779
 * Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
2780
 *
2781
 * This function converts a value, specified in decimal degrees into
2782
 * packed DMS angle. The standard packed DMS format is:
2783
 *
2784
 *  degrees * 1000000 + minutes * 1000 + seconds
2785
 *
2786
 * See also CPLPackedDMSToDec().
2787
 *
2788
 * @param dfDec Angle in decimal degrees.
2789
 *
2790
 * @return Angle in packed DMS format.
2791
 *
2792
 */
2793

2794
double CPLDecToPackedDMS(double dfDec)
8✔
2795
{
2796
    const double dfSign = dfDec < 0.0 ? -1 : 1;
8✔
2797

2798
    dfDec = std::abs(dfDec);
8✔
2799
    const double dfDegrees = floor(dfDec);
8✔
2800
    const double dfMinutes = floor((dfDec - dfDegrees) * 60.0);
8✔
2801
    const double dfSeconds = (dfDec - dfDegrees) * 3600.0 - dfMinutes * 60.0;
8✔
2802

2803
    return dfSign * (dfDegrees * 1000000.0 + dfMinutes * 1000.0 + dfSeconds);
8✔
2804
}
2805

2806
/************************************************************************/
2807
/*                         CPLStringToComplex()                         */
2808
/************************************************************************/
2809

2810
/** Fetch the real and imaginary part of a serialized complex number */
2811
CPLErr CPL_DLL CPLStringToComplex(const char *pszString, double *pdfReal,
2,429✔
2812
                                  double *pdfImag)
2813

2814
{
2815
    while (*pszString == ' ')
2,429✔
2816
        pszString++;
1✔
2817

2818
    char *end;
2819
    *pdfReal = CPLStrtod(pszString, &end);
2,428✔
2820

2821
    int iPlus = -1;
2,428✔
2822
    int iImagEnd = -1;
2,428✔
2823

2824
    if (pszString == end)
2,428✔
2825
    {
2826
        goto error;
5✔
2827
    }
2828

2829
    *pdfImag = 0.0;
2,423✔
2830

2831
    for (int i = static_cast<int>(end - pszString);
2,477✔
2832
         i < 100 && pszString[i] != '\0' && pszString[i] != ' '; i++)
2,477✔
2833
    {
2834
        if (pszString[i] == '+')
56✔
2835
        {
2836
            if (iPlus != -1)
8✔
2837
                goto error;
×
2838
            iPlus = i;
8✔
2839
        }
2840
        if (pszString[i] == '-')
56✔
2841
        {
2842
            if (iPlus != -1)
2✔
2843
                goto error;
1✔
2844
            iPlus = i;
1✔
2845
        }
2846
        if (pszString[i] == 'i')
55✔
2847
        {
2848
            if (iPlus == -1)
9✔
2849
                goto error;
1✔
2850
            iImagEnd = i;
8✔
2851
        }
2852
    }
2853

2854
    // If we have a "+" or "-" we must also have an "i"
2855
    if ((iPlus == -1) != (iImagEnd == -1))
2,421✔
2856
    {
2857
        goto error;
1✔
2858
    }
2859

2860
    // Parse imaginary component, if any
2861
    if (iPlus > -1)
2,420✔
2862
    {
2863
        *pdfImag = CPLStrtod(pszString + iPlus, &end);
7✔
2864
    }
2865

2866
    // Check everything remaining is whitespace
2867
    for (; *end != '\0'; end++)
2,425✔
2868
    {
2869
        if (!isspace(*end) && end - pszString != iImagEnd)
11✔
2870
        {
2871
            goto error;
6✔
2872
        }
2873
    }
2874

2875
    return CE_None;
2,414✔
2876

2877
error:
14✔
2878
    CPLError(CE_Failure, CPLE_AppDefined, "Failed to parse number: %s",
14✔
2879
             pszString);
2880
    return CE_Failure;
14✔
2881
}
2882

2883
/************************************************************************/
2884
/*                           CPLOpenShared()                            */
2885
/************************************************************************/
2886

2887
/**
2888
 * Open a shared file handle.
2889
 *
2890
 * Some operating systems have limits on the number of file handles that can
2891
 * be open at one time.  This function attempts to maintain a registry of
2892
 * already open file handles, and reuse existing ones if the same file
2893
 * is requested by another part of the application.
2894
 *
2895
 * Note that access is only shared for access types "r", "rb", "r+" and
2896
 * "rb+".  All others will just result in direct VSIOpen() calls.  Keep in
2897
 * mind that a file is only reused if the file name is exactly the same.
2898
 * Different names referring to the same file will result in different
2899
 * handles.
2900
 *
2901
 * The VSIFOpen() or VSIFOpenL() function is used to actually open the file,
2902
 * when an existing file handle can't be shared.
2903
 *
2904
 * @param pszFilename the name of the file to open.
2905
 * @param pszAccess the normal fopen()/VSIFOpen() style access string.
2906
 * @param bLargeIn If TRUE VSIFOpenL() (for large files) will be used instead of
2907
 * VSIFOpen().
2908
 *
2909
 * @return a file handle or NULL if opening fails.
2910
 */
2911

2912
FILE *CPLOpenShared(const char *pszFilename, const char *pszAccess,
39✔
2913
                    int bLargeIn)
2914

2915
{
2916
    const bool bLarge = CPL_TO_BOOL(bLargeIn);
39✔
2917
    CPLMutexHolderD(&hSharedFileMutex);
78✔
2918
    const GIntBig nPID = CPLGetPID();
39✔
2919

2920
    /* -------------------------------------------------------------------- */
2921
    /*      Is there an existing file we can use?                           */
2922
    /* -------------------------------------------------------------------- */
2923
    const bool bReuse = EQUAL(pszAccess, "rb") || EQUAL(pszAccess, "rb+");
39✔
2924

2925
    for (int i = 0; bReuse && i < nSharedFileCount; i++)
43✔
2926
    {
2927
        if (strcmp(pasSharedFileList[i].pszFilename, pszFilename) == 0 &&
20✔
2928
            !bLarge == !pasSharedFileList[i].bLarge &&
4✔
2929
            EQUAL(pasSharedFileList[i].pszAccess, pszAccess) &&
16✔
2930
            nPID == pasSharedFileListExtra[i].nPID)
4✔
2931
        {
2932
            pasSharedFileList[i].nRefCount++;
4✔
2933
            return pasSharedFileList[i].fp;
4✔
2934
        }
2935
    }
2936

2937
    /* -------------------------------------------------------------------- */
2938
    /*      Open the file.                                                  */
2939
    /* -------------------------------------------------------------------- */
2940
    FILE *fp = bLarge
2941
                   ? reinterpret_cast<FILE *>(VSIFOpenL(pszFilename, pszAccess))
35✔
2942
                   : VSIFOpen(pszFilename, pszAccess);
×
2943

2944
    if (fp == nullptr)
35✔
2945
        return nullptr;
9✔
2946

2947
    /* -------------------------------------------------------------------- */
2948
    /*      Add an entry to the list.                                       */
2949
    /* -------------------------------------------------------------------- */
2950
    nSharedFileCount++;
26✔
2951

2952
    pasSharedFileList = static_cast<CPLSharedFileInfo *>(
26✔
2953
        CPLRealloc(const_cast<CPLSharedFileInfo *>(pasSharedFileList),
52✔
2954
                   sizeof(CPLSharedFileInfo) * nSharedFileCount));
26✔
2955
    pasSharedFileListExtra = static_cast<CPLSharedFileInfoExtra *>(
26✔
2956
        CPLRealloc(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra),
52✔
2957
                   sizeof(CPLSharedFileInfoExtra) * nSharedFileCount));
26✔
2958

2959
    pasSharedFileList[nSharedFileCount - 1].fp = fp;
26✔
2960
    pasSharedFileList[nSharedFileCount - 1].nRefCount = 1;
26✔
2961
    pasSharedFileList[nSharedFileCount - 1].bLarge = bLarge;
26✔
2962
    pasSharedFileList[nSharedFileCount - 1].pszFilename =
52✔
2963
        CPLStrdup(pszFilename);
26✔
2964
    pasSharedFileList[nSharedFileCount - 1].pszAccess = CPLStrdup(pszAccess);
26✔
2965
    pasSharedFileListExtra[nSharedFileCount - 1].nPID = nPID;
26✔
2966

2967
    return fp;
26✔
2968
}
2969

2970
/************************************************************************/
2971
/*                           CPLCloseShared()                           */
2972
/************************************************************************/
2973

2974
/**
2975
 * Close shared file.
2976
 *
2977
 * Dereferences the indicated file handle, and closes it if the reference
2978
 * count has dropped to zero.  A CPLError() is issued if the file is not
2979
 * in the shared file list.
2980
 *
2981
 * @param fp file handle from CPLOpenShared() to deaccess.
2982
 */
2983

2984
void CPLCloseShared(FILE *fp)
30✔
2985

2986
{
2987
    CPLMutexHolderD(&hSharedFileMutex);
30✔
2988

2989
    /* -------------------------------------------------------------------- */
2990
    /*      Search for matching information.                                */
2991
    /* -------------------------------------------------------------------- */
2992
    int i = 0;
30✔
2993
    for (; i < nSharedFileCount && fp != pasSharedFileList[i].fp; i++)
32✔
2994
    {
2995
    }
2996

2997
    if (i == nSharedFileCount)
30✔
2998
    {
2999
        CPLError(CE_Failure, CPLE_AppDefined,
×
3000
                 "Unable to find file handle %p in CPLCloseShared().", fp);
3001
        return;
×
3002
    }
3003

3004
    /* -------------------------------------------------------------------- */
3005
    /*      Dereference and return if there are still some references.      */
3006
    /* -------------------------------------------------------------------- */
3007
    if (--pasSharedFileList[i].nRefCount > 0)
30✔
3008
        return;
4✔
3009

3010
    /* -------------------------------------------------------------------- */
3011
    /*      Close the file, and remove the information.                     */
3012
    /* -------------------------------------------------------------------- */
3013
    if (pasSharedFileList[i].bLarge)
26✔
3014
    {
3015
        if (VSIFCloseL(reinterpret_cast<VSILFILE *>(pasSharedFileList[i].fp)) !=
26✔
3016
            0)
3017
        {
3018
            CPLError(CE_Failure, CPLE_FileIO, "Error while closing %s",
×
3019
                     pasSharedFileList[i].pszFilename);
×
3020
        }
3021
    }
3022
    else
3023
    {
3024
        VSIFClose(pasSharedFileList[i].fp);
×
3025
    }
3026

3027
    CPLFree(pasSharedFileList[i].pszFilename);
26✔
3028
    CPLFree(pasSharedFileList[i].pszAccess);
26✔
3029

3030
    nSharedFileCount--;
26✔
3031
    memmove(
26✔
3032
        const_cast<CPLSharedFileInfo *>(pasSharedFileList + i),
26✔
3033
        const_cast<CPLSharedFileInfo *>(pasSharedFileList + nSharedFileCount),
26✔
3034
        sizeof(CPLSharedFileInfo));
3035
    memmove(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra + i),
26✔
3036
            const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra +
26✔
3037
                                                 nSharedFileCount),
26✔
3038
            sizeof(CPLSharedFileInfoExtra));
3039

3040
    if (nSharedFileCount == 0)
26✔
3041
    {
3042
        CPLFree(const_cast<CPLSharedFileInfo *>(pasSharedFileList));
23✔
3043
        pasSharedFileList = nullptr;
23✔
3044
        CPLFree(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra));
23✔
3045
        pasSharedFileListExtra = nullptr;
23✔
3046
    }
3047
}
3048

3049
/************************************************************************/
3050
/*                   CPLCleanupSharedFileMutex()                        */
3051
/************************************************************************/
3052

3053
void CPLCleanupSharedFileMutex()
1,122✔
3054
{
3055
    if (hSharedFileMutex != nullptr)
1,122✔
3056
    {
3057
        CPLDestroyMutex(hSharedFileMutex);
×
3058
        hSharedFileMutex = nullptr;
×
3059
    }
3060
}
1,122✔
3061

3062
/************************************************************************/
3063
/*                          CPLGetSharedList()                          */
3064
/************************************************************************/
3065

3066
/**
3067
 * Fetch list of open shared files.
3068
 *
3069
 * @param pnCount place to put the count of entries.
3070
 *
3071
 * @return the pointer to the first in the array of shared file info
3072
 * structures.
3073
 */
3074

3075
CPLSharedFileInfo *CPLGetSharedList(int *pnCount)
×
3076

3077
{
3078
    if (pnCount != nullptr)
×
3079
        *pnCount = nSharedFileCount;
×
3080

3081
    return const_cast<CPLSharedFileInfo *>(pasSharedFileList);
×
3082
}
3083

3084
/************************************************************************/
3085
/*                         CPLDumpSharedList()                          */
3086
/************************************************************************/
3087

3088
/**
3089
 * Report open shared files.
3090
 *
3091
 * Dumps all open shared files to the indicated file handle.  If the
3092
 * file handle is NULL information is sent via the CPLDebug() call.
3093
 *
3094
 * @param fp File handle to write to.
3095
 */
3096

3097
void CPLDumpSharedList(FILE *fp)
103✔
3098

3099
{
3100
    if (nSharedFileCount > 0)
103✔
3101
    {
3102
        if (fp == nullptr)
×
3103
            CPLDebug("CPL", "%d Shared files open.", nSharedFileCount);
×
3104
        else
3105
            fprintf(fp, "%d Shared files open.", nSharedFileCount);
×
3106
    }
3107

3108
    for (int i = 0; i < nSharedFileCount; i++)
103✔
3109
    {
3110
        if (fp == nullptr)
×
3111
            CPLDebug("CPL", "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
×
3112
                     pasSharedFileList[i].bLarge,
×
3113
                     pasSharedFileList[i].pszAccess,
×
3114
                     pasSharedFileList[i].pszFilename);
×
3115
        else
3116
            fprintf(fp, "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
×
3117
                    pasSharedFileList[i].bLarge, pasSharedFileList[i].pszAccess,
×
3118
                    pasSharedFileList[i].pszFilename);
×
3119
    }
3120
}
103✔
3121

3122
/************************************************************************/
3123
/*                           CPLUnlinkTree()                            */
3124
/************************************************************************/
3125

3126
/** Recursively unlink a directory.
3127
 *
3128
 * @return 0 on successful completion, -1 if function fails.
3129
 */
3130

3131
int CPLUnlinkTree(const char *pszPath)
52✔
3132

3133
{
3134
    /* -------------------------------------------------------------------- */
3135
    /*      First, ensure there is such a file.                             */
3136
    /* -------------------------------------------------------------------- */
3137
    VSIStatBufL sStatBuf;
3138

3139
    if (VSIStatL(pszPath, &sStatBuf) != 0)
52✔
3140
    {
3141
        CPLError(CE_Failure, CPLE_AppDefined,
2✔
3142
                 "It seems no file system object called '%s' exists.", pszPath);
3143

3144
        return -1;
2✔
3145
    }
3146

3147
    /* -------------------------------------------------------------------- */
3148
    /*      If it is a simple file, just delete it.                         */
3149
    /* -------------------------------------------------------------------- */
3150
    if (VSI_ISREG(sStatBuf.st_mode))
50✔
3151
    {
3152
        if (VSIUnlink(pszPath) != 0)
34✔
3153
        {
3154
            CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
×
3155
                     pszPath);
3156

3157
            return -1;
×
3158
        }
3159

3160
        return 0;
34✔
3161
    }
3162

3163
    /* -------------------------------------------------------------------- */
3164
    /*      If it is a directory recurse then unlink the directory.         */
3165
    /* -------------------------------------------------------------------- */
3166
    else if (VSI_ISDIR(sStatBuf.st_mode))
16✔
3167
    {
3168
        char **papszItems = VSIReadDir(pszPath);
16✔
3169

3170
        for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
32✔
3171
        {
3172
            if (papszItems[i][0] == '\0' || EQUAL(papszItems[i], ".") ||
16✔
3173
                EQUAL(papszItems[i], ".."))
16✔
3174
                continue;
×
3175

3176
            const std::string osSubPath =
3177
                CPLFormFilenameSafe(pszPath, papszItems[i], nullptr);
16✔
3178

3179
            const int nErr = CPLUnlinkTree(osSubPath.c_str());
16✔
3180

3181
            if (nErr != 0)
16✔
3182
            {
3183
                CSLDestroy(papszItems);
×
3184
                return nErr;
×
3185
            }
3186
        }
3187

3188
        CSLDestroy(papszItems);
16✔
3189

3190
        if (VSIRmdir(pszPath) != 0)
16✔
3191
        {
3192
            CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
×
3193
                     pszPath);
3194

3195
            return -1;
×
3196
        }
3197

3198
        return 0;
16✔
3199
    }
3200

3201
    /* -------------------------------------------------------------------- */
3202
    /*      otherwise report an error.                                      */
3203
    /* -------------------------------------------------------------------- */
3204
    CPLError(CE_Failure, CPLE_AppDefined,
×
3205
             "Failed to unlink %s.\nUnrecognised filesystem object.", pszPath);
3206
    return 1000;
×
3207
}
3208

3209
/************************************************************************/
3210
/*                            CPLCopyFile()                             */
3211
/************************************************************************/
3212

3213
/** Copy a file */
3214
int CPLCopyFile(const char *pszNewPath, const char *pszOldPath)
2,254✔
3215

3216
{
3217
    return VSICopyFile(pszOldPath, pszNewPath, nullptr,
2,254✔
3218
                       static_cast<vsi_l_offset>(-1), nullptr, nullptr,
3219
                       nullptr);
2,254✔
3220
}
3221

3222
/************************************************************************/
3223
/*                            CPLCopyTree()                             */
3224
/************************************************************************/
3225

3226
/** Recursively copy a tree */
3227
int CPLCopyTree(const char *pszNewPath, const char *pszOldPath)
4✔
3228

3229
{
3230
    VSIStatBufL sStatBuf;
3231
    if (VSIStatL(pszNewPath, &sStatBuf) == 0)
4✔
3232
    {
3233
        CPLError(
1✔
3234
            CE_Failure, CPLE_AppDefined,
3235
            "It seems that a file system object called '%s' already exists.",
3236
            pszNewPath);
3237

3238
        return -1;
1✔
3239
    }
3240

3241
    if (VSIStatL(pszOldPath, &sStatBuf) != 0)
3✔
3242
    {
3243
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
3244
                 "It seems no file system object called '%s' exists.",
3245
                 pszOldPath);
3246

3247
        return -1;
1✔
3248
    }
3249

3250
    if (VSI_ISDIR(sStatBuf.st_mode))
2✔
3251
    {
3252
        if (VSIMkdir(pszNewPath, 0755) != 0)
1✔
3253
        {
3254
            CPLError(CE_Failure, CPLE_AppDefined,
×
3255
                     "Cannot create directory '%s'.", pszNewPath);
3256

3257
            return -1;
×
3258
        }
3259

3260
        char **papszItems = VSIReadDir(pszOldPath);
1✔
3261

3262
        for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
4✔
3263
        {
3264
            if (EQUAL(papszItems[i], ".") || EQUAL(papszItems[i], ".."))
3✔
3265
                continue;
2✔
3266

3267
            const std::string osNewSubPath =
3268
                CPLFormFilenameSafe(pszNewPath, papszItems[i], nullptr);
1✔
3269
            const std::string osOldSubPath =
3270
                CPLFormFilenameSafe(pszOldPath, papszItems[i], nullptr);
1✔
3271

3272
            const int nErr =
3273
                CPLCopyTree(osNewSubPath.c_str(), osOldSubPath.c_str());
1✔
3274

3275
            if (nErr != 0)
1✔
3276
            {
3277
                CSLDestroy(papszItems);
×
3278
                return nErr;
×
3279
            }
3280
        }
3281
        CSLDestroy(papszItems);
1✔
3282

3283
        return 0;
1✔
3284
    }
3285
    else if (VSI_ISREG(sStatBuf.st_mode))
1✔
3286
    {
3287
        return CPLCopyFile(pszNewPath, pszOldPath);
1✔
3288
    }
3289
    else
3290
    {
3291
        CPLError(CE_Failure, CPLE_AppDefined,
×
3292
                 "Unrecognized filesystem object : '%s'.", pszOldPath);
3293
        return -1;
×
3294
    }
3295
}
3296

3297
/************************************************************************/
3298
/*                            CPLMoveFile()                             */
3299
/************************************************************************/
3300

3301
/** Move a file */
3302
int CPLMoveFile(const char *pszNewPath, const char *pszOldPath)
186✔
3303

3304
{
3305
    if (VSIRename(pszOldPath, pszNewPath) == 0)
186✔
3306
        return 0;
183✔
3307

3308
    const int nRet = CPLCopyFile(pszNewPath, pszOldPath);
3✔
3309

3310
    if (nRet == 0)
3✔
3311
        VSIUnlink(pszOldPath);
3✔
3312
    return nRet;
3✔
3313
}
3314

3315
/************************************************************************/
3316
/*                             CPLSymlink()                             */
3317
/************************************************************************/
3318

3319
/** Create a symbolic link */
3320
#ifdef _WIN32
3321
int CPLSymlink(const char *, const char *, CSLConstList)
3322
{
3323
    return -1;
3324
}
3325
#else
3326
int CPLSymlink(const char *pszOldPath, const char *pszNewPath,
×
3327
               CSLConstList /* papszOptions */)
3328
{
3329
    return symlink(pszOldPath, pszNewPath);
×
3330
}
3331
#endif
3332

3333
/************************************************************************/
3334
/* ==================================================================== */
3335
/*                              CPLLocaleC                              */
3336
/* ==================================================================== */
3337
/************************************************************************/
3338

3339
//! @cond Doxygen_Suppress
3340
/************************************************************************/
3341
/*                             CPLLocaleC()                             */
3342
/************************************************************************/
3343

3344
CPLLocaleC::CPLLocaleC() : pszOldLocale(nullptr)
130✔
3345
{
3346
    if (CPLTestBool(CPLGetConfigOption("GDAL_DISABLE_CPLLOCALEC", "NO")))
130✔
3347
        return;
×
3348

3349
    pszOldLocale = CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr));
130✔
3350
    if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
130✔
3351
        CPLsetlocale(LC_NUMERIC, "C") == nullptr)
×
3352
    {
3353
        CPLFree(pszOldLocale);
130✔
3354
        pszOldLocale = nullptr;
130✔
3355
    }
3356
}
3357

3358
/************************************************************************/
3359
/*                            ~CPLLocaleC()                             */
3360
/************************************************************************/
3361

3362
CPLLocaleC::~CPLLocaleC()
×
3363

3364
{
3365
    if (pszOldLocale == nullptr)
130✔
3366
        return;
130✔
3367

3368
    CPLsetlocale(LC_NUMERIC, pszOldLocale);
×
3369
    CPLFree(pszOldLocale);
×
3370
}
130✔
3371

3372
/************************************************************************/
3373
/*                        CPLThreadLocaleCPrivate                       */
3374
/************************************************************************/
3375

3376
#ifdef HAVE_USELOCALE
3377

3378
class CPLThreadLocaleCPrivate
3379
{
3380
    locale_t nNewLocale;
3381
    locale_t nOldLocale;
3382

3383
    CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3384

3385
  public:
3386
    CPLThreadLocaleCPrivate();
3387
    ~CPLThreadLocaleCPrivate();
3388
};
3389

3390
CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
×
3391
    : nNewLocale(newlocale(LC_NUMERIC_MASK, "C", nullptr)),
×
3392
      nOldLocale(uselocale(nNewLocale))
×
3393
{
3394
}
×
3395

3396
CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
×
3397
{
3398
    uselocale(nOldLocale);
×
3399
    freelocale(nNewLocale);
×
3400
}
×
3401

3402
#elif defined(_MSC_VER)
3403

3404
class CPLThreadLocaleCPrivate
3405
{
3406
    int nOldValConfigThreadLocale;
3407
    char *pszOldLocale;
3408

3409
    CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3410

3411
  public:
3412
    CPLThreadLocaleCPrivate();
3413
    ~CPLThreadLocaleCPrivate();
3414
};
3415

3416
CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
3417
{
3418
    nOldValConfigThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
3419
    pszOldLocale = setlocale(LC_NUMERIC, "C");
3420
    if (pszOldLocale)
3421
        pszOldLocale = CPLStrdup(pszOldLocale);
3422
}
3423

3424
CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
3425
{
3426
    if (pszOldLocale != nullptr)
3427
    {
3428
        setlocale(LC_NUMERIC, pszOldLocale);
3429
        CPLFree(pszOldLocale);
3430
    }
3431
    _configthreadlocale(nOldValConfigThreadLocale);
3432
}
3433

3434
#else
3435

3436
class CPLThreadLocaleCPrivate
3437
{
3438
    char *pszOldLocale;
3439

3440
    CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3441

3442
  public:
3443
    CPLThreadLocaleCPrivate();
3444
    ~CPLThreadLocaleCPrivate();
3445
};
3446

3447
CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
3448
    : pszOldLocale(CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr)))
3449
{
3450
    if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
3451
        CPLsetlocale(LC_NUMERIC, "C") == nullptr)
3452
    {
3453
        CPLFree(pszOldLocale);
3454
        pszOldLocale = nullptr;
3455
    }
3456
}
3457

3458
CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
3459
{
3460
    if (pszOldLocale != nullptr)
3461
    {
3462
        CPLsetlocale(LC_NUMERIC, pszOldLocale);
3463
        CPLFree(pszOldLocale);
3464
    }
3465
}
3466

3467
#endif
3468

3469
/************************************************************************/
3470
/*                        CPLThreadLocaleC()                            */
3471
/************************************************************************/
3472

3473
CPLThreadLocaleC::CPLThreadLocaleC() : m_private(new CPLThreadLocaleCPrivate)
×
3474
{
3475
}
×
3476

3477
/************************************************************************/
3478
/*                       ~CPLThreadLocaleC()                            */
3479
/************************************************************************/
3480

3481
CPLThreadLocaleC::~CPLThreadLocaleC()
×
3482

3483
{
3484
    delete m_private;
×
3485
}
×
3486

3487
//! @endcond
3488

3489
/************************************************************************/
3490
/*                          CPLsetlocale()                              */
3491
/************************************************************************/
3492

3493
/**
3494
 * Prevents parallel executions of setlocale().
3495
 *
3496
 * Calling setlocale() concurrently from two or more threads is a
3497
 * potential data race. A mutex is used to provide a critical region so
3498
 * that only one thread at a time can be executing setlocale().
3499
 *
3500
 * The return should not be freed, and copied quickly as it may be invalidated
3501
 * by a following next call to CPLsetlocale().
3502
 *
3503
 * @param category See your compiler's documentation on setlocale.
3504
 * @param locale See your compiler's documentation on setlocale.
3505
 *
3506
 * @return See your compiler's documentation on setlocale.
3507
 */
3508
char *CPLsetlocale(int category, const char *locale)
132✔
3509
{
3510
    CPLMutexHolder oHolder(&hSetLocaleMutex);
264✔
3511
    char *pszRet = setlocale(category, locale);
132✔
3512
    if (pszRet == nullptr)
132✔
3513
        return pszRet;
×
3514

3515
    // Make it thread-locale storage.
3516
    return const_cast<char *>(CPLSPrintf("%s", pszRet));
132✔
3517
}
3518

3519
/************************************************************************/
3520
/*                       CPLCleanupSetlocaleMutex()                     */
3521
/************************************************************************/
3522

3523
void CPLCleanupSetlocaleMutex(void)
1,122✔
3524
{
3525
    if (hSetLocaleMutex != nullptr)
1,122✔
3526
        CPLDestroyMutex(hSetLocaleMutex);
5✔
3527
    hSetLocaleMutex = nullptr;
1,122✔
3528
}
1,122✔
3529

3530
/************************************************************************/
3531
/*                            IsPowerOfTwo()                            */
3532
/************************************************************************/
3533

3534
int CPLIsPowerOfTwo(unsigned int i)
152✔
3535
{
3536
    if (i == 0)
152✔
3537
        return FALSE;
×
3538
    return (i & (i - 1)) == 0 ? TRUE : FALSE;
152✔
3539
}
3540

3541
/************************************************************************/
3542
/*                          CPLCheckForFile()                           */
3543
/************************************************************************/
3544

3545
/**
3546
 * Check for file existence.
3547
 *
3548
 * The function checks if a named file exists in the filesystem, hopefully
3549
 * in an efficient fashion if a sibling file list is available.   It exists
3550
 * primarily to do faster file checking for functions like GDAL open methods
3551
 * that get a list of files from the target directory.
3552
 *
3553
 * If the sibling file list exists (is not NULL) it is assumed to be a list
3554
 * of files in the same directory as the target file, and it will be checked
3555
 * (case insensitively) for a match.  If a match is found, pszFilename is
3556
 * updated with the correct case and TRUE is returned.
3557
 *
3558
 * If papszSiblingFiles is NULL, a VSIStatL() is used to test for the files
3559
 * existence, and no case insensitive testing is done.
3560
 *
3561
 * @param pszFilename name of file to check for - filename case updated in
3562
 * some cases.
3563
 * @param papszSiblingFiles a list of files in the same directory as
3564
 * pszFilename if available, or NULL. This list should have no path components.
3565
 *
3566
 * @return TRUE if a match is found, or FALSE if not.
3567
 */
3568

3569
int CPLCheckForFile(char *pszFilename, char **papszSiblingFiles)
166,293✔
3570

3571
{
3572
    /* -------------------------------------------------------------------- */
3573
    /*      Fallback case if we don't have a sibling file list.             */
3574
    /* -------------------------------------------------------------------- */
3575
    if (papszSiblingFiles == nullptr)
166,293✔
3576
    {
3577
        VSIStatBufL sStatBuf;
3578

3579
        return VSIStatExL(pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
11,536✔
3580
    }
3581

3582
    /* -------------------------------------------------------------------- */
3583
    /*      We have sibling files, compare the non-path filename portion    */
3584
    /*      of pszFilename too all entries.                                 */
3585
    /* -------------------------------------------------------------------- */
3586
    const CPLString osFileOnly = CPLGetFilename(pszFilename);
309,513✔
3587

3588
    for (int i = 0; papszSiblingFiles[i] != nullptr; i++)
15,792,200✔
3589
    {
3590
        if (EQUAL(papszSiblingFiles[i], osFileOnly))
15,637,600✔
3591
        {
3592
            strcpy(pszFilename + strlen(pszFilename) - osFileOnly.size(),
306✔
3593
                   papszSiblingFiles[i]);
152✔
3594
            return TRUE;
154✔
3595
        }
3596
    }
3597

3598
    return FALSE;
154,602✔
3599
}
3600

3601
/************************************************************************/
3602
/*      Stub implementation of zip services if we don't have libz.      */
3603
/************************************************************************/
3604

3605
#if !defined(HAVE_LIBZ)
3606

3607
void *CPLCreateZip(const char *, char **)
3608

3609
{
3610
    CPLError(CE_Failure, CPLE_NotSupported,
3611
             "This GDAL/OGR build does not include zlib and zip services.");
3612
    return nullptr;
3613
}
3614

3615
CPLErr CPLCreateFileInZip(void *, const char *, char **)
3616
{
3617
    return CE_Failure;
3618
}
3619

3620
CPLErr CPLWriteFileInZip(void *, const void *, int)
3621
{
3622
    return CE_Failure;
3623
}
3624

3625
CPLErr CPLCloseFileInZip(void *)
3626
{
3627
    return CE_Failure;
3628
}
3629

3630
CPLErr CPLCloseZip(void *)
3631
{
3632
    return CE_Failure;
3633
}
3634

3635
void *CPLZLibDeflate(const void *, size_t, int, void *, size_t,
3636
                     size_t *pnOutBytes)
3637
{
3638
    if (pnOutBytes != nullptr)
3639
        *pnOutBytes = 0;
3640
    return nullptr;
3641
}
3642

3643
void *CPLZLibInflate(const void *, size_t, void *, size_t, size_t *pnOutBytes)
3644
{
3645
    if (pnOutBytes != nullptr)
3646
        *pnOutBytes = 0;
3647
    return nullptr;
3648
}
3649

3650
#endif /* !defined(HAVE_LIBZ) */
3651

3652
/************************************************************************/
3653
/* ==================================================================== */
3654
/*                          CPLConfigOptionSetter                       */
3655
/* ==================================================================== */
3656
/************************************************************************/
3657

3658
//! @cond Doxygen_Suppress
3659
/************************************************************************/
3660
/*                         CPLConfigOptionSetter()                      */
3661
/************************************************************************/
3662

3663
CPLConfigOptionSetter::CPLConfigOptionSetter(const char *pszKey,
26,337✔
3664
                                             const char *pszValue,
3665
                                             bool bSetOnlyIfUndefined)
26,337✔
3666
    : m_pszKey(CPLStrdup(pszKey)), m_pszOldValue(nullptr),
26,337✔
3667
      m_bRestoreOldValue(false)
26,322✔
3668
{
3669
    const char *pszOldValue = CPLGetThreadLocalConfigOption(pszKey, nullptr);
26,322✔
3670
    if ((bSetOnlyIfUndefined &&
42,320✔
3671
         CPLGetConfigOption(pszKey, nullptr) == nullptr) ||
36,674✔
3672
        !bSetOnlyIfUndefined)
10,355✔
3673
    {
3674
        m_bRestoreOldValue = true;
26,327✔
3675
        if (pszOldValue)
26,327✔
3676
            m_pszOldValue = CPLStrdup(pszOldValue);
651✔
3677
        CPLSetThreadLocalConfigOption(pszKey, pszValue);
26,327✔
3678
    }
3679
}
26,228✔
3680

3681
/************************************************************************/
3682
/*                        ~CPLConfigOptionSetter()                      */
3683
/************************************************************************/
3684

3685
CPLConfigOptionSetter::~CPLConfigOptionSetter()
52,454✔
3686
{
3687
    if (m_bRestoreOldValue)
26,232✔
3688
    {
3689
        CPLSetThreadLocalConfigOption(m_pszKey, m_pszOldValue);
26,205✔
3690
        CPLFree(m_pszOldValue);
26,243✔
3691
    }
3692
    CPLFree(m_pszKey);
26,159✔
3693
}
26,222✔
3694

3695
//! @endcond
3696

3697
/************************************************************************/
3698
/*                          CPLIsInteractive()                          */
3699
/************************************************************************/
3700

3701
/** Returns whether the provided file refers to a terminal.
3702
 *
3703
 * This function is a wrapper of the ``isatty()`` POSIX function.
3704
 *
3705
 * @param f File to test. Typically stdin, stdout or stderr
3706
 * @return true if it is an open file referring to a terminal.
3707
 * @since GDAL 3.11
3708
 */
3709
bool CPLIsInteractive(FILE *f)
696✔
3710
{
3711
#ifndef _WIN32
3712
    return isatty(static_cast<int>(fileno(f)));
696✔
3713
#else
3714
    return _isatty(_fileno(f));
3715
#endif
3716
}
3717

3718
/************************************************************************/
3719
/*                          CPLLockFileStruct                          */
3720
/************************************************************************/
3721

3722
//! @cond Doxygen_Suppress
3723
struct CPLLockFileStruct
3724
{
3725
    std::string osLockFilename{};
3726
    std::atomic<bool> bStop = false;
3727
    CPLJoinableThread *hThread = nullptr;
3728
};
3729

3730
//! @endcond
3731

3732
/************************************************************************/
3733
/*                          CPLLockFileEx()                             */
3734
/************************************************************************/
3735

3736
/** Create and acquire a lock file.
3737
 *
3738
 * Only one caller can acquire the lock file at a time. The O_CREAT|O_EXCL
3739
 * flags of open() are used for that purpose (there might be limitations for
3740
 * network file systems).
3741
 *
3742
 * The lock file is continuously touched by a thread started by this function,
3743
 * to indicate it is still alive. If an existing lock file is found that has
3744
 * not been recently refreshed it will be considered stalled, and will be
3745
 * deleted before attempting to recreate it.
3746
 *
3747
 * This function must be paired with CPLUnlockFileEx().
3748
 *
3749
 * Available options are:
3750
 * <ul>
3751
 * <li>WAIT_TIME=value_in_sec/inf: Maximum amount of time in second that this
3752
 *     function can spend waiting for the lock. If not set, default to infinity.
3753
 * </li>
3754
 * <li>STALLED_DELAY=value_in_sec: Delay in second to consider that an existing
3755
 * lock file that has not been touched since STALLED_DELAY is stalled, and can
3756
 * be re-acquired. Defaults to 10 seconds.
3757
 * </li>
3758
 * <li>VERBOSE_WAIT_MESSAGE=YES/NO: Whether to emit a CE_Warning message while
3759
 * waiting for a busy lock. Default to NO.
3760
 * </li>
3761
 * </ul>
3762

3763
 * @param pszLockFileName Lock file name. The directory must already exist.
3764
 *                        Must not be NULL.
3765
 * @param[out] phLockFileHandle Pointer to at location where to store the lock
3766
 *                              handle that must be passed to CPLUnlockFileEx().
3767
 *                              *phLockFileHandle will be null if the return
3768
 *                              code of that function is not CLFS_OK.
3769
 * @param papszOptions NULL terminated list of strings, or NULL.
3770
 *
3771
 * @return lock file status.
3772
 *
3773
 * @since 3.11
3774
 */
3775
CPLLockFileStatus CPLLockFileEx(const char *pszLockFileName,
15✔
3776
                                CPLLockFileHandle *phLockFileHandle,
3777
                                CSLConstList papszOptions)
3778
{
3779
    if (!pszLockFileName || !phLockFileHandle)
15✔
3780
        return CLFS_API_MISUSE;
2✔
3781

3782
    *phLockFileHandle = nullptr;
13✔
3783

3784
    const double dfWaitTime =
3785
        CPLAtof(CSLFetchNameValueDef(papszOptions, "WAIT_TIME", "inf"));
13✔
3786
    const double dfStalledDelay =
3787
        CPLAtof(CSLFetchNameValueDef(papszOptions, "STALLED_DELAY", "10"));
13✔
3788
    const bool bVerboseWait =
3789
        CPLFetchBool(papszOptions, "VERBOSE_WAIT_MESSAGE", false);
13✔
3790

3791
    for (int i = 0; i < 2; ++i)
14✔
3792
    {
3793
#ifdef _WIN32
3794
        wchar_t *pwszFilename =
3795
            CPLRecodeToWChar(pszLockFileName, CPL_ENC_UTF8, CPL_ENC_UCS2);
3796
        int fd = _wopen(pwszFilename, _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
3797
        CPLFree(pwszFilename);
3798
#else
3799
        int fd = open(pszLockFileName, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
14✔
3800
#endif
3801
        if (fd == -1)
14✔
3802
        {
3803
            if (errno != EEXIST || i == 1)
3✔
3804
            {
3805
                return CLFS_CANNOT_CREATE_LOCK;
×
3806
            }
3807
            else
3808
            {
3809
                // Wait for the .lock file to have been removed or
3810
                // not refreshed since dfStalledDelay seconds.
3811
                double dfCurWaitTime = dfWaitTime;
3✔
3812
                VSIStatBufL sStat;
3813
                while (VSIStatL(pszLockFileName, &sStat) == 0 &&
15✔
3814
                       static_cast<double>(sStat.st_mtime) + dfStalledDelay >
7✔
3815
                           static_cast<double>(time(nullptr)))
7✔
3816
                {
3817
                    if (dfCurWaitTime <= 1e-5)
6✔
3818
                        return CLFS_LOCK_BUSY;
2✔
3819

3820
                    if (bVerboseWait)
5✔
3821
                    {
3822
                        CPLError(CE_Warning, CPLE_AppDefined,
4✔
3823
                                 "Waiting for %s to be freed...",
3824
                                 pszLockFileName);
3825
                    }
3826
                    else
3827
                    {
3828
                        CPLDebug("CPL", "Waiting for %s to be freed...",
1✔
3829
                                 pszLockFileName);
3830
                    }
3831

3832
                    const double dfPauseDelay = std::min(0.5, dfWaitTime);
5✔
3833
                    CPLSleep(dfPauseDelay);
5✔
3834
                    dfCurWaitTime -= dfPauseDelay;
5✔
3835
                }
3836

3837
                if (VSIUnlink(pszLockFileName) != 0)
2✔
3838
                {
3839
                    return CLFS_CANNOT_CREATE_LOCK;
1✔
3840
                }
3841
            }
3842
        }
3843
        else
3844
        {
3845
            close(fd);
11✔
3846
            break;
11✔
3847
        }
3848
    }
3849

3850
    // Touch regularly the lock file to show it is still alive
3851
    struct KeepAliveLockFile
3852
    {
3853
        static void func(void *user_data)
11✔
3854
        {
3855
            CPLLockFileHandle hLockFileHandle =
11✔
3856
                static_cast<CPLLockFileHandle>(user_data);
3857
            while (!hLockFileHandle->bStop)
23✔
3858
            {
3859
                auto f = VSIVirtualHandleUniquePtr(
3860
                    VSIFOpenL(hLockFileHandle->osLockFilename.c_str(), "wb"));
24✔
3861
                if (f)
12✔
3862
                {
3863
                    f.reset();
12✔
3864
                }
3865
                constexpr double REFRESH_DELAY = 0.5;
12✔
3866
                CPLSleep(REFRESH_DELAY);
12✔
3867
            }
3868
        }
11✔
3869
    };
3870

3871
    *phLockFileHandle = new CPLLockFileStruct();
11✔
3872
    (*phLockFileHandle)->osLockFilename = pszLockFileName;
11✔
3873

3874
    (*phLockFileHandle)->hThread =
22✔
3875
        CPLCreateJoinableThread(KeepAliveLockFile::func, *phLockFileHandle);
11✔
3876
    if ((*phLockFileHandle)->hThread == nullptr)
11✔
3877
    {
3878
        VSIUnlink(pszLockFileName);
×
3879
        delete *phLockFileHandle;
×
3880
        *phLockFileHandle = nullptr;
×
3881
        return CLFS_THREAD_CREATION_FAILED;
×
3882
    }
3883

3884
    return CLFS_OK;
11✔
3885
}
3886

3887
/************************************************************************/
3888
/*                         CPLUnlockFileEx()                            */
3889
/************************************************************************/
3890

3891
/** Release and delete a lock file.
3892
 *
3893
 * This function must be paired with CPLLockFileEx().
3894
 *
3895
 * @param hLockFileHandle Lock handle (value of *phLockFileHandle argument
3896
 *                        set by CPLLockFileEx()), or NULL.
3897
 *
3898
 * @since 3.11
3899
 */
3900
void CPLUnlockFileEx(CPLLockFileHandle hLockFileHandle)
12✔
3901
{
3902
    if (hLockFileHandle)
12✔
3903
    {
3904
        // Remove .lock file
3905
        hLockFileHandle->bStop = true;
11✔
3906
        CPLJoinThread(hLockFileHandle->hThread);
11✔
3907
        VSIUnlink(hLockFileHandle->osLockFilename.c_str());
11✔
3908

3909
        delete hLockFileHandle;
11✔
3910
    }
3911
}
12✔
3912

3913
/************************************************************************/
3914
/*                       CPLFormatReadableFileSize()                    */
3915
/************************************************************************/
3916

3917
template <class T>
3918
static std::string CPLFormatReadableFileSizeInternal(T nSizeInBytes)
10✔
3919
{
3920
    constexpr T ONE_MEGA_BYTE = 1000 * 1000;
10✔
3921
    constexpr T ONE_GIGA_BYTE = 1000 * ONE_MEGA_BYTE;
10✔
3922
    constexpr T ONE_TERA_BYTE = 1000 * ONE_GIGA_BYTE;
10✔
3923
    constexpr T ONE_PETA_BYTE = 1000 * ONE_TERA_BYTE;
10✔
3924
    constexpr T ONE_HEXA_BYTE = 1000 * ONE_PETA_BYTE;
10✔
3925

3926
    if (nSizeInBytes > ONE_HEXA_BYTE)
10✔
3927
        return CPLSPrintf("%.02f HB", static_cast<double>(nSizeInBytes) /
3928
                                          static_cast<double>(ONE_HEXA_BYTE));
2✔
3929

3930
    if (nSizeInBytes > ONE_PETA_BYTE)
8✔
3931
        return CPLSPrintf("%.02f PB", static_cast<double>(nSizeInBytes) /
3932
                                          static_cast<double>(ONE_PETA_BYTE));
2✔
3933

3934
    if (nSizeInBytes > ONE_TERA_BYTE)
6✔
3935
        return CPLSPrintf("%.02f TB", static_cast<double>(nSizeInBytes) /
3936
                                          static_cast<double>(ONE_TERA_BYTE));
1✔
3937

3938
    if (nSizeInBytes > ONE_GIGA_BYTE)
5✔
3939
        return CPLSPrintf("%.02f GB", static_cast<double>(nSizeInBytes) /
3940
                                          static_cast<double>(ONE_GIGA_BYTE));
3✔
3941

3942
    if (nSizeInBytes > ONE_MEGA_BYTE)
2✔
3943
        return CPLSPrintf("%.02f MB", static_cast<double>(nSizeInBytes) /
3944
                                          static_cast<double>(ONE_MEGA_BYTE));
1✔
3945

3946
    return CPLSPrintf("%03d,%03d bytes", static_cast<int>(nSizeInBytes) / 1000,
3947
                      static_cast<int>(nSizeInBytes) % 1000);
1✔
3948
}
3949

3950
/** Return a file size in a human readable way.
3951
 *
3952
 * e.g 1200000 -> "1.20 MB"
3953
 *
3954
 * @since 3.12
3955
 */
3956
std::string CPLFormatReadableFileSize(uint64_t nSizeInBytes)
3✔
3957
{
3958
    return CPLFormatReadableFileSizeInternal(nSizeInBytes);
3✔
3959
}
3960

3961
/** Return a file size in a human readable way.
3962
 *
3963
 * e.g 1200000 -> "1.20 MB"
3964
 *
3965
 * @since 3.12
3966
 */
3967
std::string CPLFormatReadableFileSize(double dfSizeInBytes)
7✔
3968
{
3969
    return CPLFormatReadableFileSizeInternal(dfSizeInBytes);
7✔
3970
}
3971

3972
/************************************************************************/
3973
/*                 CPLGetRemainingFileDescriptorCount()                 */
3974
/************************************************************************/
3975

3976
/** \fn CPLGetRemainingFileDescriptorCount()
3977
 *
3978
 * Return the number of file descriptors that can still be opened by the
3979
 * current process.
3980
 *
3981
 * Only implemented on non-Windows operating systems
3982
 *
3983
 * Return a negative value in case of error or not implemented.
3984
 *
3985
 * @since 3.12
3986
 */
3987

3988
#if defined(__FreeBSD__)
3989

3990
int CPLGetRemainingFileDescriptorCount()
3991
{
3992
    struct rlimit limitNumberOfFilesPerProcess;
3993
    if (getrlimit(RLIMIT_NOFILE, &limitNumberOfFilesPerProcess) != 0)
3994
    {
3995
        return -1;
3996
    }
3997
    const int maxNumberOfFilesPerProcess =
3998
        static_cast<int>(limitNumberOfFilesPerProcess.rlim_cur);
3999

4000
    const pid_t pid = getpid();
4001
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_FILEDESC,
4002
                  static_cast<int>(pid)};
4003

4004
    size_t len = 0;
4005

4006
    if (sysctl(mib, 4, nullptr, &len, nullptr, 0) == -1)
4007
    {
4008
        return -1;
4009
    }
4010

4011
    return maxNumberOfFilesPerProcess -
4012
           static_cast<int>(len / sizeof(struct kinfo_file));
4013
}
4014

4015
#else
4016

4017
int CPLGetRemainingFileDescriptorCount()
87✔
4018
{
4019
#if !defined(_WIN32) && HAVE_GETRLIMIT
4020
    struct rlimit limitNumberOfFilesPerProcess;
4021
    if (getrlimit(RLIMIT_NOFILE, &limitNumberOfFilesPerProcess) != 0)
87✔
4022
    {
4023
        return -1;
×
4024
    }
4025
    const int maxNumberOfFilesPerProcess =
87✔
4026
        static_cast<int>(limitNumberOfFilesPerProcess.rlim_cur);
87✔
4027

4028
    int countFilesInUse = 0;
87✔
4029
    {
4030
        const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr};
87✔
4031
#ifdef __linux
4032
        VSIDIR *dir = VSIOpenDir("/proc/self/fd", 0, apszOptions);
87✔
4033
#else
4034
        // MacOSX
4035
        VSIDIR *dir = VSIOpenDir("/dev/fd", 0, apszOptions);
4036
#endif
4037
        if (dir)
87✔
4038
        {
4039
            while (VSIGetNextDirEntry(dir))
1,308✔
4040
                ++countFilesInUse;
1,221✔
4041
            countFilesInUse -= 2;  // do not count . and ..
87✔
4042
            VSICloseDir(dir);
87✔
4043
        }
4044
    }
4045

4046
    if (countFilesInUse <= 0)
87✔
4047
    {
4048
        // Fallback if above method does not work
4049
        for (int fd = 0; fd < maxNumberOfFilesPerProcess; fd++)
×
4050
        {
4051
            errno = 0;
×
4052
            if (fcntl(fd, F_GETFD) != -1 || errno != EBADF)
×
4053
            {
4054
                countFilesInUse++;
×
4055
            }
4056
        }
4057
    }
4058

4059
    return maxNumberOfFilesPerProcess - countFilesInUse;
87✔
4060
#else
4061
    return -1;
4062
#endif
4063
}
4064

4065
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc