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 }