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

OSGeo / gdal / 15992523769

01 Jul 2025 07:16AM UTC coverage: 71.09% (-0.004%) from 71.094%
15992523769

Pull #12682

github

web-flow
Merge 1383a7df3 into f6ed9706f
Pull Request #12682: Bump msys2/setup-msys2 from 2.27.0 to 2.28.0

574092 of 807557 relevant lines covered (71.09%)

250020.23 hits per line

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

91.57
/port/cplstringlist.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  CPLStringList implementation.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_port.h"
15
#include "cpl_string.h"
16

17
#include <cstddef>
18
#include <cstdio>
19
#include <cstdlib>
20
#include <cstring>
21

22
#include <algorithm>
23
#include <limits>
24
#include <string>
25

26
#include "cpl_conv.h"
27
#include "cpl_error.h"
28

29
/************************************************************************/
30
/*                           CPLStringList()                            */
31
/************************************************************************/
32

33
CPLStringList::CPLStringList() = default;
34

35
/************************************************************************/
36
/*                           CPLStringList()                            */
37
/************************************************************************/
38

39
/**
40
 * CPLStringList constructor.
41
 *
42
 * @param papszListIn the NULL terminated list of strings to consume.
43
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
44
 * of the list of strings which implies responsibility to free them.
45
 */
46

47
CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
1,870,960✔
48
    : CPLStringList()
1,870,960✔
49

50
{
51
    Assign(papszListIn, bTakeOwnership);
1,831,410✔
52
}
1,803,390✔
53

54
/************************************************************************/
55
/*                           CPLStringList()                            */
56
/************************************************************************/
57

58
/**
59
 * CPLStringList constructor.
60
 *
61
 * The input list is copied.
62
 *
63
 * @param papszListIn the NULL terminated list of strings to ingest.
64
 */
65

66
CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
4,484✔
67

68
{
69
    Assign(CSLDuplicate(papszListIn));
4,484✔
70
}
4,484✔
71

72
/************************************************************************/
73
/*                           CPLStringList()                            */
74
/************************************************************************/
75

76
/**
77
 * CPLStringList constructor.
78
 *
79
 * The input list is copied.
80
 *
81
 * @param aosList input list.
82
 *
83
 * @since GDAL 3.9
84
 */
