LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 304 330 92.1 %
Date: 2024-11-21 22:18:42 Functions: 36 36 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     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

Generated by: LCOV version 1.14