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