LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 307 332 92.5 %
Date: 2025-07-03 09:54:33 Functions: 37 37 100.0 %

          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     1935290 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
      48     1935290 :     : CPLStringList()
      49             : 
      50             : {
      51     1935150 :     Assign(papszListIn, bTakeOwnership);
      52     1934550 : }
      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        4323 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
      67             : 
      68             : {
      69        4323 :     Assign(CSLDuplicate(papszListIn));
      70        4323 : }
      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        2670 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
      86             : {
      87        2670 :     if (!aosList.empty())
      88             :     {
      89         545 :         bOwnList = true;
      90         545 :         papszList = static_cast<char **>(
      91         545 :             VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
      92         545 :         nCount = static_cast<int>(aosList.size());
      93        2932 :         for (int i = 0; i < nCount; ++i)
      94             :         {
      95        2387 :             papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
      96             :         }
      97             :     }
      98        2670 : }
      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       24864 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
     127             : 
     128             : {
     129       24864 :     operator=(oOther);
     130       24865 : }
     131             : 
     132             : /************************************************************************/
     133             : /*                           CPLStringList()                            */
     134             : /************************************************************************/
     135             : 
     136             : //! Move constructor
     137     3546480 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
     138             : 
     139             : {
     140     3541330 :     operator=(std::move(oOther));
     141     3543400 : }
     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      275820 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
     169             : {
     170      275820 :     if (this != &oOther)
     171             :     {
     172      275819 :         char **l_papszList = CSLDuplicate(oOther.papszList);
     173      275820 :         if (l_papszList)
     174             :         {
     175        6248 :             Assign(l_papszList, TRUE);
     176        6249 :             nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
     177        6249 :             nCount = oOther.nCount;
     178        6249 :             bIsSorted = oOther.bIsSorted;
     179             :         }
     180             :     }
     181             : 
     182      275822 :     return *this;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                             operator=()                              */
     187             : /************************************************************************/
     188             : 
     189     3549450 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
     190             : {
     191     3549450 :     if (this != &oOther)
     192             :     {
     193     3550180 :         Clear();
     194     3549520 :         papszList = oOther.papszList;
     195     3549520 :         oOther.papszList = nullptr;
     196     3549520 :         nCount = oOther.nCount;
     197     3549520 :         oOther.nCount = 0;
     198     3549520 :         nAllocation = oOther.nAllocation;
     199     3549520 :         oOther.nAllocation = 0;
     200     3549520 :         bOwnList = oOther.bOwnList;
     201     3549520 :         oOther.bOwnList = false;
     202     3549520 :         bIsSorted = oOther.bIsSorted;
     203     3549520 :         oOther.bIsSorted = true;
     204             :     }
     205             : 
     206     3548790 :     return *this;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                             operator=()                              */
     211             : /************************************************************************/
     212             : 
     213       99885 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
     214             : {
     215       99885 :     if (papszListIn != papszList)
     216             :     {
     217       15411 :         Assign(CSLDuplicate(papszListIn));
     218       15411 :         bIsSorted = false;
     219             :     }
     220             : 
     221       99885 :     return *this;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                           ~CPLStringList()                           */
     226             : /************************************************************************/
     227             : 
     228    24162000 : CPLStringList::~CPLStringList()
     229             : 
     230             : {
     231    12091400 :     Clear();
     232    12070600 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                               Clear()                                */
     236             : /************************************************************************/
     237             : 
     238             : /**
     239             :  * Clear the string list.
     240             :  */
     241    18080800 : CPLStringList &CPLStringList::Clear()
     242             : 
     243             : {
     244    18080800 :     if (bOwnList)
     245             :     {
     246     3200780 :         CSLDestroy(papszList);
     247     3197690 :         papszList = nullptr;
     248             : 
     249     3197690 :         bOwnList = FALSE;
     250     3197690 :         nAllocation = 0;
     251     3197690 :         nCount = 0;
     252             :     }
     253             : 
     254    18077800 :     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     2344420 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
     273             : 
     274             : {
     275     2344420 :     Clear();
     276             : 
     277     2344220 :     papszList = papszListIn;
     278     2344220 :     bOwnList = CPL_TO_BOOL(bTakeOwnership);
     279             : 
     280     2344260 :     if (papszList == nullptr || *papszList == nullptr)
     281     1879940 :         nCount = 0;
     282             :     else
     283      464317 :         nCount = -1;  // unknown
     284             : 
     285     2344260 :     nAllocation = 0;
     286     2344260 :     bIsSorted = FALSE;
     287             : 
     288     2344260 :     return *this;
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                               Count()                                */
     293             : /************************************************************************/
     294             : 
     295             : /**
     296             :  * @return count of strings in the list, zero if empty.
     297             :  */
     298             : 
     299     3112320 : int CPLStringList::Count() const
     300             : 
     301             : {
     302     3112320 :     if (nCount == -1)
     303             :     {
     304      450484 :         if (papszList == nullptr)
     305             :         {
     306           0 :             nCount = 0;
     307           0 :             nAllocation = 0;
     308             :         }
     309             :         else
     310             :         {
     311      450484 :             nCount = CSLCount(papszList);
     312      450488 :             nAllocation = std::max(nCount + 1, nAllocation);
     313             :         }
     314             :     }
     315             : 
     316     3112370 :     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     7453900 : bool CPLStringList::MakeOurOwnCopy()
     327             : 
     328             : {
     329     7453900 :     if (bOwnList)
     330     4147630 :         return true;
     331             : 
     332     3306270 :     if (papszList == nullptr)
     333     3306160 :         return true;
     334             : 
     335         108 :     Count();
     336          86 :     char **papszListNew = CSLDuplicate(papszList);
     337          86 :     if (papszListNew == nullptr)
     338             :     {
     339           0 :         return false;
     340             :     }
     341          86 :     papszList = papszListNew;
     342          86 :     bOwnList = true;
     343          86 :     nAllocation = nCount + 1;
     344          86 :     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    10545600 : bool CPLStringList::EnsureAllocation(int nMaxList)
     356             : 
     357             : {
     358    10545600 :     if (!bOwnList)
     359             :     {
     360     2598490 :         if (!MakeOurOwnCopy())
     361           0 :             return false;
     362             :     }
     363             : 
     364    10545300 :     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     5352570 :         if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
     369     2676700 :             static_cast<size_t>(nMaxList) >
     370     2676700 :                 std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
     371             :         {
     372           0 :             return false;
     373             :         }
     374     2676020 :         int nNewAllocation = nMaxList + 1;
     375     2676020 :         if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
     376             :                                   static_cast<int>(sizeof(char *)))
     377     2676120 :             nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
     378     2676310 :         if (papszList == nullptr)
     379             :         {
     380     2600790 :             papszList = static_cast<char **>(
     381     2600690 :                 VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
     382     2600790 :             bOwnList = true;
     383     2600790 :             nCount = 0;
     384     2600790 :             if (papszList == nullptr)
     385           0 :                 return false;
     386             :         }
     387             :         else
     388             :         {
     389       75622 :             char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
     390             :                 papszList, nNewAllocation * sizeof(char *)));
     391       75623 :             if (papszListNew == nullptr)
     392           0 :                 return false;
     393       75623 :             papszList = papszListNew;
     394             :         }
     395     2676410 :         nAllocation = nNewAllocation;
     396             :     }
     397    10545200 :     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    10538200 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
     414             : 
     415             : {
     416    10538200 :     if (nCount == -1)
     417         289 :         Count();
     418             : 
     419    10538200 :     if (!EnsureAllocation(nCount + 1))
     420             :     {
     421         111 :         VSIFree(pszNewString);
     422           0 :         return *this;
     423             :     }
     424             : 
     425    10538000 :     papszList[nCount++] = pszNewString;
     426    10538000 :     papszList[nCount] = nullptr;
     427             : 
     428    10538000 :     bIsSorted = false;
     429             : 
     430    10538000 :     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     5887030 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
     446             : 
     447             : {
     448     5887030 :     char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
     449     5886780 :     if (pszDupString == nullptr)
     450           0 :         return *this;
     451     5886780 :     return AddStringDirectly(pszDupString);
     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       25023 : CPLStringList &CPLStringList::AddString(const std::string &newString)
     467             : {
     468       25023 :     return AddString(newString.c_str());
     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     4799500 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
     486             :                                            const char *pszValue)
     487             : 
     488             : {
     489     4799500 :     if (pszKey == nullptr || pszValue == nullptr)
     490      142144 :         return *this;
     491             : 
     492     4657360 :     if (!MakeOurOwnCopy())
     493           0 :         return *this;
     494             : 
     495             :     /* -------------------------------------------------------------------- */
     496             :     /*      Format the line.                                                */
     497             :     /* -------------------------------------------------------------------- */
     498     9315160 :     if (strlen(pszKey) >
     499     9315430 :             std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     500     4657980 :         strlen(pszKey) + strlen(pszValue) >
     501     4657980 :             std::numeric_limits<size_t>::max() - 2)
     502             :     {
     503           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     504             :                  "Too big strings in AddNameValue()");
     505           0 :         return *this;
     506             :     }
     507     4657530 :     const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     508     4657530 :     char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     509     4657800 :     if (pszLine == nullptr)
     510           0 :         return *this;
     511     4657800 :     snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     512             : 
     513             :     /* -------------------------------------------------------------------- */
     514             :     /*      If we don't need to keep the sort order things are pretty       */
     515             :     /*      straight forward.                                               */
     516             :     /* -------------------------------------------------------------------- */
     517     4657800 :     if (!IsSorted())
     518     4650880 :         return AddStringDirectly(pszLine);
     519             : 
     520             :     /* -------------------------------------------------------------------- */
     521             :     /*      Find the proper insertion point.                                */
     522             :     /* -------------------------------------------------------------------- */
     523        6753 :     CPLAssert(IsSorted());
     524        6732 :     const int iKey = FindSortedInsertionPoint(pszLine);
     525        6732 :     InsertStringDirectly(iKey, pszLine);
     526        6732 :     bIsSorted = true;  // We have actually preserved sort order.
     527             : 
     528        6732 :     return *this;
     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     4865320 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
     547             :                                            const char *pszValue)
     548             : 
     549             : {
     550     4865320 :     int iKey = FindName(pszKey);
     551             : 
     552     4865080 :     if (iKey == -1)
     553     4764440 :         return AddNameValue(pszKey, pszValue);
     554             : 
     555      100636 :     Count();
     556      100312 :     if (!MakeOurOwnCopy())
     557           0 :         return *this;
     558             : 
     559      100313 :     CPLFree(papszList[iKey]);
     560      100313 :     if (pszValue == nullptr)  // delete entry
     561             :     {
     562             : 
     563             :         // shift everything down by one.
     564         281 :         do
     565             :         {
     566        2338 :             papszList[iKey] = papszList[iKey + 1];
     567        2338 :         } while (papszList[iKey++] != nullptr);
     568             : 
     569        2057 :         nCount--;
     570             :     }
     571             :     else
     572             :     {
     573      196512 :         if (strlen(pszKey) >
     574      196512 :                 std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     575       98256 :             strlen(pszKey) + strlen(pszValue) >
     576       98256 :                 std::numeric_limits<size_t>::max() - 2)
     577             :         {
     578           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     579             :                      "Too big strings in AddNameValue()");
     580           0 :             return *this;
     581             :         }
     582       98256 :         const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     583       98256 :         char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     584       98256 :         if (pszLine == nullptr)
     585           0 :             return *this;
     586       98256 :         snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     587             : 
     588       98256 :         papszList[iKey] = pszLine;
     589             :     }
     590             : 
     591      100313 :     return *this;
     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     1342440 : char *CPLStringList::operator[](int i)
     609             : 
     610             : {
     611     1342440 :     if (nCount == -1)
     612         165 :         Count();
     613             : 
     614     1342440 :     if (i < 0 || i >= nCount)
     615          52 :         return nullptr;
     616             : 
     617     1342380 :     return papszList[i];
     618             : }
     619             : 
     620      454449 : const char *CPLStringList::operator[](int i) const
     621             : 
     622             : {
     623      454449 :     if (nCount == -1)
     624         162 :         Count();
     625             : 
     626      454449 :     if (i < 0 || i >= nCount)
     627           2 :         return nullptr;
     628             : 
     629      454447 :     return papszList[i];
     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     1436980 : char **CPLStringList::StealList()
     645             : 
     646             : {
     647     1436980 :     char **papszRetList = papszList;
     648             : 
     649     1436980 :     bOwnList = false;
     650     1436980 :     papszList = nullptr;
     651     1436980 :     nCount = 0;
     652     1436980 :     nAllocation = 0;
     653             : 
     654     1436980 :     return papszRetList;
     655             : }
     656             : 
     657             : /* Case insensitive comparison function */
     658      758360 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
     659             : {
     660      758360 :     const char *pszItera = pszKVa;
     661      758360 :     const char *pszIterb = pszKVb;
     662             :     while (true)
     663             :     {
     664     5138320 :         char cha = *pszItera;
     665     5138320 :         char chb = *pszIterb;
     666     5138320 :         if (cha == '=' || cha == '\0')
     667             :         {
     668        4047 :             if (chb == '=' || chb == '\0')
     669           2 :                 return 0;
     670             :             else
     671        4045 :                 return -1;
     672             :         }
     673     5134270 :         if (chb == '=' || chb == '\0')
     674             :         {
     675        6372 :             return 1;
     676             :         }
     677     5127900 :         if (cha >= 'a' && cha <= 'z')
     678      498135 :             cha -= ('a' - 'A');
     679     5127900 :         if (chb >= 'a' && chb <= 'z')
     680      498913 :             chb -= ('a' - 'A');
     681     5127900 :         if (cha < chb)
     682      450173 :             return -1;
     683     4677730 :         else if (cha > chb)
     684      297768 :             return 1;
     685     4379960 :         pszItera++;
     686     4379960 :         pszIterb++;
     687     4379960 :     }
     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       97744 : CPLStringList &CPLStringList::Sort()
     707             : 
     708             : {
     709       97744 :     Count();
     710       97744 :     if (!MakeOurOwnCopy())
     711           0 :         return *this;
     712             : 
     713       97744 :     if (nCount > 1)
     714             :     {
     715        5563 :         std::sort(papszList, papszList + nCount,
     716      708020 :                   [](const char *a, const char *b)
     717      708020 :                   { return CPLCompareKeyValueString(a, b) < 0; });
     718             :     }
     719       97744 :     bIsSorted = true;
     720             : 
     721       97744 :     return *this;
     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    16351200 : int CPLStringList::FindName(const char *pszKey) const
     741             : 
     742             : {
     743    16351200 :     if (!IsSorted())
     744    16319600 :         return CSLFindName(papszList, pszKey);
     745             : 
     746             :     // If we are sorted, we can do an optimized binary search.
     747       20870 :     int iStart = 0;
     748       20870 :     int iEnd = nCount - 1;
     749       20870 :     size_t nKeyLen = strlen(pszKey);
     750             : 
     751       52616 :     while (iStart <= iEnd)
     752             :     {
     753       39008 :         const int iMiddle = (iEnd + iStart) / 2;
     754       39008 :         const char *pszMiddle = papszList[iMiddle];
     755             : 
     756       39008 :         if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
     757        7639 :             (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
     758        7262 :             return iMiddle;
     759             : 
     760       31746 :         if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
     761        8879 :             iEnd = iMiddle - 1;
     762             :         else
     763       22867 :             iStart = iMiddle + 1;
     764             :     }
     765             : 
     766       13608 :     return -1;
     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       13344 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
     790             : 
     791             : {
     792       13344 :     const char *pszValue = FetchNameValue(pszKey);
     793             : 
     794       13343 :     if (pszValue == nullptr)
     795       13109 :         return bDefault;
     796             : 
     797         234 :     return CPLTestBool(pszValue);
     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        3201 : int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
     821             : 
     822             : {
     823        3201 :     return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
     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    11468800 : const char *CPLStringList::FetchNameValue(const char *pszName) const
     844             : 
     845             : {
     846    11468800 :     const int iKey = FindName(pszName);
     847             : 
     848    11482200 :     if (iKey == -1)
     849     4002880 :         return nullptr;
     850             : 
     851     7479330 :     CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
     852             :               papszList[iKey][strlen(pszName)] == ':');
     853             : 
     854     7479330 :     return papszList[iKey] + strlen(pszName) + 1;
     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       32047 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
     874             :                                              const char *pszDefault) const
     875             : 
     876             : {
     877       32047 :     const char *pszValue = FetchNameValue(pszName);
     878       32047 :     if (pszValue == nullptr)
     879       24103 :         return pszDefault;
     880             : 
     881        7944 :     return pszValue;
     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        7090 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
     920             :                                                    char *pszNewLine)
     921             : 
     922             : {
     923        7090 :     if (nCount == -1)
     924          27 :         Count();
     925             : 
     926        7090 :     if (!EnsureAllocation(nCount + 1))
     927             :     {
     928           0 :         VSIFree(pszNewLine);
     929           0 :         return *this;
     930             :     }
     931             : 
     932        7090 :     if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
     933             :     {
     934           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     935             :                  "CPLStringList::InsertString() requested beyond list end.");
     936           0 :         return *this;
     937             :     }
     938             : 
     939        7090 :     bIsSorted = false;
     940             : 
     941       24611 :     for (int i = nCount; i > nInsertAtLineNo; i--)
     942       17521 :         papszList[i] = papszList[i - 1];
     943             : 
     944        7090 :     papszList[nInsertAtLineNo] = pszNewLine;
     945        7090 :     papszList[++nCount] = nullptr;
     946             : 
     947        7090 :     return *this;
     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        6732 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
     958             : 
     959             : {
     960        6732 :     CPLAssert(IsSorted());
     961             : 
     962        6732 :     int iStart = 0;
     963        6732 :     int iEnd = nCount - 1;
     964             : 
     965       20049 :     while (iStart <= iEnd)
     966             :     {
     967       13317 :         const int iMiddle = (iEnd + iStart) / 2;
     968       13317 :         const char *pszMiddle = papszList[iMiddle];
     969             : 
     970       13317 :         if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
     971        2294 :             iEnd = iMiddle - 1;
     972             :         else
     973       11023 :             iStart = iMiddle + 1;
     974             :     }
     975             : 
     976        6732 :     iEnd++;
     977        6732 :     CPLAssert(iEnd >= 0 && iEnd <= nCount);
     978        6732 :     CPLAssert(iEnd == 0 ||
     979             :               CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
     980        6732 :     CPLAssert(iEnd == nCount ||
     981             :               CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
     982             : 
     983        6732 :     return iEnd;
     984             : }
     985             : 
     986             : namespace cpl
     987             : {
     988             : 
     989             : /************************************************************************/
     990             : /*             CSLIterator::operator==(const CSLIterator &other)        */
     991             : /************************************************************************/
     992             : 
     993             : /*! @cond Doxygen_Suppress */
     994      270021 : bool CSLIterator::operator==(const CSLIterator &other) const
     995             : {
     996      270021 :     if (!m_bAtEnd && other.m_bAtEnd)
     997             :     {
     998      270020 :         return m_papszList == nullptr || *m_papszList == nullptr;
     999             :     }
    1000           1 :     if (!m_bAtEnd && !other.m_bAtEnd)
    1001             :     {
    1002           0 :         return m_papszList == other.m_papszList;
    1003             :     }
    1004           1 :     if (m_bAtEnd && other.m_bAtEnd)
    1005             :     {
    1006           0 :         return true;
    1007             :     }
    1008           1 :     return false;
    1009             : }
    1010             : 
    1011             : /*! @endcond */
    1012             : 
    1013             : /************************************************************************/
    1014             : /*                      CSLNameValueIterator::operator*()               */
    1015             : /************************************************************************/
    1016             : 
    1017             : /*! @cond Doxygen_Suppress */
    1018        3596 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
    1019             : {
    1020        3596 :     if (m_papszList)
    1021             :     {
    1022        3597 :         while (*m_papszList)
    1023             :         {
    1024        3597 :             char *pszKey = nullptr;
    1025        3597 :             const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
    1026        3597 :             if (pszKey)
    1027             :             {
    1028        3594 :                 m_osKey = pszKey;
    1029        3594 :                 CPLFree(pszKey);
    1030        3594 :                 return {m_osKey.c_str(), pszValue};
    1031             :             }
    1032           3 :             else if (m_bReturnNullKeyIfNotNameValue)
    1033             :             {
    1034           2 :                 return {nullptr, *m_papszList};
    1035             :             }
    1036             :             // Skip entries that are not name=value pairs.
    1037           1 :             ++m_papszList;
    1038             :         }
    1039             :     }
    1040             :     // Should not happen
    1041           0 :     CPLAssert(false);
    1042             :     return {"", ""};
    1043             : }
    1044             : 
    1045             : /*! @endcond */
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                   CSLNameValueIteratorWrapper::end()                 */
    1049             : /************************************************************************/
    1050             : 
    1051             : /*! @cond Doxygen_Suppress */
    1052        5359 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
    1053             : {
    1054        5359 :     int nCount = CSLCount(m_papszList);
    1055        5359 :     if (!m_bReturnNullKeyIfNotNameValue)
    1056             :     {
    1057        5287 :         while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
    1058          12 :             --nCount;
    1059             :     }
    1060        5359 :     return CSLNameValueIterator{m_papszList + nCount,
    1061        5359 :                                 m_bReturnNullKeyIfNotNameValue};
    1062             : }
    1063             : 
    1064             : /*! @endcond */
    1065             : 
    1066             : }  // namespace cpl

Generated by: LCOV version 1.14