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

OSGeo / gdal / 8872387746

29 Apr 2024 02:16AM UTC coverage: 69.076% (+0.003%) from 69.073%
8872387746

Pull #9801

github

web-flow
Bump actions/upload-artifact from 4.3.2 to 4.3.3

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/1746f4ab6...65462800f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #9801: Bump actions/upload-artifact from 4.3.2 to 4.3.3

534153 of 773282 relevant lines covered (69.08%)

205719.18 hits per line

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

91.24
/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
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included
19
 * in all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29

30
#include "cpl_port.h"
31
#include "cpl_string.h"
32

33
#include <cstddef>
34
#include <cstdio>
35
#include <cstdlib>
36
#include <cstring>
37

38
#include <algorithm>
39
#include <limits>
40
#include <string>
41

42
#include "cpl_conv.h"
43
#include "cpl_error.h"
44

45
/************************************************************************/
46
/*                           CPLStringList()                            */
47
/************************************************************************/
48

49
CPLStringList::CPLStringList() = default;
50

51
/************************************************************************/
52
/*                           CPLStringList()                            */
53
/************************************************************************/
54

55
/**
56
 * CPLStringList constructor.
57
 *
58
 * @param papszListIn the NULL terminated list of strings to consume.
59
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
60
 * of the list of strings which implies responsibility to free them.
61
 */
62

63
CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
247,973✔
64
    : CPLStringList()
247,973✔
65

66
{
67
    Assign(papszListIn, bTakeOwnership);
247,973✔
68
}
247,973✔
69

70
/************************************************************************/
71
/*                           CPLStringList()                            */
72
/************************************************************************/
73

74
/**
75
 * CPLStringList constructor.
76
 *
77
 * The input list is copied.
78
 *
79
 * @param papszListIn the NULL terminated list of strings to ingest.
80
 */
81

82
CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
3,555✔
83

84
{
85
    Assign(CSLDuplicate(papszListIn));
3,555✔
86
}
3,555✔
87

88
/************************************************************************/
89
/*                           CPLStringList()                            */
90
/************************************************************************/
91

92
/**
93
 * CPLStringList constructor.
94
 *
95
 * The input list is copied.
96
 *
97
 * @param aosList input list.
98
 *
99
 * @since GDAL 3.9
100
 */
