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