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