101
CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
170✔
102
{
103
    if (!aosList.empty())
170✔
104
    {
105
        bOwnList = true;
134✔
106
        papszList = static_cast<char **>(
134✔
107
            VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
134✔
108
        nCount = static_cast<int>(aosList.size());
134✔
109
        for (int i = 0; i < nCount; ++i)
275✔
110
        {
111
            papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
141✔
112
        }
113
    }
114
}
170✔
115

116
/************************************************************************/
117
/*                           CPLStringList()                            */
118
/************************************************************************/
119

120
/**
121
 * CPLStringList constructor.
122
 *
123
 * The input list is copied.
124
 *
125
 * @param oInitList input list.
126
 *
127
 * @since GDAL 3.9
128
 */
129
CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
3✔
130
{
131
    for (const char *pszStr : oInitList)
9✔
132
    {
133
        AddString(pszStr);
6✔
134
    }
135
}
3✔
136

137
/************************************************************************/
138
/*                           CPLStringList()                            */
139
/************************************************************************/
140

141
//! Copy constructor
142
CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
15,289✔
143

144
{
145
    operator=(oOther);
15,289✔
146
}
15,289✔
147

148
/************************************************************************/
149
/*                           CPLStringList()                            */
150
/************************************************************************/
151

152
//! Move constructor
153
CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
786,088✔
154

155
{
156
    operator=(std::move(oOther));
786,037✔
157
}
786,049✔
158

159
/************************************************************************/
160
/*                           BoundToConstList()                         */
161
/************************************************************************/
162

163
/**
164
 * Return a CPLStringList that wraps the passed list.
165
 *
166
 * The input list is *NOT* copied and must be kept alive while the
167
 * return CPLStringList is used.
168
 *
169
 * @param papszListIn a NULL terminated list of strings to wrap into the CPLStringList
170
 * @since GDAL 3.9
171
 */
172

173
/* static */
174
const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
94✔
175
{
176
    return CPLStringList(const_cast<char **>(papszListIn),
177
                         /* bTakeOwnership= */ false);
94✔
178
}
179

180
/************************************************************************/
181
/*                             operator=()                              */
182
/************************************************************************/
183

184
CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
18,003✔
185
{
186
    if (this != &oOther)
18,003✔
187
    {
188
        char **l_papszList = CSLDuplicate(oOther.papszList);
18,002✔
189
        if (l_papszList)
18,002✔
190
        {
191
            Assign(l_papszList, TRUE);
5,436✔
192
            nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
5,436✔
193
            nCount = oOther.nCount;
5,436✔
194
            bIsSorted = oOther.bIsSorted;
5,436✔
195
        }
196
    }
197

198
    return *this;
18,003✔
199
}
200

201
/************************************************************************/
202
/*                             operator=()                              */
203
/************************************************************************/
204

205
CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
790,776✔
206
{
207
    if (this != &oOther)
790,776✔
208
    {
209
        Clear();
790,768✔
210
        papszList = oOther.papszList;
790,799✔
211
        oOther.papszList = nullptr;
790,799✔
212
        nCount = oOther.nCount;
790,799✔
213
        oOther.nCount = 0;
790,799✔
214
        nAllocation = oOther.nAllocation;
790,799✔
215
        oOther.nAllocation = 0;
790,799✔
216
        bOwnList = oOther.bOwnList;
790,799✔
217
        oOther.bOwnList = false;
790,799✔
218
        bIsSorted = oOther.bIsSorted;
790,799✔
219
        oOther.bIsSorted = true;
790,799✔
220
    }
221

222
    return *this;
790,807✔
223
}
224

225
/************************************************************************/
226
/*                             operator=()                              */
227
/************************************************************************/
228

229
CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
22,171✔
230
{
231
    if (papszListIn != papszList)
22,171✔
232
    {
233
        Assign(CSLDuplicate(papszListIn));
10,254✔
234
        bIsSorted = false;
10,254✔
235
    }
236

237
    return *this;
22,171✔
238
}
239

240
/************************************************************************/
241
/*                           ~CPLStringList()                           */
242
/************************************************************************/
243

244
CPLStringList::~CPLStringList()
9,759,830✔
245

246
{
247
    Clear();
4,879,960✔
248
}
4,879,880✔
249

250
/************************************************************************/
251
/*                               Clear()                                */
252
/************************************************************************/
253

254
/**
255
 * Clear the string list.
256
 */
257
CPLStringList &CPLStringList::Clear()
6,133,600✔
258

259
{
260
    if (bOwnList)
6,133,600✔
261
    {
262
        CSLDestroy(papszList);
956,853✔
263
        papszList = nullptr;
956,853✔
264

265
        bOwnList = FALSE;
956,853✔
266
        nAllocation = 0;
956,853✔
267
        nCount = 0;
956,853✔
268
    }
269

270
    return *this;
6,133,600✔
271
}
272

273
/************************************************************************/
274
/*                               Assign()                               */
275
/************************************************************************/
276

277
/**
278
 * Assign a list of strings.
279
 *
280
 *
281
 * @param papszListIn the NULL terminated list of strings to consume.
282
 * @param bTakeOwnership TRUE if the CPLStringList should take ownership
283
 * of the list of strings which implies responsibility to free them.
284
 *
285
 * @return a reference to the CPLStringList on which it was invoked.
286
 */
287

288
CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
336,419✔
289

290
{
291
    Clear();
336,419✔
292

293
    papszList = papszListIn;
336,419✔
294
    bOwnList = CPL_TO_BOOL(bTakeOwnership);
336,419✔
295

296
    if (papszList == nullptr || *papszList == nullptr)
336,419✔
297
        nCount = 0;
63,759✔
298
    else
299
        nCount = -1;  // unknown
272,660✔
300

301
    nAllocation = 0;
336,419✔
302
    bIsSorted = FALSE;
336,419✔
303

304
    return *this;
336,419✔
305
}
306

307
/************************************************************************/
308
/*                               Count()                                */
309
/************************************************************************/
310

311
/**
312
 * @return count of strings in the list, zero if empty.
313
 */
314

315
int CPLStringList::Count() const
1,991,380✔
316

317
{
318
    if (nCount == -1)
1,991,380✔
319
    {
320
        if (papszList == nullptr)
261,798✔
321
        {
322
            nCount = 0;
×
323
            nAllocation = 0;
×
324
        }
325
        else
326
        {
327
            nCount = CSLCount(papszList);
261,798✔
328
            nAllocation = std::max(nCount + 1, nAllocation);
261,798✔
329
        }
330
    }
331

332
    return nCount;
1,991,380✔
333
}
334

335
/************************************************************************/
336
/*                           MakeOurOwnCopy()                           */
337
/*                                                                      */
338
/*      If we don't own the list, a copy is made which we own.          */
339
/*      Necessary if we are going to modify the list.                   */
340
/************************************************************************/
341

342
bool CPLStringList::MakeOurOwnCopy()
5,356,660✔
343

344
{
345
    if (bOwnList)
5,356,660✔
346
        return true;
3,077,930✔
347

348
    if (papszList == nullptr)
2,278,730✔
349
        return true;
2,278,640✔
350

351
    Count();
95✔
352
    char **papszListNew = CSLDuplicate(papszList);
80✔
353
    if (papszListNew == nullptr)
80✔
354
    {
355
        return false;
×
356
    }
357
    papszList = papszListNew;
80✔
358
    bOwnList = true;
80✔
359
    nAllocation = nCount + 1;
80✔
360
    return true;
80✔
361
}
362

363
/************************************************************************/
364
/*                          EnsureAllocation()                          */
365
/*                                                                      */
366
/*      Ensure we have enough room allocated for at least the           */
367
/*      requested number of strings (so nAllocation will be at least    */
368
/*      one more than the target)                                       */
369
/************************************************************************/
370

371
bool CPLStringList::EnsureAllocation(int nMaxList)
8,073,960✔
372

373
{
374
    if (!bOwnList)
8,073,960✔
375
    {
376
        if (!MakeOurOwnCopy())
1,839,070✔
377
            return false;
×
378
    }
379

380
    if (papszList == nullptr || nAllocation <= nMaxList)
8,073,860✔
381
    {
382
        // we need to be able to store nMaxList+1 as an int,
383
        // and allocate (nMaxList+1) * sizeof(char*) bytes
384
        if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
3,788,390✔
385
            static_cast<size_t>(nMaxList) >
1,894,260✔
386
                std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
1,894,260✔
387
        {
388
            return false;
×
389
        }
390
        int nNewAllocation = nMaxList + 1;
1,894,170✔
391
        if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
1,894,170✔
392
                                  static_cast<int>(sizeof(char *)))
393
            nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
1,894,200✔
394
        if (papszList == nullptr)
1,894,190✔
395
        {
396
            papszList = static_cast<char **>(
1,841,220✔
397
                VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
1,841,180✔
398
            bOwnList = true;
1,841,220✔
399
            nCount = 0;
1,841,220✔
400
            if (papszList == nullptr)
1,841,220✔
401
                return false;
×
402
        }
403
        else
404
        {
405
            char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
53,010✔
406
                papszList, nNewAllocation * sizeof(char *)));
407
            if (papszListNew == nullptr)
53,010✔
408
                return false;
×
409
            papszList = papszListNew;
53,010✔
410
        }
411
        nAllocation = nNewAllocation;
1,894,230✔
412
    }
