00001 // $Id: basestr.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 /************************************************************************************** 00099 00100 00101 Definition of the string class, as declared in StringBase.h. 00102 ***************************************************************************************/ 00103 00104 #include "camtypes.h" 00105 #include <iostream> 00106 #include <stdarg.h> 00107 00108 //#include "basestr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 #include "camelot.h" 00110 //#include "fixmem.h" // for CCMalloc, etc... - in camtypes.h [AUTOMATICALLY REMOVED] 00111 //#include "reshelp.h" 00112 //#include "oilmods.h" // for OILModule::xx 00113 #if !defined(EXCLUDE_FROM_XARLIB) 00114 //#include "convert.h" // for MakePercent - in camtypes.h [AUTOMATICALLY REMOVED] 00115 #endif 00116 00117 //#include "Res/UKEnglish/stringtbl.h" 00118 00119 //#include "richard3.h" // for MakePercent 00120 //#include "mario.h" 00121 00122 DECLARE_SOURCE("$Revision: 1282 $"); 00123 00124 BOOL StringBase::ThrowExceptionStack[str_MAXEXCEPTIONS]; 00125 INT32 StringBase::CurrEx = -1; 00126 00127 00128 /************************************************************************************** 00129 > virtual BOOL StringBase::Alloc(INT32 size) 00130 00131 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00132 Created: 22nd April 1993 00133 Inputs: The number of characters the string is to hold (EXCLUDING the 00134 terminating 0). 00135 Returns: TRUE if the allocation was successful. 00136 Purpose: Allocates space on the heap for a 0-terminated string of the 00137 passed size. This function should only be called for the StringBase 00138 base class, NOT for any of its fixed-length derivatives. 00139 Errors: _R(IDE_NOMORE_MEMORY) 00140 Scope: Public 00141 ***************************************************************************************/ 00142 BOOL StringBase::Alloc(INT32 size) 00143 { 00144 ERROR3IF(size < 0, "Attempt to ALLOCate a String of negative length"); 00145 if (text) delete[] text; 00146 #ifdef _UNICODE 00147 text = new TCHAR[length = size + 1]; 00148 #else 00149 text = new TCHAR[length = (size + 1) * 2]; // MBCS 00150 #endif 00151 ERRORIF(text == 0, _R(IDE_NOMORE_MEMORY), FALSE); 00152 *text = 0; 00153 return TRUE; 00154 } 00155 00156 00157 00158 00159 /************************************************************************************** 00160 > BOOL StringBase::Load(UINT32 resourceID, UINT32 moduleID = 0) 00161 00162 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00163 Created: 22nd April 1993 00164 Inputs: A string resource identifier and an optional module handle. Specify 00165 a module handle only if the resource is not located in the default 00166 place (CAMELOT.EXE). Most resources will be. 00167 If a moduleID is given, the string will try to be loaded from that module. 00168 If it fails, it will fall-back to the .exe file. The string will be truncated 00169 if required to fit the available buffer size. 00170 Returns: TRUE of the string is successfully loaded, FALSE otherwise. 00171 Purpose: Extracts a string from the application's .EXE file, by default, 00172 or another module (eg. a dedicated DLL), overwriting the old contents 00173 of this StringBase object. 00174 SeeAlso: SmartLoadString 00175 ***************************************************************************************/ 00176 BOOL StringBase::Load(UINT32 resID, UINT32 moduleID) 00177 { 00178 ERROR3IF(text == 0, "Attempt to LOAD a String which hasn't been ALLOCated"); 00179 00180 // Load the string resource. Get OIL layer to truncate to suit the destination. 00181 if (!text) return FALSE; 00182 return SmartLoadString(moduleID, resID, text, length*sizeof(TCHAR)); 00183 } 00184 00185 00186 00187 00188 /************************************************************************************** 00189 > StringBase& StringBase::toTitle() 00190 00191 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 00192 Created: 30/10/97 00193 Purpose: Converts all the first letters of words to uppercase and 00194 the rest to lower case. 00195 ***************************************************************************************/ 00196 StringBase& StringBase::toTitle() 00197 { 00198 ERROR3IF(text == 0, "Call to TOLOWER for an unALLOCated String"); 00199 00200 //First set up a pointer with which to go through the string 00201 TCHAR* pText=text; 00202 00203 //And set up a buffer, which we will use to convert the case of single 00204 //characters 00205 00206 //GTODO: Put this in a separate function? 00207 TCHAR bufToConvert[2]; 00208 bufToConvert[0]='\0'; 00209 bufToConvert[1]='\0'; 00210 00211 //Now, until we reach the end of the string 00212 while (pText && *pText!='\0') 00213 { 00214 //Move pText through the string until it points 00215 //to a letter 00216 while (pText && !IsAlpha(*pText) && *pText!='\0') 00217 { 00218 pText++; 00219 } 00220 00221 //And, if we are not at the end of the string 00222 if (pText && *pText!='\0') 00223 { 00224 //Convert that letter to upper case 00225 bufToConvert[0]=*pText; 00226 00227 CharUpper(bufToConvert); 00228 00229 *pText=bufToConvert[0]; 00230 00231 //Now advance to the next character 00232 pText++; 00233 } 00234 00235 //And convert any following letters to lower case, until 00236 //we reach the end of the string of letters. We also 00237 //count apostrophes as letters, since they may be part of 00238 //a word 00239 while (pText && (IsAlpha(*pText) || *pText=='\'')) 00240 { 00241 // Convert that letter to lower case 00242 bufToConvert[0]=*pText; 00243 CharLower(bufToConvert); 00244 *pText=bufToConvert[0]; 00245 00246 // And advance to the next letter 00247 pText++; 00248 } 00249 } 00250 00251 return *this; 00252 } 00253 00254 00255 00256 /************************************************************************************** 00257 00258 > INT32 StringBase::CompareTo(const StringBase& other, BOOL CaseSensitive = TRUE) const 00259 00260 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00261 Created: 24/5/94 00262 Inputs: other - A string against which this one will be compared 00263 Returns: The same as the standard C strcmp, i.e: 00264 00265 A negative value if this is considered 'less than' other 00266 00267 Zero, if the strings are considered equal 00268 00269 A positive value if this is considered 'greater than' other 00270 00271 Purpose: Compare this StringBase object to another string. This is mainly 00272 intended for use internally by the comparison operators, but 00273 may also come in handy in other places. 00274 00275 Notes: This function is VERY SLOW, but does proper comparisons for the 00276 locale to determine relative positioning of strings. Use 00277 StringBase::IsIdentical to see if 2 strings are exactly the same. 00278 00279 Errors: If either of the strings is 0, an ENSURE failure is generated 00280 00281 SeeAlso: StringBase::IsIdentical 00282 00283 **************************************************************************************/ 00284 00285 INT32 StringBase::CompareTo(const StringBase& other, BOOL CaseSensitive) const 00286 { 00287 ERROR3IF(text == 0 || other.text == 0, "StringBase::CompareTo: not ALLOCed"); 00288 PORTNOTE("other", "StringBase::CompareTo should be locale specific"); 00289 #if FALSE 00290 DWORD dw = NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH; 00291 if (!CaseSensitive) dw |= NORM_IGNORECASE; 00292 return CompareString(LOCALE_USER_DEFAULT, dw, text, -1, other.text, -1) - 2; 00293 #endif 00294 00295 if( CaseSensitive ) 00296 { 00297 return camStrcmp( text, other.text ); 00298 } 00299 else 00300 { 00301 return camStricmp( text, other.text ); 00302 } 00303 } 00304 00305 00306 00307 /************************************************************************************** 00308 00309 > INT32 StringBase::CompareTo(const TCHAR *other, BOOL CaseSensitive) const 00310 00311 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00312 Created: 24/5/94 00313 Inputs: other - A string against which this one will be compared 00314 Returns: The same as the standard C strcmp, i.e: 00315 00316 A negative value if this is considered 'less than' other 00317 00318 Zero, if the strings are considered equal 00319 00320 A positive value if this is considered 'greater than' other 00321 00322 Purpose: Compare this StringBase object to another string. This is mainly 00323 intended for use internally by the comparison operators, but 00324 may also come in handy in other places. 00325 00326 Notes: This function is VERY SLOW, but does proper comparisons for the 00327 locale to determine relative positioning of strings. Use 00328 StringBase::IsIdentical to see if 2 strings are exactly the same. 00329 00330 Errors: If either of the strings is 0, an ENSURE failure is generated 00331 00332 SeeAlso: StringBase::IsIdentical 00333 00334 **************************************************************************************/ 00335 00336 INT32 StringBase::CompareTo(const TCHAR* other, BOOL CaseSensitive) const 00337 { 00338 ERROR3IF(text == 0 || other == 0, "StringBase::CompareTo: null buffers"); 00339 PORTNOTE("other", "StringBase::CompareTo should be locale specific"); 00340 #if FALSE 00341 DWORD dw = NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH; 00342 if (!CaseSensitive) dw |= NORM_IGNORECASE; 00343 return CompareString(LOCALE_USER_DEFAULT, dw, text, -1, other, -1) - 2; 00344 #endif 00345 00346 if( CaseSensitive ) 00347 { 00348 return camStrcmp( text, other ); 00349 } 00350 else 00351 { 00352 return camStricmp( text, other ); 00353 } 00354 } 00355 00356 00357 00358 /************************************************************************************** 00359 > StringBase& StringBase::operator=(const StringBase& rhs) 00360 00361 00362 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00363 Created: 22nd April 1993 00364 Inputs: A reference to a constant String. 00365 Returns: A reference to this. 00366 Purpose: Assignment (set equal to) operator, eg. 00367 StringBase x("rhubarb"); 00368 x = "custard"; 00369 ***************************************************************************************/ 00370 StringBase& StringBase::operator=(const StringBase& other) 00371 { 00372 ERROR3IF(!text || !other.text, "Call to String::operator= for an unALLOCated String"); 00373 // ERROR3IF(camStrlen(other.text) >= length, "Call to String::operator= will result in overflow"); 00374 00375 if (text && other.text) 00376 { 00377 if(camStrlen(other.text) >= length) 00378 camStrncpy(text, other.text, (INT32)length - 1); 00379 else 00380 camStrcpy(text, other.text); 00381 } 00382 return *this; 00383 } 00384 00385 00386 00387 /************************************************************************************** 00388 > StringBase& StringBase::operator=(const TCHAR* pcsz) 00389 00390 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00391 Created: 22nd April 1993 00392 Inputs: A pointer to a constant C-style (possibly wide-character) string. 00393 Returns: A reference to this. 00394 Purpose: Assignment (set equal to) operator, eg. 00395 StringBase x("rhubarb"); 00396 x = "custard"; 00397 ***************************************************************************************/ 00398 StringBase& StringBase::operator=(const TCHAR* s) 00399 { 00400 ERROR3IF(!text || !s, "Call to String::operator= for an unALLOCated String or 0 char*"); 00401 // ERROR3IF(camStrlen(s) >= length, "Call to String::operator= will result in overflow"); 00402 00403 if (text && s) 00404 { 00405 if(camStrlen(s) >= length) 00406 camStrncpy(text, s, (INT32)length-1); 00407 else 00408 camStrcpy(text, s); 00409 } 00410 return *this; 00411 } 00412 00413 00414 00415 /************************************************************************************** 00416 > StringBase& StringBase::operator+=(const TCHAR* s) 00417 00418 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00419 Created: 22nd April 1993 00420 Inputs: The C-style character "string" to add to the end of this String. 00421 Returns: A reference to the lhs, ie. this StringBase as an lvalue. 00422 Purpose: Append string y onto the end of string x, eg. 00423 x = TEXT("hello"); 00424 cout << (x += TEXT(" world!")) << endl; 00425 ***************************************************************************************/ 00426 StringBase& StringBase::operator+=(const TCHAR* s) 00427 { 00428 ERROR3IF(!text || !s, "Call to String::operator+= for an unALLOCated String"); 00429 ERROR3IF(camStrlen(text) + camStrlen(s) >= length, 00430 "Call to String::operator+= will result in overflow"); 00431 if (text && s) SafeCat(text, s, length-1); 00432 return *this; 00433 } 00434 00435 00436 /************************************************************************************** 00437 > StringBase& StringBase::operator+=(const TCHAR ch) 00438 00439 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00440 Created: 11/12/95 00441 Inputs: A character to add to the end of this String. 00442 Returns: A reference to the lhs, ie. this StringBase as an lvalue. 00443 Purpose: Appends this character to the end of this string 00444 ***************************************************************************************/ 00445 StringBase& StringBase::operator+=(const TCHAR ch) 00446 { 00447 ERROR3IF(text == 0, "Call to String::operator+= for an unALLOCated String"); 00448 INT32 CurrentLength = camStrlen(text); 00449 ERROR3IF(CurrentLength == MaxLength() - 1, "StringBase::operator+= will overflow"); 00450 00451 text[CurrentLength] = ch; 00452 text[CurrentLength + 1] = 0; 00453 return *this; 00454 } 00455 00456 00457 00458 /************************************************************************************** 00459 00460 > static TCHAR *StringBase::SafeCat(TCHAR *string1, const TCHAR *string2, INT32 Max ) 00461 00462 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 00463 Created: 26th February 1996 00464 00465 Inputs: string1 0-terminated destination string 00466 string2 0-terminated source string 00467 Max Maximum number of characters string1 is allowed to contain 00468 00469 Outputs: string1 Resulting string 00470 Returns: string1 00471 00472 Purpose: Appends string2 to the end of string1 and returns string1 as the result. 00473 The difference between this and camStrcat is the Max parameter which helps 00474 alleviate the buffer overwrite problems. Setting max to the length member 00475 of a stringbase will ERROR3IF that we don't go overwriting ends of buffers 00476 and suchlike... In such cases the result will be trucated. 00477 00478 eg, TCHAR String1[256] = "Fish"; 00479 SafeCat(String1, "cake", 7); 00480 will result in "Fishcak" being placed in String1... 00481 00482 ***************************************************************************************/ 00483 00484 TCHAR *StringBase::SafeCat(TCHAR *string1, const TCHAR *string2, UINT32 Max ) 00485 { 00486 ERROR3IF(string1 == 0 || string2 == 0, "StringBase::SafeCat given 0 params"); 00487 00488 UINT32 len1 = camStrlen(string1); 00489 00490 ERROR3IF(len1 > Max, "First parameter to StringBase::SafeCat already larger than safe"); 00491 00492 // No point trying if all space used up 00493 if (len1 <= Max) 00494 { 00495 // Are we going to overflow ? 00496 if ((len1 + camStrlen(string2)) > Max) 00497 { 00498 ERROR3("Call to StringBase::SafeCat will give truncated result"); 00499 00500 // Yeah, so we need to chop some of the second string off before concatenation 00501 INT32 Required = Max - len1; 00502 if (Required > 0) 00503 { 00504 camStrncpy( &(string1[len1]), string2, Required); 00505 string1[Max] = 0; 00506 } 00507 } 00508 else 00509 { 00510 // No, just do a normal strcat 00511 camStrcat(string1, string2); 00512 } 00513 } 00514 00515 return string1; 00516 } 00517 00518 00519 00520 /************************************************************************************** 00521 > const StringBase& StringBase::Left(StringBase* out, INT32 count) const 00522 00523 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00524 Created: 22nd April 1993 00525 Inputs: The number of characters in the prefix. 00526 Outputs: The leftmost [count] characters of the StringBase. If count is greater than 00527 the StringBase's length, the the whole StringBase is returned. If count is equal 00528 to zero, the 0 StringBase is output. 00529 Purpose: Similar to the BASIC Left$() string function. 00530 Errors: ERROR3IF failure if (count) is negative, or if the out StringBase is not 00531 large enough to hold the result. 00532 SeeAlso: StringBase::Right 00533 StringBase::Mid 00534 ***************************************************************************************/ 00535 const StringBase& StringBase::Left(StringBase* out, UINT32 count) const 00536 { 00537 ERROR3IF(out == 0, "0 output parameter in StringBase::Left"); 00538 ERROR3IF(!text || !out->text, "Call to String::Left for unALLOCated String"); 00539 ERROR3IF(count < 0, "Call to String::Left with a meaningless character count"); 00540 ERROR3IF(out->length <= count, "Call to String::Left will overflow"); 00541 00542 if (text && out && out->text) 00543 { 00544 if (count == 0) 00545 *(out->text) = 0; 00546 else if (count >= camStrlen(text)) 00547 camStrcpy(out->text, text); 00548 else 00549 { 00550 camStrncpy(out->text, text, (INT32)count); 00551 out->text[count] = 0; 00552 } 00553 } 00554 00555 return *this; 00556 } 00557 00558 00559 00560 00561 /************************************************************************************** 00562 > const StringBase& StringBase::Mid(StringBase* out, INT32 first, INT32 count) const 00563 00564 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00565 Created: 22nd April 1993 00566 Inputs: The position of the first character to extract and the total number of 00567 characters to include in the sub-string. Note that the first character 00568 of a string is at position 0, like C, not 1, like BASIC. 00569 Outputs: Places the n characters starting at position m in [out], which must be 00570 large enough. 00571 Purpose: Similar to the BASIC Mid$() function. 00572 SeeAlso: StringBase::Left 00573 StringBase::Right 00574 ***************************************************************************************/ 00575 const StringBase& StringBase::Mid(StringBase* out, UINT32 first, UINT32 count) const 00576 { 00577 ERROR3IF(out == 0, "0 output parameter in StringBase::Mid"); 00578 ERROR3IF(!text || !out->text, "Call to String::Mid for unALLOCated String"); 00579 ERROR3IF(count < 0, "Call to String::Mid with a meaningless character count"); 00580 ERROR3IF(out->length <= count, "Call to String::Mid will overflow"); 00581 00582 if (text && out && out->text) 00583 { 00584 UINT32 L = camStrlen(text); 00585 if ((first + count) > L) count = L - first; 00586 if (count <= 0) 00587 *(out->text) = 0; 00588 else 00589 { 00590 camStrncpy(out->text, text + first, (INT32)count); 00591 out->text[count] = 0; 00592 } 00593 } 00594 00595 return *this; 00596 } 00597 00598 00599 00600 00601 /************************************************************************************** 00602 > const StringBase& StringBase::Right(StringBase* out, INT32 count) const 00603 00604 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00605 Created: 22nd April 1993 00606 Inputs: The number of characters in the postfix. 00607 Returns: The rightmost n characters of the StringBase. If n is greater than the 00608 StringBase's length, the value of the whole StringBase is returned. If n is 00609 less than or equal to zero, the 0 StringBase is returned. 00610 Purpose: Similar to the BASIC Right$() function. 00611 SeeAlso: StringBase::Left 00612 StringBase::Mid 00613 ***************************************************************************************/ 00614 const StringBase& StringBase::Right(StringBase* out, UINT32 count) const 00615 { 00616 ERROR3IF(out == 0, "0 output parameter in StringBase::Right"); 00617 ERROR3IF(!text || !out->text, "Call to StringBase::Right for unALLOCated String"); 00618 ERROR3IF(count < 0, "Call to StringBase::Right with a meaningless character count"); 00619 ERROR3IF(out->length <= count, "Call to StringBase::Right will overflow"); 00620 00621 if (text && out && out->text) 00622 { 00623 UINT32 L = camStrlen(text); 00624 if (count == 0) 00625 *(out->text) = 0; 00626 else if (count >= L) 00627 camStrcpy(out->text, text); 00628 else 00629 { 00630 camStrncpy(out->text, text + L - count, (INT32)count); 00631 out->text[count] = 0; 00632 } 00633 } 00634 00635 return *this; 00636 } 00637 00638 00639 00640 /************************************************************************************** 00641 > void StringBase::Split(StringBase* pstrStart, StringBase* pstrEnd, 00642 INT32 iSplit, BOOL fIncludeSplitChar) 00643 00644 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 00645 Created: 2/5/97 00646 Inputs: iSplit Index of the splitting character 00647 fIncludeSplitChar 00648 TRUE Put the splitting character at the end of strStart 00649 FALSE Put the splitting character at the start of strEnd 00650 Outputs: pstrStart The string into which to put everything before 00651 the splitting character 00652 pstrEnd The string into which to put everything before 00653 the splitting character 00654 00655 Purpose: Splits a string into two separate strings at a given character. 00656 00657 Note that pstrStart or pstrEnd may either be 0 or may point 00658 at this string. 00659 00660 Useful in parsing URLs. 00661 00662 Errors: If any parameters are invalid 00663 SeeAlso: WebAddress::Parse 00664 ***************************************************************************************/ 00665 void StringBase::Split(StringBase* pstrStart, StringBase* pstrEnd, INT32 iSplit, BOOL fIncludeSplitChar) 00666 { 00667 //First check our parameters 00668 if (iSplit<0) 00669 { 00670 ERROR2RAW("StringBase::Split - 0 parameter"); 00671 return; 00672 } 00673 00674 //If iSplit is greater than the length of the string, then 00675 //put the entire string into pstrStart 00676 if (iSplit>=Length()) 00677 { 00678 if (pstrStart) 00679 *pstrStart=*this; 00680 00681 if (pstrEnd) 00682 pstrEnd->Empty(); 00683 00684 return; 00685 } 00686 00687 //This variable is 1 if we're including the splitting character 00688 //and 0 otherwise 00689 INT32 iIncludeSplitChar=(fIncludeSplitChar? 1 : 0); 00690 00691 //And get the length 00692 INT32 iLength=Length(); 00693 00694 //Now, let's get the start string 00695 String_256 strStart; 00696 00697 //This is the number of characters to include in the start string 00698 INT32 iStartChars=iSplit+iIncludeSplitChar; 00699 00700 //And now actually create the start string 00701 Left(&strStart, iStartChars); 00702 00703 //And the end string 00704 String_256 strEnd; 00705 00706 Right(&strEnd, iLength-iStartChars); 00707 00708 //Now, if we have been passed an output start string 00709 if (pstrStart) 00710 //Copy our start string into it 00711 *pstrStart=strStart; 00712 00713 //And if we have been passed an output end string 00714 if (pstrEnd) 00715 //Copy our end string into it 00716 *pstrEnd=strEnd; 00717 00718 } 00719 00720 00721 /************************************************************************************** 00722 > INT32 StringBase::Sub(const StringBase& mask, INT32 from = 0, TCHAR wildcard = 0) const 00723 00724 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00725 Created: 22nd April 1993 00726 Inputs: A reference to the substring (mask) to search for; optionally the first 00727 character position to search from (default is first character in the 00728 string); optionally the character in the mask which is acting as a 00729 wildcard (if not specified, there is no wildcard in the mask). 00730 Returns: Returns the starting position of the substring, or -1 if the 00731 substring does not appear within "this". 00732 Purpose: Similar to the (non-standard) BASIC Instr$() function. 00733 Scope: Public 00734 ***************************************************************************************/ 00735 INT32 StringBase::Sub(const StringBase& mask, UINT32 from, TCHAR fuzz) const 00736 { 00737 ERROR3IF(!text || !mask.text, "Call to String::Sub for an unALLOCated String"); 00738 ERROR3IF(from < 0, "Call to String::Sub with a negative \"from\" character position"); 00739 00740 if (text && mask.text) 00741 { 00742 if (from >= camStrlen(text) || camStrlen(mask.text) == 0) 00743 return -1; 00744 00745 BOOL matched = FALSE; // 2 state DFA 00746 const TCHAR* pSub = mask.text; 00747 for (const TCHAR* pThis = text + from; *pThis; pThis++) 00748 if (*pSub != fuzz && *pThis != *pSub) // current pair match? 00749 { 00750 if (matched) // no, so if we had a match previously 00751 { 00752 pThis--; // then we must go back one character 00753 matched = FALSE; 00754 } 00755 pSub = mask.text; // and also match from beginning of mask 00756 } 00757 else 00758 { 00759 matched = TRUE; // yes, we have a match 00760 if (*++pSub == 0) // matched all of mask? 00761 return (pThis - text) - (pSub - mask.text) + 1; 00762 } 00763 } 00764 00765 // return NOT FOUND 00766 return -1; 00767 } 00768 00769 /************************************************************************************** 00770 > INT32 StringBase::SubWithoutCase(const StringBase& strToFind) const 00771 00772 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 00773 Created: 26/6/97 00774 Inputs: mask The string to search for 00775 from (optional) the character to search from 00776 Returns: Returns the starting position of the substring, or -1 if the 00777 substring does not appear within "this". 00778 00779 The comparison is done without regard to case. For example, trying 00780 to find the string "fILe" in the following string: 00781 00782 "The Rockford Files" 00783 00784 would give a result of 13. 00785 Purpose: Similar to the (non-standard) BASIC Instr$() function. 00786 Scope: Public 00787 ***************************************************************************************/ 00788 INT32 StringBase::SubWithoutCase(const StringBase& strToFind) const 00789 { 00790 ERROR3IF(!text || !strToFind.text, "Call to String::Sub for an unALLOCated String"); 00791 00792 if (IsEmpty() || strToFind.IsEmpty()) 00793 return -1; 00794 00795 #if !defined(__WXMAC__) 00796 //First set up a pointer to search this string with 00797 TCHAR* pcThisChar=text; 00798 INT32 iThisChar=0; 00799 00800 //Now, while pcThisChar is valid 00801 while (pcThisChar!=0 && *pcThisChar!='\0') 00802 { 00803 //Is strToSearch from pcThisChar onwards the same 00804 //as strToFind, doing a case insensitive comparision? 00805 if (camStrnicmp(pcThisChar, strToFind, camStrlen(strToFind))==0) 00806 { 00807 //Yes. So return the index of the character we found 00808 return iThisChar; 00809 } 00810 00811 pcThisChar=camStrinc(pcThisChar); 00812 iThisChar++; 00813 } 00814 #else 00815 PORTNOTE("macport", "StringBase::SubWithoutCase not yet implemented"); 00816 ERROR3("StringBase::SubWithoutCase not yet implemented"); 00817 #endif 00818 //Otherwise return -1 00819 return -1; 00820 00821 } 00822 00823 00824 00825 00826 /************************************************************************************** 00827 > void StringBase::Insert(StringBase *InsertString, INT32 Position); 00828 00829 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00830 Created: 26th August 1994 00831 Inputs: InsertString - the string to inserted. 00832 Position - the number of the character before which InsertString is 00833 to be inserted. Counting starts at 0. 00834 Returns: - 00835 Purpose: Inserting a string into another one. 00836 Scope: Public 00837 ***************************************************************************************/ 00838 void StringBase::Insert( const StringBase &InsertString, INT32 Position) 00839 { 00840 ERROR3IF(Position < 0,"Negative position passed to StringBase::Insert"); 00841 ERROR3IF(!text || !InsertString.text, "Not ALLOCed in StringBase::Insert"); 00842 00843 if (text && InsertString && InsertString.text) 00844 { 00845 INT32 LeftL = Position; 00846 INT32 RightL = Length()-Position; 00847 StringBase LeftS; 00848 StringBase RightS; 00849 00850 if (LeftL<=0) 00851 { 00852 RightS.Alloc(this->Length()); 00853 RightS=*this; 00854 *this=*InsertString; 00855 *this+=RightS; 00856 } 00857 else 00858 { 00859 if (RightL<=0) 00860 { 00861 *this+=*InsertString; 00862 } 00863 else 00864 { 00865 LeftS.Alloc(LeftL); 00866 Left(&LeftS, LeftL); 00867 RightS.Alloc(RightL); 00868 Right(&RightS, RightL); 00869 00870 *this=LeftS; 00871 *this+=*InsertString; 00872 *this+=RightS; 00873 } 00874 } 00875 } 00876 } 00877 00878 00879 00880 /************************************************************************************** 00881 > void StringBase::Remove(INT32 Position, INT32 Number); 00882 00883 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00884 Created: 26th August 1994 00885 Position - the position of the first character to be removed. Counting 00886 starts at 0. 00887 Number - the number of characters to be removed. 00888 Returns: - 00889 Purpose: Inserting a string into another one. 00890 Scope: Public 00891 ***************************************************************************************/ 00892 void StringBase::Remove(INT32 nchStartPos, INT32 nchRemove) 00893 { 00894 ERROR3IF(nchStartPos < 0,"Bad start position passed to StringBase::Remove"); 00895 if (!text) 00896 { 00897 ERROR3("Not ALLOCed in StringBase::Remove"); 00898 return; 00899 } 00900 00901 StringBase strLeftSeg; 00902 StringBase strRightSeg; 00903 INT32 nchRightSeg = Length() - nchStartPos - nchRemove; 00904 00905 if (nchStartPos <= 0) 00906 { 00907 if (nchRightSeg <= 0) 00908 Empty(); 00909 else 00910 Right(this, nchRightSeg); 00911 } 00912 else 00913 { 00914 if (nchRightSeg <= 0) 00915 { 00916 Left(this, nchStartPos); 00917 } 00918 else 00919 { 00920 if (!strLeftSeg.Alloc(nchStartPos) || !strRightSeg.Alloc(nchRightSeg)) return; 00921 Left(&strLeftSeg, nchStartPos); 00922 Right(&strRightSeg, nchRightSeg); 00923 *this = strLeftSeg; 00924 *this += strRightSeg; 00925 } 00926 } 00927 } 00928 00929 00930 00931 00932 /************************************************************************************** 00933 00934 > void StringBase::SwapChar(const TCHAR schar, const TCHAR rchar) 00935 00936 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00937 Created: 19/04/95 00938 Inputs: schar - the search character 00939 rchar - the replacement character 00940 Returns: - 00941 Purpose: Exchange all schar characters in the string with rchar characters 00942 Scope: Public 00943 00944 ***************************************************************************************/ 00945 00946 void StringBase::SwapChar(const TCHAR schar, const TCHAR rchar) 00947 { 00948 ERROR3IF(!text ,"Call to String::SwapChar for an unALLOCated String"); 00949 if (text) 00950 { 00951 TCHAR* pThis = text; 00952 while( *pThis != wxT('\0') ) 00953 { 00954 if (*pThis == schar) 00955 *pThis = rchar; 00956 pThis = camStrinc(pThis); 00957 } 00958 } 00959 } 00960 00961 00962 /************************************************************************************** 00963 00964 > INT32 StringBase::CountChar(const TCHAR tchar) 00965 00966 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 00967 Created: 20/11/95 00968 Inputs: tchar - the search character 00969 Returns: Number of times 'tchar' appears in the string 00970 Purpose: Count all tchar characters in the string 00971 Scope: Public 00972 00973 ***************************************************************************************/ 00974 00975 INT32 StringBase::CountChar(const TCHAR tchar) 00976 { 00977 ERROR3IF(!text, "Call to String::CountChar for an unALLOCated String"); 00978 INT32 Count = 0; 00979 if (text) 00980 { 00981 TCHAR* pThis = text; 00982 while (*pThis != 0) 00983 { 00984 if (*pThis == tchar) 00985 Count ++; 00986 pThis = camStrinc(pThis); 00987 } 00988 } 00989 return Count; 00990 } 00991 00992 00993 #if !defined(EXCLUDE_FROM_XARLIB) 00994 /************************************************************************************** 00995 > void StringBase::MakePercent(INT32 Value); 00996 void StringBase::MakePercent(double Value); 00997 void StringBase::MakePercent(TCHAR *Value); 00998 00999 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01000 Created: 22nd November 1995 01001 Inputs: Takes a number / string 01002 Purpose: Set the string equal to the given argument + a % character, or however 01003 the current locale wants it 01004 Example: String_32 Str; 01005 Str.MakePercent(23); 01006 For UK, Str now equals "23%" 01007 **************************************************************************************/ 01008 01009 void StringBase::MakePercent(INT32 Value) 01010 { 01011 if (text) 01012 { 01013 String_32 Format(_R(IDS_PERCENT_LONG)); 01014 Format.FixFormat(); 01015 camSnprintf( text, 32, (TCHAR *)Format, Value ); 01016 } 01017 } 01018 01019 void StringBase::MakePercent(double Value) 01020 { 01021 if (text) 01022 { 01023 String_32 TmpStr; 01024 if(Convert::DoubleToString(Value, &TmpStr)) 01025 MakePercent((TCHAR *)TmpStr); 01026 } 01027 } 01028 01029 void StringBase::MakePercent(TCHAR *Value) 01030 { 01031 if (text) 01032 { 01033 // Some callers seem to call this with Value=Text ... Grrr 01034 String_32 tmp(Value); 01035 String_32 Format(_R(IDS_PERCENT_STRING)); 01036 Format.FixFormat(); 01037 camSnprintf( text, 32, (TCHAR *)Format, tmp.text ); 01038 } 01039 } 01040 01041 // Make formats into Unicode compatible variants 01042 void StringBase::FixFormat() 01043 { 01044 #if FALSE 01045 #if 0 != wxUSE_UNICODE 01046 INT32 i=0; 01047 while ((i+1)<Length()) // Don't look at the last character 01048 { 01049 if ( (text[i]==_T('%')) && ( (text[i+1]==_T('s')) || (text[i+1]==_T('c')) ) ) 01050 { 01051 String_8 l(_T("l")); 01052 Insert(l, i+1); 01053 i++; // Skip over the inserted char too 01054 } 01055 i++; 01056 } 01057 #endif 01058 #endif 01059 } 01060 01061 #endif 01062 01063 01064 /*********************************************************************************************** 01065 > INT32 SmartLoadString(UINT32 modID, UINT32 resID, LPTCHAR buf, INT32 size) 01066 01067 Author: Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com> 01068 Created: 24/8/93 01069 Inputs: modID (portable) module ID, or 0 for Kernel 01070 resID ID of required string 01071 size byte size of return buffer 01072 Outputs: buf result buffer address 01073 Returns: 0 if failed to load, else number of bytes read 01074 Purpose: Loading a string resource, possibly from a .DLL. If modID is non-zero then 01075 that module is tried first, falling back to the main program if not found. 01076 Also has to work-around a nasty bug in Win32s LoadStringA. Also recognises 01077 Tool resource IDs and works out the module automatically (if modID is zero). 01078 01079 Actually when we say 'falling back to the main program' we really mean 01080 'checking if it's in an external resources dll before falling back to the 01081 main program'. If no modID is given, we also check the external resource dll 01082 first. Well, actually that's not TRUE, since if it's a tool resource it's going 01083 to be in the tools dll rather than the resource only one, so we jump the queue 01084 a little there... 01085 01086 Errors: Returns 0 if not found anywhere. 01087 01088 ***********************************************************************************************/ 01089 01090 INT32 SmartLoadString(UINT32 modID, UINT32 resID, LPTCHAR buf, INT32 size) 01091 { 01092 PORTNOTE("other","SmartLoadString - needs to be converted to GetText") 01093 ERROR3IF(resID == 0, "Zero string resource ID in SmartLoadString"); 01094 ERROR3IF(buf == 0, "No output buffer in SmartLoadString"); 01095 INT32 numchars = size/sizeof(TCHAR); 01096 ERROR3IF(numchars < 2, "Buffer too small in SmartLoadString"); 01097 01098 camStrncpy( buf, CamResource::GetText(resID), numchars ); // NB GetText cannot fail 01099 buf[numchars-1]=0; // ensure zero terminated 01100 return (camStrlen(buf)+1)*sizeof(TCHAR); // return number of bytes copied 01101 } 01102 01103 #if 0 01104 const HINSTANCE hMain = AfxGetResourceHandle(); // This is the main program 01105 HINSTANCE hLib = ExtraDLLs[Resources_DLL]; // This is the resources dll, and will 01106 // be 0 (or HINSTANCE_ERROR) if it's not loaded 01107 if(hLib <= (HINSTANCE)HINSTANCE_ERROR) 01108 hLib = 0; 01109 01110 HINSTANCE hInst = hMain; 01111 01112 // if module ID given (and tools.dll present) then use it 01113 if (modID && DLLs[0] != 0 && DLLs[0] != (HINSTANCE)HINSTANCE_ERROR) 01114 hInst = OILModule::GetInstance(modID); 01115 else 01116 { 01117 // if no ID given, first have a rummage through the external resource dll (if loaded) 01118 if(hLib && !(((resID >= EXTERNAL_RESOURCES_START) && (resID < EXTERNAL_RESOURCES_END) ) 01119 || ( (resID >= VIEWRC_RESOURCES_START) && (resID < VIEWRC_RESOURCES_END)))) 01120 { 01121 // Note that when using FindResource on strings, the number has to be 01122 // altered - see PSS Q20011 for further details 01123 HRSRC hRes = FindResource(ExtraDLLs[Resources_DLL], MAKEINTRESOURCE((resID/16)+1), RT_STRING); 01124 01125 // if cannot find it then fall back to the built-in resources 01126 if (hRes != 0) 01127 { 01128 INT32 External = ::LoadString(ExtraDLLs[Resources_DLL], resID, buf, size ); 01129 if(External) 01130 return External; 01131 } 01132 else 01133 { 01134 TRACEUSER( "Richard", _T("Resource (0x%x) NOT found in external dll\n"), resID); 01135 } 01136 } 01137 01138 // Resource isn't in the external resources DLL... 01139 // this will return the toolsID or the mainID, or 0 if it's completely confused 01140 hInst = ResHelp::GetInstanceFromID(resID); 01141 } 01142 01143 // We're ok doing this because hLib will be 0 if not loaded 01144 if((hInst == hMain || hInst == 0) && hLib != 0) 01145 hInst = hLib; 01146 if(hInst == 0 && hLib == 0) 01147 hInst = hMain; 01148 01149 hInst = hMain; 01150 INT32 LoadStringResult = ::LoadString( hInst, resID, buf, size ); 01151 if(!LoadStringResult) 01152 { 01153 // Temporary bodge until we can fix the string-resource bug. I'm preventing ERROR3IF's from 01154 // going off, and filling buffers with safe crud so that calling code won't stiff. 01155 // ERROR3("Failed to load string resource!"); 01156 if (size > 8) size = 8; 01157 LoadStringResult = size - 1; 01158 buf[--size] = TEXT('\0'); 01159 while (size) buf[--size] = TEXT('X'); 01160 01161 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX) 01162 // (Richard) A Trace by popular request 01163 TRACE( _T("String resource (0x%x, %d) failed to load (searching 0x%x) - GetLastError is 0x%lX\n"), 01164 resID, resID, hInst, (DWORD)::GetLastError()); 01165 #endif 01166 } 01167 else 01168 { 01169 TRACEUSER( "JustinF", _T("LoadString (#%u, %d chrs): \"%s\"\n"), 01170 (UINT32) resID, (INT32) nRetVal, (LPCTSTR) buf); 01171 } 01172 01173 return LoadStringResult; 01174 #endif 01175 01176 01177 01178 #ifdef _DEBUG 01179 /************************************************************************************** 01180 > void StringBase::AssertValid() const 01181 01182 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01183 Created: 22nd April 1993 01184 Purpose: MFC required debugging facilities - this checks if the string is valid 01185 (or rather, doesn't have really stupid data) 01186 Errors: ERROR3IF failure if the string's length is negative or if its text 01187 pointer doesn't point to readable memory, and isn't 0. 01188 ***************************************************************************************/ 01189 void StringBase::AssertValid() const 01190 { 01191 CCObject::AssertValid(); 01192 ERROR3IF(length < 0, "StringBase has a negative length!\n"); 01193 #if defined( __WXMSW__ ) 01194 ERROR3IF(!text || ::IsBadReadPtr(text, length), "StringBase has bad text pointer!"); 01195 #else 01196 ERROR3IF(!text , "StringBase has bad text pointer!"); 01197 #endif 01198 } 01199 01200 01201 01202 01203 /************************************************************************************** 01204 > void StringBase::Dump(CDumpContext& dc) const 01205 01206 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01207 Created: 22nd April 1993 01208 Inputs: A reference to an MFC dump context (a little like an ostream). 01209 Purpose: MFC required debugging facilities - this prints on the dump context 01210 the string and how many references there are to it. 01211 ***************************************************************************************/ 01212 PORTNOTE("other","Removed StringBase::Dump") 01213 #ifndef EXCLUDE_FROM_XARALX 01214 void StringBase::Dump(CDumpContext& dc) const 01215 { 01216 CCObject::Dump(dc); 01217 dc << text; 01218 } 01219 #endif 01220 #endif // _DEBUG 01221 01222 01223 01224 01225 /************************************************************************************** 01226 > istream& operator>>(istream& is, StringBase& s) 01227 01228 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01229 Created: 22nd April 1993 01230 Inputs: A reference to an input stream and a reference to the string whose 01231 value is to be read. 01232 Returns: A reference to the input stream, which enables the chaining of stream 01233 operations. 01234 Purpose: Read a string from a (non-persistent) stream. The input is terminated 01235 by a newline character (NOT whitespace, cf. reading C-style character 01236 arrays). If the string is longer than MAX_STRING_RES_LENGTH get() will 01237 read as many characters as possible and put a newline at the end. 01238 SeeAlso: ostream& operator<<(ostream& os, const StringBase& s) 01239 ***************************************************************************************/ 01240 std::istream &operator>>( std::istream& is, StringBase& s ) 01241 { 01242 ERROR3IF(!s.text, "Call to istream >> for an unALLOCated String"); 01243 01244 char temp[MAX_STRING_RES_LENGTH]; 01245 is >> std::ws; // skip any leading whitespace 01246 is.get(temp, MAX_STRING_RES_LENGTH); // grab a chunk of input, up to a newline 01247 01248 ERROR3IF( size_t(s.length) <= strlen(temp), "Call to istream >> will overflow String" ); 01249 #if wxUSE_UNICODE 01250 PORTNOTE("other","This is not very efficient needs revisiting") 01251 TCHAR ptsz[MAX_STRING_RES_LENGTH]; 01252 mbstowcs( ptsz, temp, MAX_STRING_RES_LENGTH ); 01253 #else 01254 s = temp; // NB. s.operator=(const TCHAR*) 01255 #endif 01256 return is; 01257 } 01258 01259 01260 01261 01262 /************************************************************************************** 01263 > ostream& operator<<(ostream& os, const StringBase& s) 01264 01265 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01266 Created: 22nd April 1993 01267 Inputs: A reference to an output stream) and a reference to the constant string 01268 to write to it. 01269 Returns: Reference to the output stream. 01270 Purpose: Write a string to a (non-persistent) stream. If the string is 0 then 01271 "[0]" is printed. 01272 SeeAlso: istream& operator>>(istream& is, StringBase& s) 01273 ***************************************************************************************/ 01274 std::ostream& operator<<(std::ostream& os, const StringBase& s) 01275 { 01276 ERROR3IF(!s.text, "Call to ostream << for an unALLOCated String"); 01277 os << (s.Length() ? s.text : TEXT("[0]")); 01278 return os; 01279 } 01280 01281 01282 /************************************************************************************** 01283 01284 > BOOL StringBase::EnableExceptionHandler(BOOL PushNewHandler=TRUE) 01285 01286 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01287 Created: 29/07/96 01288 Inputs: PushNewHandler = a default parameter, determining whether a new 01289 exception handler state is pushed on the handler stack 01290 or not. 01291 Returns: TRUE if throwing exceptions is enabled 01292 FALSE if a new exception state could not be pushed. 01293 Purpose: This function adds a new exception handler to the string exception 01294 handler stack (if PushNewHandler is TRUE). Otherwise it will simply 01295 change the state of the most recently pushed handler. If there are no 01296 handlers and Push is FALSE, an ERROR3IF will be generated. 01297 Errors: if an attempt is made to push a new handler when the stack is full 01298 if an attempt is made to set the current exception handler to 'on' when 01299 there's no exception handlers on the stack 01300 01301 ***************************************************************************************/ 01302 01303 BOOL StringBase::EnableExceptionHandler(BOOL PushNewHandler) 01304 { 01305 if (PushNewHandler) CurrEx++; 01306 01307 ERROR2IF(CurrEx >= str_MAXEXCEPTIONS, FALSE, "StringBase::EnableExceptions overflow!"); 01308 ERROR2IF(CurrEx < 0, FALSE, "StringBase::EnableExceptions - handler does not exist"); 01309 01310 ThrowExceptionStack[CurrEx]=TRUE; 01311 return TRUE; 01312 } 01313 01314 01315 /************************************************************************************** 01316 01317 > void StringBase::DisableExceptionHandler(BOOL PopHandler=TRUE) 01318 01319 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01320 Created: 29/07/96 01321 Inputs: PopHandler = a default parameter, determining whether the current 01322 handler state is poped or not 01323 Returns: TRUE if all goes well 01324 FALSE if there are no exception states to pop! 01325 Purpose: This function disables or completely removes the most previously 01326 enabled exception state. FALSE will be returned if the exception stack 01327 is empty. The default parameter allows you to temporarily disable 01328 the exception state without poping the handler. 01329 Errors: 01330 01331 ***************************************************************************************/ 01332 01333 BOOL StringBase::DisableExceptionHandler(BOOL PopHandler) 01334 { 01335 ERROR2IF(CurrEx < 0, FALSE, "StringBase::DisableExceptions; Nothing on the exception stack!"); 01336 ThrowExceptionStack[CurrEx]=FALSE; 01337 if (PopHandler) CurrEx--; 01338 return TRUE; 01339 } 01340 01341 01342 01343 /************************************************************************************** 01344 01345 > BOOL StringBase::WillThrowException() 01346 01347 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01348 Created: 29/07/96 01349 Inputs: - 01350 Returns: TRUE if exceptions will currently be thrown 01351 FALSE if functions will return errors (ie out of range indexes) 01352 Purpose: This function interogates the exceptions state stack and determins 01353 whether exceptions will be thrown or not. 01354 01355 ***************************************************************************************/ 01356 01357 BOOL StringBase::WillThrowException() 01358 { 01359 return (CurrEx < 0) ? FALSE : ThrowExceptionStack[CurrEx]; 01360 } 01361 01362 01363 01364 /************************************************************************************** 01365 01366 > void StringBase::ThrowStringException() 01367 01368 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01369 Created: 29/07/96 01370 Purpose: Throws a 'User' exception if the string exception stack says 'Yes' 01371 01372 ***************************************************************************************/ 01373 01374 void StringBase::ThrowStringException() 01375 { 01376 PORTNOTETRACE("other","StringBase::ThrowStringException - do nothing"); 01377 #ifndef EXCLUDE_FROM_XARALX 01378 if (StringBase::WillThrowException()) AfxThrowUserException(); 01379 #endif 01380 } 01381 01382 01383 01384 /************************************************************************************** 01385 01386 > INT32 StringBase::SkipComma(INT32 pos=0) const 01387 01388 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01389 Created: 29/07/96 01390 Inputs: pos = the character index from which to start 01391 Returns: the index of the next none space character after the comma, 01392 -1 if none, OR an exception is thrown 01393 Throws an exception if string exceptions are enabled 01394 Purpose: Find the next comma (starting from pos) and skip on to the next 01395 none space character beyond it. 01396 Notes: ** Throws an exception if string exceptions are enabled ** 01397 01398 ***************************************************************************************/ 01399 01400 INT32 StringBase::SkipComma(INT32 pos) const 01401 { 01402 if ((pos = FindNextChar(TEXT(','), pos)) >= 0) pos = FindNextChar(pos + 1); 01403 return pos; 01404 } 01405 01406 01407 /************************************************************************************** 01408 01409 > INT32 StringBase::FindNextChar(INT32 position=0) const 01410 01411 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01412 Created: 29/07/96 01413 Inputs: position = the character index from which to start 01414 Returns: the index of the next none space character 01415 -1 if none, OR an exception is thrown 01416 Purpose: Find the next none space character starting from pos. If pos is a 01417 none space character, the function will simply return with the same 01418 index. 01419 Notes: ** Throws an exception if string exceptions are enabled ** 01420 01421 ***************************************************************************************/ 01422 01423 INT32 StringBase::FindNextChar(INT32 position) const 01424 { 01425 ERROR3IF(!text, "Call to StringBase::FindNextChar for unALLOCated String"); 01426 01427 // get the length of this string in characters 01428 INT32 nchars = Length(); 01429 if (!text || position<0 || position>=nchars) 01430 return IllegalIndex(); 01431 01432 TCHAR c = TEXT(' '); 01433 while ((text[position]==c) && position<nchars) 01434 position=NextIndex(position); 01435 01436 return ((position==nchars) ? (IllegalIndex()) : (position)); 01437 } 01438 01439 01440 /************************************************************************************** 01441 01442 > INT32 StringBase::FindNextChar(TCHAR c, INT32 position=0) const 01443 01444 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01445 Created: 29/07/96 01446 Inputs: c = the character whose index we need 01447 position = the character index from which to start 01448 Returns: the index of the next none space character, 01449 -1 if none, OR an exception is thrown 01450 Purpose: Find the next character to match c starting from position. 01451 Notes: ** Throws an exception if string exceptions are enabled ** 01452 01453 ***************************************************************************************/ 01454 01455 INT32 StringBase::FindNextChar(TCHAR c, INT32 position) const 01456 { 01457 ERROR3IF(!text, "Call to StringBase::FindNextChar for unALLOCated String"); 01458 INT32 nchars = Length(); 01459 if (!text || position<0 || position>=nchars) 01460 return IllegalIndex(); 01461 01462 while ((text[position]!=c) && position<nchars) 01463 position=NextIndex(position); 01464 01465 return ((position==nchars) ? (IllegalIndex()) : (position)); 01466 } 01467 01468 /************************************************************************************** 01469 01470 > INT32 StringBase::ReverseFind(TCHAR cToFind) const 01471 01472 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>, from Mike 01473 Created: 2/5/97 01474 Inputs: c = the character whose index we need 01475 Returns: The index of the last occurrence of character cToFind 01476 in the string. 01477 Purpose: As above 01478 01479 ***************************************************************************************/ 01480 01481 INT32 StringBase::ReverseFind(TCHAR cToFind) const 01482 { 01483 ERROR2IF(text==0, IllegalIndex(), "Call to StringBase::ReverseFind for unALLOCated String"); 01484 01485 INT32 iPosition=Length()-1; 01486 01487 while ((text[iPosition]!=cToFind) && iPosition>=0) 01488 iPosition--; 01489 01490 if (iPosition<0) 01491 return IllegalIndex(); 01492 else 01493 return iPosition; 01494 } 01495 01496 01497 01498 01499 01500 /************************************************************************************** 01501 01502 > INT32 StringBase::ConvertToInteger(INT32& position) const 01503 01504 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 01505 Created: 29/07/96 01506 Inputs: position = the character index 01507 Outputs: position = the new character index 01508 Returns: A signed numeric value for the sequence of characters starting 01509 at position in this string. 01510 Purpose: Convert the sequence of characters starting from position into a numeric 01511 value. 32 bits of precision are returned and hence approx 10 digit 01512 numbers can be represented. If the numeric string is longer, the value 01513 0x7FFFFFFF is returned (ie represting an overflow). If string exceptions 01514 are enabled, an exception will be thrown in this instance. 01515 All valid numeric digits will be read, no matter whether an overflow is 01516 immanent or not, hence you can safely continue to parse what is expected 01517 to be the next token along the string. 01518 The types of numbers allowed are 01519 +123686 01520 -12394 01521 124802398 01522 but not 01523 12439127397123 01524 01525 Notes: ** Throws an exception if string exceptions are enabled ** 01526 01527 ***************************************************************************************/ 01528 01529 INT32 StringBase::ConvertToInteger(INT32& position) const 01530 { 01531 ERROR3IF(!text, "Call to StringBase::ConvertToInteger for unALLOCated String"); 01532 01533 const TCHAR pos = TEXT('+'); 01534 const TCHAR neg = TEXT('-'); 01535 01536 INT32 value = 0; 01537 BOOL isneg = FALSE; 01538 INT32 maxdigs = 10; 01539 INT32 nchars = Length(); 01540 01541 position = SkipSpace(position); 01542 if (position>-1 && position<nchars) 01543 { 01544 isneg = (text[position]==neg); 01545 if (isneg || text[position]==pos) 01546 position=NextIndex(position); 01547 01548 while (position<nchars && IsNumeric(text[position])) 01549 { 01550 value = value*10 + (StringBase::TCharToNum(text[position])); 01551 position=NextIndex(position); 01552 maxdigs--; 01553 } 01554 01555 if (maxdigs<0) 01556 { 01557 TRACEUSER("Mike", wxT("Overflow during ConvertToInteger") ); 01558 StringBase::ThrowStringException(); 01559 return ((isneg) ? 0x80000000 : 0x7FFFFFFF); 01560 } 01561 01562 value = (isneg) ? (-value) : (value); 01563 } 01564 01565 return value; 01566 } 01567 01568 01569 01571 01572 /************************************************************************************** 01573 > void StringBase::Serialize(CArchive& arc) 01574 01575 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 01576 Created: 22nd April 1993 01577 Inputs: A reference to an MFC archive object. 01578 Purpose: Read/write a string to/from a persistent stream, a.k.a. an archive, 01579 depending upon the value of ar.IsStoring(). 01580 ***************************************************************************************/ 01581 /* 01582 void StringBase::Serialize(CArchive& archive) 01583 { 01584 ERROR3IF(!text, "Call to String::Serialize for an unALLOCated String"); 01585 CCObject::Serialize(archive); 01586 01587 INT32 L; 01588 if (archive.IsStoring()) 01589 { 01590 L = camStrlen(text); 01591 archive.Write(&L, sizeof(L)); 01592 archive.Write(text, L * sizeof(TCHAR)); 01593 } 01594 else 01595 { 01596 archive.Read(&L, sizeof(L)); 01597 ERROR3IF(L >= length, "Call to String::Serialize will overflow"); 01598 archive.Read(text, L * sizeof(TCHAR)); 01599 } 01600 } 01601 01602 01603 01604 01605 // And the rest . . . 01606 IMPLEMENT_SERIAL(StringBase, CCObject, 1); 01607 */ 01608 01610 01611 01612 /************************************************************************************** 01613 01614 > TCHAR* cc_lstrstr(TCHAR *String1, TCHAR *String2) 01615 01616 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01617 Created: 21st November 1995 01618 01619 Inputs: String 1 - String to search in 01620 String 2 - String to search for 01621 01622 Returns: Returns a pointer to the first occurrence of string2 in 01623 string1, or 0 if string2 does not occur in string1 01624 01625 Purpose: Finds the first occurrence of string2 in string1 01626 This version is case sensitive. 01627 Notes: Replaces the Windows API version which seems to be missing. Uses TCHAR's 01628 instead of char's, and also uses CompareString for multinational support 01629 01630 ***************************************************************************************/ 01631 01632 const TCHAR *cc_lstrstr(const TCHAR* String1, const TCHAR* String2) 01633 { 01634 ERROR3IF(String1 == 0 || String2 == 0, 01635 "0 (zero) parameters passed to cc_lstrstr"); 01636 01637 if (String1 == 0 || String2 == 0) return 0; 01638 if (!*String2) return String1; 01639 return camStrstr(String1, String2); 01640 01641 // TCHAR *cp = String1; 01642 // TCHAR *s1; 01643 // TCHAR *s2; 01644 01645 // while (*cp) 01646 // { 01647 // s1 = cp; 01648 // s2 = String2; 01649 01650 // // DCBS compatible case sensitive string compare 01651 // while(*s1 && *s2 && (CompareString(LOCALE_USER_DEFAULT, 01652 // (NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH), 01653 // s1, 1, s2, 1) == 2)) 01654 // s1++, s2++; 01655 // if(!*s2) 01656 // return(cp); 01657 // cp++; 01658 // } 01659 // 01660 // return(0); 01661 } 01662 01663 /************************************************************************************** 01664 01665 > TCHAR* cc_lstristr(LPCTSTR String1, LPCTSTR *String2) 01666 01667 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01668 Created: 21st November 1995 01669 01670 Inputs: String 1 - String to search in 01671 String 2 - String to search for 01672 01673 Returns: Returns a pointer to the first occurrence of string2 in 01674 string1, or 0 if string2 does not occur in string1 01675 01676 Purpose: Finds the first occurrence of string2 in string1. 01677 This version is case insensitive. 01678 Notes: Replaces the Windows API version which seems to be missing. Uses TCHAR's 01679 instead of char's, and also uses CompareString for multinational support 01680 01681 ***************************************************************************************/ 01682 01683 /*TCHAR* cc_lstristr(LPCTSTR String1, LPCTSTR String2) 01684 { 01685 #if !defined(__WXMSW__) 01686 return wcsstr( String1, String2 ); 01687 #else 01688 ERROR3IF(String1 == 0 || String2 == 0, 01689 "0 (zero) parameters passed to cc_lstristr"); 01690 01691 if (String1 == 0 || String2 == 0) return 0; 01692 if (!*String2) return String1; 01693 01694 TCHAR *cp = String1; 01695 TCHAR *s1; 01696 TCHAR *s2; 01697 01698 while (*cp) 01699 { 01700 s1 = cp; 01701 s2 = String2; 01702 01703 // DCBS compatible case insensitive string compare 01704 while(*s1 && *s2 && (CompareString(LOCALE_USER_DEFAULT, 01705 (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH), 01706 s1, 1, s2, 1) == 2)) 01707 s1++, s2++; 01708 01709 if(!*s2) 01710 return(cp); 01711 cp++; 01712 } 01713 01714 return(0); 01715 #endif 01716 } 01717 */ 01718 01719 01720 /************************************************************************************** 01721 01722 > TCHAR* cc_lstrichr(TCHAR *Str, TCHAR c) 01723 01724 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01725 Created: 21st November 1995 01726 01727 Inputs: Str - String to search in 01728 c - Character to search for 01729 01730 Returns: returns pointer to the first occurence of c in string 01731 returns 0 if c does not occur in string 01732 01733 Purpose: Searches a string for a given character, which may be the 01734 0 character '\0'. 01735 This version is case insensitive. 01736 Notes: Replaces the Windows API version which seems to be missing. Uses TCHAR's 01737 instead of char's, and also uses CompareString for multinational support 01738 01739 ***************************************************************************************/ 01740 01741 /*TCHAR* cc_lstrichr(TCHAR *Str, TCHAR c) 01742 { 01743 #if !defined(__WXMSW__) 01744 return wcschr( Str, c ); 01745 #else 01746 ERROR3IF(Str == 0, "0 (zero) parameters passed to cc_lstrichr"); 01747 01748 if(Str == 0) 01749 return 0; 01750 01751 while(*Str && (CompareString(LOCALE_USER_DEFAULT, 01752 (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH), 01753 Str, 1, &c, 1) != 2)) 01754 Str++; 01755 01756 if(CompareString(LOCALE_USER_DEFAULT, 01757 (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH), 01758 Str, 1, &c, 1) == 2) 01759 return(Str); 01760 01761 return(0); 01762 #endif 01763 } 01764 */