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 }

Generated at Sat Dec 21 14:01:57 2002 for GDAL by doxygen1.2.3-20001105 written by Dimitri van Heesch, © 1997-2000