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