85
CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
2,488✔
86
{
87
    if (!aosList.empty())
2,488✔
88
    {
89
        bOwnList = true;
472✔
90
        papszList = static_cast<char **>(
472✔
91
            VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
472✔
92
        nCount = static_cast<int>(aosList.size());
472✔
93
        for (int i = 0; i < nCount; ++i)
2,786✔
94
        {
95
            papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
2,314✔
96
        }
97
    }
98
}
2,488✔
99

100
/************************************************************************/
101
/*                           CPLStringList()                            */
102
/************************************************************************/
103

104
/**
105
 * CPLStringList constructor.
106
 *
107
 * The input list is copied.
108
 *
109
 * @param oInitList input list.
110
 *
111
 * @since GDAL 3.9
112
 */
113
CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
3✔
114
{
115
    for (const char *pszStr : oInitList)
9✔
116
    {
117
        AddString(pszStr);
6✔
118
    }
119
}
3✔
120

121
/************************************************************************/
122
/*                           CPLStringList()                            */
123
/************************************************************************/
124

125
//! Copy constructor
126
CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
24,843✔
127

128
{
129
    operator=(oOther);
24,842✔
130
}
24,841✔
131

132
/************************************************************************/
133
/*                           CPLStringList()                            */
134
/************************************************************************/
135

136
//! Move constructor
137
CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
3,426,300✔
138

139
{
140
    operator=(std::move(oOther));
3,380,560✔
141
}
3,426,330✔
142

143
/************************************************************************/
144
/*                           BoundToConstList()                         */
145
/************************************************************************/
146

147
/**
148
 * Return a CPLStringList that wraps the passed list.
149
 *
150
 * The input list is *NOT* copied and must be kept alive while the
151
 * return CPLStringList is used.
152
 *
153
 * @param papszListIn a NULL terminated list of strings to wrap into the CPLStringList
154
 * @since GDAL 3.9
155
 */
156

157
/* static */
158
const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
94✔
159
{
160
    return CPLStringList(const_cast<char **>(papszListIn),
161
                         /* bTakeOwnership= */ false);
94✔
162
}
163

164
/************************************************************************/
165
/*                             operator=()                              */
166
/************************************************************************/
167

168
CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
275,900✔
169
{
170
    if (this != &oOther)
275,900✔
171
    {
172
        char **l_papszList = CSLDuplicate(oOther.papszList);
275,899✔
173
        if (l_papszList)
275,900✔
174
        {
175
            Assign(l_papszList, TRUE);
6,342✔
176
            nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
6,339✔
177
            nCount = oOther.nCount;
6,339✔
178
            bIsSorted = oOther.bIsSorted;
6,339✔
179
        }
180
    }
181

182
    return *this;
275,898✔
183
}
184

185
/************************************************************************/
186
/*                             operator=()                              */
187
/************************************************************************/
188

189
CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
3,423,490✔
190
{
191
    if (this != &oOther)
3,423,490✔
192
    {
193
        Clear();
3,428,360✔
194
        papszList = oOther.papszList;
3,410,390✔
195
        oOther.papszList = nullptr;
3,410,390✔
196
        nCount = oOther.nCount;
3,410,390✔
197
        oOther.nCount = 0;
3,410,390✔
198
        nAllocation = oOther.nAllocation;
3,410,390✔
199
        oOther.nAllocation = 0;
3,410,390✔
200
        bOwnList = oOther.bOwnList;
3,410,390✔
201
        oOther.bOwnList = false;
3,410,390✔
202
        bIsSorted = oOther.bIsSorted;
3,410,390✔
203
        oOther.bIsSorted = true;
3,410,390✔
204
    }
205

206
    return *this;
3,405,520✔
207
}
208

209
/************************************************************************/
210
/*                             operator=()                              */
211
/************************************************************************/
212

213
CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
99,751✔
214
{
215
    if (papszListIn != papszList)
99,751✔
216
    {
217
        Assign(CSLDuplicate(papszListIn));
15,352✔
218
        bIsSorted = false;
15,352✔
219
    }
220

221
    return *this;
99,751✔
222
}
223

224
/************************************************************************/
225
/*                           ~CPLStringList()                           */
226
/************************************************************************/
227

228
CPLStringList::~CPLStringList()
23,465,100✔
229

230
{
231
    Clear();
11,761,900✔
232
}
11,703,200✔
233

234
/************************************************************************/
235
/*                               Clear()                                */
236
/************************************************************************/
237

238
/**
239
 * Clear the string list.
240
 */
241
CPLStringList &CPLStringList::Clear()
17,539,900✔
242

243
{
244
    if (bOwnList)
17,539,900✔
245
    {
246
        CSLDestroy(papszList);
3,169,800✔
247
        papszList = nullptr;
3,184,570✔
248

249
        bOwnList = FALSE;
3,184,570✔
250
        nAllocation = 0;
3,184,570✔
251
        nCount = 0;
3,184,570✔
252
    }
253

254
    return *this;
17,554,600✔
255
}
256

257
/************************************************************************/
258
/*                               Assign()                               */
259
/************************************************************************/
260

261
/**
262
 * Assign a list of strings.
263
 *
264
 *
265
 * @param papszListIn the NULL terminated list of strings to consume.
266
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
267
 * of the list of strings which implies responsibility to free them.
268
 *
269
 * @return a reference to the CPLStringList on which it was invoked.
270
 */
271

272
CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
2,246,310✔
273

274
{
275
    Clear();
2,246,310✔
276

277
    papszList = papszListIn;
2,235,600✔
278
    bOwnList = CPL_TO_BOOL(bTakeOwnership);
2,235,600✔
279

280
    if (papszList == nullptr || *papszList == nullptr)
2,215,710✔
281
        nCount = 0;
1,753,230✔
282
    else
283
        nCount = -1;  // unknown
462,479✔
284

285
    nAllocation = 0;
2,215,710✔
286
    bIsSorted = FALSE;
2,215,710✔
287

288
    return *this;
2,215,710✔
289
}
290

291
/************************************************************************/
292
/*                               Count()                                */
293
/************************************************************************/
294

295
/**
296
 * @return count of strings in the list, zero if empty.
297
 */
298

299
int CPLStringList::Count() const
3,109,300✔
300

301
{
302
    if (nCount == -1)
3,109,300✔
303
    {
304
        if (papszList == nullptr)
448,557✔
305
        {
306
            nCount = 0;
×
307
            nAllocation = 0;
×
308
        }
309
        else
310
        {
311
            nCount = CSLCount(papszList);
448,557✔
312
            nAllocation = std::max(nCount + 1, nAllocation);
448,557✔
313
        }
314
    }
315

316
    return nCount;
3,109,320✔
317
}
318

319
/************************************************************************/
320
/*                           MakeOurOwnCopy()                           */
321
/*                                                                      */
322
/*      If we don't own the list, a copy is made which we own.          */
323
/*      Necessary if we are going to modify the list.                   */
324
/************************************************************************/
325

326
bool CPLStringList::MakeOurOwnCopy()
7,401,600✔
327

328
{
329
    if (bOwnList)
7,401,600✔
330
        return true;
4,109,010✔
331

332
    if (papszList == nullptr)
3,292,590✔
333
        return true;
3,292,420✔
334

335
    Count();
174✔
336
    char **papszListNew = CSLDuplicate(papszList);
86✔
337
    if (papszListNew == nullptr)
86✔
338
    {
339
        return false;
×
340
    }
341
    papszList = papszListNew;
86✔
342
    bOwnList = true;
86✔
343
    nAllocation = nCount + 1;
86✔
344
    return true;
86✔
345
}
346

347
/************************************************************************/
348
/*                          EnsureAllocation()                          */
349
/*                                                                      */
350
/*      Ensure we have enough room allocated for at least the           */
351
/*      requested number of strings (so nAllocation will be at least    */
352
/*      one more than the target)                                       */
353
/************************************************************************/
354

355
bool CPLStringList::EnsureAllocation(int nMaxList)
10,495,500✔
356

357
{
358
    if (!bOwnList)
10,495,500✔
359
    {
360
        if (!MakeOurOwnCopy())
2,587,920✔
361
            return false;
×
362
    }
363

364
    if (papszList == nullptr || nAllocation <= nMaxList)
10,495,500✔
365
    {
366
        // we need to be able to store nMaxList+1 as an int,
367
        // and allocate (nMaxList+1) * sizeof(char*) bytes
368
        if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
5,331,270✔
369
            static_cast<size_t>(nMaxList) >
2,665,660✔
370
                std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
2,665,660✔
371
        {
372
            return false;
×
373
        }
374
        int nNewAllocation = nMaxList + 1;
2,665,610✔
375
        if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
2,665,610✔
376
                                  static_cast<int>(sizeof(char *)))
377
            nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
2,665,660✔
378
        if (papszList == nullptr)
2,665,620✔
379
        {
380
            papszList = static_cast<char **>(
2,590,360✔
381
                VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
2,590,330✔
382
            bOwnList = true;
2,590,360✔
383
            nCount = 0;
2,590,360✔
384
            if (papszList == nullptr)
2,590,360✔
385
                return false;
×
386
        }
387
        else
388
        {
389
            char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
75,287✔
390
                papszList, nNewAllocation * sizeof(char *)));
391
            if (papszListNew == nullptr)
75,287✔
392
                return false;
×
393
            papszList = papszListNew;
75,287✔
394
        }
395
        nAllocation = nNewAllocation;
2,665,650✔
396
    }