413
    return true;
8,073,890✔
414
}
415

416
/************************************************************************/
417
/*                         AddStringDirectly()                          */
418
/************************************************************************/
419

420
/**
421
 * Add a string to the list.
422
 *
423
 * This method is similar to AddString(), but ownership of the
424
 * pszNewString is transferred to the CPLStringList class.
425
 *
426
 * @param pszNewString the string to add to the list.
427
 */
428

429
CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
8,066,070✔
430

431
{
432
    if (nCount == -1)
8,066,070✔
433
        Count();
109✔
434

435
    if (!EnsureAllocation(nCount + 1))
8,066,070✔
436
    {
437
        VSIFree(pszNewString);
×
438
        return *this;
×
439
    }
440

441
    papszList[nCount++] = pszNewString;
8,066,060✔
442
    papszList[nCount] = nullptr;
8,066,060✔
443

444
    bIsSorted = false;
8,066,060✔
445

446
    return *this;
8,066,060✔
447
}
448

449
/************************************************************************/
450
/*                             AddString()                              */
451
/************************************************************************/
452

453
/**
454
 * Add a string to the list.
455
 *
456
 * A copy of the passed in string is made and inserted in the list.
457
 *
458
 * @param pszNewString the string to add to the list.
459
 */
460

461
CPLStringList &CPLStringList::AddString(const char *pszNewString)
4,649,790✔
462

