LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 306 332 92.2 %
Date: 2025-03-28 11:40:40 Functions: 37 37 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  CPLStringList implementation.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "cpl_string.h"
      16             : 
      17             : #include <cstddef>
      18             : #include <cstdio>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : 
      22             : #include <algorithm>
      23             : #include <limits>
      24             : #include <string>
      25             : 
      26             : #include "cpl_conv.h"
      27             : #include "cpl_error.h"
      28             : 
      29             : /************************************************************************/
      30             : /*                           CPLStringList()                            */
      31             : /************************************************************************/
      32             : 
      33             : CPLStringList::CPLStringList() = default;
      34             : 
      35             : /************************************************************************/
      36             : /*                           CPLStringList()                            */
      37             : /************************************************************************/
      38             : 
      39             : /**
      40             :  * CPLStringList constructor.
      41             :  *
      42             :  * @param papszListIn the NULL terminated list of strings to consume.
      43             :  * @param bTakeOwnership TRUE if the CPLStringList should take ownership
      44             :  * of the list of strings which implies responsibility to free them.
      45             :  */
      46             : 
      47     1694620 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
      48     1694620 :     : CPLStringList()
      49             : 
      50             : {
      51     1632000 :     Assign(papszListIn, bTakeOwnership);
      52     1614930 : }
      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        4035 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
      67             : 
      68             : {
      69        4035 :     Assign(CSLDuplicate(papszListIn));
      70        4035 : }
      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         795 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
      86             : {
      87         795 :     if (!aosList.empty())
      88             :     {
      89         274 :         bOwnList = true;
      90         274 :         papszList = static_cast<char **>(
      91         274 :             VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
      92         274 :         nCount = static_cast<int>(aosList.size());
      93        1228 :         for (int i = 0; i < nCount; ++i)
      94             :         {
      95         954 :             papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
      96             :         }
      97             :     }
      98         795 : }
      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       21653 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
     127             : 
     128             : {
     129       21655 :     operator=(oOther);
     130       21652 : }
     131             : 
     132             : /************************************************************************/
     133             : /*                           CPLStringList()                            */
     134             : /************************************************************************/
     135             : 
     136             : //! Move constructor
     137     2895250 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
     138             : 
     139             : {
     140     2848920 :     operator=(std::move(oOther));
     141     2947240 : }
     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       37425 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
     169             : {
     170       37425 :     if (this != &oOther)
     171             :     {
     172       37424 :         char **l_papszList = CSLDuplicate(oOther.papszList);
     173       37420 :         if (l_papszList)
     174             :         {
     175        5700 :             Assign(l_papszList, TRUE);
     176        5698 :             nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
     177        5698 :             nCount = oOther.nCount;
     178        5698 :             bIsSorted = oOther.bIsSorted;
     179             :         }
     180             :     }
     181             : 
     182       37419 :     return *this;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                             operator=()                              */
     187             : /************************************************************************/
     188             : 
     189     2920680 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
     190             : {
     191     2920680 :     if (this != &oOther)
     192             :     {
     193     2939720 :         Clear();
     194     2914060 :         papszList = oOther.papszList;
     195     2914060 :         oOther.papszList = nullptr;
     196     2914060 :         nCount = oOther.nCount;
     197     2914060 :         oOther.nCount = 0;
     198     2914060 :         nAllocation = oOther.nAllocation;
     199     2914060 :         oOther.nAllocation = 0;
     200     2914060 :         bOwnList = oOther.bOwnList;
     201     2914060 :         oOther.bOwnList = false;
     202     2914060 :         bIsSorted = oOther.bIsSorted;
     203     2914060 :         oOther.bIsSorted = true;
     204             :     }
     205             : 
     206     2895030 :     return *this;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                             operator=()                              */
     211             : /************************************************************************/
     212             : 
     213       31285 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
     214             : {
     215       31285 :     if (papszListIn != papszList)
     216             :     {
     217       13088 :         Assign(CSLDuplicate(papszListIn));
     218       13088 :         bIsSorted = false;
     219             :     }
     220             : 
     221       31285 :     return *this;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                           ~CPLStringList()                           */
     226             : /************************************************************************/
     227             : 
     228    17702400 : CPLStringList::~CPLStringList()
     229             : 
     230             : {
     231     8897850 :     Clear();
     232     8804560 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                               Clear()                                */
     236             : /************************************************************************/
     237             : 
     238             : /**
     239             :  * Clear the string list.
     240             :  */
     241    13752400 : CPLStringList &CPLStringList::Clear()
     242             : 
     243             : {
     244    13752400 :     if (bOwnList)
     245             :     {
     246     2408620 :         CSLDestroy(papszList);
     247     2455460 :         papszList = nullptr;
     248             : 
     249     2455460 :         bOwnList = FALSE;
     250     2455460 :         nAllocation = 0;
     251     2455460 :         nCount = 0;
     252             :     }
     253             : 
     254    13799300 :     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     1793060 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
     273             : 
     274             : {
     275     1793060 :     Clear();
     276             : 
     277     1758840 :     papszList = papszListIn;
     278     1758840 :     bOwnList = CPL_TO_BOOL(bTakeOwnership);
     279             : 
     280     1710480 :     if (papszList == nullptr || *papszList == nullptr)
     281     1342490 :         nCount = 0;
     282             :     else
     283      367992 :         nCount = -1;  // unknown
     284             : 
     285     1710480 :     nAllocation = 0;
     286     1710480 :     bIsSorted = FALSE;
     287             : 
     288     1710480 :     return *this;
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                               Count()                                */
     293             : /************************************************************************/
     294             : 
     295             : /**
     296             :  * @return count of strings in the list, zero if empty.
     297             :  */
     298             : 
     299     2345530 : int CPLStringList::Count() const
     300             : 
     301             : {
     302     2345530 :     if (nCount == -1)
     303             :     {
     304      355266 :         if (papszList == nullptr)
     305             :         {
     306           0 :             nCount = 0;
     307           0 :             nAllocation = 0;
     308             :         }
     309             :         else
     310             :         {
     311      355266 :             nCount = CSLCount(papszList);
     312      355266 :             nAllocation = std::max(nCount + 1, nAllocation);
     313             :         }
     314             :     }
     315             : 
     316     2345470 :     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     6142610 : bool CPLStringList::MakeOurOwnCopy()
     327             : 
     328             : {
     329     6142610 :     if (bOwnList)
     330     3431140 :         return true;
     331             : 
     332     2711470 :     if (papszList == nullptr)
     333     2710960 :         return true;
     334             : 
     335         509 :     Count();
     336          83 :     char **papszListNew = CSLDuplicate(papszList);
     337          83 :     if (papszListNew == nullptr)
     338             :     {
     339           0 :         return false;
     340             :     }
     341          83 :     papszList = papszListNew;
     342          83 :     bOwnList = true;
     343          83 :     nAllocation = nCount + 1;
     344          83 :     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     9036190 : bool CPLStringList::EnsureAllocation(int nMaxList)
     356             : 
     357             : {
     358     9036190 :     if (!bOwnList)
     359             :     {
     360     2208570 :         if (!MakeOurOwnCopy())
     361           0 :             return false;
     362             :     }
     363             : 
     364     9036110 :     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     4549310 :         if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
     369     2274760 :             static_cast<size_t>(nMaxList) >
     370     2274760 :                 std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
     371             :         {
     372           0 :             return false;
     373             :         }
     374     2274550 :         int nNewAllocation = nMaxList + 1;
     375     2274550 :         if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
     376             :                                   static_cast<int>(sizeof(char *)))
     377     2274760 :             nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
     378     2274670 :         if (papszList == nullptr)
     379             :         {
     380     2210870 :             papszList = static_cast<char **>(
     381     2210820 :                 VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
     382     2210870 :             bOwnList = true;
     383     2210870 :             nCount = 0;
     384     2210870 :             if (papszList == nullptr)
     385           0 :                 return false;
     386             :         }
     387             :         else
     388             :         {
     389       63858 :             char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
     390             :                 papszList, nNewAllocation * sizeof(char *)));
     391       63858 :             if (papszListNew == nullptr)
     392           0 :                 return false;
     393       63858 :             papszList = papszListNew;
     394             :         }
     395     2274730 :         nAllocation = nNewAllocation;
     396             :     }
     397     9036230 :     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     9029390 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
     414             : 
     415             : {
     416     9029390 :     if (nCount == -1)
     417         215 :         Count();
     418             : 
     419     9029390 :     if (!EnsureAllocation(nCount + 1))
     420             :     {
     421           0 :         VSIFree(pszNewString);
     422           0 :         return *this;
     423             :     }
     424             : 
     425     9029440 :     papszList[nCount++] = pszNewString;
     426     9029440 :     papszList[nCount] = nullptr;
     427             : 
     428     9029440 :     bIsSorted = false;
     429             : 
     430     9029440 :     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     5212230 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
     446             : 
     447             : {
     448     5212230 :     char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
     449     5212170 :     if (pszDupString == nullptr)
     450           0 :         return *this;
     451     5212170 :     return AddStringDirectly(pszDupString);
     452             : }
     453             : 
     454             : /************************************************************************/
     455             : /*                             AddString()                              */
     456             : /************************************************************************/
     457             : /**
     458             :  * Add a string to the list.
     459             :  *
     460             :  * A copy of the passed in string is made and inserted in the list.
     461             :  *
     462             :  * @param newString the string to add to the list.
     463             :  * @return a reference to the CPLStringList on which it was invoked.
     464             :  */
     465             : 
     466       24955 : CPLStringList &CPLStringList::AddString(const std::string &newString)
     467             : {
     468       24955 :     return AddString(newString.c_str());
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                            AddNameValue()                            */
     473             : /************************************************************************/
     474             : 
     475             : /**
     476             :  * Add a name=value entry to the list.
     477             :  *
     478             :  * A key=value string is prepared and appended to the list.  There is no
     479             :  * check for other values for the same key in the list.
     480             :  *
     481             :  * @param pszKey the key name to add.
     482             :  * @param pszValue the key value to add.
     483             :  */
     484             : 
     485     3826720 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
     486             :                                            const char *pszValue)
     487             : 
     488             : {
     489     3826720 :     if (pszKey == nullptr || pszValue == nullptr)
     490        3341 :         return *this;
     491             : 
     492     3823380 :     if (!MakeOurOwnCopy())
     493           0 :         return *this;
     494             : 
     495             :     /* -------------------------------------------------------------------- */
     496             :     /*      Format the line.                                                */
     497             :     /* -------------------------------------------------------------------- */
     498     7647070 :     if (strlen(pszKey) >
     499     7647010 :             std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     500     3823390 :         strlen(pszKey) + strlen(pszValue) >
     501     3823390 :             std::numeric_limits<size_t>::max() - 2)
     502             :     {
     503           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     504             :                  "Too big strings in AddNameValue()");
     505           0 :         return *this;
     506             :     }
     507     3823600 :     const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     508     3823600 :     char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     509     3823570 :     if (pszLine == nullptr)
     510           0 :         return *this;
     511     3823570 :     snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     512             : 
     513             :     /* -------------------------------------------------------------------- */
     514             :     /*      If we don't need to keep the sort order things are pretty       */
     515             :     /*      straight forward.                                               */
     516             :     /* -------------------------------------------------------------------- */
     517     3823570 :     if (!IsSorted())
     518     3816810 :         return AddStringDirectly(pszLine);
     519             : 
     520             :     /* -------------------------------------------------------------------- */
     521             :     /*      Find the proper insertion point.                                */
     522             :     /* -------------------------------------------------------------------- */
     523        6705 :     CPLAssert(IsSorted());
     524        6609 :     const int iKey = FindSortedInsertionPoint(pszLine);
     525        6609 :     InsertStringDirectly(iKey, pszLine);
     526        6609 :     bIsSorted = true;  // We have actually preserved sort order.
     527             : 
     528        6609 :     return *this;
     529             : }
     530             : 
     531             : /************************************************************************/
     532             : /*                            SetNameValue()                            */
     533             : /************************************************************************/
     534             : 
     535             : /**
     536             :  * Set name=value entry in the list.
     537             :  *
     538             :  * Similar to AddNameValue(), except if there is already a value for
     539             :  * the key in the list it is replaced instead of adding a new entry to
     540             :  * the list.  If pszValue is NULL any existing key entry is removed.
     541             :  *
     542             :  * @param pszKey the key name to add.
     543             :  * @param pszValue the key value to add.
     544             :  */
     545             : 
     546     3875060 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
     547             :                                            const char *pszValue)
     548             : 
     549             : {
     550     3875060 :     int iKey = FindName(pszKey);
     551             : 
     552     3875030 :     if (iKey == -1)
     553     3793760 :         return AddNameValue(pszKey, pszValue);
     554             : 
     555       81273 :     Count();
     556       81061 :     if (!MakeOurOwnCopy())
     557           0 :         return *this;
     558             : 
     559       81061 :     CPLFree(papszList[iKey]);
     560       81061 :     if (pszValue == nullptr)  // delete entry
     561             :     {
     562             : 
     563             :         // shift everything down by one.
     564         119 :         do
     565             :         {
     566         225 :             papszList[iKey] = papszList[iKey + 1];
     567         225 :         } while (papszList[iKey++] != nullptr);
     568             : 
     569         106 :         nCount--;
     570             :     }
     571             :     else
     572             :     {
     573      161910 :         if (strlen(pszKey) >
     574      161910 :                 std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     575       80955 :             strlen(pszKey) + strlen(pszValue) >
     576       80955 :                 std::numeric_limits<size_t>::max() - 2)
     577             :         {
     578           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     579             :                      "Too big strings in AddNameValue()");
     580           0 :             return *this;
     581             :         }
     582       80955 :         const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     583       80955 :         char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     584       80955 :         if (pszLine == nullptr)
     585           0 :             return *this;
     586       80955 :         snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     587             : 
     588       80955 :         papszList[iKey] = pszLine;
     589             :     }
     590             : 
     591       81061 :     return *this;
     592             : }
     593             : 
     594             : /************************************************************************/
     595             : /*                              operator[]                              */
     596             : /************************************************************************/
     597             : 
     598             : /**
     599             :  * Fetch entry "i".
     600             :  *
     601             :  * Fetches the requested item in the list.  Note that the returned string
     602             :  * remains owned by the CPLStringList.  If "i" is out of range NULL is
     603             :  * returned.
     604             :  *
     605             :  * @param i the index of the list item to return.
     606             :  * @return selected entry in the list.
     607             :  */
     608     1094870 : char *CPLStringList::operator[](int i)
     609             : 
     610             : {
     611     1094870 :     if (nCount == -1)
     612         181 :         Count();
     613             : 
     614     1094870 :     if (i < 0 || i >= nCount)
     615          52 :         return nullptr;
     616             : 
     617     1094810 :     return papszList[i];
     618             : }
     619             : 
     620      295728 : const char *CPLStringList::operator[](int i) const
     621             : 
     622             : {
     623      295728 :     if (nCount == -1)
     624          22 :         Count();
     625             : 
     626      295728 :     if (i < 0 || i >= nCount)
     627           2 :         return nullptr;
     628             : 
     629      295726 :     return papszList[i];
     630             : }
     631             : 
     632             : /************************************************************************/
     633             : /*                             StealList()                              */
     634             : /************************************************************************/
     635             : 
     636             : /**
     637             :  * Seize ownership of underlying string array.
     638             :  *
     639             :  * This method is similar to List(), except that the returned list is
     640             :  * now owned by the caller and the CPLStringList is emptied.
     641             :  *
     642             :  * @return the C style string list.
     643             :  */
     644     1316520 : char **CPLStringList::StealList()
     645             : 
     646             : {
     647     1316520 :     char **papszRetList = papszList;
     648             : 
     649     1316520 :     bOwnList = false;
     650     1316520 :     papszList = nullptr;
     651     1316520 :     nCount = 0;
     652     1316520 :     nAllocation = 0;
     653             : 
     654     1316520 :     return papszRetList;
     655             : }
     656             : 
     657             : /* Case insensitive comparison function */
     658      489828 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
     659             : {
     660      489828 :     const char *pszItera = pszKVa;
     661      489828 :     const char *pszIterb = pszKVb;
     662             :     while (true)
     663             :     {
     664     3738960 :         char cha = *pszItera;
     665     3738960 :         char chb = *pszIterb;
     666     3738960 :         if (cha == '=' || cha == '\0')
     667             :         {
     668        2337 :             if (chb == '=' || chb == '\0')
     669           2 :                 return 0;
     670             :             else
     671        2335 :                 return -1;
     672             :         }
     673     3736620 :         if (chb == '=' || chb == '\0')
     674             :         {
     675        2890 :             return 1;
     676             :         }
     677     3733730 :         if (cha >= 'a' && cha <= 'z')
     678      490743 :             cha -= ('a' - 'A');
     679     3733730 :         if (chb >= 'a' && chb <= 'z')
     680      491491 :             chb -= ('a' - 'A');
     681     3733730 :         if (cha < chb)
     682      286621 :             return -1;
     683     3447110 :         else if (cha > chb)
     684      197980 :             return 1;
     685     3249130 :         pszItera++;
     686     3249130 :         pszIterb++;
     687     3249130 :     }
     688             : }
     689             : 
     690             : /************************************************************************/
     691             : /*                                Sort()                                */
     692             : /************************************************************************/
     693             : 
     694             : /**
     695             :  * Sort the entries in the list and mark list sorted.
     696             :  *
     697             :  * Note that once put into "sorted" mode, the CPLStringList will attempt to
     698             :  * keep things in sorted order through calls to AddString(),
     699             :  * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
     700             :  * assignments (via Assign() and operator= will clear the sorting state.
     701             :  * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
     702             :  * will do a binary search to find the key, substantially improve lookup
     703             :  * performance in large lists.
     704             :  */
     705             : 
     706       29211 : CPLStringList &CPLStringList::Sort()
     707             : 
     708             : {
     709       29211 :     Count();
     710       29211 :     if (!MakeOurOwnCopy())
     711           0 :         return *this;
     712             : 
     713       29211 :     if (nCount > 1)
     714             :     {
     715        3836 :         std::sort(papszList, papszList + nCount,
     716      440944 :                   [](const char *a, const char *b)
     717      440944 :                   { return CPLCompareKeyValueString(a, b) < 0; });
     718             :     }
     719       29211 :     bIsSorted = true;
     720             : 
     721       29211 :     return *this;
     722             : }
     723             : 
     724             : /************************************************************************/
     725             : /*                              FindName()                              */
     726             : /************************************************************************/
     727             : 
     728             : /**
     729             :  * Get index of given name/value keyword.
     730             :  *
     731             :  * Note that this search is for a line in the form name=value or name:value.
     732             :  * Use FindString() or PartialFindString() for searches not based on name=value
     733             :  * pairs.
     734             :  *
     735             :  * @param pszKey the name to search for.
     736             :  *
     737             :  * @return the string list index of this name, or -1 on failure.
     738             :  */
     739             : 
     740    14750600 : int CPLStringList::FindName(const char *pszKey) const
     741             : 
     742             : {
     743    14750600 :     if (!IsSorted())
     744    14697300 :         return CSLFindName(papszList, pszKey);
     745             : 
     746             :     // If we are sorted, we can do an optimized binary search.
     747       26073 :     int iStart = 0;
     748       26073 :     int iEnd = nCount - 1;
     749       26073 :     size_t nKeyLen = strlen(pszKey);
     750             : 
     751       56671 :     while (iStart <= iEnd)
     752             :     {
     753       37528 :         const int iMiddle = (iEnd + iStart) / 2;
     754       37528 :         const char *pszMiddle = papszList[iMiddle];
     755             : 
     756       37528 :         if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
     757        7283 :             (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
     758        6930 :             return iMiddle;
     759             : 
     760       30598 :         if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
     761        8647 :             iEnd = iMiddle - 1;
     762             :         else
     763       21951 :             iStart = iMiddle + 1;
     764             :     }
     765             : 
     766       19143 :     return -1;
     767             : }
     768             : 
     769             : /************************************************************************/
     770             : /*                            FetchBool()                               */
     771             : /************************************************************************/
     772             : /**
     773             :  *
     774             :  * Check for boolean key value.
     775             :  *
     776             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     777             :  * with the given name, and if it can be interpreted as being TRUE.  If
     778             :  * the key appears without any "=Value" portion it will be considered true.
     779             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     780             :  * if the key appears in the list it will be considered TRUE.  If the key
     781             :  * doesn't appear at all, the indicated default value will be returned.
     782             :  *
     783             :  * @param pszKey the key value to look for (case insensitive).
     784             :  * @param bDefault the value to return if the key isn't found at all.
     785             :  *
     786             :  * @return true or false
     787             :  */
     788             : 
     789       12814 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
     790             : 
     791             : {
     792       12814 :     const char *pszValue = FetchNameValue(pszKey);
     793             : 
     794       12813 :     if (pszValue == nullptr)
     795       12604 :         return bDefault;
     796             : 
     797         209 :     return CPLTestBool(pszValue);
     798             : }
     799             : 
     800             : /************************************************************************/
     801             : /*                            FetchBoolean()                            */
     802             : /************************************************************************/
     803             : /**
     804             :  *
     805             :  * DEPRECATED: Check for boolean key value.
     806             :  *
     807             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     808             :  * with the given name, and if it can be interpreted as being TRUE.  If
     809             :  * the key appears without any "=Value" portion it will be considered true.
     810             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     811             :  * if the key appears in the list it will be considered TRUE.  If the key
     812             :  * doesn't appear at all, the indicated default value will be returned.
     813             :  *
     814             :  * @param pszKey the key value to look for (case insensitive).
     815             :  * @param bDefault the value to return if the key isn't found at all.
     816             :  *
     817             :  * @return TRUE or FALSE
     818             :  */
     819             : 
     820        3153 : int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
     821             : 
     822             : {
     823        3153 :     return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
     824             : }
     825             : 
     826             : /************************************************************************/
     827             : /*                           FetchNameValue()                           */
     828             : /************************************************************************/
     829             : 
     830             : /**
     831             :  * Fetch value associated with this key name.
     832             :  *
     833             :  * If this list sorted, a fast binary search is done, otherwise a linear
     834             :  * scan is done.  Name lookup is case insensitive.
     835             :  *
     836             :  * @param pszName the key name to search for.
     837             :  *
     838             :  * @return the corresponding value or NULL if not found.  The returned string
     839             :  * should not be modified and points into internal object state that may
     840             :  * change on future calls.
     841             :  */
     842             : 
     843    10878700 : const char *CPLStringList::FetchNameValue(const char *pszName) const
     844             : 
     845             : {
     846    10878700 :     const int iKey = FindName(pszName);
     847             : 
     848    10903500 :     if (iKey == -1)
     849     3779540 :         return nullptr;
     850             : 
     851     7123990 :     CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
     852             :               papszList[iKey][strlen(pszName)] == ':');
     853             : 
     854     7123990 :     return papszList[iKey] + strlen(pszName) + 1;
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                         FetchNameValueDef()                          */
     859             : /************************************************************************/
     860             : 
     861             : /**
     862             :  * Fetch value associated with this key name.
     863             :  *
     864             :  * If this list sorted, a fast binary search is done, otherwise a linear
     865             :  * scan is done.  Name lookup is case insensitive.
     866             :  *
     867             :  * @param pszName the key name to search for.
     868             :  * @param pszDefault the default value returned if the named entry isn't found.
     869             :  *
     870             :  * @return the corresponding value or the passed default if not found.
     871             :  */
     872             : 
     873       30777 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
     874             :                                              const char *pszDefault) const
     875             : 
     876             : {
     877       30777 :     const char *pszValue = FetchNameValue(pszName);
     878       30777 :     if (pszValue == nullptr)
     879       22859 :         return pszDefault;
     880             : 
     881        7918 :     return pszValue;
     882             : }
     883             : 
     884             : /************************************************************************/
     885             : /*                            InsertString()                            */
     886             : /************************************************************************/
     887             : 
     888             : /**
     889             :  * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
     890             :  *                                                 const char *pszNewLine );
     891             :  *
     892             :  * \brief Insert into the list at identified location.
     893             :  *
     894             :  * This method will insert a string into the list at the identified
     895             :  * location.  The insertion point must be within or at the end of the list.
     896             :  * The following entries are pushed down to make space.
     897             :  *
     898             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
     899             :  * @param pszNewLine to the line to insert.  This string will be copied.
     900             :  */
     901             : 
     902             : /************************************************************************/
     903             : /*                        InsertStringDirectly()                        */
     904             : /************************************************************************/
     905             : 
     906             : /**
     907             :  * Insert into the list at identified location.
     908             :  *
     909             :  * This method will insert a string into the list at the identified
     910             :  * location.  The insertion point must be within or at the end of the list.
     911             :  * The following entries are pushed down to make space.
     912             :  *
     913             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
     914             :  * @param pszNewLine to the line to insert, the ownership of this string
     915             :  * will be taken over the by the object.  It must have been allocated on the
     916             :  * heap.
     917             :  */
     918             : 
     919        6827 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
     920             :                                                    char *pszNewLine)
     921             : 
     922             : {
     923        6827 :     if (nCount == -1)
     924          27 :         Count();
     925             : 
     926        6827 :     if (!EnsureAllocation(nCount + 1))
     927             :     {
     928           0 :         VSIFree(pszNewLine);
     929           0 :         return *this;
     930             :     }
     931             : 
     932        6827 :     if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
     933             :     {
     934           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     935             :                  "CPLStringList::InsertString() requested beyond list end.");
     936           0 :         return *this;
     937             :     }
     938             : 
     939        6827 :     bIsSorted = false;
     940             : 
     941       23252 :     for (int i = nCount; i > nInsertAtLineNo; i--)
     942       16425 :         papszList[i] = papszList[i - 1];
     943             : 
     944        6827 :     papszList[nInsertAtLineNo] = pszNewLine;
     945        6827 :     papszList[++nCount] = nullptr;
     946             : 
     947        6827 :     return *this;
     948             : }
     949             : 
     950             : /************************************************************************/
     951             : /*                      FindSortedInsertionPoint()                      */
     952             : /*                                                                      */
     953             : /*      Find the location at which the indicated line should be         */
     954             : /*      inserted in order to keep things in sorted order.               */
     955             : /************************************************************************/
     956             : 
     957        6609 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
     958             : 
     959             : {
     960        6609 :     CPLAssert(IsSorted());
     961             : 
     962        6609 :     int iStart = 0;
     963        6609 :     int iEnd = nCount - 1;
     964             : 
     965       19732 :     while (iStart <= iEnd)
     966             :     {
     967       13123 :         const int iMiddle = (iEnd + iStart) / 2;
     968       13123 :         const char *pszMiddle = papszList[iMiddle];
     969             : 
     970       13123 :         if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
     971        2256 :             iEnd = iMiddle - 1;
     972             :         else
     973       10867 :             iStart = iMiddle + 1;
     974             :     }
     975             : 
     976        6609 :     iEnd++;
     977        6609 :     CPLAssert(iEnd >= 0 && iEnd <= nCount);
     978        6609 :     CPLAssert(iEnd == 0 ||
     979             :               CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
     980        6609 :     CPLAssert(iEnd == nCount ||
     981             :               CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
     982             : 
     983        6609 :     return iEnd;
     984             : }
     985             : 
     986             : namespace cpl
     987             : {
     988             : 
     989             : /************************************************************************/
     990             : /*             CSLIterator::operator==(const CSLIterator &other)        */
     991             : /************************************************************************/
     992             : 
     993             : /*! @cond Doxygen_Suppress */
     994      255425 : bool CSLIterator::operator==(const CSLIterator &other) const
     995             : {
     996      255425 :     if (!m_bAtEnd && other.m_bAtEnd)
     997             :     {
     998      255419 :         return m_papszList == nullptr || *m_papszList == nullptr;
     999             :     }
    1000           6 :     if (!m_bAtEnd && !other.m_bAtEnd)
    1001             :     {
    1002           0 :         return m_papszList == other.m_papszList;
    1003             :     }
    1004           6 :     if (m_bAtEnd && other.m_bAtEnd)
    1005             :     {
    1006           0 :         return true;
    1007             :     }
    1008           6 :     return false;
    1009             : }
    1010             : 
    1011             : /*! @endcond */
    1012             : 
    1013             : /************************************************************************/
    1014             : /*                      CSLNameValueIterator::operator*()               */
    1015             : /************************************************************************/
    1016             : 
    1017             : /*! @cond Doxygen_Suppress */
    1018        1297 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
    1019             : {
    1020        1297 :     if (m_papszList)
    1021             :     {
    1022        1298 :         while (*m_papszList)
    1023             :         {
    1024        1298 :             char *pszKey = nullptr;
    1025        1298 :             const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
    1026        1298 :             if (pszKey)
    1027             :             {
    1028        1295 :                 m_osKey = pszKey;
    1029        1295 :                 CPLFree(pszKey);
    1030        1295 :                 return {m_osKey.c_str(), pszValue};
    1031             :             }
    1032           3 :             else if (m_bReturnNullKeyIfNotNameValue)
    1033             :             {
    1034           2 :                 return {nullptr, *m_papszList};
    1035             :             }
    1036             :             // Skip entries that are not name=value pairs.
    1037           1 :             ++m_papszList;
    1038             :         }
    1039             :     }
    1040             :     // Should not happen
    1041           0 :     CPLAssert(false);
    1042             :     return {"", ""};
    1043             : }
    1044             : 
    1045             : /*! @endcond */
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                   CSLNameValueIteratorWrapper::end()                 */
    1049             : /************************************************************************/
    1050             : 
    1051             : /*! @cond Doxygen_Suppress */
    1052        3949 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
    1053             : {
    1054        3949 :     int nCount = CSLCount(m_papszList);
    1055        3949 :     if (!m_bReturnNullKeyIfNotNameValue)
    1056             :     {
    1057        3884 :         while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
    1058          12 :             --nCount;
    1059             :     }
    1060        3949 :     return CSLNameValueIterator{m_papszList + nCount,
    1061        3949 :                                 m_bReturnNullKeyIfNotNameValue};
    1062             : }
    1063             : 
    1064             : /*! @endcond */
    1065             : 
    1066             : }  // namespace cpl

Generated by: LCOV version 1.14