397
    return true;
10,495,500✔
398
}
399

400
/************************************************************************/
401
/*                         AddStringDirectly()                          */
402
/************************************************************************/
403

404
/**
405
 * Add a string to the list.
406
 *
407
 * This method is similar to AddString(), but ownership of the
408
 * pszNewString is transferred to the CPLStringList class.
409
 *
410
 * @param pszNewString the string to add to the list.
411
 */
412

413
CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
10,488,400✔
414

415
{
416
    if (nCount == -1)
10,488,400✔
417
        Count();
289✔
418

419
    if (!EnsureAllocation(nCount + 1))
10,488,400✔
420
    {
421
        VSIFree(pszNewString);
35✔
422
        return *this;
×
423
    }
424

425
    papszList[nCount++] = pszNewString;
10,488,300✔
426
    papszList[nCount] = nullptr;
10,488,300✔
427

428
    bIsSorted = false;
10,488,300✔
429

430
    return *this;
10,488,300✔
431
}
432

433
/************************************************************************/
434
/*                             AddString()                              */
435
/************************************************************************/
436

437
/**
438
 * Add a string to the list.
439
 *
440
 * A copy of the passed in string is made and inserted in the list.
441
 *
442
 * @param pszNewString the string to add to the list.
443
 */
444

445
CPLStringList &CPLStringList::AddString(const char *pszNewString)
5,878,320✔
446

