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

doxygen1.2.2 Dimitri van Heesch, © 1997-2000