LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 337 370 91.1 %
Date: 2026-06-27 16:33:51 Functions: 43 43 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             : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb);
      30             : 
      31             : /************************************************************************/
      32             : /*                           CPLStringList()                            */
      33             : /************************************************************************/
      34             : 
      35             : CPLStringList::CPLStringList() = default;
      36             : 
      37             : /************************************************************************/
      38             : /*                           CPLStringList()                            */
      39             : /************************************************************************/
      40             : 
      41             : /**
      42             :  * CPLStringList constructor.
      43             :  *
      44             :  * @param papszListIn the NULL terminated list of strings to consume.
      45             :  * @param bTakeOwnership TRUE if the CPLStringList should take ownership
      46             :  * of the list of strings which implies responsibility to free them.
      47             :  */
      48             : 
      49     3653330 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
      50     3653330 :     : CPLStringList()
      51             : 
      52             : {
      53     3642450 :     Assign(papszListIn, bTakeOwnership);
      54     3640550 : }
      55             : 
      56             : /************************************************************************/
      57             : /*                           CPLStringList()                            */
      58             : /************************************************************************/
      59             : 
      60             : /**
      61             :  * CPLStringList constructor.
      62             :  *
      63             :  * The input list is copied.
      64             :  *
      65             :  * @param papszListIn the NULL terminated list of strings to ingest.
      66             :  */
      67             : 
      68       18737 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
      69             : 
      70             : {
      71       18737 :     Assign(CSLDuplicate(papszListIn));
      72       18737 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                           CPLStringList()                            */
      76             : /************************************************************************/
      77             : 
      78             : /**
      79             :  * CPLStringList constructor.
      80             :  *
      81             :  * The input list is copied.
      82             :  *
      83             :  * @param aosList input list.
      84             :  *
      85             :  * @since GDAL 3.9
      86             :  */
      87      169389 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
      88             : {
      89      169389 :     if (!aosList.empty())
      90             :     {
      91       47379 :         bOwnList = true;
      92       47379 :         papszList = static_cast<char **>(
      93       47379 :             VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
      94       47379 :         nCount = static_cast<int>(aosList.size());
      95      111863 :         for (int i = 0; i < nCount; ++i)
      96             :         {
      97       64484 :             papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
      98             :         }
      99             :     }
     100      169389 : }
     101             : 
     102             : /************************************************************************/
     103             : /*                           CPLStringList()                            */
     104             : /************************************************************************/
     105             : 
     106             : /**
     107             :  * CPLStringList constructor.
     108             :  *
     109             :  * The input list is copied.
     110             :  *
     111             :  * @param oInitList input list.
     112             :  *
     113             :  * @since GDAL 3.9
     114             :  */
     115           3 : CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
     116             : {
     117           9 :     for (const char *pszStr : oInitList)
     118             :     {
     119           6 :         AddString(pszStr);
     120             :     }
     121           3 : }
     122             : 
     123             : /************************************************************************/
     124             : /*                           CPLStringList()                            */
     125             : /************************************************************************/
     126             : 
     127             : //! Copy constructor
     128       35282 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
     129             : 
     130             : {
     131       35282 :     operator=(oOther);
     132       35283 : }
     133             : 
     134             : /************************************************************************/
     135             : /*                           CPLStringList()                            */
     136             : /************************************************************************/
     137             : 
     138             : //! Move constructor
     139     3706390 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
     140             : 
     141             : {
     142     3698140 :     operator=(std::move(oOther));
     143     3708540 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                          BoundToConstList()                          */
     147             : /************************************************************************/
     148             : 
     149             : /**
     150             :  * Return a CPLStringList that wraps the passed list.
     151             :  *
     152             :  * The input list is *NOT* copied and must be kept alive while the
     153             :  * return CPLStringList is used.
     154             :  *
     155             :  * @param papszListIn a NULL terminated list of strings to wrap into the CPLStringList
     156             :  * @since GDAL 3.9
     157             :  */
     158             : 
     159             : /* static */
     160          98 : const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
     161             : {
     162             :     return CPLStringList(const_cast<char **>(papszListIn),
     163          98 :                          /* bTakeOwnership= */ false);
     164             : }
     165             : 
     166             : /************************************************************************/
     167             : /*                             operator=()                              */
     168             : /************************************************************************/
     169             : 
     170      289772 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
     171             : {
     172      289772 :     if (this != &oOther)
     173             :     {
     174      289771 :         char **l_papszList = CSLDuplicate(oOther.papszList);
     175      289771 :         if (l_papszList)
     176             :         {
     177       12487 :             Assign(l_papszList, TRUE);
     178       12488 :             nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
     179       12488 :             nCount = oOther.nCount;
     180       12488 :             bIsSorted = oOther.bIsSorted;
     181             :         }
     182             :     }
     183             : 
     184      289773 :     return *this;
     185             : }
     186             : 
     187             : /************************************************************************/
     188             : /*                             operator=()                              */
     189             : /************************************************************************/
     190             : 
     191     3708680 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
     192             : {
     193     3708680 :     if (this != &oOther)
     194             :     {
     195     3711750 :         Clear();
     196     3716610 :         papszList = oOther.papszList;
     197     3716610 :         oOther.papszList = nullptr;
     198     3716610 :         nCount = oOther.nCount;
     199     3716610 :         oOther.nCount = 0;
     200     3716610 :         nAllocation = oOther.nAllocation;
     201     3716610 :         oOther.nAllocation = 0;
     202     3716610 :         bOwnList = oOther.bOwnList;
     203     3716610 :         oOther.bOwnList = false;
     204     3716610 :         bIsSorted = oOther.bIsSorted;
     205     3716610 :         oOther.bIsSorted = true;
     206             :     }
     207             : 
     208     3713540 :     return *this;
     209             : }
     210             : 
     211             : /************************************************************************/
     212             : /*                             operator=()                              */
     213             : /************************************************************************/
     214             : 
     215      105482 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
     216             : {
     217      105482 :     if (papszListIn != papszList)
     218             :     {
     219       17559 :         Assign(CSLDuplicate(papszListIn));
     220       17559 :         bIsSorted = false;
     221             :     }
     222             : 
     223      105482 :     return *this;
     224             : }
     225             : 
     226             : /************************************************************************/
     227             : /*                           ~CPLStringList()                           */
     228             : /************************************************************************/
     229             : 
     230    29793300 : CPLStringList::~CPLStringList()
     231             : 
     232             : {
     233    14903500 :     Clear();
     234    14889800 : }
     235             : 
     236             : /************************************************************************/
     237             : /*                               Clear()                                */
     238             : /************************************************************************/
     239             : 
     240             : /**
     241             :  * Clear the string list.
     242             :  */
     243    22822800 : CPLStringList &CPLStringList::Clear()
     244             : 
     245             : {
     246    22822800 :     if (bOwnList)
     247             :     {
     248     3638030 :         CSLDestroy(papszList);
     249     3630190 :         papszList = nullptr;
     250             : 
     251     3630190 :         bOwnList = FALSE;
     252     3630190 :         nAllocation = 0;
     253     3630190 :         nCount = 0;
     254             :     }
     255             : 
     256    22815000 :     return *this;
     257             : }
     258             : 
     259             : /************************************************************************/
     260             : /*                               Assign()                               */
     261             : /************************************************************************/
     262             : 
     263             : /**
     264             :  * Assign a list of strings.
     265             :  *
     266             :  *
     267             :  * @param papszListIn the NULL terminated list of strings to consume.
     268             :  * @param bTakeOwnership TRUE if the CPLStringList should take ownership
     269             :  * of the list of strings which implies responsibility to free them.
     270             :  *
     271             :  * @return a reference to the CPLStringList on which it was invoked.
     272             :  */
     273             : 
     274     4094080 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
     275             : 
     276             : {
     277     4094080 :     Clear();
     278             : 
     279     4088240 :     papszList = papszListIn;
     280     4088240 :     bOwnList = CPL_TO_BOOL(bTakeOwnership);
     281             : 
     282     4085300 :     if (papszList == nullptr || *papszList == nullptr)
     283     1910280 :         nCount = 0;
     284             :     else
     285     2175020 :         nCount = -1;  // unknown
     286             : 
     287     4085300 :     nAllocation = 0;
     288     4085300 :     bIsSorted = FALSE;
     289             : 
     290     4085300 :     return *this;
     291             : }
     292             : 
     293             : /************************************************************************/
     294             : /*                               Count()                                */
     295             : /************************************************************************/
     296             : 
     297             : /**
     298             :  * @return count of strings in the list, zero if empty.
     299             :  */
     300             : 
     301     3725250 : int CPLStringList::Count() const
     302             : 
     303             : {
     304     3725250 :     if (nCount == -1)
     305             :     {
     306      601085 :         if (papszList == nullptr)
     307             :         {
     308           0 :             nCount = 0;
     309           0 :             nAllocation = 0;
     310             :         }
     311             :         else
     312             :         {
     313      601085 :             nCount = CSLCount(papszList);
     314      601098 :             nAllocation = std::max(nCount + 1, nAllocation);
     315             :         }
     316             :     }
     317             : 
     318     3725200 :     return nCount;
     319             : }
     320             : 
     321             : /************************************************************************/
     322             : /*                           MakeOurOwnCopy()                           */
     323             : /*                                                                      */
     324             : /*      If we don't own the list, a copy is made which we own.          */
     325             : /*      Necessary if we are going to modify the list.                   */
     326             : /************************************************************************/
     327             : 
     328     8994780 : bool CPLStringList::MakeOurOwnCopy()
     329             : 
     330             : {
     331     8994780 :     if (bOwnList)
     332     5036100 :         return true;
     333             : 
     334     3958690 :     if (papszList == nullptr)
     335     3958240 :         return true;
     336             : 
     337         451 :     Count();
     338          99 :     char **papszListNew = CSLDuplicate(papszList);
     339          99 :     if (papszListNew == nullptr)
     340             :     {
     341           0 :         return false;
     342             :     }
     343          99 :     papszList = papszListNew;
     344          99 :     bOwnList = true;
     345          99 :     nAllocation = nCount + 1;
     346          99 :     return true;
     347             : }
     348             : 
     349             : /************************************************************************/
     350             : /*                          EnsureAllocation()                          */
     351             : /*                                                                      */
     352             : /*      Ensure we have enough room allocated for at least the           */
     353             : /*      requested number of strings (so nAllocation will be at least    */
     354             : /*      one more than the target)                                       */
     355             : /************************************************************************/
     356             : 
     357    13051100 : bool CPLStringList::EnsureAllocation(int nMaxList)
     358             : 
     359             : {
     360    13051100 :     if (!bOwnList)
     361             :     {
     362     3130550 :         if (!MakeOurOwnCopy())
     363           0 :             return false;
     364             :     }
     365             : 
     366    13050900 :     if (papszList == nullptr || nAllocation <= nMaxList)
     367             :     {
     368             :         // we need to be able to store nMaxList+1 as an int,
     369             :         // and allocate (nMaxList+1) * sizeof(char*) bytes
     370     6482420 :         if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
     371     3241500 :             static_cast<size_t>(nMaxList) >
     372     3241500 :                 std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
     373             :         {
     374           0 :             return false;
     375             :         }
     376     3241110 :         int nNewAllocation = nMaxList + 1;
     377     3241110 :         if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
     378             :                                   static_cast<int>(sizeof(char *)))
     379     3241320 :             nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
     380     3241160 :         if (papszList == nullptr)
     381             :         {
     382     3133860 :             papszList = static_cast<char **>(
     383     3133690 :                 VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
     384     3133860 :             bOwnList = true;
     385     3133860 :             nCount = 0;
     386     3133860 :             if (papszList == nullptr)
     387           0 :                 return false;
     388             :         }
     389             :         else
     390             :         {
     391      107463 :             char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
     392             :                 papszList, nNewAllocation * sizeof(char *)));
     393      107463 :             if (papszListNew == nullptr)
     394           0 :                 return false;
     395      107463 :             papszList = papszListNew;
     396             :         }
     397     3241330 :         nAllocation = nNewAllocation;
     398             :     }
     399    13051000 :     return true;
     400             : }
     401             : 
     402             : /************************************************************************/
     403             : /*                         AddStringDirectly()                          */
     404             : /************************************************************************/
     405             : 
     406             : /**
     407             :  * Add a string to the list.
     408             :  *
     409             :  * This method is similar to AddString(), but ownership of the
     410             :  * pszNewString is transferred to the CPLStringList class.
     411             :  *
     412             :  * @param pszNewString the string to add to the list.
     413             :  */
     414             : 
     415    13043100 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
     416             : 
     417             : {
     418    13043100 :     if (nCount == -1)
     419         716 :         Count();
     420             : 
     421    13043100 :     if (!EnsureAllocation(nCount + 1))
     422             :     {
     423          86 :         VSIFree(pszNewString);
     424           0 :         return *this;
     425             :     }
     426             : 
     427    13043200 :     papszList[nCount++] = pszNewString;
     428    13043200 :     papszList[nCount] = nullptr;
     429             : 
     430    13043200 :     bIsSorted = false;
     431             : 
     432    13043200 :     return *this;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                             AddString()                              */
     437             : /************************************************************************/
     438             : 
     439             : /**
     440             :  * Add a string to the list.
     441             :  *
     442             :  * A copy of the passed in string is made and inserted in the list.
     443             :  *
     444             :  * @param pszNewString the string to add to the list.
     445             :  */
     446             : 
     447     4160910 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
     448             : 
     449             : {
     450     4160910 :     char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
     451     4160940 :     if (pszDupString == nullptr)
     452           0 :         return *this;
     453     4160940 :     return AddStringDirectly(pszDupString);
     454             : }
     455             : 
     456             : /************************************************************************/
     457             : /*                             AddString()                              */
     458             : /************************************************************************/
     459             : /**
     460             :  * Add a string to the list.
     461             :  *
     462             :  * A copy of the passed in string is made and inserted in the list.
     463             :  *
     464             :  * @param newString the string to add to the list.
     465             :  * @return a reference to the CPLStringList on which it was invoked.
     466             :  */
     467             : 
     468       27595 : CPLStringList &CPLStringList::AddString(const std::string &newString)
     469             : {
     470       27595 :     return AddString(newString.c_str());
     471             : }
     472             : 
     473             : /************************************************************************/
     474             : /*                             AddString()                              */
     475             : /************************************************************************/
     476             : /**
     477             :  * Add a string to the list.
     478             :  *
     479             :  * A copy of the passed in string_view is made and inserted in the list.
     480             :  *
     481             :  * @param newString the string to add to the list.
     482             :  * @return a reference to the CPLStringList on which it was invoked.
     483             :  */
     484             : 
     485     3212840 : CPLStringList &CPLStringList::AddString(std::string_view newString)
     486             : {
     487             :     char *pszDupString =
     488     3212840 :         static_cast<char *>(VSI_MALLOC_VERBOSE(newString.size() + 1));
     489     3212820 :     if (pszDupString == nullptr)
     490             :     {
     491           0 :         return *this;
     492             :     }
     493     3212820 :     std::memcpy(pszDupString, newString.data(), newString.size());
     494     3212810 :     pszDupString[newString.size()] = '\0';
     495             : 
     496     3212820 :     return AddStringDirectly(pszDupString);
     497             : }
     498             : 
     499             : /************************************************************************/
     500             : /*                             push_back()                              */
     501             : /************************************************************************/
     502             : 
     503             : /**
     504             :  * Add a string to the list.
     505             :  *
     506             :  * A copy of the passed in string is made and inserted in the list.
     507             :  *
     508             :  * @param svStr the string to add to the list.
     509             :  *
     510             :  * @since 3.13
     511             :  */
     512             : 
     513          92 : void CPLStringList::push_back(std::string_view svStr)
     514             : 
     515             : {
     516             :     char *pszDupString =
     517          92 :         static_cast<char *>(VSI_MALLOC_VERBOSE(svStr.size() + 1));
     518          92 :     if (pszDupString == nullptr)
     519           0 :         return;
     520          92 :     memcpy(pszDupString, svStr.data(), svStr.size());
     521          92 :     pszDupString[svStr.size()] = 0;
     522          92 :     CPL_IGNORE_RET_VAL(AddStringDirectly(pszDupString));
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                            AddNameValue()                            */
     527             : /************************************************************************/
     528             : 
     529             : /**
     530             :  * Add a name=value entry to the list.
     531             :  *
     532             :  * A key=value string is prepared and appended to the list.  There is no
     533             :  * check for other values for the same key in the list.
     534             :  *
     535             :  * @param pszKey the key name to add.
     536             :  * @param pszValue the key value to add.
     537             :  */
     538             : 
     539     5778970 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
     540             :                                            const char *pszValue)
     541             : 
     542             : {
     543     5778970 :     if (pszKey == nullptr || pszValue == nullptr)
     544      144933 :         return *this;
     545             : 
     546     5634040 :     if (!MakeOurOwnCopy())
     547           0 :         return *this;
     548             : 
     549             :     /* -------------------------------------------------------------------- */
     550             :     /*      Format the line.                                                */
     551             :     /* -------------------------------------------------------------------- */
     552    11268300 :     if (strlen(pszKey) >
     553    11268400 :             std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     554     5634350 :         strlen(pszKey) + strlen(pszValue) >
     555     5634350 :             std::numeric_limits<size_t>::max() - 2)
     556             :     {
     557           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     558             :                  "Too big strings in AddNameValue()");
     559           0 :         return *this;
     560             :     }
     561     5634070 :     const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     562     5634070 :     char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     563     5634210 :     if (pszLine == nullptr)
     564           0 :         return *this;
     565     5634210 :     snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     566             : 
     567             :     /* -------------------------------------------------------------------- */
     568             :     /*      If we don't need to keep the sort order things are pretty       */
     569             :     /*      straight forward.                                               */
     570             :     /* -------------------------------------------------------------------- */
     571     5634210 :     if (!IsSorted())
     572     5626890 :         return AddStringDirectly(pszLine);
     573             : 
     574             :     /* -------------------------------------------------------------------- */
     575             :     /*      Find the proper insertion point.                                */
     576             :     /* -------------------------------------------------------------------- */
     577        7332 :     CPLAssert(IsSorted());
     578        7304 :     const int iKey = FindSortedInsertionPoint(pszLine);
     579        7304 :     InsertStringDirectly(iKey, pszLine);
     580        7304 :     bIsSorted = true;  // We have actually preserved sort order.
     581             : 
     582        7304 :     return *this;
     583             : }
     584             : 
     585             : /************************************************************************/
     586             : /*                            SetNameValue()                            */
     587             : /************************************************************************/
     588             : 
     589             : /**
     590             :  * Set name=value entry in the list.
     591             :  *
     592             :  * Similar to AddNameValue(), except if there is already a value for
     593             :  * the key in the list it is replaced instead of adding a new entry to
     594             :  * the list.  If pszValue is NULL any existing key entry is removed.
     595             :  *
     596             :  * @param pszKey the key name to add.
     597             :  * @param pszValue the key value to add.
     598             :  */
     599             : 
     600     5871420 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
     601             :                                            const char *pszValue)
     602             : 
     603             : {
     604     5871420 :     int iKey = FindName(pszKey);
     605             : 
     606     5871400 :     if (iKey == -1)
     607     5742320 :         return AddNameValue(pszKey, pszValue);
     608             : 
     609      129081 :     Count();
     610      128819 :     if (!MakeOurOwnCopy())
     611           0 :         return *this;
     612             : 
     613      128819 :     CPLFree(papszList[iKey]);
     614      128819 :     if (pszValue == nullptr)  // delete entry
     615             :     {
     616             : 
     617             :         // shift everything down by one.
     618         930 :         do
     619             :         {
     620        3598 :             papszList[iKey] = papszList[iKey + 1];
     621        3598 :         } while (papszList[iKey++] != nullptr);
     622             : 
     623        2668 :         nCount--;
     624             :     }
     625             :     else
     626             :     {
     627      252302 :         if (strlen(pszKey) >
     628      252302 :                 std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     629      126151 :             strlen(pszKey) + strlen(pszValue) >
     630      126151 :                 std::numeric_limits<size_t>::max() - 2)
     631             :         {
     632           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     633             :                      "Too big strings in AddNameValue()");
     634           0 :             return *this;
     635             :         }
     636      126151 :         const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     637      126151 :         char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     638      126151 :         if (pszLine == nullptr)
     639           0 :             return *this;
     640      126151 :         snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     641             : 
     642      126151 :         papszList[iKey] = pszLine;
     643             :     }
     644             : 
     645      128819 :     return *this;
     646             : }
     647             : 
     648             : /************************************************************************/
     649             : /*                             SetString()                              */
     650             : /************************************************************************/
     651             : 
     652             : /**
     653             :  * Replace a string within the list.
     654             :  *
     655             :  * @param pos 0-index position of the string to replace
     656             :  * @param pszString value to be used (will be copied)
     657             :  * @return a reference to the CPLStringList on which it was invoked.
     658             :  * @since 3.13
     659             :  */
     660           6 : CPLStringList &CPLStringList::SetString(int pos, const char *pszString)
     661             : {
     662           6 :     return SetStringDirectly(pos, VSI_STRDUP_VERBOSE(pszString));
     663             : }
     664             : 
     665             : /**
     666             :  * Replace a string within the list.
     667             :  *
     668             :  * @param pos 0-index position of the string to replace
     669             :  * @param osString value to be used (will be copied)
     670             :  * @return a reference to the CPLStringList on which it was invoked.
     671             :  * @since 3.13
     672             :  */
     673           1 : CPLStringList &CPLStringList::SetString(int pos, const std::string &osString)
     674             : {
     675           1 :     return SetString(pos, osString.c_str());
     676             : }
     677             : 
     678             : /**
     679             :  * Replace a string within the list.
     680             :  *
     681             :  * @param pos 0-index position of the string to replace
     682             :  * @param pszString value to be used (ownership is taken)
     683             :  * @return a reference to the CPLStringList on which it was invoked.
     684             :  * @since 3.13
     685             :  */
     686           6 : CPLStringList &CPLStringList::SetStringDirectly(int pos, char *pszString)
     687             : {
     688           6 :     if (!MakeOurOwnCopy())
     689           0 :         return *this;
     690             : 
     691           6 :     CPLFree(papszList[pos]);
     692           6 :     papszList[pos] = pszString;
     693             : 
     694           6 :     if (bIsSorted)
     695             :     {
     696           8 :         if (pos > 0 &&
     697           2 :             CPLCompareKeyValueString(papszList[pos], papszList[pos - 1]) == -1)
     698             :         {
     699           0 :             bIsSorted = false;
     700             :         }
     701          11 :         if (pos < Count() - 1 &&
     702           5 :             CPLCompareKeyValueString(papszList[pos], papszList[pos + 1]) == 1)
     703             :         {
     704           3 :             bIsSorted = false;
     705             :         }
     706             :     }
     707             : 
     708           6 :     return *this;
     709             : }
     710             : 
     711             : /************************************************************************/
     712             : /*                              operator[]                              */
     713             : /************************************************************************/
     714             : 
     715             : /**
     716             :  * Fetch entry "i".
     717             :  *
     718             :  * Fetches the requested item in the list.  Note that the returned string
     719             :  * remains owned by the CPLStringList.  If "i" is out of range NULL is
     720             :  * returned.
     721             :  *
     722             :  * @param i the index of the list item to return.
     723             :  * @return selected entry in the list.
     724             :  */
     725     1507660 : char *CPLStringList::operator[](int i)
     726             : 
     727             : {
     728     1507660 :     if (nCount == -1)
     729         282 :         Count();
     730             : 
     731     1507660 :     if (i < 0 || i >= nCount)
     732          50 :         return nullptr;
     733             : 
     734     1507610 :     return papszList[i];
     735             : }
     736             : 
     737      807350 : const char *CPLStringList::operator[](int i) const
     738             : 
     739             : {
     740      807350 :     if (nCount == -1)
     741         743 :         Count();
     742             : 
     743      807345 :     if (i < 0 || i >= nCount)
     744           2 :         return nullptr;
     745             : 
     746      807343 :     return papszList[i];
     747             : }
     748             : 
     749             : /************************************************************************/
     750             : /*                             StealList()                              */
     751             : /************************************************************************/
     752             : 
     753             : /**
     754             :  * Seize ownership of underlying string array.
     755             :  *
     756             :  * This method is similar to List(), except that the returned list is
     757             :  * now owned by the caller and the CPLStringList is emptied.
     758             :  *
     759             :  * @return the C style string list.
     760             :  */
     761     3488060 : char **CPLStringList::StealList()
     762             : 
     763             : {
     764     3488060 :     char **papszRetList = papszList;
     765             : 
     766     3488060 :     bOwnList = false;
     767     3488060 :     papszList = nullptr;
     768     3488060 :     nCount = 0;
     769     3488060 :     nAllocation = 0;
     770             : 
     771     3488060 :     return papszRetList;
     772             : }
     773             : 
     774             : /* Case insensitive comparison function */
     775      916906 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
     776             : {
     777      916906 :     const char *pszItera = pszKVa;
     778      916906 :     const char *pszIterb = pszKVb;
     779             :     while (true)
     780             :     {
     781     6240420 :         char cha = *pszItera;
     782     6240420 :         char chb = *pszIterb;
     783     6240420 :         if (cha == '=' || cha == '\0')
     784             :         {
     785        4293 :             if (chb == '=' || chb == '\0')
     786           2 :                 return 0;
     787             :             else
     788        4291 :                 return -1;
     789             :         }
     790     6236130 :         if (chb == '=' || chb == '\0')
     791             :         {
     792        9544 :             return 1;
     793             :         }
     794     6226590 :         if (cha >= 'a' && cha <= 'z')
     795      529851 :             cha -= ('a' - 'A');
     796     6226590 :         if (chb >= 'a' && chb <= 'z')
     797      531144 :             chb -= ('a' - 'A');
     798     6226590 :         if (cha < chb)
     799      532665 :             return -1;
     800     5693920 :         else if (cha > chb)
     801      370404 :             return 1;
     802     5323520 :         pszItera++;
     803     5323520 :         pszIterb++;
     804     5323520 :     }
     805             : }
     806             : 
     807             : /************************************************************************/
     808             : /*                                Sort()                                */
     809             : /************************************************************************/
     810             : 
     811             : /**
     812             :  * Sort the entries in the list and mark list sorted.
     813             :  *
     814             :  * Note that once put into "sorted" mode, the CPLStringList will attempt to
     815             :  * keep things in sorted order through calls to AddString(),
     816             :  * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
     817             :  * assignments (via Assign() and operator= will clear the sorting state.
     818             :  * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
     819             :  * will do a binary search to find the key, substantially improve lookup
     820             :  * performance in large lists.
     821             :  */
     822             : 
     823      101175 : CPLStringList &CPLStringList::Sort()
     824             : 
     825             : {
     826      101175 :     Count();
     827      101176 :     if (!MakeOurOwnCopy())
     828           0 :         return *this;
     829             : 
     830      101175 :     if (nCount > 1)
     831             :     {
     832        6366 :         std::sort(papszList, papszList + nCount,
     833      858718 :                   [](const char *a, const char *b)
     834      858718 :                   { return CPLCompareKeyValueString(a, b) < 0; });
     835             :     }
     836      101176 :     bIsSorted = true;
     837             : 
     838      101176 :     return *this;
     839             : }
     840             : 
     841             : /************************************************************************/
     842             : /*                              FindName()                              */
     843             : /************************************************************************/
     844             : 
     845             : /**
     846             :  * Get index of given name/value keyword.
     847             :  *
     848             :  * Note that this search is for a line in the form name=value or name:value.
     849             :  * Use FindString() or PartialFindString() for searches not based on name=value
     850             :  * pairs.
     851             :  *
     852             :  * @param pszKey the name to search for.
     853             :  *
     854             :  * @return the string list index of this name, or -1 on failure.
     855             :  */
     856             : 
     857    18282000 : int CPLStringList::FindName(const char *pszKey) const
     858             : 
     859             : {
     860    18282000 :     if (!IsSorted())
     861    18259200 :         return CSLFindName(papszList, pszKey);
     862             : 
     863             :     // If we are sorted, we can do an optimized binary search.
     864       22730 :     int iStart = 0;
     865       22730 :     int iEnd = nCount - 1;
     866       22730 :     size_t nKeyLen = strlen(pszKey);
     867             : 
     868       58530 :     while (iStart <= iEnd)
     869             :     {
     870       43215 :         const int iMiddle = (iEnd + iStart) / 2;
     871       43215 :         const char *pszMiddle = papszList[iMiddle];
     872             : 
     873       43215 :         if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
     874        7884 :             (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
     875        7415 :             return iMiddle;
     876             : 
     877       35800 :         if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
     878        9348 :             iEnd = iMiddle - 1;
     879             :         else
     880       26452 :             iStart = iMiddle + 1;
     881             :     }
     882             : 
     883       15315 :     return -1;
     884             : }
     885             : 
     886             : /************************************************************************/
     887             : /*                             FetchBool()                              */
     888             : /************************************************************************/
     889             : /**
     890             :  *
     891             :  * Check for boolean key value.
     892             :  *
     893             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     894             :  * with the given name, and if it can be interpreted as being TRUE.  If
     895             :  * the key appears without any "=Value" portion it will be considered true.
     896             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     897             :  * if the key appears in the list it will be considered TRUE.  If the key
     898             :  * doesn't appear at all, the indicated default value will be returned.
     899             :  *
     900             :  * @param pszKey the key value to look for (case insensitive).
     901             :  * @param bDefault the value to return if the key isn't found at all.
     902             :  *
     903             :  * @return true or false
     904             :  */
     905             : 
     906       16081 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
     907             : 
     908             : {
     909       16081 :     const char *pszValue = FetchNameValue(pszKey);
     910             : 
     911       16082 :     if (pszValue == nullptr)
     912       15793 :         return bDefault;
     913             : 
     914         289 :     return CPLTestBool(pszValue);
     915             : }
     916             : 
     917             : /************************************************************************/
     918             : /*                            FetchBoolean()                            */
     919             : /************************************************************************/
     920             : /**
     921             :  *
     922             :  * DEPRECATED: Check for boolean key value.
     923             :  *
     924             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     925             :  * with the given name, and if it can be interpreted as being TRUE.  If
     926             :  * the key appears without any "=Value" portion it will be considered true.
     927             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     928             :  * if the key appears in the list it will be considered TRUE.  If the key
     929             :  * doesn't appear at all, the indicated default value will be returned.
     930             :  *
     931             :  * @param pszKey the key value to look for (case insensitive).
     932             :  * @param bDefault the value to return if the key isn't found at all.
     933             :  *
     934             :  * @return TRUE or FALSE
     935             :  */
     936             : 
     937        2985 : int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
     938             : 
     939             : {
     940        2985 :     return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                           FetchNameValue()                           */
     945             : /************************************************************************/
     946             : 
     947             : /**
     948             :  * Fetch value associated with this key name.
     949             :  *
     950             :  * If this list sorted, a fast binary search is done, otherwise a linear
     951             :  * scan is done.  Name lookup is case insensitive.
     952             :  *
     953             :  * @param pszName the key name to search for.
     954             :  *
     955             :  * @return the corresponding value or NULL if not found.  The returned string
     956             :  * should not be modified and points into internal object state that may
     957             :  * change on future calls.
     958             :  */
     959             : 
     960    12411300 : const char *CPLStringList::FetchNameValue(const char *pszName) const
     961             : 
     962             : {
     963    12411300 :     const int iKey = FindName(pszName);
     964             : 
     965    12411000 :     if (iKey == -1)
     966     4758540 :         return nullptr;
     967             : 
     968     7652420 :     CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
     969             :               papszList[iKey][strlen(pszName)] == ':');
     970             : 
     971     7652420 :     return papszList[iKey] + strlen(pszName) + 1;
     972             : }
     973             : 
     974             : /************************************************************************/
     975             : /*                         FetchNameValueDef()                          */
     976             : /************************************************************************/
     977             : 
     978             : /**
     979             :  * Fetch value associated with this key name.
     980             :  *
     981             :  * If this list sorted, a fast binary search is done, otherwise a linear
     982             :  * scan is done.  Name lookup is case insensitive.
     983             :  *
     984             :  * @param pszName the key name to search for.
     985             :  * @param pszDefault the default value returned if the named entry isn't found.
     986             :  *
     987             :  * @return the corresponding value or the passed default if not found.
     988             :  */
     989             : 
     990       49523 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
     991             :                                              const char *pszDefault) const
     992             : 
     993             : {
     994       49523 :     const char *pszValue = FetchNameValue(pszName);
     995       49523 :     if (pszValue == nullptr)
     996       35015 :         return pszDefault;
     997             : 
     998       14508 :     return pszValue;
     999             : }
    1000             : 
    1001             : /************************************************************************/
    1002             : /*                            InsertString()                            */
    1003             : /************************************************************************/
    1004             : 
    1005             : /**
    1006             :  * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
    1007             :  *                                                 const char *pszNewLine );
    1008             :  *
    1009             :  * \brief Insert into the list at identified location.
    1010             :  *
    1011             :  * This method will insert a string into the list at the identified
    1012             :  * location.  The insertion point must be within or at the end of the list.
    1013             :  * The following entries are pushed down to make space.
    1014             :  *
    1015             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
    1016             :  * @param pszNewLine to the line to insert.  This string will be copied.
    1017             :  */
    1018             : 
    1019             : /************************************************************************/
    1020             : /*                        InsertStringDirectly()                        */
    1021             : /************************************************************************/
    1022             : 
    1023             : /**
    1024             :  * Insert into the list at identified location.
    1025             :  *
    1026             :  * This method will insert a string into the list at the identified
    1027             :  * location.  The insertion point must be within or at the end of the list.
    1028             :  * The following entries are pushed down to make space.
    1029             :  *
    1030             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
    1031             :  * @param pszNewLine to the line to insert, the ownership of this string
    1032             :  * will be taken over the by the object.  It must have been allocated on the
    1033             :  * heap.
    1034             :  */
    1035             : 
    1036        7700 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
    1037             :                                                    char *pszNewLine)
    1038             : 
    1039             : {
    1040        7700 :     if (nCount == -1)
    1041          27 :         Count();
    1042             : 
    1043        7700 :     if (!EnsureAllocation(nCount + 1))
    1044             :     {
    1045           0 :         VSIFree(pszNewLine);
    1046           0 :         return *this;
    1047             :     }
    1048             : 
    1049        7700 :     if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
    1050             :     {
    1051           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1052             :                  "CPLStringList::InsertString() requested beyond list end.");
    1053           0 :         return *this;
    1054             :     }
    1055             : 
    1056        7700 :     bIsSorted = false;
    1057             : 
    1058       24108 :     for (int i = nCount; i > nInsertAtLineNo; i--)
    1059       16408 :         papszList[i] = papszList[i - 1];
    1060             : 
    1061        7700 :     papszList[nInsertAtLineNo] = pszNewLine;
    1062        7700 :     papszList[++nCount] = nullptr;
    1063             : 
    1064        7700 :     return *this;
    1065             : }
    1066             : 
    1067             : /************************************************************************/
    1068             : /*                           RemoveStrings()                            */
    1069             : /************************************************************************/
    1070             : 
    1071             : /**
    1072             :  * Remove strings inside a CPLStringList.
    1073             :  *
    1074             :  * @param nFirstLineToDelete the 0-based index of the first string to
    1075             :  * remove. If this value is -1 or is larger than the actual
    1076             :  * number of strings in list then the nNumToRemove last strings are
    1077             :  * removed.
    1078             :  * @param nNumToRemove the number of strings to remove
    1079             :  *
    1080             :  * @return a reference to the CPLStringList on which it was invoked.
    1081             :  * @since 3.13
    1082             :  */
    1083           3 : CPLStringList &CPLStringList::RemoveStrings(int nFirstLineToDelete,
    1084             :                                             int nNumToRemove)
    1085             : {
    1086           3 :     if (!MakeOurOwnCopy())
    1087           0 :         return *this;
    1088             : 
    1089           3 :     papszList =
    1090           3 :         CSLRemoveStrings(papszList, nFirstLineToDelete, nNumToRemove, nullptr);
    1091           3 :     nCount = -1;
    1092           3 :     return *this;
    1093             : }
    1094             : 
    1095             : /************************************************************************/
    1096             : /*                      FindSortedInsertionPoint()                      */
    1097             : /*                                                                      */
    1098             : /*      Find the location at which the indicated line should be         */
    1099             : /*      inserted in order to keep things in sorted order.               */
    1100             : /************************************************************************/
    1101             : 
    1102        7304 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
    1103             : 
    1104             : {
    1105        7304 :     CPLAssert(IsSorted());
    1106             : 
    1107        7304 :     int iStart = 0;
    1108        7304 :     int iEnd = nCount - 1;
    1109             : 
    1110       23554 :     while (iStart <= iEnd)
    1111             :     {
    1112       16250 :         const int iMiddle = (iEnd + iStart) / 2;
    1113       16250 :         const char *pszMiddle = papszList[iMiddle];
    1114             : 
    1115       16250 :         if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
    1116        2411 :             iEnd = iMiddle - 1;
    1117             :         else
    1118       13839 :             iStart = iMiddle + 1;
    1119             :     }
    1120             : 
    1121        7304 :     iEnd++;
    1122        7304 :     CPLAssert(iEnd >= 0 && iEnd <= nCount);
    1123        7304 :     CPLAssert(iEnd == 0 ||
    1124             :               CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
    1125        7304 :     CPLAssert(iEnd == nCount ||
    1126             :               CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
    1127             : 
    1128        7304 :     return iEnd;
    1129             : }
    1130             : 
    1131             : namespace cpl
    1132             : {
    1133             : 
    1134             : /************************************************************************/
    1135             : /*          CSLIterator::operator==(const CSLIterator &other)           */
    1136             : /************************************************************************/
    1137             : 
    1138             : /*! @cond Doxygen_Suppress */
    1139    22917200 : bool CSLIterator::operator==(const CSLIterator &other) const
    1140             : {
    1141    22917200 :     if (!m_bAtEnd && other.m_bAtEnd)
    1142             :     {
    1143    22917200 :         return m_papszList == nullptr || *m_papszList == nullptr;
    1144             :     }
    1145           0 :     if (!m_bAtEnd && !other.m_bAtEnd)
    1146             :     {
    1147           0 :         return m_papszList == other.m_papszList;
    1148             :     }
    1149           0 :     if (m_bAtEnd && other.m_bAtEnd)
    1150             :     {
    1151           0 :         return true;
    1152             :     }
    1153           0 :     return false;
    1154             : }
    1155             : 
    1156             : /*! @endcond */
    1157             : 
    1158             : /************************************************************************/
    1159             : /*                  CSLNameValueIterator::operator*()                   */
    1160             : /************************************************************************/
    1161             : 
    1162             : /*! @cond Doxygen_Suppress */
    1163        8374 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
    1164             : {
    1165        8374 :     if (m_papszList)
    1166             :     {
    1167        8375 :         while (*m_papszList)
    1168             :         {
    1169        8375 :             char *pszKey = nullptr;
    1170        8375 :             const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
    1171        8375 :             if (pszKey)
    1172             :             {
    1173        8372 :                 m_osKey = pszKey;
    1174        8372 :                 CPLFree(pszKey);
    1175        8372 :                 return {m_osKey.c_str(), pszValue};
    1176             :             }
    1177           3 :             else if (m_bReturnNullKeyIfNotNameValue)
    1178             :             {
    1179           2 :                 return {nullptr, *m_papszList};
    1180             :             }
    1181             :             // Skip entries that are not name=value pairs.
    1182           1 :             ++m_papszList;
    1183             :         }
    1184             :     }
    1185             :     // Should not happen
    1186           0 :     CPLAssert(false);
    1187             :     return {"", ""};
    1188             : }
    1189             : 
    1190             : /*! @endcond */
    1191             : 
    1192             : /************************************************************************/
    1193             : /*                  CSLNameValueIteratorWrapper::end()                  */
    1194             : /************************************************************************/
    1195             : 
    1196             : /*! @cond Doxygen_Suppress */
    1197       13615 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
    1198             : {
    1199       13615 :     int nCount = CSLCount(m_papszList);
    1200       13615 :     if (!m_bReturnNullKeyIfNotNameValue)
    1201             :     {
    1202       13512 :         while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
    1203          12 :             --nCount;
    1204             :     }
    1205       13615 :     return CSLNameValueIterator{m_papszList + nCount,
    1206       13615 :                                 m_bReturnNullKeyIfNotNameValue};
    1207             : }
    1208             : 
    1209             : /*! @endcond */
    1210             : 
    1211             : }  // namespace cpl

Generated by: LCOV version 1.14