447
{
448
    char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
5,878,320✔
449
    if (pszDupString == nullptr)
5,878,290✔
450
        return *this;
×
451
    return AddStringDirectly(pszDupString);
5,878,290✔
452
}
453

454
/************************************************************************/
455
/*                             AddString()                              */
456
/************************************************************************/
457
/**
458
 * Add a string to the list.
459
 *
460
 * A copy of the passed in string is made and inserted in the list.
461
 *
462
 * @param newString the string to add to the list.
463
 * @return a reference to the CPLStringList on which it was invoked.
464
 */
465

466
CPLStringList &CPLStringList::AddString(const std::string &newString)
25,021✔
467
{
468
    return AddString(newString.c_str());
25,021✔
469
}
470

471
/************************************************************************/
472
/*                            AddNameValue()                            */
473
/************************************************************************/
474

475
/**
476
 * Add a name=value entry to the list.
477
 *
478
 * A key=value string is prepared and appended to the list.  There is no
479
 * check for other values for the same key in the list.
480
 *
481
 * @param pszKey the key name to add.
482
 * @param pszValue the key value to add.
483
 */
484

485
CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
4,758,540✔
486
                                           const char *pszValue)
487

488
{
489
    if (pszKey == nullptr || pszValue == nullptr)
4,758,540✔
490
        return *this;
142,065✔
491

492
    if (!MakeOurOwnCopy())
4,616,470✔
493
        return *this;
×
494

495
    /* -------------------------------------------------------------------- */
496
    /*      Format the line.                                                */
497
    /* -------------------------------------------------------------------- */
498
    if (strlen(pszKey) >
9,233,040✔
499
            std::numeric_limits<size_t>::max() - strlen(pszValue) ||
9,233,000✔
500
        strlen(pszKey) + strlen(pszValue) >
4,616,470✔
501
            std::numeric_limits<size_t>::max() - 2)
4,616,470✔
502
    {
503
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
504
                 "Too big strings in AddNameValue()");
505
        return *this;
×
506
    }
507
    const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
4,616,530✔
508
    char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
4,616,530✔
509
    if (pszLine == nullptr)
4,616,530✔
510
        return *this;
×
511
    snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
4,616,530✔
512

513
    /* -------------------------------------------------------------------- */
514
    /*      If we don't need to keep the sort order things are pretty       */
515
    /*      straight forward.                                               */
516
    /* -------------------------------------------------------------------- */
517
    if (!IsSorted())
4,616,530✔
518
        return AddStringDirectly(pszLine);
4,609,760✔
519

520
    /* -------------------------------------------------------------------- */
521
    /*      Find the proper insertion point.                                */
522
    /* -------------------------------------------------------------------- */
523
    CPLAssert(IsSorted());
6,754✔
524
    const int iKey = FindSortedInsertionPoint(pszLine);
6,732✔
525
    InsertStringDirectly(iKey, pszLine);
6,732✔
526
    bIsSorted = true;  // We have actually preserved sort order.
6,732✔
527

528
    return *this;
6,732✔
529
}
530

531
/************************************************************************/
532
/*                            SetNameValue()                            */
533
/************************************************************************/
534

535
/**
536
 * Set name=value entry in the list.
537
 *
538
 * Similar to AddNameValue(), except if there is already a value for
539
 * the key in the list it is replaced instead of adding a new entry to
540
 * the list.  If pszValue is NULL any existing key entry is removed.
541
 *
542
 * @param pszKey the key name to add.
543
 * @param pszValue the key value to add.
544
 */
545

546
CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
4,823,480✔
547
                                           const char *pszValue)
548