463
{
464
    char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
4,649,790✔
465
    if (pszDupString == nullptr)
4,649,760✔
466
        return *this;
×
467
    return AddStringDirectly(pszDupString);
4,649,760✔
468
}
469

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

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

484
CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
3,426,650✔
485
                                           const char *pszValue)
486

487
{
488
    if (pszKey == nullptr || pszValue == nullptr)
3,426,650✔
489
        return *this;
3,000✔
490

491
    if (!MakeOurOwnCopy())
3,423,650✔
492
        return *this;
×
493

494
    /* -------------------------------------------------------------------- */
495
    /*      Format the line.                                                */
496
    /* -------------------------------------------------------------------- */
497
    if (strlen(pszKey) >
6,847,420✔
498
            std::numeric_limits<size_t>::max() - strlen(pszValue) ||
6,847,420✔
499
        strlen(pszKey) + strlen(pszValue) >
3,423,720✔
500
            std::numeric_limits<size_t>::max() - 2)
3,423,720✔
501
    {
502
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
503
                 "Too big strings in AddNameValue()");
504
        return *this;
×
505
    }
506
    const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
3,423,730✔
507
    char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
3,423,730✔
508
    if (pszLine == nullptr)
3,423,740✔
509
        return *this;
×
510
    snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
3,423,740✔
511

512
    /* -------------------------------------------------------------------- */
513
    /*      If we don't need to keep the sort order things are pretty       */
514
    /*      straight forward.                                               */
515
    /* -------------------------------------------------------------------- */
516
    if (!IsSorted())
3,423,740✔
517
        return AddStringDirectly(pszLine);
3,415,960✔
518

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

527
    return *this;
7,702✔
528
}
529

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

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

545
CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
3,467,620✔
546
                                           const char *pszValue)
547

548
{
549
    int iKey = FindName(pszKey);
3,467,620✔
550

551
    if (iKey == -1)
3,467,590✔
552
        return AddNameValue(pszKey, pszValue);
3,393,730✔
553

554
    Count();
73,855✔
555
    if (!MakeOurOwnCopy())
73,785✔
556
        return *this;
×
557

558
    CPLFree(papszList[iKey]);
73,785✔
559
    if (pszValue == nullptr)  // delete entry
73,785✔
560
    {
561

562
        // shift everything down by one.
563
        do
110✔
564
        {
565
            papszList[iKey] = papszList[iKey + 1];
198✔
566
        } while (papszList[iKey++] != nullptr);
198✔
567

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

587
        papszList[iKey] = pszLine;
73,697✔
588
    }
589

590
    return *this;
73,785✔
591
}
592

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

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

609
{
610
    if (nCount == -1)
1,053,100✔
611
        Count();
161✔
612

613
    if (i < 0 || i >= nCount)
1,053,100✔
614
        return nullptr;
49✔
615

616
    return papszList[i];
1,053,060✔
617
}
618

