Main Page Class Hierarchy Compound List File List Compound Members File Members Related Pages

# cpl_string.cpp

    00001 /**********************************************************************
    00002  * $Id: cpl_string_cpp-source.html,v 1.1 2000/09/25 20:50:11 warmerda Exp $
    00003  *
    00004  * Name:     cpl_string.cpp
    00005  * Project:  CPL - Common Portability Library
    00006  * Purpose:  String and Stringlist manipulation functions.
    00007  * Author:   Daniel Morissette, danmo@videotron.ca
    00008  *
    00009  **********************************************************************
    00010  * Copyright (c) 1998, Daniel Morissette
    00011  *
    00012  * Permission is hereby granted, free of charge, to any person obtaining a
    00013  * copy of this software and associated documentation files (the "Software"),
    00014  * to deal in the Software without restriction, including without limitation
    00015  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    00016  * and/or sell copies of the Software, and to permit persons to whom the
    00017  * Software is furnished to do so, subject to the following conditions:
    00018  *
    00019  * The above copyright notice and this permission notice shall be included
    00020  * in all copies or substantial portions of the Software.
    00021  *
    00022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    00023  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00024  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    00025  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00026  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    00027  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    00028  * DEALINGS IN THE SOFTWARE.
    00029  **********************************************************************
    00030  *
    00031  * $Log: cpl_string_cpp-source.html,v $
    00031  * Revision 1.1  2000/09/25 20:50:11  warmerda
    00031  * New
    00031  *
    00032  * Revision 1.13  2000/08/22 17:47:50  warmerda
    00033  * Fixed declaration of gnCPLSPrintfBuffer.
    00034  *
    00035  * Revision 1.12  2000/08/18 21:20:54  svillene
    00036  * *** empty log message ***
    00037  *
    00038  * Revision 1.11  2000/03/30 05:38:48  warmerda
    00039  * added CPLParseNameValue
    00040  *
    00041  * Revision 1.10  1999/06/26 14:05:10  warmerda
    00042  * Added CSLFindString().
    00043  *
    00044  * Revision 1.9  1999/04/28 02:33:02  danmo
    00045  * CSLInsertStrings(): make sure papszStrList is NULL-terminated properly
    00046  *
    00047  * Revision 1.8  1999/03/12 21:19:49  danmo
    00048  * Fixed TokenizeStringComplex() vs strings ending with empty token,
    00049  * and fixed a problem with CSLAdd/SetNameValue() vs empty string list.
    00050  *
    00051  * Revision 1.7  1999/03/09 21:29:57  warmerda
    00052  * Added backslash escaping within string constants for tokenize function.
    00053  *
    00054  * Revision 1.6  1999/02/25 04:40:46  danmo
    00055  * Modif. CSLLoad() to use CPLReadLine() (better handling of newlines)
    00056  *
    00057  * Revision 1.5  1999/02/17 01:41:58  warmerda
    00058  * Added CSLGetField
    00059  *
    00060  * Revision 1.4  1998/12/15 19:01:40  warmerda
    00061  * *** empty log message ***
    00062  *
    00063  * Revision 1.3  1998/12/05 23:04:21  warmerda
    00064  * Use EQUALN() instead of strincmp() which doesn't exist on Linux.
    00065  *
    00066  * Revision 1.2  1998/12/04 21:40:42  danmo
    00067  * Added more Name=Value manipulation fuctions
    00068  *
    00069  * Revision 1.1  1998/12/03 18:26:02  warmerda
    00070  * New
    00071  *
    00072  **********************************************************************/
    00073
    00074 #include "cpl_string.h"
    00075 #include "cpl_vsi.h"
    00076
    00077 /*=====================================================================
    00078                     StringList manipulation functions.
    00079  =====================================================================*/
    00080
    00081 /**********************************************************************
    00082  *                       CSLAddString()
    00083  *
    00084  * Append a string to a StringList and return a pointer to the modified
    00085  * StringList.
    00086  * If the input StringList is NULL, then a new StringList is created.
    00087  **********************************************************************/
    00088 char **CSLAddString(char **papszStrList, const char *pszNewString)
    00089 {
    00090     int nItems=0;
    00091
    00092     if (pszNewString == NULL)
    00093         return papszStrList;    /* Nothing to do!*/
    00094
    00095     /* Allocate room for the new string */
    00096     if (papszStrList == NULL)
    00097         papszStrList = (char**) CPLCalloc(2,sizeof(char*));
    00098     else
    00099     {
    00100         nItems = CSLCount(papszStrList);
    00101         papszStrList = (char**)CPLRealloc(papszStrList,
    00102                                           (nItems+2)*sizeof(char*));
    00103     }
    00104
    00105     /* Copy the string in the list */
    00106     papszStrList[nItems] = CPLStrdup(pszNewString);
    00107     papszStrList[nItems+1] = NULL;
    00108
    00109     return papszStrList;
    00110 }
    00111
    00112 /**********************************************************************
    00113  *                       CSLCount()
    00114  *
    00115  * Return the number of lines in a Stringlist.
    00116  **********************************************************************/
    00117 int CSLCount(char **papszStrList)
    00118 {
    00119     int nItems=0;
    00120
    00121     if (papszStrList)
    00122     {
    00123         while(*papszStrList != NULL)
    00124         {
    00125             nItems++;
    00126             papszStrList++;
    00127         }
    00128     }
    00129
    00130     return nItems;
    00131 }
    00132
    00133
    00134 /************************************************************************/
    00135 /*                            CSLGetField()                             */
    00136 /*                                                                      */
    00137 /*      Fetches the indicated field, being careful not to crash if      */
    00138 /*      the field doesn't exist within this string list.  The           */
    00139 /*      returned pointer should not be freed, and doesn't               */
    00140 /*      necessarily last long.                                          */
    00141 /************************************************************************/
    00142
    00143 const char * CSLGetField( char ** papszStrList, int iField )
    00144
    00145 {
    00146     int         i;
    00147
    00148     if( papszStrList == NULL || iField < 0 )
    00149         return( "" );
    00150
    00151     for( i = 0; i < iField+1; i++ )
    00152     {
    00153         if( papszStrList[i] == NULL )
    00154             return "";
    00155     }
    00156
    00157     return( papszStrList[iField] );
    00158 }
    00159
    00160 /**********************************************************************
    00161  *                       CSLDestroy()
    00162  *
    00163  * Free all memory used by a StringList.
    00164  **********************************************************************/
    00165 void CSLDestroy(char **papszStrList)
    00166 {
    00167     char **papszPtr;
    00168
    00169     if (papszStrList)
    00170     {
    00171         papszPtr = papszStrList;
    00172         while(*papszPtr != NULL)
    00173         {
    00174             CPLFree(*papszPtr);
    00175             papszPtr++;
    00176         }
    00177
    00178         CPLFree(papszStrList);
    00179     }
    00180 }
    00181
    00182
    00183 /**********************************************************************
    00184  *                       CSLDuplicate()
    00185  *
    00186  * Allocate and return a copy of a StringList.
    00187  **********************************************************************/
    00188 char    **CSLDuplicate(char **papszStrList)
    00189 {
    00190     char **papszNewList, **papszSrc, **papszDst;
    00191     int  nLines;
    00192
    00193     nLines = CSLCount(papszStrList);
    00194
    00195     if (nLines == 0)
    00196         return NULL;
    00197
    00198     papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*));
    00199     papszSrc = papszStrList;
    00200     papszDst = papszNewList;
    00201
    00202     while(*papszSrc != NULL)
    00203     {
    00204         *papszDst = CPLStrdup(*papszSrc);
    00205
    00206         papszSrc++;
    00207         papszDst++;
    00208     }
    00209     *papszDst = NULL;
    00210
    00211     return papszNewList;
    00212 }
    00213
    00214 /**********************************************************************
    00215  *                       CSLLoad()
    00216  *
    00217  * Load a test file into a stringlist.
    00218  *
    00219  * Lines are limited in length by the size fo the CPLReadLine() buffer.
    00220  **********************************************************************/
    00221 char **CSLLoad(const char *pszFname)
    00222 {
    00223     FILE        *fp;
    00224     const char  *pszLine;
    00225     char        **papszStrList=NULL;
    00226
    00227     fp = VSIFOpen(pszFname, "rt");
    00228
    00229     if (fp)
    00230     {
    00231         while(!VSIFEof(fp))
    00232         {
    00233             if ( (pszLine = CPLReadLine(fp)) != NULL )
    00234             {
    00235                 papszStrList = CSLAddString(papszStrList, pszLine);
    00236             }
    00237         }
    00238
    00239         VSIFClose(fp);
    00240     }
    00241     else
    00242     {
    00243         /* Unable to open file */
    00244         CPLError(CE_Failure, CPLE_OpenFailed,
    00245                  "CSLLoad(%s): %s", pszFname, strerror(errno));
    00246     }
    00247
    00248     return papszStrList;
    00249 }
    00250
    00251 /**********************************************************************
    00252  *                       CSLSave()
    00253  *
    00254  * Write a stringlist to a text file.
    00255  *
    00256  * Returns the number of lines written, or 0 if the file could not
    00257  * be written.
    00258  **********************************************************************/
    00259 int  CSLSave(char **papszStrList, const char *pszFname)
    00260 {
    00261     FILE    *fp;
    00262     int     nLines=0;
    00263
    00264     if (papszStrList)
    00265     {
    00266         if ((fp = VSIFOpen(pszFname, "wt")) != NULL)
    00267         {
    00268             while(*papszStrList != NULL)
    00269             {
    00270                 if (VSIFPuts(*papszStrList, fp) == EOF ||
    00271                     VSIFPutc('\n', fp) == EOF)
    00272                 {
    00273                     CPLError(CE_Failure, CPLE_FileIO,
    00274                              "CSLSave(%s): %s", pszFname,
    00275                              strerror(errno));
    00276                     break;  /* A Problem happened... abort */
    00277                 }
    00278
    00279                 nLines++;
    00280                 papszStrList++;
    00281             }
    00282
    00283             VSIFClose(fp);
    00284         }
    00285         else
    00286         {
    00287             /* Unable to open file */
    00288             CPLError(CE_Failure, CPLE_OpenFailed,
    00289                      "CSLSave(%s): %s", pszFname, strerror(errno));
    00290         }
    00291     }
    00292
    00293     return nLines;
    00294 }
    00295
    00296 /**********************************************************************
    00297  *                       CSLPrint()
    00298  *
    00299  * Print a StringList to fpOut.  If fpOut==NULL, then output is sent
    00300  * to stdout.
    00301  *
    00302  * Returns the number of lines printed.
    00303  **********************************************************************/
    00304 int  CSLPrint(char **papszStrList, FILE *fpOut)
    00305 {
    00306     int     nLines=0;
    00307
    00308     if (fpOut == NULL)
    00309         fpOut = stdout;
    00310
    00311     if (papszStrList)
    00312     {
    00313         while(*papszStrList != NULL)
    00314         {
    00315             VSIFPrintf(fpOut, "%s\n", *papszStrList);
    00316             nLines++;
    00317             papszStrList++;
    00318         }
    00319     }
    00320
    00321     return nLines;
    00322 }
    00323
    00324
    00325 /**********************************************************************
    00326  *                       CSLInsertStrings()
    00327  *
    00328  * Copies the contents of a StringList inside another StringList
    00329  * before the specified line.
    00330  *
    00331  * nInsertAtLineNo is a 0-based line index before which the new strings
    00332  * should be inserted.  If this value is -1 or is larger than the actual
    00333  * number of strings in the list then the strings are added at the end
    00334  * of the source StringList.
    00335  *
    00336  * Returns the modified StringList.
    00337  **********************************************************************/
    00338 char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
    00339                         char **papszNewLines)
    00340 {
    00341     int     i, nSrcLines, nDstLines, nToInsert;
    00342     char    **ppszSrc, **ppszDst;
    00343
    00344     if (papszNewLines == NULL ||
    00345         ( nToInsert = CSLCount(papszNewLines) ) == 0)
    00346         return papszStrList;    /* Nothing to do!*/
    00347
    00348     nSrcLines = CSLCount(papszStrList);
    00349     nDstLines = nSrcLines + nToInsert;
    00350
    00351     /* Allocate room for the new strings */
    00352     papszStrList = (char**)CPLRealloc(papszStrList,
    00353                                       (nDstLines+1)*sizeof(char*));
    00354
    00355     /* Make sure the array is NULL-terminated... it may not be if
    00356      * papszStrList was NULL before Realloc()
    00357      */
    00358     papszStrList[nSrcLines] = NULL;
    00359
    00360     /* Make some room in the original list at the specified location
    00361      * Note that we also have to move the NULL pointer at the end of
    00362      * the source StringList.
    00363      */
    00364     if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
    00365         nInsertAtLineNo = nSrcLines;
    00366
    00367     ppszSrc = papszStrList + nSrcLines;
    00368     ppszDst = papszStrList + nDstLines;
    00369
    00370     for (i=nSrcLines; i>=nInsertAtLineNo; i--)
    00371     {
    00372         *ppszDst = *ppszSrc;
    00373         ppszDst--;
    00374         ppszSrc--;
    00375     }
    00376
    00377     /* Copy the strings to the list */
    00378     ppszSrc = papszNewLines;
    00379     ppszDst = papszStrList + nInsertAtLineNo;
    00380
    00381     for (; *ppszSrc != NULL; ppszSrc++, ppszDst++)
    00382     {
    00383         *ppszDst = CPLStrdup(*ppszSrc);
    00384     }
    00385
    00386     return papszStrList;
    00387 }
    00388
    00389 /**********************************************************************
    00390  *                       CSLInsertString()
    00391  *
    00392  * Insert a string at a given line number inside a StringList
    00393  *
    00394  * nInsertAtLineNo is a 0-based line index before which the new string
    00395  * should be inserted.  If this value is -1 or is larger than the actual
    00396  * number of strings in the list then the string is added at the end
    00397  * of the source StringList.
    00398  *
    00399  * Returns the modified StringList.
    00400  **********************************************************************/
    00401 char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
    00402                            char *pszNewLine)
    00403 {
    00404     char *apszList[2];
    00405
    00406     /* Create a temporary StringList and call CSLInsertStrings()
    00407      */
    00408     apszList[0] = pszNewLine;
    00409     apszList[1] = NULL;
    00410
    00411     return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
    00412 }
    00413
    00414
    00415 /**********************************************************************
    00416  *                       CSLRemoveStrings()
    00417  *
    00418  * Remove strings inside a StringList
    00419  *
    00420  * nFirstLineToDelete is the 0-based line index of the first line to
    00421  * remove. If this value is -1 or is larger than the actual
    00422  * number of strings in list then the nNumToRemove last strings are
    00423  * removed.
    00424  *
    00425  * If ppapszRetStrings != NULL then the deleted strings won't be
    00426  * free'd, they will be stored in a new StringList and the pointer to
    00427  * this new list will be returned in *ppapszRetStrings.
    00428  *
    00429  * Returns the modified StringList.
    00430  **********************************************************************/
    00431 char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
    00432                         int nNumToRemove, char ***ppapszRetStrings)
    00433 {
    00434     int     i, nSrcLines, nDstLines;
    00435     char    **ppszSrc, **ppszDst;
    00436
    00437     nSrcLines = CSLCount(papszStrList);
    00438     nDstLines = nSrcLines - nNumToRemove;
    00439
    00440     if (nNumToRemove < 1 || nSrcLines == 0)
    00441         return papszStrList;    /* Nothing to do!*/
    00442
    00443     /* If operation will result in an empty StringList then don't waste
    00444      * time here!
    00445      */
    00446     if (nDstLines < 1)
    00447     {
    00448         CSLDestroy(papszStrList);
    00449         return NULL;
    00450     }
    00451
    00452
    00453     /* Remove lines from the source StringList...
    00454      * Either free() each line or store them to a new StringList depending on
    00455      * the caller's choice.
    00456      */
    00457     ppszDst = papszStrList + nFirstLineToDelete;
    00458
    00459     if (ppapszRetStrings == NULL)
    00460     {
    00461         /* free() all the strings that will be removed.
    00462          */
    00463         for (i=0; i < nNumToRemove; i++)
    00464         {
    00465             CPLFree(*ppszDst);
    00466             *ppszDst = NULL;
    00467         }
    00468     }
    00469     else
    00470     {
    00471         /* Store the strings to remove in a new StringList
    00472          */
    00473         *ppapszRetStrings = (char **)CPLCalloc(nNumToRemove+1, sizeof(char*));
    00474
    00475         for (i=0; i < nNumToRemove; i++)
    00476         {
    00477             (*ppapszRetStrings)[i] = *ppszDst;
    00478             *ppszDst = NULL;
    00479             ppszDst++;
    00480         }
    00481     }
    00482
    00483
    00484     /* Shift down all the lines that follow the lines to remove.
    00485      */
    00486     if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
    00487         nFirstLineToDelete = nDstLines;
    00488
    00489     ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
    00490     ppszDst = papszStrList + nFirstLineToDelete;
    00491
    00492     for ( ; *ppszSrc != NULL; ppszSrc++, ppszDst++)
    00493     {
    00494         *ppszDst = *ppszSrc;
    00495     }
    00496     /* Move the NULL pointer at the end of the StringList     */
    00497     *ppszDst = *ppszSrc;
    00498
    00499     /* At this point, we could realloc() papszStrList to a smaller size, but
    00500      * since this array will likely grow again in further operations on the
    00501      * StringList we'll leave it as it is.
    00502      */
    00503
    00504     return papszStrList;
    00505 }
    00506
    00507 /************************************************************************/
    00508 /*                           CSLFindString()                            */
    00509 /*                                                                      */
    00510 /*      Find a string within a string list.  The string must match      */
    00511 /*      the full length, but the comparison is case insensitive.        */
    00512 /*      Return -1 on failure.                                           */
    00513 /************************************************************************/
    00514
    00515 int CSLFindString( char ** papszList, const char * pszTarget )
    00516
    00517 {
    00518     int         i;
    00519
    00520     if( papszList == NULL )
    00521         return -1;
    00522
    00523     for( i = 0; papszList[i] != NULL; i++ )
    00524     {
    00525         if( EQUAL(papszList[i],pszTarget) )
    00526             return i;
    00527     }
    00528
    00529     return -1;
    00530 }
    00531
    00532 /**********************************************************************
    00533  *                       CSLTokenizeString()
    00534  *
    00535  * Tokenizes a string and returns a StringList with one string for
    00536  * each token.
    00537  **********************************************************************/
    00538 char    **CSLTokenizeString( const char *pszString )
    00539 {
    00540     return CSLTokenizeStringComplex( pszString, " ", TRUE, FALSE );
    00541 }
    00542
    00543 /************************************************************************/
    00544 /*                      CSLTokenizeStringComplex()                      */
    00545 /*                                                                      */
    00546 /*      The ultimate tokenizer?                                         */
    00547 /************************************************************************/
    00548
    00549 char ** CSLTokenizeStringComplex( const char * pszString,
    00550                                   const char * pszDelimiters,
    00551                                   int bHonourStrings, int bAllowEmptyTokens )
    00552
    00553 {
    00554     char        **papszRetList = NULL;
    00555     char        *pszToken;
    00556     int         nTokenMax, nTokenLen;
    00557
    00558     pszToken = (char *) CPLCalloc(10,1);
    00559     nTokenMax = 10;
    00560
    00561     while( pszString != NULL && *pszString != '\0' )
    00562     {
    00563         int     bInString = FALSE;
    00564
    00565         nTokenLen = 0;
    00566
    00567         /* Try to find the next delimeter, marking end of token */
    00568         for( ; *pszString != '\0'; pszString++ )
    00569         {
    00570
    00571             /* End if this is a delimeter skip it and break. */
    00572             if( !bInString && strchr(pszDelimiters, *pszString) != NULL )
    00573             {
    00574                 pszString++;
    00575                 break;
    00576             }
    00577
    00578             /* If this is a quote, and we are honouring constant
    00579                strings, then process the constant strings, with out delim
    00580                but don't copy over the quotes */
    00581             if( bHonourStrings && *pszString == '"' )
    00582             {
    00583                 if( bInString )
    00584                 {
    00585                     bInString = FALSE;
    00586                     continue;
    00587                 }
    00588                 else
    00589                 {
    00590                     bInString = TRUE;
    00591                     continue;
    00592                 }
    00593             }
    00594
    00595             /* Within string constants we allow for escaped quotes, but
    00596                in processing them we will unescape the quotes */
    00597             if( bInString && pszString[0] == '\\' && pszString[1] == '"' )
    00598             {
    00599                 pszString++;
    00600             }
    00601
    00602             /* Within string constants a \\ sequence reduces to \ */
    00603             else if( bInString
    00604                      && pszString[0] == '\\' && pszString[1] == '\\' )
    00605             {
    00606                 pszString++;
    00607             }
    00608
    00609             if( nTokenLen >= nTokenMax-1 )
    00610             {
    00611                 nTokenMax = nTokenMax * 2 + 10;
    00612                 pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
    00613             }
    00614
    00615             pszToken[nTokenLen] = *pszString;
    00616             nTokenLen++;
    00617         }
    00618
    00619         pszToken[nTokenLen] = '\0';
    00620
    00621         if( pszToken[0] != '\0' || bAllowEmptyTokens )
    00622         {
    00623             papszRetList = CSLAddString( papszRetList, pszToken );
    00624         }
    00625
    00626         /* If the last token is an empty token, then we have to catch
    00627          * it now, otherwise we won't reenter the loop and it will be lost.
    00628          */
    00629         if ( *pszString == '\0' && bAllowEmptyTokens &&
    00630              strchr(pszDelimiters, *(pszString-1)) )
    00631         {
    00632             papszRetList = CSLAddString( papszRetList, "" );
    00633         }
    00634     }
    00635
    00636     if( papszRetList == NULL )
    00637         papszRetList = (char **) CPLCalloc(sizeof(char *),1);
    00638
    00639     CPLFree( pszToken );
    00640
    00641     return papszRetList;
    00642 }
    00643
    00644 /**********************************************************************
    00645  *                       CPLSPrintf()
    00646  *
    00647  * My own version of CPLSPrintf() that works with 10 static buffer.
    00648  *
    00649  * It returns a ref. to a static buffer that should not be freed and
    00650  * is valid only until the next call to CPLSPrintf().
    00651  *
    00652  * NOTE: This function should move to cpl_conv.cpp.
    00653  **********************************************************************/
    00654 /* For now, assume that a 8000 chars buffer will be enough.
    00655  */
    00656 #define CPLSPrintf_BUF_SIZE 8000
    00657 #define CPLSPrintf_BUF_Count 10
    00658 static char gszCPLSPrintfBuffer[CPLSPrintf_BUF_Count][CPLSPrintf_BUF_SIZE];
    00659 static int gnCPLSPrintfBuffer = 0;
    00660
    00661 const char *CPLSPrintf(char *fmt, ...)
    00662 {
    00663     va_list args;
    00664
    00665     va_start(args, fmt);
    00666     vsprintf(gszCPLSPrintfBuffer[gnCPLSPrintfBuffer], fmt, args);
    00667     va_end(args);
    00668
    00669    int nCurrent = gnCPLSPrintfBuffer;
    00670
    00671     if (++gnCPLSPrintfBuffer == CPLSPrintf_BUF_Count)
    00672       gnCPLSPrintfBuffer = 0;
    00673
    00674     return gszCPLSPrintfBuffer[nCurrent];
    00675 }
    00676
    00677 /**********************************************************************
    00678  *                       CSLAppendPrintf()
    00679  *
    00680  * Use CPLSPrintf() to append a new line at the end of a StringList.
    00681  *
    00682  * Returns the modified StringList.
    00683  **********************************************************************/
    00684 char **CSLAppendPrintf(char **papszStrList, char *fmt, ...)
    00685 {
    00686     va_list args;
    00687
    00688     va_start(args, fmt);
    00689     vsprintf(gszCPLSPrintfBuffer[gnCPLSPrintfBuffer], fmt, args);
    00690     va_end(args);
    00691
    00692     int nCurrent = gnCPLSPrintfBuffer;
    00693
    00694     if (++gnCPLSPrintfBuffer == CPLSPrintf_BUF_Count)
    00695       gnCPLSPrintfBuffer = 0;
    00696
    00697     return CSLAddString(papszStrList, gszCPLSPrintfBuffer[nCurrent]);
    00698 }
    00699
    00700
    00701 /**********************************************************************
    00702  *                       CSLFetchNameValue()
    00703  *
    00704  * In a StringList of "Name=Value" pairs, look for the
    00705  * first value associated with the specified name.  The search is not
    00706  * case sensitive.
    00707  * ("Name:Value" pairs are also supported for backward compatibility
    00708  * with older stuff.)
    00709  *
    00710  * Returns a reference to the value in the StringList that the caller
    00711  * should not attempt to free.
    00712  *
    00713  * Returns NULL if the name is not found.
    00714  **********************************************************************/
    00715 const char *CSLFetchNameValue(char **papszStrList, const char *pszName)
    00716 {
    00717     int nLen;
    00718
    00719     if (papszStrList == NULL || pszName == NULL)
    00720         return NULL;
    00721
    00722     nLen = strlen(pszName);
    00723     while(*papszStrList != NULL)
    00724     {
    00725         if (EQUALN(*papszStrList, pszName, nLen)
    00726             && ( (*papszStrList)[nLen] == '=' ||
    00727                  (*papszStrList)[nLen] == ':' ) )
    00728         {
    00729             return (*papszStrList)+nLen+1;
    00730         }
    00731         papszStrList++;
    00732     }
    00733     return NULL;
    00734 }
    00735
    00736 /**********************************************************************
    00737  *                       CPLParseNameValue()
    00738  **********************************************************************/
    00739
    00760 const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey )
    00761
    00762 {
    00763     int  i;
    00764     const char *pszValue;
    00765
    00766     for( i = 0; pszNameValue[i] != '\0'; i++ )
    00767     {
    00768         if( pszNameValue[i] == '=' || pszNameValue[i] == ':' )
    00769         {
    00770             pszValue = pszNameValue + i + 1;
    00771             while( *pszValue == ' ' || *pszValue == '\t' )
    00772                 pszValue++;
    00773
    00774             if( ppszKey != NULL )
    00775             {
    00776                 *ppszKey = (char *) CPLMalloc(i+1);
    00777                 strncpy( *ppszKey, pszNameValue, i );
    00778                 (*ppszKey)[i] = '\0';
    00779                 while( i > 0 &&
    00780                        ( (*ppszKey)[i] == ' ' || (*ppszKey)[i] == '\t') )
    00781                 {
    00782                     (*ppszKey)[i] = '\0';
    00783                     i--;
    00784                 }
    00785             }
    00786
    00787             return pszValue;
    00788         }
    00789
    00790     }
    00791
    00792     return NULL;
    00793 }
    00794
    00795 /**********************************************************************
    00796  *                       CSLFetchNameValueMultiple()
    00797  *
    00798  * In a StringList of "Name=Value" pairs, look for all the
    00799  * values with the specified name.  The search is not case
    00800  * sensitive.
    00801  * ("Name:Value" pairs are also supported for backward compatibility
    00802  * with older stuff.)
    00803  *
    00804  * Returns stringlist with one entry for each occurence of the
    00805  * specified name.  The stringlist should eventually be destroyed
    00806  * by calling CSLDestroy().
    00807  *
    00808  * Returns NULL if the name is not found.
    00809  **********************************************************************/
    00810 char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName)
    00811 {
    00812     int nLen;
    00813     char **papszValues = NULL;
    00814
    00815     if (papszStrList == NULL || pszName == NULL)
    00816         return NULL;
    00817
    00818     nLen = strlen(pszName);
    00819     while(*papszStrList != NULL)
    00820     {
    00821         if (EQUALN(*papszStrList, pszName, nLen)
    00822             && ( (*papszStrList)[nLen] == '=' ||
    00823                  (*papszStrList)[nLen] == ':' ) )
    00824         {
    00825             papszValues = CSLAddString(papszValues,
    00826                                           (*papszStrList)+nLen+1);
    00827         }
    00828         papszStrList++;
    00829     }
    00830
    00831     return papszValues;
    00832 }
    00833
    00834
    00835 /**********************************************************************
    00836  *                       CSLAddNameValue()
    00837  *
    00838  * Add a new entry to a StringList of "Name=Value" pairs,
    00839  * ("Name:Value" pairs are also supported for backward compatibility
    00840  * with older stuff.)
    00841  *
    00842  * This function does not check if a "Name=Value" pair already exists
    00843  * for that name and can generate multiple entryes for the same name.
    00844  * Use CSLSetNameValue() if you want each name to have only one value.
    00845  *
    00846  * Returns the modified stringlist.
    00847  **********************************************************************/
    00848 char **CSLAddNameValue(char **papszStrList,
    00849                     const char *pszName, const char *pszValue)
    00850 {
    00851     const char *pszLine;
    00852
    00853     if (pszName == NULL || pszValue==NULL)
    00854         return papszStrList;
    00855
    00856     pszLine = CPLSPrintf("%s=%s", pszName, pszValue);
    00857
    00858     return CSLAddString(papszStrList, pszLine);
    00859 }
    00860
    00861 /**********************************************************************
    00862  *                       CSLSetNameValue()
    00863  *
    00864  * Set the value for a given name in a StringList of "Name=Value" pairs
    00865  * ("Name:Value" pairs are also supported for backward compatibility
    00866  * with older stuff.)
    00867  *
    00868  * If there is already a value for that name in the list then the value
    00869  * is changed, otherwise a new "Name=Value" pair is added.
    00870  *
    00871  * Returns the modified stringlist.
    00872  **********************************************************************/
    00873 char **CSLSetNameValue(char **papszList,
    00874                     const char *pszName, const char *pszValue)
    00875 {
    00876     char **papszPtr;
    00877     int nLen;
    00878
    00879     if (pszName == NULL || pszValue==NULL)
    00880         return papszList;
    00881
    00882     nLen = strlen(pszName);
    00883     papszPtr = papszList;
    00884     while(papszPtr && *papszPtr != NULL)
    00885     {
    00886         if (EQUALN(*papszPtr, pszName, nLen)
    00887             && ( (*papszPtr)[nLen] == '=' ||
    00888                  (*papszPtr)[nLen] == ':' ) )
    00889         {
    00890             /* Found it!
    00891              * Change the value... make sure to keep the ':' or '='
    00892              */
    00893             char cSep;
    00894             cSep = (*papszPtr)[nLen];
    00895
    00896             free(*papszPtr);
    00897             *papszPtr = CPLStrdup(CPLSPrintf("%s%c%s", pszName,
    00898                                                        cSep, pszValue));
    00899
    00900             return papszList;
    00901         }
    00902         papszPtr++;
    00903     }
    00904
    00905     /* The name does not exist yet... create a new entry
    00906      */
    00907     return CSLAddString(papszList,
    00908                            CPLSPrintf("%s=%s", pszName, pszValue));
    00909 }