549
{
550
    int iKey = FindName(pszKey);
4,823,480✔
551

552
    if (iKey == -1)
4,823,460✔
553
        return AddNameValue(pszKey, pszValue);
4,723,930✔
554

555
    Count();
99,524✔
556
    if (!MakeOurOwnCopy())
99,491✔
557
        return *this;
×
558

559
    CPLFree(papszList[iKey]);
99,491✔
560
    if (pszValue == nullptr)  // delete entry
99,491✔
561
    {
562

563
        // shift everything down by one.
564
        do
281✔
565
        {
566
            papszList[iKey] = papszList[iKey + 1];
2,425✔
567
        } while (papszList[iKey++] != nullptr);
2,425✔
568

569
        nCount--;
2,144✔
570
    }
571
    else
572
    {
573
        if (strlen(pszKey) >
194,694✔
574
                std::numeric_limits<size_t>::max() - strlen(pszValue) ||
194,694✔
575
            strlen(pszKey) + strlen(pszValue) >
97,347✔
576
                std::numeric_limits<size_t>::max() - 2)
97,347✔
577
        {
578
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
579
                     "Too big strings in AddNameValue()");
580
            return *this;
×
581
        }
582
        const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
97,347✔
583
        char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
97,347✔
584
        if (pszLine == nullptr)
97,347✔
585
            return *this;
×
586
        snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
97,347✔
587

588
        papszList[iKey] = pszLine;
97,347✔
589
    }
590

591
    return *this;
99,491✔
592
}
593

594
/************************************************************************/
595
/*                              operator[]                              */
596
/************************************************************************/
597

598
/**
599
 * Fetch entry "i".
600
 *
601
 * Fetches the requested item in the list.  Note that the returned string
602
 * remains owned by the CPLStringList.  If "i" is out of range NULL is
603
 * returned.
604
 *
605
 * @param i the index of the list item to return.
606
 * @return selected entry in the list.
607
 */
608
char *CPLStringList::operator[](int i)
1,333,970✔
609

610
{
611
    if (nCount == -1)
1,333,970✔
612
        Count();
165✔
613

614
    if (i < 0 || i >= nCount)
1,333,970✔
615
        return nullptr;
52✔
616

617
    return papszList[i];
1,333,920✔
618
}
619

620
const char *CPLStringList::operator[](int i) const
454,311✔
621

622
{
623
    if (nCount == -1)
454,311✔
624
        Count();
145✔
625

626
    if (i < 0 || i >= nCount)
454,311✔
627
        return nullptr;
2✔
628

629
    return papszList[i];
454,309✔
630
}
631

632
/************************************************************************/
633
/*                             StealList()                              */
634
/************************************************************************/
635

636
/**
637
 * Seize ownership of underlying string array.
638
 *
639
 * This method is similar to List(), except that the returned list is
640
 * now owned by the caller and the CPLStringList is emptied.
641
 *
642
 * @return the C style string list.
643
 */
644
char **CPLStringList::StealList()
1,433,490✔
645

646
{
647
    char **papszRetList = papszList;
1,433,490✔
648

649
    bOwnList = false;
1,433,490✔
650
    papszList = nullptr;
1,433,490✔
651
    nCount = 0;
1,433,490✔
652
    nAllocation = 0;
1,433,490✔
653

654
    return papszRetList;
1,433,490✔
655
}
656

657
/* Case insensitive comparison function */
658
static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
755,692✔
659
{
660
    const char *pszItera = pszKVa;
755,692✔
661
    const char *pszIterb = pszKVb;
755,692✔
662
    while (true)
663
    {
664
        char cha = *pszItera;
5,125,030✔
665
        char chb = *pszIterb;
5,125,030✔
666
        if (cha == '=' || cha == '\0')
5,125,030✔
667
        {
668
            if (chb == '=' || chb == '\0')
4,031✔
669
                return 0;
2✔
670
            else
671
                return -1;
4,029✔
672
        }
673
        if (chb == '=' || chb == '\0')
5,121,000✔
674
        {
675
            return 1;
6,347✔
676
        }
677
        if (cha >= 'a' && cha <= 'z')
5,114,660✔
678
            cha -= ('a' - 'A');
498,135✔
679
        if (chb >= 'a' && chb <= 'z')
5,114,660✔
680
            chb -= ('a' - 'A');
498,892✔
681
        if (cha < chb)
5,114,660✔
682
            return -1;
448,549✔
683
        else if (cha > chb)
4,666,110✔
684
            return 1;
296,765✔
685
        pszItera++;
4,369,340✔
686
        pszIterb++;
4,369,340✔
687
    }
4,369,340✔
688
}
689