619
const char *CPLStringList::operator[](int i) const
193,632✔
620

621
{
622
    if (nCount == -1)
193,632✔
623
        Count();
1✔
624

625
    if (i < 0 || i >= nCount)
193,632✔
626
        return nullptr;
2✔
627

628
    return papszList[i];
193,630✔
629
}
630

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

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

645
{
646
    char **papszRetList = papszList;
1,049,410✔
647

648
    bOwnList = false;
1,049,410✔
649
    papszList = nullptr;
1,049,410✔
650
    nCount = 0;
1,049,410✔
651
    nAllocation = 0;
1,049,410✔
652

653
    return papszRetList;
1,049,410✔
654
}
655

656
static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
363,872✔
657
{
658
    const char *pszItera = pszKVa;
363,872✔
659
    const char *pszIterb = pszKVb;
363,872✔
660
    while (true)
661
    {
662
        char cha = *pszItera;
3,558,780✔
663
        char chb = *pszIterb;
3,558,780✔
664
        if (cha == '=' || cha == '\0')
3,558,780✔
665
        {
666
            if (chb == '=' || chb == '\0')
2,535✔
667
                return 0;
87✔
668
            else
669
                return -1;
2,448✔
670
        }
671
        if (chb == '=' || chb == '\0')
3,556,240✔
672
        {
673
            return 1;
2,043✔
674
        }
675
        if (cha >= 'a' && cha <= 'z')
3,554,200✔
676
            cha -= ('a' - 'A');
886,314✔
677
        if (chb >= 'a' && chb <= 'z')
3,554,200✔
678
            chb -= ('a' - 'A');
893,368✔
679
        if (cha < chb)
3,554,200✔
680
            return -1;
183,490✔
681
        else if (cha > chb)
3,370,710✔
682
            return 1;
175,804✔
683
        pszItera++;
3,194,910✔
684
        pszIterb++;
3,194,910✔
685
    }
3,194,910✔
686
}
687

688
/************************************************************************/
689
/*                            llCompareStr()                            */
690
/*                                                                      */
691
/*      Note this is case insensitive!  This is because we normally     */
692
/*      treat key value keywords as case insensitive.                   */
693
/************************************************************************/
694
static int llCompareStr(const void *a, const void *b)
303,809✔
695
{
696
    return CPLCompareKeyValueString(
303,809✔
697
        *static_cast<const char **>(const_cast<void *>(a)),
698
        *static_cast<const char **>(const_cast<void *>(b)));
303,809✔
699
}
700

701
/************************************************************************/
702
/*                                Sort()                                */
703
/************************************************************************/
704

705
/**
706
 * Sort the entries in the list and mark list sorted.
707
 *
708
 * Note that once put into "sorted" mode, the CPLStringList will attempt to
709
 * keep things in sorted order through calls to AddString(),
710
 * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
711
 * assignments (via Assign() and operator= will clear the sorting state.
712
 * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
713
 * will do a binary search to find the key, substantially improve lookup
714
 * performance in large lists.
715
 */
716

717
CPLStringList &CPLStringList::Sort()
20,203✔
718

719
{
720
    Count();
20,203✔
721
    if (!MakeOurOwnCopy())
20,203✔
722
        return *this;
×
723

724
    if (nCount)
20,203✔
725
        qsort(papszList, nCount, sizeof(char *), llCompareStr);
8,527✔
726
    bIsSorted = true;
20,203✔
727

728
    return *this;
20,203✔
729
}
730

731
/************************************************************************/
732
/*                              FindName()                              */
733
/************************************************************************/
734

735
/**
736
 * Get index of given name/value keyword.
737
 *
738
 * Note that this search is for a line in the form name=value or name:value.
739
 * Use FindString() or PartialFindString() for searches not based on name=value
740
 * pairs.
741
 *
742
 * @param pszKey the name to search for.
743
 *
744
 * @return the string list index of this name, or -1 on failure.
745
 */
746

747
int CPLStringList::FindName(const char *pszKey) const
13,812,000✔
748

