LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 302 330 91.5 %
Date: 2025-01-18 12:42:00 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     1818560 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
      48     1818560 :     : CPLStringList()
      49             : 
      50             : {
      51     1815180 :     Assign(papszListIn, bTakeOwnership);
      52     1810930 : }
      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        3780 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
      67             : 
      68             : {
      69        3780 :     Assign(CSLDuplicate(papszListIn));
      70        3780 : }
      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         551 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
      86             : {
      87         551 :     if (!aosList.empty())
      88             :     {
      89         272 :         bOwnList = true;
      90         272 :         papszList = static_cast<char **>(
      91         272 :             VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
      92         272 :         nCount = static_cast<int>(aosList.size());
      93        1214 :         for (int i = 0; i < nCount; ++i)
      94             :         {
      95         942 :             papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
      96             :         }
      97             :     }
      98         551 : }
      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       21152 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
     127             : 
     128             : {
     129       21152 :     operator=(oOther);
     130       21153 : }
     131             : 
     132             : /************************************************************************/
     133             : /*                           CPLStringList()                            */
     134             : /************************************************************************/
     135             : 
     136             : //! Move constructor
     137     3129090 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
     138             : 
     139             : {
     140     3112860 :     operator=(std::move(oOther));
     141     3123080 : }
     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       36599 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
     169             : {
     170       36599 :     if (this != &oOther)
     171             :     {
     172       36598 :         char **l_papszList = CSLDuplicate(oOther.papszList);
     173       36599 :         if (l_papszList)
     174             :         {
     175        6075 :             Assign(l_papszList, TRUE);
     176        6074 :             nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
     177        6074 :             nCount = oOther.nCount;
     178        6074 :             bIsSorted = oOther.bIsSorted;
     179             :         }
     180             :     }
     181             : 
     182       36599 :     return *this;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                             operator=()                              */
     187             : /************************************************************************/
     188             : 
     189     3122700 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
     190             : {
     191     3122700 :     if (this != &oOther)
     192             :     {
     193     3125650 :         Clear();
     194     3120230 :         papszList = oOther.papszList;
     195     3120230 :         oOther.papszList = nullptr;
     196     3120230 :         nCount = oOther.nCount;
     197     3120230 :         oOther.nCount = 0;
     198     3120230 :         nAllocation = oOther.nAllocation;
     199     3120230 :         oOther.nAllocation = 0;
     200     3120230 :         bOwnList = oOther.bOwnList;
     201     3120230 :         oOther.bOwnList = false;
     202     3120230 :         bIsSorted = oOther.bIsSorted;
     203     3120230 :         oOther.bIsSorted = true;
     204             :     }
     205             : 
     206     3117270 :     return *this;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                             operator=()                              */
     211             : /************************************************************************/
     212             : 
     213       30960 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
     214             : {
     215       30960 :     if (papszListIn != papszList)
     216             :     {
     217       13137 :         Assign(CSLDuplicate(papszListIn));
     218       13137 :         bIsSorted = false;
     219             :     }
     220             : 
     221       30960 :     return *this;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                           ~CPLStringList()                           */
     226             : /************************************************************************/
     227             : 
     228    18796700 : CPLStringList::~CPLStringList()
     229             : 
     230             : {
     231     9412250 :     Clear();
     232     9384470 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                               Clear()                                */
     236             : /************************************************************************/
     237             : 
     238             : /**
     239             :  * Clear the string list.
     240             :  */
     241    14557800 : CPLStringList &CPLStringList::Clear()
     242             : 
     243             : {
     244    14557800 :     if (bOwnList)
     245             :     {
     246     2618670 :         CSLDestroy(papszList);
     247     2619510 :         papszList = nullptr;
     248             : 
     249     2619510 :         bOwnList = FALSE;
     250     2619510 :         nAllocation = 0;
     251     2619510 :         nCount = 0;
     252             :     }
     253             : 
     254    14558700 :     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     1924890 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
     273             : 
     274             : {
     275     1924890 :     Clear();
     276             : 
     277     1916510 :     papszList = papszListIn;
     278     1916510 :     bOwnList = CPL_TO_BOOL(bTakeOwnership);
     279             : 
     280     1913270 :     if (papszList == nullptr || *papszList == nullptr)
     281     1532910 :         nCount = 0;
     282             :     else
     283      380358 :         nCount = -1;  // unknown
     284             : 
     285     1913270 :     nAllocation = 0;
     286     1913270 :     bIsSorted = FALSE;
     287             : 
     288     1913270 :     return *this;
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                               Count()                                */
     293             : /************************************************************************/
     294             : 
     295             : /**
     296             :  * @return count of strings in the list, zero if empty.
     297             :  */
     298             : 
     299     2355710 : int CPLStringList::Count() const
     300             : 
     301             : {
     302     2355710 :     if (nCount == -1)
     303             :     {
     304      367254 :         if (papszList == nullptr)
     305             :         {
     306           0 :             nCount = 0;
     307           0 :             nAllocation = 0;
     308             :         }
     309             :         else
     310             :         {
     311      367254 :             nCount = CSLCount(papszList);
     312      367254 :             nAllocation = std::max(nCount + 1, nAllocation);
     313             :         }
     314             :     }
     315             : 
     316     2355680 :     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     6316150 : bool CPLStringList::MakeOurOwnCopy()
     327             : 
     328             : {
     329     6316150 :     if (bOwnList)
     330     3557860 :         return true;
     331             : 
     332     2758290 :     if (papszList == nullptr)
     333     2758130 :         return true;
     334             : 
     335         163 :     Count();
     336          82 :     char **papszListNew = CSLDuplicate(papszList);
     337          82 :     if (papszListNew == nullptr)
     338             :     {
     339           0 :         return false;
     340             :     }
     341          82 :     papszList = papszListNew;
     342          82 :     bOwnList = true;
     343          82 :     nAllocation = nCount + 1;
     344          82 :     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     9253180 : bool CPLStringList::EnsureAllocation(int nMaxList)
     356             : 
     357             : {
     358     9253180 :     if (!bOwnList)
     359             :     {
     360     2247660 :         if (!MakeOurOwnCopy())
     361           0 :             return false;
     362             :     }
     363             : 
     364     9253110 :     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     4617020 :         if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
     369     2308710 :             static_cast<size_t>(nMaxList) >
     370     2308710 :                 std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
     371             :         {
     372           0 :             return false;
     373             :         }
     374     2308440 :         int nNewAllocation = nMaxList + 1;
     375     2308440 :         if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
     376             :                                   static_cast<int>(sizeof(char *)))
     377     2308610 :             nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
     378     2308470 :         if (papszList == nullptr)
     379             :         {
     380     2249950 :             papszList = static_cast<char **>(
     381     2249880 :                 VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
     382     2249950 :             bOwnList = true;
     383     2249950 :             nCount = 0;
     384     2249950 :             if (papszList == nullptr)
     385           0 :                 return false;
     386             :         }
     387             :         else
     388             :         {
     389       58598 :             char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
     390             :                 papszList, nNewAllocation * sizeof(char *)));
     391       58598 :             if (papszListNew == nullptr)
     392           0 :                 return false;
     393       58598 :             papszList = papszListNew;
     394             :         }
     395     2308550 :         nAllocation = nNewAllocation;
     396             :     }
     397     9253090 :     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     9246230 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
     414             : 
     415             : {
     416     9246230 :     if (nCount == -1)
     417         214 :         Count();
     418             : 
     419     9246230 :     if (!EnsureAllocation(nCount + 1))
     420             :     {
     421          33 :         VSIFree(pszNewString);
     422           0 :         return *this;
     423             :     }
     424             : 
     425     9246240 :     papszList[nCount++] = pszNewString;
     426     9246240 :     papszList[nCount] = nullptr;
     427             : 
     428     9246240 :     bIsSorted = false;
     429             : 
     430     9246240 :     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     5296580 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
     446             : 
     447             : {
     448     5296580 :     char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
     449     5296500 :     if (pszDupString == nullptr)
     450           0 :         return *this;
     451     5296500 :     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     3959160 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
     469             :                                            const char *pszValue)
     470             : 
     471             : {
     472     3959160 :     if (pszKey == nullptr || pszValue == nullptr)
     473        3183 :         return *this;
     474             : 
     475     3955980 :     if (!MakeOurOwnCopy())
     476           0 :         return *this;
     477             : 
     478             :     /* -------------------------------------------------------------------- */
     479             :     /*      Format the line.                                                */
     480             :     /* -------------------------------------------------------------------- */
     481     7912180 :     if (strlen(pszKey) >
     482     7912130 :             std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     483     3955980 :         strlen(pszKey) + strlen(pszValue) >
     484     3955980 :             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     3956120 :     const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     491     3956120 :     char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     492     3956100 :     if (pszLine == nullptr)
     493           0 :         return *this;
     494     3956100 :     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     3956100 :     if (!IsSorted())
     501     3949410 :         return AddStringDirectly(pszLine);
     502             : 
     503             :     /* -------------------------------------------------------------------- */
     504             :     /*      Find the proper insertion point.                                */
     505             :     /* -------------------------------------------------------------------- */
     506        6616 :     CPLAssert(IsSorted());
     507        6593 :     const int iKey = FindSortedInsertionPoint(pszLine);
     508        6593 :     InsertStringDirectly(iKey, pszLine);
     509        6593 :     bIsSorted = true;  // We have actually preserved sort order.
     510             : 
     511        6593 :     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     4009310 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
     530             :                                            const char *pszValue)
     531             : 
     532             : {
     533     4009310 :     int iKey = FindName(pszKey);
     534             : 
     535     4009250 :     if (iKey == -1)
     536     3925610 :         return AddNameValue(pszKey, pszValue);
     537             : 
     538       83637 :     Count();
     539       83547 :     if (!MakeOurOwnCopy())
     540           0 :         return *this;
     541             : 
     542       83547 :     CPLFree(papszList[iKey]);
     543       83547 :     if (pszValue == nullptr)  // delete entry
     544             :     {
     545             : 
     546             :         // shift everything down by one.
     547         117 :         do
     548             :         {
     549         220 :             papszList[iKey] = papszList[iKey + 1];
     550         220 :         } while (papszList[iKey++] != nullptr);
     551             : 
     552         103 :         nCount--;
     553             :     }
     554             :     else
     555             :     {
     556      166888 :         if (strlen(pszKey) >
     557      166888 :                 std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     558       83444 :             strlen(pszKey) + strlen(pszValue) >
     559       83444 :                 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       83444 :         const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     566       83444 :         char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     567       83444 :         if (pszLine == nullptr)
     568           0 :             return *this;
     569       83444 :         snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     570             : 
     571       83444 :         papszList[iKey] = pszLine;
     572             :     }
     573             : 
     574       83547 :     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     1086610 : char *CPLStringList::operator[](int i)
     592             : 
     593             : {
     594     1086610 :     if (nCount == -1)
     595         181 :         Count();
     596             : 
     597     1086610 :     if (i < 0 || i >= nCount)
     598          52 :         return nullptr;
     599             : 
     600     1086560 :     return papszList[i];
     601             : }
     602             : 
     603      323495 : const char *CPLStringList::operator[](int i) const
     604             : 
     605             : {
     606      323495 :     if (nCount == -1)
     607           6 :         Count();
     608             : 
     609      323495 :     if (i < 0 || i >= nCount)
     610           2 :         return nullptr;
     611             : 
     612      323493 :     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     1341300 : char **CPLStringList::StealList()
     628             : 
     629             : {
     630     1341300 :     char **papszRetList = papszList;
     631             : 
     632     1341300 :     bOwnList = false;
     633     1341300 :     papszList = nullptr;
     634     1341300 :     nCount = 0;
     635     1341300 :     nAllocation = 0;
     636             : 
     637     1341300 :     return papszRetList;
     638             : }
     639             : 
     640             : /* Case insensitive comparison function */
     641      485930 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
     642             : {
     643      485930 :     const char *pszItera = pszKVa;
     644      485930 :     const char *pszIterb = pszKVb;
     645             :     while (true)
     646             :     {
     647     3724360 :         char cha = *pszItera;
     648     3724360 :         char chb = *pszIterb;
     649     3724360 :         if (cha == '=' || cha == '\0')
     650             :         {
     651        2410 :             if (chb == '=' || chb == '\0')
     652           2 :                 return 0;
     653             :             else
     654        2408 :                 return -1;
     655             :         }
     656     3721950 :         if (chb == '=' || chb == '\0')
     657             :         {
     658        2872 :             return 1;
     659             :         }
     660     3719080 :         if (cha >= 'a' && cha <= 'z')
     661      490058 :             cha -= ('a' - 'A');
     662     3719080 :         if (chb >= 'a' && chb <= 'z')
     663      490793 :             chb -= ('a' - 'A');
     664     3719080 :         if (cha < chb)
     665      283376 :             return -1;
     666     3435700 :         else if (cha > chb)
     667      197272 :             return 1;
     668     3238430 :         pszItera++;
     669     3238430 :         pszIterb++;
     670     3238430 :     }
     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       28874 : CPLStringList &CPLStringList::Sort()
     690             : 
     691             : {
     692       28874 :     Count();
     693       28874 :     if (!MakeOurOwnCopy())
     694           0 :         return *this;
     695             : 
     696       28874 :     if (nCount > 1)
     697             :     {
     698        3882 :         std::sort(papszList, papszList + nCount,
     699      437086 :                   [](const char *a, const char *b)
     700      437086 :                   { return CPLCompareKeyValueString(a, b) < 0; });
     701             :     }
     702       28874 :     bIsSorted = true;
     703             : 
     704       28874 :     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    15961300 : int CPLStringList::FindName(const char *pszKey) const
     724             : 
     725             : {
     726    15961300 :     if (!IsSorted())
     727    15935600 :         return CSLFindName(papszList, pszKey);
     728             : 
     729             :     // If we are sorted, we can do an optimized binary search.
     730       26014 :     int iStart = 0;
     731       26014 :     int iEnd = nCount - 1;
     732       26014 :     size_t nKeyLen = strlen(pszKey);
     733             : 
     734       56624 :     while (iStart <= iEnd)
     735             :     {
     736       37512 :         const int iMiddle = (iEnd + iStart) / 2;
     737       37512 :         const char *pszMiddle = papszList[iMiddle];
     738             : 
     739       37512 :         if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
     740        7346 :             (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
     741        6902 :             return iMiddle;
     742             : 
     743       30610 :         if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
     744        8749 :             iEnd = iMiddle - 1;
     745             :         else
     746       21861 :             iStart = iMiddle + 1;
     747             :     }
     748             : 
     749       19112 :     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       12795 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
     773             : 
     774             : {
     775       12795 :     const char *pszValue = FetchNameValue(pszKey);
     776             : 
     777       12795 :     if (pszValue == nullptr)
     778       12586 :         return bDefault;
     779             : 
     780         209 :     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    11953200 : const char *CPLStringList::FetchNameValue(const char *pszName) const
     827             : 
     828             : {
     829    11953200 :     const int iKey = FindName(pszName);
     830             : 
     831    11942900 :     if (iKey == -1)
     832     4046280 :         return nullptr;
     833             : 
     834     7896640 :     CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
     835             :               papszList[iKey][strlen(pszName)] == ':');
     836             : 
     837     7896640 :     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       31671 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
     857             :                                              const char *pszDefault) const
     858             : 
     859             : {
     860       31671 :     const char *pszValue = FetchNameValue(pszName);
     861       31671 :     if (pszValue == nullptr)
     862       23118 :         return pszDefault;
     863             : 
     864        8553 :     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        6811 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
     903             :                                                    char *pszNewLine)
     904             : 
     905             : {
     906        6811 :     if (nCount == -1)
     907          27 :         Count();
     908             : 
     909        6811 :     if (!EnsureAllocation(nCount + 1))
     910             :     {
     911           0 :         VSIFree(pszNewLine);
     912           0 :         return *this;
     913             :     }
     914             : 
     915        6811 :     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        6811 :     bIsSorted = false;
     923             : 
     924       23264 :     for (int i = nCount; i > nInsertAtLineNo; i--)
     925       16453 :         papszList[i] = papszList[i - 1];
     926             : 
     927        6811 :     papszList[nInsertAtLineNo] = pszNewLine;
     928        6811 :     papszList[++nCount] = nullptr;
     929             : 
     930        6811 :     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        6593 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
     941             : 
     942             : {
     943        6593 :     CPLAssert(IsSorted());
     944             : 
     945        6593 :     int iStart = 0;
     946        6593 :     int iEnd = nCount - 1;
     947             : 
     948       19676 :     while (iStart <= iEnd)
     949             :     {
     950       13083 :         const int iMiddle = (iEnd + iStart) / 2;
     951       13083 :         const char *pszMiddle = papszList[iMiddle];
     952             : 
     953       13083 :         if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
     954        2265 :             iEnd = iMiddle - 1;
     955             :         else
     956       10818 :             iStart = iMiddle + 1;
     957             :     }
     958             : 
     959        6593 :     iEnd++;
     960        6593 :     CPLAssert(iEnd >= 0 && iEnd <= nCount);
     961        6593 :     CPLAssert(iEnd == 0 ||
     962             :               CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
     963        6593 :     CPLAssert(iEnd == nCount ||
     964             :               CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
     965             : 
     966        6593 :     return iEnd;
     967             : }
     968             : 
     969             : namespace cpl
     970             : {
     971             : 
     972             : /************************************************************************/
     973             : /*             CSLIterator::operator==(const CSLIterator &other)        */
     974             : /************************************************************************/
     975             : 
     976             : /*! @cond Doxygen_Suppress */
     977      263768 : bool CSLIterator::operator==(const CSLIterator &other) const
     978             : {
     979      263768 :     if (!m_bAtEnd && other.m_bAtEnd)
     980             :     {
     981      263769 :         return m_papszList == nullptr || *m_papszList == nullptr;
     982             :     }
     983           0 :     if (!m_bAtEnd && !other.m_bAtEnd)
     984             :     {
     985           0 :         return m_papszList == other.m_papszList;
     986             :     }
     987           0 :     if (m_bAtEnd && other.m_bAtEnd)
     988             :     {
     989           0 :         return true;
     990             :     }
     991           0 :     return false;
     992             : }
     993             : 
     994             : /*! @endcond */
     995             : 
     996             : /************************************************************************/
     997             : /*                      CSLNameValueIterator::operator*()               */
     998             : /************************************************************************/
     999             : 
    1000             : /*! @cond Doxygen_Suppress */
    1001        1302 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
    1002             : {
    1003        1302 :     if (m_papszList)
    1004             :     {
    1005        1303 :         while (*m_papszList)
    1006             :         {
    1007        1303 :             char *pszKey = nullptr;
    1008        1303 :             const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
    1009        1303 :             if (pszKey)
    1010             :             {
    1011        1300 :                 m_osKey = pszKey;
    1012        1300 :                 CPLFree(pszKey);
    1013        1300 :                 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        3831 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
    1036             : {
    1037        3831 :     int nCount = CSLCount(m_papszList);
    1038        3831 :     if (!m_bReturnNullKeyIfNotNameValue)
    1039             :     {
    1040        3769 :         while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
    1041          12 :             --nCount;
    1042             :     }
    1043        3831 :     return CSLNameValueIterator{m_papszList + nCount,
    1044        3831 :                                 m_bReturnNullKeyIfNotNameValue};
    1045             : }
    1046             : 
    1047             : /*! @endcond */
    1048             : 
    1049             : }  // namespace cpl

Generated by: LCOV version 1.14