690
/************************************************************************/
691
/*                                Sort()                                */
692
/************************************************************************/
693

694
/**
695
 * Sort the entries in the list and mark list sorted.
696
 *
697
 * Note that once put into "sorted" mode, the CPLStringList will attempt to
698
 * keep things in sorted order through calls to AddString(),
699
 * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
700
 * assignments (via Assign() and operator= will clear the sorting state.
701
 * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
702
 * will do a binary search to find the key, substantially improve lookup
703
 * performance in large lists.
704
 */
705

706
CPLStringList &CPLStringList::Sort()
97,610✔
707

708
{
709
    Count();
97,610✔
710
    if (!MakeOurOwnCopy())
97,610✔
711
        return *this;
×
712

713
    if (nCount > 1)
97,610✔
714
    {
715
        std::sort(papszList, papszList + nCount,
5,545✔
716
                  [](const char *a, const char *b)
705,353✔
717
                  { return CPLCompareKeyValueString(a, b) < 0; });
705,353✔
718
    }
719
    bIsSorted = true;
97,610✔
720

721
    return *this;
97,610✔
722
}
723

724
/************************************************************************/
725
/*                              FindName()                              */
726
/************************************************************************/
727

728
/**
729
 * Get index of given name/value keyword.
730
 *
731
 * Note that this search is for a line in the form name=value or name:value.
732
 * Use FindString() or PartialFindString() for searches not based on name=value
733
 * pairs.
734
 *
735
 * @param pszKey the name to search for.
736
 *
737
 * @return the string list index of this name, or -1 on failure.
738
 */
739

740
int CPLStringList::FindName(const char *pszKey) const
16,300,500✔
741

742
{
743
    if (!IsSorted())
16,300,500✔
744
        return CSLFindName(papszList, pszKey);
16,272,900✔
745

746
    // If we are sorted, we can do an optimized binary search.
747
    int iStart = 0;
20,989✔
748
    int iEnd = nCount - 1;
20,989✔
749
    size_t nKeyLen = strlen(pszKey);
20,989✔
750

751
    while (iStart <= iEnd)
52,734✔
752
    {
753
        const int iMiddle = (iEnd + iStart) / 2;
39,007✔
754
        const char *pszMiddle = papszList[iMiddle];
39,007✔
755

756
        if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
39,007✔
757
            (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
7,639✔
758
            return iMiddle;
7,262✔
759

760
        if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
31,745✔
761
            iEnd = iMiddle - 1;
8,879✔
762
        else
763
            iStart = iMiddle + 1;
22,866✔
764
    }
765

766
    return -1;
13,727✔
767
}
768

769
/************************************************************************/
770
/*                            FetchBool()                               */
771
/************************************************************************/
772
/**
773
 *
774
 * Check for boolean key value.
775
 *
776
 * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
777
 * with the given name, and if it can be interpreted as being TRUE.  If
778
 * the key appears without any "=Value" portion it will be considered true.
779
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
780
 * if the key appears in the list it will be considered TRUE.  If the key
781
 * doesn't appear at all, the indicated default value will be returned.
782
 *
783
 * @param pszKey the key value to look for (case insensitive).
784
 * @param bDefault the value to return if the key isn't found at all.
785
 *
786
 * @return true or false
787
 */
788

789
bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
13,326✔
790

791
{
792
    const char *pszValue = FetchNameValue(pszKey);
13,326✔
793

794
    if (pszValue == nullptr)
13,326✔
795
        return bDefault;
13,092✔
796

797
    return CPLTestBool(pszValue);
234✔
798
}
799

800
/************************************************************************/
801
/*                            FetchBoolean()                            */
802
/************************************************************************/
803
/**
804
 *
805
 * DEPRECATED: Check for boolean key value.
806
 *
807
 * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
808
 * with the given name, and if it can be interpreted as being TRUE.  If
809
 * the key appears without any "=Value" portion it will be considered true.
810
 * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
811
 * if the key appears in the list it will be considered TRUE.  If the key
812
 * doesn't appear at all, the indicated default value will be returned.
813
 *
814
 * @param pszKey the key value to look for (case insensitive).
815
 * @param bDefault the value to return if the key isn't found at all.
816
 *
817
 * @return TRUE or FALSE
818
 */
819

820
int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
3,201✔
821

822
{
823
    return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
3,201✔
824
}
825

826
/************************************************************************/
827
/*                           FetchNameValue()                           */
828
/************************************************************************/
829

830
/**
831
 * Fetch value associated with this key name.
832
 *
833
 * If this list sorted, a fast binary search is done, otherwise a linear
834
 * scan is done.  Name lookup is case insensitive.
835
 *
836
 * @param pszName the key name to search for.
837
 *
838
 * @return the corresponding value or NULL if not found.  The returned string
839
 * should not be modified and points into internal object state that may
840
 * change on future calls.
841
 */
842

843
const char *CPLStringList::FetchNameValue(const char *pszName) const
11,462,300✔
844

845
{
846
    const int iKey = FindName(pszName);
11,462,300✔
847

848
    if (iKey == -1)
11,468,500✔
849
        return nullptr;
3,996,460✔
850

851
    CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
7,472,070✔
852
              papszList[iKey][strlen(pszName)] == ':');
853

854
    return papszList[iKey] + strlen(pszName) + 1;
7,472,070✔
855
}
856

