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