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