857
/************************************************************************/
858
/*                         FetchNameValueDef()                          */
859
/************************************************************************/
860

861
/**
862
 * Fetch value associated with this key name.
863
 *
864
 * If this list sorted, a fast binary search is done, otherwise a linear
865
 * scan is done.  Name lookup is case insensitive.
866
 *
867
 * @param pszName the key name to search for.
868
 * @param pszDefault the default value returned if the named entry isn't found.
869
 *
870
 * @return the corresponding value or the passed default if not found.
871
 */
872

873
const char *CPLStringList::FetchNameValueDef(const char *pszName,
31,963✔
874
                                             const char *pszDefault) const
875

876
{
877
    const char *pszValue = FetchNameValue(pszName);
31,963✔
878
    if (pszValue == nullptr)
31,963✔
879
        return pszDefault;
24,019✔
880

881
    return pszValue;
7,944✔
882
}
883

884
/************************************************************************/
885
/*                            InsertString()                            */
886
/************************************************************************/
887

888
/**
889
 * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
890
 *                                                 const char *pszNewLine );
891
 *
892
 * \brief Insert into the list at identified location.
893
 *
894
 * This method will insert a string into the list at the identified
895
 * location.  The insertion point must be within or at the end of the list.
896
 * The following entries are pushed down to make space.
897
 *
898
 * @param nInsertAtLineNo the line to insert at, zero to insert at front.
899
 * @param pszNewLine to the line to insert.  This string will be copied.
900
 */
901

902
/************************************************************************/
903
/*                        InsertStringDirectly()                        */
904
/************************************************************************/
905

906
/**
907
 * Insert into the list at identified location.
908
 *
909
 * This method will insert a string into the list at the identified
910
 * location.  The insertion point must be within or at the end of the list.
911
 * The following entries are pushed down to make space.
912
 *
913
 * @param nInsertAtLineNo the line to insert at, zero to insert at front.
914
 * @param pszNewLine to the line to insert, the ownership of this string
915
 * will be taken over the by the object.  It must have been allocated on the
916
 * heap.
917
 */
918

919
CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
7,090✔
920
                                                   char *pszNewLine)
921

922
{
923
    if (nCount == -1)
7,090✔
924
        Count();
27✔
925

926
    if (!EnsureAllocation(nCount + 1))
7,090✔
927
    {
928
        VSIFree(pszNewLine);
×
929
        return *this;
×
930
    }
931

932
    if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
7,090✔
933
    {
934
        CPLError(CE_Failure, CPLE_AppDefined,
×
935
                 "CPLStringList::InsertString() requested beyond list end.");
936
        return *this;
×
937
    }
938

939
    bIsSorted = false;
7,090✔
940

941
    for (int i = nCount; i > nInsertAtLineNo; i--)
24,611✔
942
        papszList[i] = papszList[i - 1];
17,521✔
943

944
    papszList[nInsertAtLineNo] = pszNewLine;
7,090✔
945
    papszList[++nCount] = nullptr;
7,090✔
946

947
    return *this;
7,090✔
948
}
949

