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