749
{
750
    if (!IsSorted())
13,812,000✔
751
        return CSLFindName(papszList, pszKey);
13,790,200✔
752

753
    // If we are sorted, we can do an optimized binary search.
754
    int iStart = 0;
16,414✔
755
    int iEnd = nCount - 1;
16,414✔
756
    size_t nKeyLen = strlen(pszKey);
16,414✔
757

758
    while (iStart <= iEnd)
49,781✔
759
    {
760
        const int iMiddle = (iEnd + iStart) / 2;
38,290✔
761
        const char *pszMiddle = papszList[iMiddle];
38,290✔
762

763
        if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
38,290✔
764
            (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
5,366✔
765
            return iMiddle;
4,923✔
766

767
        if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
33,367✔
768
            iEnd = iMiddle - 1;
11,358✔
769
        else
770
            iStart = iMiddle + 1;
22,009✔
771
    }
772

773
    return -1;
11,491✔
774
}
775

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

796
bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
4,876✔
797

798
{
799
    const char *pszValue = FetchNameValue(pszKey);
4,876✔
800

801
    if (pszValue == nullptr)
4,876✔
802
        return bDefault;
4,822✔
803

804
    return CPLTestBool(pszValue);
54✔
805
}
806

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

827
int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
3,054✔
828

829
{
830
    return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
3,054✔
831
}
832

833
/************************************************************************/
834
/*                           FetchNameValue()                           */
835
/************************************************************************/
836

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

850
const char *CPLStringList::FetchNameValue(const char *pszName) const
10,328,000✔
851

852
{
853
    const int iKey = FindName(pszName);
10,328,000✔
854

855
    if (iKey == -1)
10,359,400✔
856
        return nullptr;
3,321,140✔
857

858
    CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
7,038,280✔
859
              papszList[iKey][strlen(pszName)] == ':');
860

861
    return papszList[iKey] + strlen(pszName) + 1;
7,038,280✔
862
}
863

864
/************************************************************************/
865
/*                         FetchNameValueDef()                          */
866
/************************************************************************/
867

868
/**
869
 * Fetch value associated with this key name.
870
 *
871
 * If this list sorted, a fast binary search is done, otherwise a linear
872
 * scan is done.  Name lookup is case insensitive.
873
 *
874
 * @param pszName the key name to search for.
875
 * @param pszDefault the default value returned if the named entry isn't found.
876
 *
877
 * @return the corresponding value or the passed default if not found.
878
 */
879

880
const char *CPLStringList::FetchNameValueDef(const char *pszName,
26,997✔
881
                                             const char *pszDefault) const
882

883
{
884
    const char *pszValue = FetchNameValue(pszName);
26,997✔
885
    if (pszValue == nullptr)
26,997✔
886
        return pszDefault;
18,755✔
887

888
    return pszValue;
8,242✔
889
}
890

891
/************************************************************************/
892
/*                            InsertString()                            */
893
/************************************************************************/
894

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

909
/************************************************************************/
910
/*                        InsertStringDirectly()                        */
911
/************************************************************************/
912

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

926
CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
7,832✔
927
                                                   char *pszNewLine)
928

929
{
930
    if (nCount == -1)
7,832✔
931
        Count();
27✔
932

933
    if (!EnsureAllocation(nCount + 1))
7,832✔
934
    {
935
        VSIFree(pszNewLine);
×
936
        return *this;
×
937
    }
938

939
    if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
7,832✔
940
    {
941
        CPLError(CE_Failure, CPLE_AppDefined,
×
942
                 "CPLStringList::InsertString() requested beyond list end.");
943
        return *this;
×
944
    }
945

946
    bIsSorted = false;
7,832✔
947

948
    for (int i = nCount; i > nInsertAtLineNo; i--)
39,186✔
949
        papszList[i] = papszList[i - 1];
31,354✔
950

951
    papszList[nInsertAtLineNo] = pszNewLine;
7,832✔
952
    papszList[++nCount] = nullptr;
7,832✔
953

954
    return *this;
7,832✔
955
}
956