950
/************************************************************************/
951
/*                      FindSortedInsertionPoint()                      */
952
/*                                                                      */
953
/*      Find the location at which the indicated line should be         */
954
/*      inserted in order to keep things in sorted order.               */
955
/************************************************************************/
956

957
int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
6,732✔
958

959
{
960
    CPLAssert(IsSorted());
6,732✔
961

962
    int iStart = 0;
6,732✔
963
    int iEnd = nCount - 1;
6,732✔
964

965
    while (iStart <= iEnd)
20,049✔
966
    {
967
        const int iMiddle = (iEnd + iStart) / 2;
13,317✔
968
        const char *pszMiddle = papszList[iMiddle];
13,317✔
969

970
        if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
13,317✔
971
            iEnd = iMiddle - 1;
2,294✔
972
        else
973
            iStart = iMiddle + 1;
11,023✔
974
    }
975

976
    iEnd++;
6,732✔
977
    CPLAssert(iEnd >= 0 && iEnd <= nCount);
6,732✔
978
    CPLAssert(iEnd == 0 ||
6,732✔
979
              CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
980
    CPLAssert(iEnd == nCount ||
6,732✔
981
              CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
982

983
    return iEnd;
6,732✔
984
}
985

986
namespace cpl
987
{
988

989
/************************************************************************/
990
/*             CSLIterator::operator==(const CSLIterator &other)        */
991
/************************************************************************/
992

993
/*! @cond Doxygen_Suppress */
994
bool CSLIterator::operator==(const CSLIterator &other) const
268,982✔
995
{
996
    if (!m_bAtEnd && other.m_bAtEnd)
268,982✔
997
    {
998
        return m_papszList == nullptr || *m_papszList == nullptr;
268,983✔
999
    }
1000
    if (!m_bAtEnd && !other.m_bAtEnd)
×
1001
    {
1002
        return m_papszList == other.m_papszList;
×
1003
    }
1004
    if (m_bAtEnd && other.m_bAtEnd)
×
1005
    {
1006
        return true;
×
1007
    }
1008
    return false;
×
1009
}
1010

1011
/*! @endcond */
1012

1013
/************************************************************************/
1014
/*                      CSLNameValueIterator::operator*()               */
1015
/************************************************************************/
1016

1017
/*! @cond Doxygen_Suppress */
1018
CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
3,523✔
1019
{
1020
    if (m_papszList)
3,523✔
1021
    {
1022
        while (*m_papszList)
3,524✔
1023
        {
1024
            char *pszKey = nullptr;
3,524✔
1025
            const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
3,524✔
1026
            if (pszKey)
3,524✔
1027
            {
1028
                m_osKey = pszKey;
3,521✔
1029
                CPLFree(pszKey);
3,521✔
1030
                return {m_osKey.c_str(), pszValue};
3,521✔
1031
            }
1032
            else if (m_bReturnNullKeyIfNotNameValue)
3✔
1033
            {
1034
                return {nullptr, *m_papszList};
2✔
1035
            }
1036
            // Skip entries that are not name=value pairs.
1037
            ++m_papszList;
1✔
1038
        }
1039
    }
1040
    // Should not happen
1041
    CPLAssert(false);
×
1042
    return {"", ""};
1043
}
1044

1045
/*! @endcond */
1046

1047
/************************************************************************/
1048
/*                   CSLNameValueIteratorWrapper::end()                 */
1049
/************************************************************************/
1050

1051
/*! @cond Doxygen_Suppress */
1052
CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
5,217✔
1053
{
1054
    int nCount = CSLCount(m_papszList);
5,217✔
1055
    if (!m_bReturnNullKeyIfNotNameValue)
5,217✔
1056
    {
1057
        while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
5,145✔
1058
            --nCount;
12✔
1059
    }
1060
    return CSLNameValueIterator{m_papszList + nCount,
5,217✔
1061
                                m_bReturnNullKeyIfNotNameValue};
5,217✔
1062
}
1063

1064
/*! @endcond */
1065

1066
}  // namespace cpl
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