LCOV - code coverage report
Current view: top level - port - cplstringlist.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 305 331 92.1 %
Date: 2024-04-28 18:08:58 Functions: 36 36 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  CPLStringList implementation.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "cpl_string.h"
      32             : 
      33             : #include <cstddef>
      34             : #include <cstdio>
      35             : #include <cstdlib>
      36             : #include <cstring>
      37             : 
      38             : #include <algorithm>
      39             : #include <limits>
      40             : #include <string>
      41             : 
      42             : #include "cpl_conv.h"
      43             : #include "cpl_error.h"
      44             : 
      45             : /************************************************************************/
      46             : /*                           CPLStringList()                            */
      47             : /************************************************************************/
      48             : 
      49             : CPLStringList::CPLStringList() = default;
      50             : 
      51             : /************************************************************************/
      52             : /*                           CPLStringList()                            */
      53             : /************************************************************************/
      54             : 
      55             : /**
      56             :  * CPLStringList constructor.
      57             :  *
      58             :  * @param papszListIn the NULL terminated list of strings to consume.
      59             :  * @param bTakeOwnership TRUE if the CPLStringList should take ownership
      60             :  * of the list of strings which implies responsibility to free them.
      61             :  */
      62             : 
      63      243025 : CPLStringList::CPLStringList(char **papszListIn, int bTakeOwnership)
      64      243025 :     : CPLStringList()
      65             : 
      66             : {
      67      243025 :     Assign(papszListIn, bTakeOwnership);
      68      243025 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                           CPLStringList()                            */
      72             : /************************************************************************/
      73             : 
      74             : /**
      75             :  * CPLStringList constructor.
      76             :  *
      77             :  * The input list is copied.
      78             :  *
      79             :  * @param papszListIn the NULL terminated list of strings to ingest.
      80             :  */
      81             : 
      82        3551 : CPLStringList::CPLStringList(CSLConstList papszListIn) : CPLStringList()
      83             : 
      84             : {
      85        3551 :     Assign(CSLDuplicate(papszListIn));
      86        3551 : }
      87             : 
      88             : /************************************************************************/
      89             : /*                           CPLStringList()                            */
      90             : /************************************************************************/
      91             : 
      92             : /**
      93             :  * CPLStringList constructor.
      94             :  *
      95             :  * The input list is copied.
      96             :  *
      97             :  * @param aosList input list.
      98             :  *
      99             :  * @since GDAL 3.9
     100             :  */
     101         170 : CPLStringList::CPLStringList(const std::vector<std::string> &aosList)
     102             : {
     103         170 :     if (!aosList.empty())
     104             :     {
     105         134 :         bOwnList = true;
     106         134 :         papszList = static_cast<char **>(
     107         134 :             VSI_CALLOC_VERBOSE(aosList.size() + 1, sizeof(char *)));
     108         134 :         nCount = static_cast<int>(aosList.size());
     109         275 :         for (int i = 0; i < nCount; ++i)
     110             :         {
     111         141 :             papszList[i] = VSI_STRDUP_VERBOSE(aosList[i].c_str());
     112             :         }
     113             :     }
     114         170 : }
     115             : 
     116             : /************************************************************************/
     117             : /*                           CPLStringList()                            */
     118             : /************************************************************************/
     119             : 
     120             : /**
     121             :  * CPLStringList constructor.
     122             :  *
     123             :  * The input list is copied.
     124             :  *
     125             :  * @param oInitList input list.
     126             :  *
     127             :  * @since GDAL 3.9
     128             :  */
     129           3 : CPLStringList::CPLStringList(std::initializer_list<const char *> oInitList)
     130             : {
     131           9 :     for (const char *pszStr : oInitList)
     132             :     {
     133           6 :         AddString(pszStr);
     134             :     }
     135           3 : }
     136             : 
     137             : /************************************************************************/
     138             : /*                           CPLStringList()                            */
     139             : /************************************************************************/
     140             : 
     141             : //! Copy constructor
     142       15289 : CPLStringList::CPLStringList(const CPLStringList &oOther) : CPLStringList()
     143             : 
     144             : {
     145       15289 :     operator=(oOther);
     146       15289 : }
     147             : 
     148             : /************************************************************************/
     149             : /*                           CPLStringList()                            */
     150             : /************************************************************************/
     151             : 
     152             : //! Move constructor
     153      784679 : CPLStringList::CPLStringList(CPLStringList &&oOther) : CPLStringList()
     154             : 
     155             : {
     156      784671 :     operator=(std::move(oOther));
     157      784673 : }
     158             : 
     159             : /************************************************************************/
     160             : /*                           BoundToConstList()                         */
     161             : /************************************************************************/
     162             : 
     163             : /**
     164             :  * Return a CPLStringList that wraps the passed list.
     165             :  *
     166             :  * The input list is *NOT* copied and must be kept alive while the
     167             :  * return CPLStringList is used.
     168             :  *
     169             :  * @param papszListIn a NULL terminated list of strings to wrap into the CPLStringList
     170             :  * @since GDAL 3.9
     171             :  */
     172             : 
     173             : /* static */
     174          94 : const CPLStringList CPLStringList::BoundToConstList(CSLConstList papszListIn)
     175             : {
     176             :     return CPLStringList(const_cast<char **>(papszListIn),
     177          94 :                          /* bTakeOwnership= */ false);
     178             : }
     179             : 
     180             : /************************************************************************/
     181             : /*                             operator=()                              */
     182             : /************************************************************************/
     183             : 
     184       18003 : CPLStringList &CPLStringList::operator=(const CPLStringList &oOther)
     185             : {
     186       18003 :     if (this != &oOther)
     187             :     {
     188       18002 :         char **l_papszList = CSLDuplicate(oOther.papszList);
     189       18002 :         if (l_papszList)
     190             :         {
     191        5436 :             Assign(l_papszList, TRUE);
     192        5436 :             nAllocation = oOther.nCount > 0 ? oOther.nCount + 1 : 0;
     193        5436 :             nCount = oOther.nCount;
     194        5436 :             bIsSorted = oOther.bIsSorted;
     195             :         }
     196             :     }
     197             : 
     198       18003 :     return *this;
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                             operator=()                              */
     203             : /************************************************************************/
     204             : 
     205      789403 : CPLStringList &CPLStringList::operator=(CPLStringList &&oOther)
     206             : {
     207      789403 :     if (this != &oOther)
     208             :     {
     209      789403 :         Clear();
     210      789424 :         papszList = oOther.papszList;
     211      789424 :         oOther.papszList = nullptr;
     212      789424 :         nCount = oOther.nCount;
     213      789424 :         oOther.nCount = 0;
     214      789424 :         nAllocation = oOther.nAllocation;
     215      789424 :         oOther.nAllocation = 0;
     216      789424 :         bOwnList = oOther.bOwnList;
     217      789424 :         oOther.bOwnList = false;
     218      789424 :         bIsSorted = oOther.bIsSorted;
     219      789424 :         oOther.bIsSorted = true;
     220             :     }
     221             : 
     222      789424 :     return *this;
     223             : }
     224             : 
     225             : /************************************************************************/
     226             : /*                             operator=()                              */
     227             : /************************************************************************/
     228             : 
     229       22156 : CPLStringList &CPLStringList::operator=(CSLConstList papszListIn)
     230             : {
     231       22156 :     if (papszListIn != papszList)
     232             :     {
     233       10254 :         Assign(CSLDuplicate(papszListIn));
     234       10254 :         bIsSorted = false;
     235             :     }
     236             : 
     237       22156 :     return *this;
     238             : }
     239             : 
     240             : /************************************************************************/
     241             : /*                           ~CPLStringList()                           */
     242             : /************************************************************************/
     243             : 
     244     9733340 : CPLStringList::~CPLStringList()
     245             : 
     246             : {
     247     4866680 :     Clear();
     248     4866660 : }
     249             : 
     250             : /************************************************************************/
     251             : /*                               Clear()                                */
     252             : /************************************************************************/
     253             : 
     254             : /**
     255             :  * Clear the string list.
     256             :  */
     257     6113980 : CPLStringList &CPLStringList::Clear()
     258             : 
     259             : {
     260     6113980 :     if (bOwnList)
     261             :     {
     262      949946 :         CSLDestroy(papszList);
     263      949951 :         papszList = nullptr;
     264             : 
     265      949951 :         bOwnList = FALSE;
     266      949951 :         nAllocation = 0;
     267      949951 :         nCount = 0;
     268             :     }
     269             : 
     270     6113990 :     return *this;
     271             : }
     272             : 
     273             : /************************************************************************/
     274             : /*                               Assign()                               */
     275             : /************************************************************************/
     276             : 
     277             : /**
     278             :  * Assign a list of strings.
     279             :  *
     280             :  *
     281             :  * @param papszListIn the NULL terminated list of strings to consume.
     282             :  * @param bTakeOwnership TRUE if the CPLStringList should take ownership
     283             :  * of the list of strings which implies responsibility to free them.
     284             :  *
     285             :  * @return a reference to the CPLStringList on which it was invoked.
     286             :  */
     287             : 
     288      331388 : CPLStringList &CPLStringList::Assign(char **papszListIn, int bTakeOwnership)
     289             : 
     290             : {
     291      331388 :     Clear();
     292             : 
     293      331388 :     papszList = papszListIn;
     294      331388 :     bOwnList = CPL_TO_BOOL(bTakeOwnership);
     295             : 
     296      331388 :     if (papszList == nullptr || *papszList == nullptr)
     297       63708 :         nCount = 0;
     298             :     else
     299      267680 :         nCount = -1;  // unknown
     300             : 
     301      331388 :     nAllocation = 0;
     302      331388 :     bIsSorted = FALSE;
     303             : 
     304      331388 :     return *this;
     305             : }
     306             : 
     307             : /************************************************************************/
     308             : /*                               Count()                                */
     309             : /************************************************************************/
     310             : 
     311             : /**
     312             :  * @return count of strings in the list, zero if empty.
     313             :  */
     314             : 
     315     1985930 : int CPLStringList::Count() const
     316             : 
     317             : {
     318     1985930 :     if (nCount == -1)
     319             :     {
     320      257247 :         if (papszList == nullptr)
     321             :         {
     322           0 :             nCount = 0;
     323           0 :             nAllocation = 0;
     324             :         }
     325             :         else
     326             :         {
     327      257247 :             nCount = CSLCount(papszList);
     328      257247 :             nAllocation = std::max(nCount + 1, nAllocation);
     329             :         }
     330             :     }
     331             : 
     332     1985930 :     return nCount;
     333             : }
     334             : 
     335             : /************************************************************************/
     336             : /*                           MakeOurOwnCopy()                           */
     337             : /*                                                                      */
     338             : /*      If we don't own the list, a copy is made which we own.          */
     339             : /*      Necessary if we are going to modify the list.                   */
     340             : /************************************************************************/
     341             : 
     342     5342460 : bool CPLStringList::MakeOurOwnCopy()
     343             : 
     344             : {
     345     5342460 :     if (bOwnList)
     346     3070800 :         return true;
     347             : 
     348     2271660 :     if (papszList == nullptr)
     349     2271550 :         return true;
     350             : 
     351         108 :     Count();
     352          80 :     char **papszListNew = CSLDuplicate(papszList);
     353          80 :     if (papszListNew == nullptr)
     354             :     {
     355           0 :         return false;
     356             :     }
     357          80 :     papszList = papszListNew;
     358          80 :     bOwnList = true;
     359          80 :     nAllocation = nCount + 1;
     360          80 :     return true;
     361             : }
     362             : 
     363             : /************************************************************************/
     364             : /*                          EnsureAllocation()                          */
     365             : /*                                                                      */
     366             : /*      Ensure we have enough room allocated for at least the           */
     367             : /*      requested number of strings (so nAllocation will be at least    */
     368             : /*      one more than the target)                                       */
     369             : /************************************************************************/
     370             : 
     371     8059600 : bool CPLStringList::EnsureAllocation(int nMaxList)
     372             : 
     373             : {
     374     8059600 :     if (!bOwnList)
     375             :     {
     376     1832620 :         if (!MakeOurOwnCopy())
     377           0 :             return false;
     378             :     }
     379             : 
     380     8059580 :     if (papszList == nullptr || nAllocation <= nMaxList)
     381             :     {
     382             :         // we need to be able to store nMaxList+1 as an int,
     383             :         // and allocate (nMaxList+1) * sizeof(char*) bytes
     384     3775480 :         if (nMaxList < 0 || nMaxList > std::numeric_limits<int>::max() - 1 ||
     385     1887770 :             static_cast<size_t>(nMaxList) >
     386     1887770 :                 std::numeric_limits<size_t>::max() / sizeof(char *) - 1)
     387             :         {
     388           0 :             return false;
     389             :         }
     390     1887710 :         int nNewAllocation = nMaxList + 1;
     391     1887710 :         if (nNewAllocation <= (std::numeric_limits<int>::max() - 20) / 2 /
     392             :                                   static_cast<int>(sizeof(char *)))
     393     1887760 :             nNewAllocation = std::max(nNewAllocation * 2 + 20, nMaxList + 1);
     394     1887740 :         if (papszList == nullptr)
     395             :         {
     396     1834780 :             papszList = static_cast<char **>(
     397     1834790 :                 VSI_CALLOC_VERBOSE(nNewAllocation, sizeof(char *)));
     398     1834780 :             bOwnList = true;
     399     1834780 :             nCount = 0;
     400     1834780 :             if (papszList == nullptr)
     401           0 :                 return false;
     402             :         }
     403             :         else
     404             :         {
     405       52951 :             char **papszListNew = static_cast<char **>(VSI_REALLOC_VERBOSE(
     406             :                 papszList, nNewAllocation * sizeof(char *)));
     407       52951 :             if (papszListNew == nullptr)
     408           0 :                 return false;
     409       52951 :             papszList = papszListNew;
     410             :         }
     411     1887740 :         nAllocation = nNewAllocation;
     412             :     }
     413     8059580 :     return true;
     414             : }
     415             : 
     416             : /************************************************************************/
     417             : /*                         AddStringDirectly()                          */
     418             : /************************************************************************/
     419             : 
     420             : /**
     421             :  * Add a string to the list.
     422             :  *
     423             :  * This method is similar to AddString(), but ownership of the
     424             :  * pszNewString is transferred to the CPLStringList class.
     425             :  *
     426             :  * @param pszNewString the string to add to the list.
     427             :  */
     428             : 
     429     8051720 : CPLStringList &CPLStringList::AddStringDirectly(char *pszNewString)
     430             : 
     431             : {
     432     8051720 :     if (nCount == -1)
     433         109 :         Count();
     434             : 
     435     8051720 :     if (!EnsureAllocation(nCount + 1))
     436             :     {
     437           0 :         VSIFree(pszNewString);
     438           0 :         return *this;
     439             :     }
     440             : 
     441     8051740 :     papszList[nCount++] = pszNewString;
     442     8051740 :     papszList[nCount] = nullptr;
     443             : 
     444     8051740 :     bIsSorted = false;
     445             : 
     446     8051740 :     return *this;
     447             : }
     448             : 
     449             : /************************************************************************/
     450             : /*                             AddString()                              */
     451             : /************************************************************************/
     452             : 
     453             : /**
     454             :  * Add a string to the list.
     455             :  *
     456             :  * A copy of the passed in string is made and inserted in the list.
     457             :  *
     458             :  * @param pszNewString the string to add to the list.
     459             :  */
     460             : 
     461     4643100 : CPLStringList &CPLStringList::AddString(const char *pszNewString)
     462             : 
     463             : {
     464     4643100 :     char *pszDupString = VSI_STRDUP_VERBOSE(pszNewString);
     465     4643080 :     if (pszDupString == nullptr)
     466           0 :         return *this;
     467     4643080 :     return AddStringDirectly(pszDupString);
     468             : }
     469             : 
     470             : /************************************************************************/
     471             : /*                            AddNameValue()                            */
     472             : /************************************************************************/
     473             : 
     474             : /**
     475             :  * Add a name=value entry to the list.
     476             :  *
     477             :  * A key=value string is prepared and appended to the list.  There is no
     478             :  * check for other values for the same key in the list.
     479             :  *
     480             :  * @param pszKey the key name to add.
     481             :  * @param pszValue the key value to add.
     482             :  */
     483             : 
     484     3418990 : CPLStringList &CPLStringList::AddNameValue(const char *pszKey,
     485             :                                            const char *pszValue)
     486             : 
     487             : {
     488     3418990 :     if (pszKey == nullptr || pszValue == nullptr)
     489        2950 :         return *this;
     490             : 
     491     3416040 :     if (!MakeOurOwnCopy())
     492           0 :         return *this;
     493             : 
     494             :     /* -------------------------------------------------------------------- */
     495             :     /*      Format the line.                                                */
     496             :     /* -------------------------------------------------------------------- */
     497     6832110 :     if (strlen(pszKey) >
     498     6832120 :             std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     499     3416060 :         strlen(pszKey) + strlen(pszValue) >
     500     3416060 :             std::numeric_limits<size_t>::max() - 2)
     501             :     {
     502           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     503             :                  "Too big strings in AddNameValue()");
     504           0 :         return *this;
     505             :     }
     506     3416070 :     const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     507     3416070 :     char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     508     3416080 :     if (pszLine == nullptr)
     509           0 :         return *this;
     510     3416080 :     snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     511             : 
     512             :     /* -------------------------------------------------------------------- */
     513             :     /*      If we don't need to keep the sort order things are pretty       */
     514             :     /*      straight forward.                                               */
     515             :     /* -------------------------------------------------------------------- */
     516     3416080 :     if (!IsSorted())
     517     3408340 :         return AddStringDirectly(pszLine);
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      Find the proper insertion point.                                */
     521             :     /* -------------------------------------------------------------------- */
     522        7726 :     CPLAssert(IsSorted());
     523        7702 :     const int iKey = FindSortedInsertionPoint(pszLine);
     524        7702 :     InsertStringDirectly(iKey, pszLine);
     525        7702 :     bIsSorted = true;  // We have actually preserved sort order.
     526             : 
     527        7702 :     return *this;
     528             : }
     529             : 
     530             : /************************************************************************/
     531             : /*                            SetNameValue()                            */
     532             : /************************************************************************/
     533             : 
     534             : /**
     535             :  * Set name=value entry in the list.
     536             :  *
     537             :  * Similar to AddNameValue(), except if there is already a value for
     538             :  * the key in the list it is replaced instead of adding a new entry to
     539             :  * the list.  If pszValue is NULL any existing key entry is removed.
     540             :  *
     541             :  * @param pszKey the key name to add.
     542             :  * @param pszValue the key value to add.
     543             :  */
     544             : 
     545     3459780 : CPLStringList &CPLStringList::SetNameValue(const char *pszKey,
     546             :                                            const char *pszValue)
     547             : 
     548             : {
     549     3459780 :     int iKey = FindName(pszKey);
     550             : 
     551     3459750 :     if (iKey == -1)
     552     3386120 :         return AddNameValue(pszKey, pszValue);
     553             : 
     554       73635 :     Count();
     555       73608 :     if (!MakeOurOwnCopy())
     556           0 :         return *this;
     557             : 
     558       73608 :     CPLFree(papszList[iKey]);
     559       73608 :     if (pszValue == nullptr)  // delete entry
     560             :     {
     561             : 
     562             :         // shift everything down by one.
     563         110 :         do
     564             :         {
     565         198 :             papszList[iKey] = papszList[iKey + 1];
     566         198 :         } while (papszList[iKey++] != nullptr);
     567             : 
     568          88 :         nCount--;
     569             :     }
     570             :     else
     571             :     {
     572      147040 :         if (strlen(pszKey) >
     573      147040 :                 std::numeric_limits<size_t>::max() - strlen(pszValue) ||
     574       73520 :             strlen(pszKey) + strlen(pszValue) >
     575       73520 :                 std::numeric_limits<size_t>::max() - 2)
     576             :         {
     577           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     578             :                      "Too big strings in AddNameValue()");
     579           0 :             return *this;
     580             :         }
     581       73520 :         const size_t nLen = strlen(pszKey) + strlen(pszValue) + 2;
     582       73520 :         char *pszLine = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen));
     583       73520 :         if (pszLine == nullptr)
     584           0 :             return *this;
     585       73520 :         snprintf(pszLine, nLen, "%s=%s", pszKey, pszValue);
     586             : 
     587       73520 :         papszList[iKey] = pszLine;
     588             :     }
     589             : 
     590       73608 :     return *this;
     591             : }
     592             : 
     593             : /************************************************************************/
     594             : /*                              operator[]                              */
     595             : /************************************************************************/
     596             : 
     597             : /**
     598             :  * Fetch entry "i".
     599             :  *
     600             :  * Fetches the requested item in the list.  Note that the returned string
     601             :  * remains owned by the CPLStringList.  If "i" is out of range NULL is
     602             :  * returned.
     603             :  *
     604             :  * @param i the index of the list item to return.
     605             :  * @return selected entry in the list.
     606             :  */
     607     1048550 : char *CPLStringList::operator[](int i)
     608             : 
     609             : {
     610     1048550 :     if (nCount == -1)
     611         161 :         Count();
     612             : 
     613     1048550 :     if (i < 0 || i >= nCount)
     614          49 :         return nullptr;
     615             : 
     616     1048500 :     return papszList[i];
     617             : }
     618             : 
     619      193612 : const char *CPLStringList::operator[](int i) const
     620             : 
     621             : {
     622      193612 :     if (nCount == -1)
     623           1 :         Count();
     624             : 
     625      193612 :     if (i < 0 || i >= nCount)
     626           2 :         return nullptr;
     627             : 
     628      193610 :     return papszList[i];
     629             : }
     630             : 
     631             : /************************************************************************/
     632             : /*                             StealList()                              */
     633             : /************************************************************************/
     634             : 
     635             : /**
     636             :  * Seize ownership of underlying string array.
     637             :  *
     638             :  * This method is similar to List(), except that the returned list is
     639             :  * now owned by the caller and the CPLStringList is emptied.
     640             :  *
     641             :  * @return the C style string list.
     642             :  */
     643     1044820 : char **CPLStringList::StealList()
     644             : 
     645             : {
     646     1044820 :     char **papszRetList = papszList;
     647             : 
     648     1044820 :     bOwnList = false;
     649     1044820 :     papszList = nullptr;
     650     1044820 :     nCount = 0;
     651     1044820 :     nAllocation = 0;
     652             : 
     653     1044820 :     return papszRetList;
     654             : }
     655             : 
     656      363872 : static int CPLCompareKeyValueString(const char *pszKVa, const char *pszKVb)
     657             : {
     658      363872 :     const char *pszItera = pszKVa;
     659      363872 :     const char *pszIterb = pszKVb;
     660             :     while (true)
     661             :     {
     662     3558780 :         char cha = *pszItera;
     663     3558780 :         char chb = *pszIterb;
     664     3558780 :         if (cha == '=' || cha == '\0')
     665             :         {
     666        2535 :             if (chb == '=' || chb == '\0')
     667          87 :                 return 0;
     668             :             else
     669        2448 :                 return -1;
     670             :         }
     671     3556240 :         if (chb == '=' || chb == '\0')
     672             :         {
     673        2043 :             return 1;
     674             :         }
     675     3554200 :         if (cha >= 'a' && cha <= 'z')
     676      886314 :             cha -= ('a' - 'A');
     677     3554200 :         if (chb >= 'a' && chb <= 'z')
     678      893368 :             chb -= ('a' - 'A');
     679     3554200 :         if (cha < chb)
     680      183490 :             return -1;
     681     3370710 :         else if (cha > chb)
     682      175804 :             return 1;
     683     3194910 :         pszItera++;
     684     3194910 :         pszIterb++;
     685     3194910 :     }
     686             : }
     687             : 
     688             : /************************************************************************/
     689             : /*                            llCompareStr()                            */
     690             : /*                                                                      */
     691             : /*      Note this is case insensitive!  This is because we normally     */
     692             : /*      treat key value keywords as case insensitive.                   */
     693             : /************************************************************************/
     694      303809 : static int llCompareStr(const void *a, const void *b)
     695             : {
     696      303809 :     return CPLCompareKeyValueString(
     697             :         *static_cast<const char **>(const_cast<void *>(a)),
     698      303809 :         *static_cast<const char **>(const_cast<void *>(b)));
     699             : }
     700             : 
     701             : /************************************************************************/
     702             : /*                                Sort()                                */
     703             : /************************************************************************/
     704             : 
     705             : /**
     706             :  * Sort the entries in the list and mark list sorted.
     707             :  *
     708             :  * Note that once put into "sorted" mode, the CPLStringList will attempt to
     709             :  * keep things in sorted order through calls to AddString(),
     710             :  * AddStringDirectly(), AddNameValue(), SetNameValue(). Complete list
     711             :  * assignments (via Assign() and operator= will clear the sorting state.
     712             :  * When in sorted order FindName(), FetchNameValue() and FetchNameValueDef()
     713             :  * will do a binary search to find the key, substantially improve lookup
     714             :  * performance in large lists.
     715             :  */
     716             : 
     717       20188 : CPLStringList &CPLStringList::Sort()
     718             : 
     719             : {
     720       20188 :     Count();
     721       20188 :     if (!MakeOurOwnCopy())
     722           0 :         return *this;
     723             : 
     724       20188 :     if (nCount)
     725        8527 :         qsort(papszList, nCount, sizeof(char *), llCompareStr);
     726       20188 :     bIsSorted = true;
     727             : 
     728       20188 :     return *this;
     729             : }
     730             : 
     731             : /************************************************************************/
     732             : /*                              FindName()                              */
     733             : /************************************************************************/
     734             : 
     735             : /**
     736             :  * Get index of given name/value keyword.
     737             :  *
     738             :  * Note that this search is for a line in the form name=value or name:value.
     739             :  * Use FindString() or PartialFindString() for searches not based on name=value
     740             :  * pairs.
     741             :  *
     742             :  * @param pszKey the name to search for.
     743             :  *
     744             :  * @return the string list index of this name, or -1 on failure.
     745             :  */
     746             : 
     747    13809300 : int CPLStringList::FindName(const char *pszKey) const
     748             : 
     749             : {
     750    13809300 :     if (!IsSorted())
     751    13791300 :         return CSLFindName(papszList, pszKey);
     752             : 
     753             :     // If we are sorted, we can do an optimized binary search.
     754       16414 :     int iStart = 0;
     755       16414 :     int iEnd = nCount - 1;
     756       16414 :     size_t nKeyLen = strlen(pszKey);
     757             : 
     758       49781 :     while (iStart <= iEnd)
     759             :     {
     760       38290 :         const int iMiddle = (iEnd + iStart) / 2;
     761       38290 :         const char *pszMiddle = papszList[iMiddle];
     762             : 
     763       38290 :         if (EQUALN(pszMiddle, pszKey, nKeyLen) &&
     764        5366 :             (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':'))
     765        4923 :             return iMiddle;
     766             : 
     767       33367 :         if (CPLCompareKeyValueString(pszKey, pszMiddle) < 0)
     768       11358 :             iEnd = iMiddle - 1;
     769             :         else
     770       22009 :             iStart = iMiddle + 1;
     771             :     }
     772             : 
     773       11491 :     return -1;
     774             : }
     775             : 
     776             : /************************************************************************/
     777             : /*                            FetchBool()                               */
     778             : /************************************************************************/
     779             : /**
     780             :  *
     781             :  * Check for boolean key value.
     782             :  *
     783             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     784             :  * with the given name, and if it can be interpreted as being TRUE.  If
     785             :  * the key appears without any "=Value" portion it will be considered true.
     786             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     787             :  * if the key appears in the list it will be considered TRUE.  If the key
     788             :  * doesn't appear at all, the indicated default value will be returned.
     789             :  *
     790             :  * @param pszKey the key value to look for (case insensitive).
     791             :  * @param bDefault the value to return if the key isn't found at all.
     792             :  *
     793             :  * @return true or false
     794             :  */
     795             : 
     796        4876 : bool CPLStringList::FetchBool(const char *pszKey, bool bDefault) const
     797             : 
     798             : {
     799        4876 :     const char *pszValue = FetchNameValue(pszKey);
     800             : 
     801        4876 :     if (pszValue == nullptr)
     802        4822 :         return bDefault;
     803             : 
     804          54 :     return CPLTestBool(pszValue);
     805             : }
     806             : 
     807             : /************************************************************************/
     808             : /*                            FetchBoolean()                            */
     809             : /************************************************************************/
     810             : /**
     811             :  *
     812             :  * DEPRECATED: Check for boolean key value.
     813             :  *
     814             :  * In a CPLStringList of "Name=Value" pairs, look to see if there is a key
     815             :  * with the given name, and if it can be interpreted as being TRUE.  If
     816             :  * the key appears without any "=Value" portion it will be considered true.
     817             :  * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
     818             :  * if the key appears in the list it will be considered TRUE.  If the key
     819             :  * doesn't appear at all, the indicated default value will be returned.
     820             :  *
     821             :  * @param pszKey the key value to look for (case insensitive).
     822             :  * @param bDefault the value to return if the key isn't found at all.
     823             :  *
     824             :  * @return TRUE or FALSE
     825             :  */
     826             : 
     827        3054 : int CPLStringList::FetchBoolean(const char *pszKey, int bDefault) const
     828             : 
     829             : {
     830        3054 :     return FetchBool(pszKey, CPL_TO_BOOL(bDefault)) ? TRUE : FALSE;
     831             : }
     832             : 
     833             : /************************************************************************/
     834             : /*                           FetchNameValue()                           */
     835             : /************************************************************************/
     836             : 
     837             : /**
     838             :  * Fetch value associated with this key name.
     839             :  *
     840             :  * If this list sorted, a fast binary search is done, otherwise a linear
     841             :  * scan is done.  Name lookup is case insensitive.
     842             :  *
     843             :  * @param pszName the key name to search for.
     844             :  *
     845             :  * @return the corresponding value or NULL if not found.  The returned string
     846             :  * should not be modified and points into internal object state that may
     847             :  * change on future calls.
     848             :  */
     849             : 
     850    10349900 : const char *CPLStringList::FetchNameValue(const char *pszName) const
     851             : 
     852             : {
     853    10349900 :     const int iKey = FindName(pszName);
     854             : 
     855    10356300 :     if (iKey == -1)
     856     3319050 :         return nullptr;
     857             : 
     858     7037240 :     CPLAssert(papszList[iKey][strlen(pszName)] == '=' ||
     859             :               papszList[iKey][strlen(pszName)] == ':');
     860             : 
     861     7037240 :     return papszList[iKey] + strlen(pszName) + 1;
     862             : }
     863             : 
     864             : /************************************************************************/
     865             : /*                         FetchNameValueDef()                          */
     866             : /************************************************************************/
     867             : 
     868             : /**
     869             :  * Fetch value associated with this key name.
     870             :  *
     871             :  * If this list sorted, a fast binary search is done, otherwise a linear
     872             :  * scan is done.  Name lookup is case insensitive.
     873             :  *
     874             :  * @param pszName the key name to search for.
     875             :  * @param pszDefault the default value returned if the named entry isn't found.
     876             :  *
     877             :  * @return the corresponding value or the passed default if not found.
     878             :  */
     879             : 
     880       26823 : const char *CPLStringList::FetchNameValueDef(const char *pszName,
     881             :                                              const char *pszDefault) const
     882             : 
     883             : {
     884       26823 :     const char *pszValue = FetchNameValue(pszName);
     885       26823 :     if (pszValue == nullptr)
     886       18647 :         return pszDefault;
     887             : 
     888        8176 :     return pszValue;
     889             : }
     890             : 
     891             : /************************************************************************/
     892             : /*                            InsertString()                            */
     893             : /************************************************************************/
     894             : 
     895             : /**
     896             :  * \fn CPLStringList *CPLStringList::InsertString( int nInsertAtLineNo,
     897             :  *                                                 const char *pszNewLine );
     898             :  *
     899             :  * \brief Insert into the list at identified location.
     900             :  *
     901             :  * This method will insert a string into the list at the identified
     902             :  * location.  The insertion point must be within or at the end of the list.
     903             :  * The following entries are pushed down to make space.
     904             :  *
     905             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
     906             :  * @param pszNewLine to the line to insert.  This string will be copied.
     907             :  */
     908             : 
     909             : /************************************************************************/
     910             : /*                        InsertStringDirectly()                        */
     911             : /************************************************************************/
     912             : 
     913             : /**
     914             :  * Insert into the list at identified location.
     915             :  *
     916             :  * This method will insert a string into the list at the identified
     917             :  * location.  The insertion point must be within or at the end of the list.
     918             :  * The following entries are pushed down to make space.
     919             :  *
     920             :  * @param nInsertAtLineNo the line to insert at, zero to insert at front.
     921             :  * @param pszNewLine to the line to insert, the ownership of this string
     922             :  * will be taken over the by the object.  It must have been allocated on the
     923             :  * heap.
     924             :  */
     925             : 
     926        7832 : CPLStringList &CPLStringList::InsertStringDirectly(int nInsertAtLineNo,
     927             :                                                    char *pszNewLine)
     928             : 
     929             : {
     930        7832 :     if (nCount == -1)
     931          27 :         Count();
     932             : 
     933        7832 :     if (!EnsureAllocation(nCount + 1))
     934             :     {
     935           0 :         VSIFree(pszNewLine);
     936           0 :         return *this;
     937             :     }
     938             : 
     939        7832 :     if (nInsertAtLineNo < 0 || nInsertAtLineNo > nCount)
     940             :     {
     941           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     942             :                  "CPLStringList::InsertString() requested beyond list end.");
     943           0 :         return *this;
     944             :     }
     945             : 
     946        7832 :     bIsSorted = false;
     947             : 
     948       39186 :     for (int i = nCount; i > nInsertAtLineNo; i--)
     949       31354 :         papszList[i] = papszList[i - 1];
     950             : 
     951        7832 :     papszList[nInsertAtLineNo] = pszNewLine;
     952        7832 :     papszList[++nCount] = nullptr;
     953             : 
     954        7832 :     return *this;
     955             : }
     956             : 
     957             : /************************************************************************/
     958             : /*                      FindSortedInsertionPoint()                      */
     959             : /*                                                                      */
     960             : /*      Find the location at which the indicated line should be         */
     961             : /*      inserted in order to keep things in sorted order.               */
     962             : /************************************************************************/
     963             : 
     964        7702 : int CPLStringList::FindSortedInsertionPoint(const char *pszLine)
     965             : 
     966             : {
     967        7702 :     CPLAssert(IsSorted());
     968             : 
     969        7702 :     int iStart = 0;
     970        7702 :     int iEnd = nCount - 1;
     971             : 
     972       26860 :     while (iStart <= iEnd)
     973             :     {
     974       19158 :         const int iMiddle = (iEnd + iStart) / 2;
     975       19158 :         const char *pszMiddle = papszList[iMiddle];
     976             : 
     977       19158 :         if (CPLCompareKeyValueString(pszLine, pszMiddle) < 0)
     978        5159 :             iEnd = iMiddle - 1;
     979             :         else
     980       13999 :             iStart = iMiddle + 1;
     981             :     }
     982             : 
     983        7702 :     iEnd++;
     984        7702 :     CPLAssert(iEnd >= 0 && iEnd <= nCount);
     985        7702 :     CPLAssert(iEnd == 0 ||
     986             :               CPLCompareKeyValueString(pszLine, papszList[iEnd - 1]) >= 0);
     987        7702 :     CPLAssert(iEnd == nCount ||
     988             :               CPLCompareKeyValueString(pszLine, papszList[iEnd]) <= 0);
     989             : 
     990        7702 :     return iEnd;
     991             : }
     992             : 
     993             : namespace cpl
     994             : {
     995             : 
     996             : /************************************************************************/
     997             : /*             CSLIterator::operator==(const CSLIterator &other)        */
     998             : /************************************************************************/
     999             : 
    1000             : /*! @cond Doxygen_Suppress */
    1001      220406 : bool CSLIterator::operator==(const CSLIterator &other) const
    1002             : {
    1003      220406 :     if (!m_bAtEnd && other.m_bAtEnd)
    1004             :     {
    1005      220405 :         return m_papszList == nullptr || *m_papszList == nullptr;
    1006             :     }
    1007           1 :     if (!m_bAtEnd && !other.m_bAtEnd)
    1008             :     {
    1009           0 :         return m_papszList == other.m_papszList;
    1010             :     }
    1011           1 :     if (m_bAtEnd && other.m_bAtEnd)
    1012             :     {
    1013           0 :         return true;
    1014             :     }
    1015           1 :     return false;
    1016             : }
    1017             : 
    1018             : /*! @endcond */
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                      CSLNameValueIterator::operator*()               */
    1022             : /************************************************************************/
    1023             : 
    1024             : /*! @cond Doxygen_Suppress */
    1025        1120 : CSLNameValueIterator::value_type CSLNameValueIterator::operator*()
    1026             : {
    1027        1120 :     if (m_papszList)
    1028             :     {
    1029        1121 :         while (*m_papszList)
    1030             :         {
    1031        1121 :             char *pszKey = nullptr;
    1032        1121 :             const char *pszValue = CPLParseNameValue(*m_papszList, &pszKey);
    1033        1121 :             if (pszKey)
    1034             :             {
    1035        1118 :                 m_osKey = pszKey;
    1036        1118 :                 CPLFree(pszKey);
    1037        1118 :                 return {m_osKey.c_str(), pszValue};
    1038             :             }
    1039           3 :             else if (m_bReturnNullKeyIfNotNameValue)
    1040             :             {
    1041           2 :                 return {nullptr, *m_papszList};
    1042             :             }
    1043             :             // Skip entries that are not name=value pairs.
    1044           1 :             ++m_papszList;
    1045             :         }
    1046             :     }
    1047             :     // Should not happen
    1048           0 :     CPLAssert(false);
    1049             :     return {"", ""};
    1050             : }
    1051             : 
    1052             : /*! @endcond */
    1053             : 
    1054             : /************************************************************************/
    1055             : /*                   CSLNameValueIteratorWrapper::end()                 */
    1056             : /************************************************************************/
    1057             : 
    1058             : /*! @cond Doxygen_Suppress */
    1059        2443 : CSLNameValueIterator CSLNameValueIteratorWrapper::end() const
    1060             : {
    1061        2443 :     int nCount = CSLCount(m_papszList);
    1062        2443 :     if (!m_bReturnNullKeyIfNotNameValue)
    1063             :     {
    1064        2385 :         while (nCount > 0 && strchr(m_papszList[nCount - 1], '=') == nullptr)
    1065          12 :             --nCount;
    1066             :     }
    1067        2443 :     return CSLNameValueIterator{m_papszList + nCount,
    1068        2443 :                                 m_bReturnNullKeyIfNotNameValue};
    1069             : }
    1070             : 
    1071             : /*! @endcond */
    1072             : 
    1073             : }  // namespace cpl

Generated by: LCOV version 1.14