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

doxygen1.2.3-20001105 Dimitri van Heesch, © 1997-2000