957
/************************************************************************/
958
/*                      FindSortedInsertionPoint()                      */
959
/*                                                                      */
960
/*      Find the location at which the indicated line should be         */
961
/*      inserted in order to keep things in sorted order.               */
962
/************************************************************************/
963

964
int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
7,702✔
965

966
{
967
    CPLAssert(IsSorted());
7,702✔
968

969
    int iStart = 0;
7,702✔
970
    int iEnd = nCount - 1;
7,702✔
971

972
    while (iStart <= iEnd)
26,860✔
973
    {
974
        const int iMiddle = (iEnd + iStart) / 2;
19,158✔
975
        const char *pszMiddle = papszList[iMiddle];
19,158✔
976

977
        if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
19,158✔
978
            iEnd = iMiddle - 1;
5,159✔
979
        else
980
            iStart = iMiddle + 1;
13,999✔
981
    }
982

983
    iEnd++;
7,702✔
984
    CPLAssert(iEnd >= 0 && iEnd <= nCount);
7,702✔
985
    CPLAssert(iEnd == 0 ||
7,702✔
986
              CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
987
    CPLAssert(iEnd == nCount ||
7,702✔
988
              CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
989

990
    return iEnd;
7,702✔
991
}
992

993
namespace cpl
994
{
995

996
/************************************************************************/
997
/*             CSLIterator::operator==(const CSLIterator &other)        */
998
/************************************************************************/
999

1000
/*! @cond Doxygen_Suppress */
1001
bool CSLIterator::operator==(const CSLIterator &other) const
241,935✔
1002
{
1003
    if (!m_bAtEnd && other.m_bAtEnd)
241,935✔
1004
    {
1005
        return m_papszList == nullptr || *m_papszList == nullptr;
241,935✔
1006
    }
1007
    if (!m_bAtEnd && !other.m_bAtEnd)
×
1008
    {
1009
        return m_papszList == other.m_papszList;
×
1010
    }
1011
    if (m_bAtEnd && other.m_bAtEnd)
×
1012
    {
1013
        return true;
×
1014
    }
1015
    return false;
×
1016
}
1017

1018
/*! @endcond */
1019

1020
/************************************************************************/
1021
/*                      CSLNameValueIterator::operator*()               */
1022
/************************************************************************/
1023

1024
/*! @cond Doxygen_Suppress */
1025
CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
1,120✔
1026
{
1027
    if (m_papszList)
1,120✔
1028
    {
1029
        while (*m_papszList)
1,121✔
1030
        {
1031
            char *pszKey = nullptr;
1,121✔
1032
            const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
1,121✔
1033
            if (pszKey)
1,121✔
1034
            {
1035
                m_osKey = pszKey;
1,118✔
1036
                CPLFree(pszKey);
1,118✔
1037
                return {m_osKey.c_str(), pszValue};
1,118✔
1038
            }
1039
            else if (m_bReturnNullKeyIfNotNameValue)
3✔
1040
            {
1041
                return {nullptr, *m_papszList};
2✔
1042
            }
1043
            // Skip entries that are not name=value pairs.
1044
            ++m_papszList;
1✔
1045
        }
1046
    }
1047
    // Should not happen
1048
    CPLAssert(false);
×
1049
    return {"", ""};
1050
}
1051

1052
/*! @endcond */
1053

1054
/************************************************************************/
1055
/*                   CSLNameValueIteratorWrapper::end()                 */
1056
/************************************************************************/
1057

1058
/*! @cond Doxygen_Suppress */
1059
CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
2,443✔
1060
{
1061
    int nCount = CSLCount(m_papszList);
2,443✔
1062
    if (!m_bReturnNullKeyIfNotNameValue)
2,443✔
1063
    {
1064
        while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
2,385✔
1065
            --nCount;
12✔
1066
    }
1067
    return CSLNameValueIterator{m_papszList + nCount,
2,443✔
1068
                                m_bReturnNullKeyIfNotNameValue};
2,443✔
1069
}
1070

1071
/*! @endcond */
1072

1073
}  // 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