Line data Source code
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 1829390 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
48 1829390 : : CPLStringList()
49 :
50 : {
51 1824900 : Assign(papszListIn, bTakeOwnership);
52 1822690 : }
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 3583 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
67 :
68 : {
69 3583 : Assign(CSLDuplicate(papszListIn));
70 3583 : }
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 299 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
86 : {
87 299 : if (!aosList.empty())
88 : {
89 262 : bOwnList = true;
90 262 : papszList = static_cast<char **>(
91 262 : VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
92 262 : nCount = static_cast<int>(aosList.size());
93 1175 : for (int i = 0; i < nCount; ++i)
94 : {
95 913 : papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
96 : }
97 : }
98 299 : }
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 3 : CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
114 : {
115 9 : for (const char *pszStr : oInitList)
116 : {
117 6 : AddString(pszStr);
118 : }
119 3 : }
120 :
121 : /************************************************************************/
122 : /* CPLStringList() */
123 : /************************************************************************/
124 :
125 : //! Copy constructor
126 20208 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
127 :
128 : {
129 20208 : operator=(oOther);
130 20207 : }
131 :
132 : /************************************************************************/
133 : /* CPLStringList() */
134 : /************************************************************************/
135 :
136 : //! Move constructor
137 3086700 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
138 :
139 : {
140 3074910 : operator=(std::move(oOther));
141 3084700 : }
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 94 : const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
159 : {
160 : return CPLStringList(const_cast<char **>(papszListIn),
161 94 : /* bTakeOwnership= */ false);
162 : }
163 :
164 : /************************************************************************/
165 : /* operator=() */
166 : /************************************************************************/
167 :
168 35421 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
169 : {
170 35421 : if (this != &oOther)
171 : {
172 35420 : char **l_papszList = CSLDuplicate(oOther.papszList);
173 35419 : if (l_papszList)
174 : {
175 5972 : Assign(l_papszList, TRUE);
176 5973 : nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
177 5973 : nCount = oOther.nCount;
178 5973 : bIsSorted = oOther.bIsSorted;
179 : }
180 : }
181 :
182 35421 : return *this;
183 : }
184 :
185 : /************************************************************************/
186 : /* operator=() */
187 : /************************************************************************/
188 :
189 3087970 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
190 : {
191 3087970 : if (this != &oOther)
192 : {
193 3089630 : Clear();
194 3085460 : papszList = oOther.papszList;
195 3085460 : oOther.papszList = nullptr;
196 3085460 : nCount = oOther.nCount;
197 3085460 : oOther.nCount = 0;
198 3085460 : nAllocation = oOther.nAllocation;
199 3085460 : oOther.nAllocation = 0;
200 3085460 : bOwnList = oOther.bOwnList;
201 3085460 : oOther.bOwnList = false;
202 3085460 : bIsSorted = oOther.bIsSorted;
203 3085460 : oOther.bIsSorted = true;
204 : }
205 :
206 3083800 : return *this;
207 : }
208 :
209 : /************************************************************************/
210 : /* operator=() */
211 : /************************************************************************/
212 :
213 30455 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
214 : {
215 30455 : if (papszListIn != papszList)
216 : {
217 12865 : Assign(CSLDuplicate(papszListIn));
218 12865 : bIsSorted = false;
219 : }
220 :
221 30455 : return *this;
222 : }
223 :
224 : /************************************************************************/
225 : /* ~CPLStringList() */
226 : /************************************************************************/
227 :
228 18378700 : CPLStringList::~CPLStringList()
229 :
230 : {
231 9195100 : Clear();
232 9183620 : }
233 :
234 : /************************************************************************/
235 : /* Clear() */
236 : /************************************************************************/
237 :
238 : /**
239 : * Clear the string list.
240 : */
241 14322300 : CPLStringList &CPLStringList::Clear()
242 :
243 : {
244 14322300 : if (bOwnList)
245 : {
246 2609360 : CSLDestroy(papszList);
247 2611680 : papszList = nullptr;
248 :
249 2611680 : bOwnList = FALSE;
250 2611680 : nAllocation = 0;
251 2611680 : nCount = 0;
252 : }
253 :
254 14324600 : return *this;
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 1930740 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
273 :
274 : {
275 1930740 : Clear();
276 :
277 1924890 : papszList = papszListIn;
278 1924890 : bOwnList = CPL_TO_BOOL(bTakeOwnership);
279 :
280 1924370 : if (papszList == nullptr || *papszList == nullptr)
281 1556340 : nCount = 0;
282 : else
283 368029 : nCount = -1; // unknown
284 :
285 1924370 : nAllocation = 0;
286 1924370 : bIsSorted = FALSE;
287 :
288 1924370 : return *this;
289 : }
290 :
291 : /************************************************************************/
292 : /* Count() */
293 : /************************************************************************/
294 :
295 : /**
296 : * @return count of strings in the list, zero if empty.
297 : */
298 :
299 2232600 : int CPLStringList::Count() const
300 :
301 : {
302 2232600 : if (nCount == -1)
303 : {
304 356097 : if (papszList == nullptr)
305 : {
306 0 : nCount = 0;
307 0 : nAllocation = 0;
308 : }
309 : else
310 : {
311 356097 : nCount = CSLCount(papszList);
312 356097 : nAllocation = std::max(nCount + 1, nAllocation);
313 : }
314 : }
315 :
316 2232560 : return nCount;
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 5974180 : bool CPLStringList::MakeOurOwnCopy()
327 :
328 : {
329 5974180 : if (bOwnList)
330 3314400 : return true;
331 :
332 2659770 : if (papszList == nullptr)
333 2659570 : return true;
334 :
335 204 : Count();
336 80 : char **papszListNew = CSLDuplicate(papszList);
337 80 : if (papszListNew == nullptr)
338 : {
339 0 : return false;
340 : }
341 80 : papszList = papszListNew;
342 80 : bOwnList = true;
343 80 : nAllocation = nCount + 1;
344 80 : return true;
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 8876930 : bool CPLStringList::EnsureAllocation(int nMaxList)
356 :
357 : {
358 8876930 : if (!bOwnList)
359 : {
360 2177900 : if (!MakeOurOwnCopy())
361 0 : return false;
362 : }
363 :
364 8876840 : if (papszList == nullptr || nAllocation <= nMaxList)
365 : {
366 : // we need to be able to store nMaxList+1 as an int,
367 : // and allocate (nMaxList+1) * sizeof(char*) bytes
368 4472690 : if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
369 2236450 : static_cast<size_t>(nMaxList) >
370 2236450 : std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
371 : {
372 0 : return false;
373 : }
374 2236270 : int nNewAllocation = nMaxList + 1;
375 2236270 : if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
376 : static_cast<int>(sizeof(char *)))
377 2236440 : nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
378 2236350 : if (papszList == nullptr)
379 : {
380 2180170 : papszList = static_cast<char **>(
381 2180110 : VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
382 2180170 : bOwnList = true;
383 2180170 : nCount = 0;
384 2180170 : if (papszList == nullptr)
385 0 : return false;
386 : }
387 : else
388 : {
389 56238 : char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
390 : papszList, nNewAllocation * sizeof(char *)));
391 56238 : if (papszListNew == nullptr)
392 0 : return false;
393 56238 : papszList = papszListNew;
394 : }
395 2236400 : nAllocation = nNewAllocation;
396 : }
397 8876850 : return true;
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 8868890 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
414 :
415 : {
416 8868890 : if (nCount == -1)
417 181 : Count();
418 :
419 8868890 : if (!EnsureAllocation(nCount + 1))
420 : {
421 0 : VSIFree(pszNewString);
422 0 : return *this;
423 : }
424 :
425 8868930 : papszList[nCount++] = pszNewString;
426 8868930 : papszList[nCount] = nullptr;
427 :
428 8868930 : bIsSorted = false;
429 :
430 8868930 : return *this;
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 5187180 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
446 :
447 : {
448 5187180 : char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
449 5187110 : if (pszDupString == nullptr)
450 0 : return *this;
451 5187110 : return AddStringDirectly(pszDupString);
452 : }
453 :
454 : /************************************************************************/
455 : /* AddNameValue() */
456 : /************************************************************************/
457 :
458 : /**
459 : * Add a name=value entry to the list.
460 : *
461 : * A key=value string is prepared and appended to the list. There is no
462 : * check for other values for the same key in the list.
463 : *
464 : * @param pszKey the key name to add.
465 : * @param pszValue the key value to add.
466 : */
467 :
468 3692400 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
469 : const char *pszValue)
470 :
471 : {
472 3692400 : if (pszKey == nullptr || pszValue == nullptr)
473 3272 : return *this;
474 :
475 3689120 : if (!MakeOurOwnCopy())
476 0 : return *this;
477 :
478 : /* -------------------------------------------------------------------- */
479 : /* Format the line. */
480 : /* -------------------------------------------------------------------- */
481 7378420 : if (strlen(pszKey) >
482 7378380 : std::numeric_limits<size_t>::max() - strlen(pszValue) ||
483 3689140 : strlen(pszKey) + strlen(pszValue) >
484 3689140 : std::numeric_limits<size_t>::max() - 2)
485 : {
486 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
487 : "Too big strings in AddNameValue()");
488 0 : return *this;
489 : }
490 3689240 : const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
491 3689240 : char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
492 3689220 : if (pszLine == nullptr)
493 0 : return *this;
494 3689220 : snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
495 :
496 : /* -------------------------------------------------------------------- */
497 : /* If we don't need to keep the sort order things are pretty */
498 : /* straight forward. */
499 : /* -------------------------------------------------------------------- */
500 3689220 : if (!IsSorted())
501 3681460 : return AddStringDirectly(pszLine);
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Find the proper insertion point. */
505 : /* -------------------------------------------------------------------- */
506 7719 : CPLAssert(IsSorted());
507 7683 : const int iKey = FindSortedInsertionPoint(pszLine);
508 7683 : InsertStringDirectly(iKey, pszLine);
509 7683 : bIsSorted = true; // We have actually preserved sort order.
510 :
511 7683 : return *this;
512 : }
513 :
514 : /************************************************************************/
515 : /* SetNameValue() */
516 : /************************************************************************/
517 :
518 : /**
519 : * Set name=value entry in the list.
520 : *
521 : * Similar to AddNameValue(), except if there is already a value for
522 : * the key in the list it is replaced instead of adding a new entry to
523 : * the list. If pszValue is NULL any existing key entry is removed.
524 : *
525 : * @param pszKey the key name to add.
526 : * @param pszValue the key value to add.
527 : */
528 :
529 3737790 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
530 : const char *pszValue)
531 :
532 : {
533 3737790 : int iKey = FindName(pszKey);
534 :
535 3737760 : if (iKey == -1)
536 3658950 : return AddNameValue(pszKey, pszValue);
537 :
538 78815 : Count();
539 78691 : if (!MakeOurOwnCopy())
540 0 : return *this;
541 :
542 78691 : CPLFree(papszList[iKey]);
543 78691 : if (pszValue == nullptr) // delete entry
544 : {
545 :
546 : // shift everything down by one.
547 116 : do
548 : {
549 218 : papszList[iKey] = papszList[iKey + 1];
550 218 : } while (papszList[iKey++] != nullptr);
551 :
552 102 : nCount--;
553 : }
554 : else
555 : {
556 157178 : if (strlen(pszKey) >
557 157178 : std::numeric_limits<size_t>::max() - strlen(pszValue) ||
558 78590 : strlen(pszKey) + strlen(pszValue) >
559 78590 : std::numeric_limits<size_t>::max() - 2)
560 : {
561 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
562 : "Too big strings in AddNameValue()");
563 0 : return *this;
564 : }
565 78589 : const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
566 78589 : char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
567 78590 : if (pszLine == nullptr)
568 0 : return *this;
569 78590 : snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
570 :
571 78590 : papszList[iKey] = pszLine;
572 : }
573 :
574 78692 : return *this;
575 : }
576 :
577 : /************************************************************************/
578 : /* operator[] */
579 : /************************************************************************/
580 :
581 : /**
582 : * Fetch entry "i".
583 : *
584 : * Fetches the requested item in the list. Note that the returned string
585 : * remains owned by the CPLStringList. If "i" is out of range NULL is
586 : * returned.
587 : *
588 : * @param i the index of the list item to return.
589 : * @return selected entry in the list.
590 : */
591 1078520 : char *CPLStringList::operator[](int i)
592 :
593 : {
594 1078520 : if (nCount == -1)
595 183 : Count();
596 :
597 1078520 : if (i < 0 || i >= nCount)
598 49 : return nullptr;
599 :
600 1078470 : return papszList[i];
601 : }
602 :
603 276196 : const char *CPLStringList::operator[](int i) const
604 :
605 : {
606 276196 : if (nCount == -1)
607 1 : Count();
608 :
609 276196 : if (i < 0 || i >= nCount)
610 2 : return nullptr;
611 :
612 276194 : return papszList[i];
613 : }
614 :
615 : /************************************************************************/
616 : /* StealList() */
617 : /************************************************************************/
618 :
619 : /**
620 : * Seize ownership of underlying string array.
621 : *
622 : * This method is similar to List(), except that the returned list is
623 : * now owned by the caller and the CPLStringList is emptied.
624 : *
625 : * @return the C style string list.
626 : */
627 1325060 : char **CPLStringList::StealList()
628 :
629 : {
630 1325060 : char **papszRetList = papszList;
631 :
632 1325060 : bOwnList = false;
633 1325060 : papszList = nullptr;
634 1325060 : nCount = 0;
635 1325060 : nAllocation = 0;
636 :
637 1325060 : return papszRetList;
638 : }
639 :
640 : /* Case insensitive comparison function */
641 540269 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
642 : {
643 540269 : const char *pszItera = pszKVa;
644 540269 : const char *pszIterb = pszKVb;
645 : while (true)
646 : {
647 5078560 : char cha = *pszItera;
648 5078560 : char chb = *pszIterb;
649 5078560 : if (cha == '=' || cha == '\0')
650 : {
651 2640 : if (chb == '=' || chb == '\0')
652 97 : return 0;
653 : else
654 2543 : return -1;
655 : }
656 5075920 : if (chb == '=' || chb == '\0')
657 : {
658 3017 : return 1;
659 : }
660 5072900 : if (cha >= 'a' && cha <= 'z')
661 1289210 : cha -= ('a' - 'A');
662 5072900 : if (chb >= 'a' && chb <= 'z')
663 1297710 : chb -= ('a' - 'A');
664 5072900 : if (cha < chb)
665 318418 : return -1;
666 4754480 : else if (cha > chb)
667 216194 : return 1;
668 4538290 : pszItera++;
669 4538290 : pszIterb++;
670 4538290 : }
671 : }
672 :
673 : /************************************************************************/
674 : /* Sort() */
675 : /************************************************************************/
676 :
677 : /**
678 : * Sort the entries in the list and mark list sorted.
679 : *
680 : * Note that once put into "sorted" mode, the CPLStringList will attempt to
681 : * keep things in sorted order through calls to AddString(),
682 : * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
683 : * assignments (via Assign() and operator= will clear the sorting state.
684 : * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
685 : * will do a binary search to find the key, substantially improve lookup
686 : * performance in large lists.
687 : */
688 :
689 28458 : CPLStringList &CPLStringList::Sort()
690 :
691 : {
692 28458 : Count();
693 28458 : if (!MakeOurOwnCopy())
694 0 : return *this;
695 :
696 28458 : if (nCount > 1)
697 : {
698 3889 : std::sort(papszList, papszList + nCount,
699 477333 : [](const char *a, const char *b)
700 477333 : { return CPLCompareKeyValueString(a, b) < 0; });
701 : }
702 28458 : bIsSorted = true;
703 :
704 28458 : return *this;
705 : }
706 :
707 : /************************************************************************/
708 : /* FindName() */
709 : /************************************************************************/
710 :
711 : /**
712 : * Get index of given name/value keyword.
713 : *
714 : * Note that this search is for a line in the form name=value or name:value.
715 : * Use FindString() or PartialFindString() for searches not based on name=value
716 : * pairs.
717 : *
718 : * @param pszKey the name to search for.
719 : *
720 : * @return the string list index of this name, or -1 on failure.
721 : */
722 :
723 15397200 : int CPLStringList::FindName(const char *pszKey) const
724 :
725 : {
726 15397200 : if (!IsSorted())
727 15356500 : return CSLFindName(papszList, pszKey);
728 :
729 : // If we are sorted, we can do an optimized binary search.
730 26975 : int iStart = 0;
731 26975 : int iEnd = nCount - 1;
732 26975 : size_t nKeyLen = strlen(pszKey);
733 :
734 63491 : while (iStart <= iEnd)
735 : {
736 43332 : const int iMiddle = (iEnd + iStart) / 2;
737 43332 : const char *pszMiddle = papszList[iMiddle];
738 :
739 43332 : if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
740 7260 : (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
741 6816 : return iMiddle;
742 :
743 36516 : if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
744 11423 : iEnd = iMiddle - 1;
745 : else
746 25093 : iStart = iMiddle + 1;
747 : }
748 :
749 20159 : return -1;
750 : }
751 :
752 : /************************************************************************/
753 : /* FetchBool() */
754 : /************************************************************************/
755 : /**
756 : *
757 : * Check for boolean key value.
758 : *
759 : * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
760 : * with the given name, and if it can be interpreted as being TRUE. If
761 : * the key appears without any "=Value" portion it will be considered true.
762 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
763 : * if the key appears in the list it will be considered TRUE. If the key
764 : * doesn't appear at all, the indicated default value will be returned.
765 : *
766 : * @param pszKey the key value to look for (case insensitive).
767 : * @param bDefault the value to return if the key isn't found at all.
768 : *
769 : * @return true or false
770 : */
771 :
772 5811 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
773 :
774 : {
775 5811 : const char *pszValue = FetchNameValue(pszKey);
776 :
777 5811 : if (pszValue == nullptr)
778 5755 : return bDefault;
779 :
780 56 : return CPLTestBool(pszValue);
781 : }
782 :
783 : /************************************************************************/
784 : /* FetchBoolean() */
785 : /************************************************************************/
786 : /**
787 : *
788 : * DEPRECATED: Check for boolean key value.
789 : *
790 : * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
791 : * with the given name, and if it can be interpreted as being TRUE. If
792 : * the key appears without any "=Value" portion it will be considered true.
793 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
794 : * if the key appears in the list it will be considered TRUE. If the key
795 : * doesn't appear at all, the indicated default value will be returned.
796 : *
797 : * @param pszKey the key value to look for (case insensitive).
798 : * @param bDefault the value to return if the key isn't found at all.
799 : *
800 : * @return TRUE or FALSE
801 : */
802 :
803 3132 : int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
804 :
805 : {
806 3132 : return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
807 : }
808 :
809 : /************************************************************************/
810 : /* FetchNameValue() */
811 : /************************************************************************/
812 :
813 : /**
814 : * Fetch value associated with this key name.
815 : *
816 : * If this list sorted, a fast binary search is done, otherwise a linear
817 : * scan is done. Name lookup is case insensitive.
818 : *
819 : * @param pszName the key name to search for.
820 : *
821 : * @return the corresponding value or NULL if not found. The returned string
822 : * should not be modified and points into internal object state that may
823 : * change on future calls.
824 : */
825 :
826 11655900 : const char *CPLStringList::FetchNameValue(const char *pszName) const
827 :
828 : {
829 11655900 : const int iKey = FindName(pszName);
830 :
831 11681100 : if (iKey == -1)
832 3928120 : return nullptr;
833 :
834 7752960 : CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
835 : papszList[iKey][strlen(pszName)] == ':');
836 :
837 7752960 : return papszList[iKey] + strlen(pszName) + 1;
838 : }
839 :
840 : /************************************************************************/
841 : /* FetchNameValueDef() */
842 : /************************************************************************/
843 :
844 : /**
845 : * Fetch value associated with this key name.
846 : *
847 : * If this list sorted, a fast binary search is done, otherwise a linear
848 : * scan is done. Name lookup is case insensitive.
849 : *
850 : * @param pszName the key name to search for.
851 : * @param pszDefault the default value returned if the named entry isn't found.
852 : *
853 : * @return the corresponding value or the passed default if not found.
854 : */
855 :
856 31042 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
857 : const char *pszDefault) const
858 :
859 : {
860 31042 : const char *pszValue = FetchNameValue(pszName);
861 31040 : if (pszValue == nullptr)
862 22544 : return pszDefault;
863 :
864 8496 : return pszValue;
865 : }
866 :
867 : /************************************************************************/
868 : /* InsertString() */
869 : /************************************************************************/
870 :
871 : /**
872 : * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
873 : * const char *pszNewLine );
874 : *
875 : * \brief Insert into the list at identified location.
876 : *
877 : * This method will insert a string into the list at the identified
878 : * location. The insertion point must be within or at the end of the list.
879 : * The following entries are pushed down to make space.
880 : *
881 : * @param nInsertAtLineNo the line to insert at, zero to insert at front.
882 : * @param pszNewLine to the line to insert. This string will be copied.
883 : */
884 :
885 : /************************************************************************/
886 : /* InsertStringDirectly() */
887 : /************************************************************************/
888 :
889 : /**
890 : * Insert into the list at identified location.
891 : *
892 : * This method will insert a string into the list at the identified
893 : * location. The insertion point must be within or at the end of the list.
894 : * The following entries are pushed down to make space.
895 : *
896 : * @param nInsertAtLineNo the line to insert at, zero to insert at front.
897 : * @param pszNewLine to the line to insert, the ownership of this string
898 : * will be taken over the by the object. It must have been allocated on the
899 : * heap.
900 : */
901 :
902 7901 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
903 : char *pszNewLine)
904 :
905 : {
906 7901 : if (nCount == -1)
907 27 : Count();
908 :
909 7901 : if (!EnsureAllocation(nCount + 1))
910 : {
911 0 : VSIFree(pszNewLine);
912 0 : return *this;
913 : }
914 :
915 7901 : if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
916 : {
917 0 : CPLError(CE_Failure, CPLE_AppDefined,
918 : "CPLStringList::InsertString() requested beyond list end.");
919 0 : return *this;
920 : }
921 :
922 7901 : bIsSorted = false;
923 :
924 39862 : for (int i = nCount; i > nInsertAtLineNo; i--)
925 31961 : papszList[i] = papszList[i - 1];
926 :
927 7901 : papszList[nInsertAtLineNo] = pszNewLine;
928 7901 : papszList[++nCount] = nullptr;
929 :
930 7901 : return *this;
931 : }
932 :
933 : /************************************************************************/
934 : /* FindSortedInsertionPoint() */
935 : /* */
936 : /* Find the location at which the indicated line should be */
937 : /* inserted in order to keep things in sorted order. */
938 : /************************************************************************/
939 :
940 7683 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
941 :
942 : {
943 7683 : CPLAssert(IsSorted());
944 :
945 7683 : int iStart = 0;
946 7683 : int iEnd = nCount - 1;
947 :
948 26763 : while (iStart <= iEnd)
949 : {
950 19080 : const int iMiddle = (iEnd + iStart) / 2;
951 19080 : const char *pszMiddle = papszList[iMiddle];
952 :
953 19080 : if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
954 4992 : iEnd = iMiddle - 1;
955 : else
956 14088 : iStart = iMiddle + 1;
957 : }
958 :
959 7683 : iEnd++;
960 7683 : CPLAssert(iEnd >= 0 && iEnd <= nCount);
961 7683 : CPLAssert(iEnd == 0 ||
962 : CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
963 7683 : CPLAssert(iEnd == nCount ||
964 : CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
965 :
966 7683 : return iEnd;
967 : }
968 :
969 : namespace cpl
970 : {
971 :
972 : /************************************************************************/
973 : /* CSLIterator::operator==(const CSLIterator &other) */
974 : /************************************************************************/
975 :
976 : /*! @cond Doxygen_Suppress */
977 254686 : bool CSLIterator::operator==(const CSLIterator &other) const
978 : {
979 254686 : if (!m_bAtEnd && other.m_bAtEnd)
980 : {
981 254683 : return m_papszList == nullptr || *m_papszList == nullptr;
982 : }
983 3 : if (!m_bAtEnd && !other.m_bAtEnd)
984 : {
985 0 : return m_papszList == other.m_papszList;
986 : }
987 3 : if (m_bAtEnd && other.m_bAtEnd)
988 : {
989 0 : return true;
990 : }
991 3 : return false;
992 : }
993 :
994 : /*! @endcond */
995 :
996 : /************************************************************************/
997 : /* CSLNameValueIterator::operator*() */
998 : /************************************************************************/
999 :
1000 : /*! @cond Doxygen_Suppress */
1001 1231 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
1002 : {
1003 1231 : if (m_papszList)
1004 : {
1005 1232 : while (*m_papszList)
1006 : {
1007 1232 : char *pszKey = nullptr;
1008 1232 : const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
1009 1232 : if (pszKey)
1010 : {
1011 1229 : m_osKey = pszKey;
1012 1229 : CPLFree(pszKey);
1013 1229 : return {m_osKey.c_str(), pszValue};
1014 : }
1015 3 : else if (m_bReturnNullKeyIfNotNameValue)
1016 : {
1017 2 : return {nullptr, *m_papszList};
1018 : }
1019 : // Skip entries that are not name=value pairs.
1020 1 : ++m_papszList;
1021 : }
1022 : }
1023 : // Should not happen
1024 0 : CPLAssert(false);
1025 : return {"", ""};
1026 : }
1027 :
1028 : /*! @endcond */
1029 :
1030 : /************************************************************************/
1031 : /* CSLNameValueIteratorWrapper::end() */
1032 : /************************************************************************/
1033 :
1034 : /*! @cond Doxygen_Suppress */
1035 3693 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
1036 : {
1037 3693 : int nCount = CSLCount(m_papszList);
1038 3693 : if (!m_bReturnNullKeyIfNotNameValue)
1039 : {
1040 3631 : while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
1041 12 : --nCount;
1042 : }
1043 3693 : return CSLNameValueIterator{m_papszList + nCount,
1044 3693 : m_bReturnNullKeyIfNotNameValue};
1045 : }
1046 :
1047 : /*! @endcond */
1048 :
1049 : } // namespace cpl
|