basestr.cpp

Go to the documentation of this file.
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 */

Generated on Sat Nov 10 03:48:04 2007 for Camelot by  doxygen 1.4.4