+ return true;
+}
+
+
+// check that the string ends with suffix and return the rest of it in the
+// provided pointer if it is not NULL, otherwise return false
+bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
+{
+ wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
+
+ int start = length() - wxStrlen(suffix);
+ if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 )
+ return false;
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ rest->assign(*this, 0, start);
+ }
+
+ return true;
+}
+
+
+// extract nCount last (rightmost) characters
+wxString wxString::Right(size_t nCount) const
+{
+ if ( nCount > length() )
+ nCount = length();
+
+ wxString dest(*this, length() - nCount, nCount);
+ if ( dest.length() != nCount ) {
+ wxFAIL_MSG( _T("out of memory in wxString::Right") );
+ }
+ return dest;
+}
+
+// get all characters after the last occurence of ch
+// (returns the whole string if ch not found)
+wxString wxString::AfterLast(wxChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos == wxNOT_FOUND )
+ str = *this;
+ else
+ str = c_str() + iPos + 1;
+
+ return str;
+}
+
+// extract nCount first (leftmost) characters
+wxString wxString::Left(size_t nCount) const
+{
+ if ( nCount > length() )
+ nCount = length();
+
+ wxString dest(*this, 0, nCount);
+ if ( dest.length() != nCount ) {
+ wxFAIL_MSG( _T("out of memory in wxString::Left") );
+ }
+ return dest;
+}
+
+// get all characters before the first occurence of ch
+// (returns the whole string if ch not found)
+wxString wxString::BeforeFirst(wxChar ch) const
+{
+ int iPos = Find(ch);
+ if ( iPos == wxNOT_FOUND ) iPos = length();
+ return wxString(*this, 0, iPos);
+}
+
+/// get all characters before the last occurence of ch
+/// (returns empty string if ch not found)
+wxString wxString::BeforeLast(wxChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos != wxNOT_FOUND && iPos != 0 )
+ str = wxString(c_str(), iPos);
+
+ return str;
+}
+
+/// get all characters after the first occurence of ch
+/// (returns empty string if ch not found)
+wxString wxString::AfterFirst(wxChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch);
+ if ( iPos != wxNOT_FOUND )
+ str = c_str() + iPos + 1;
+
+ return str;
+}
+
+// replace first (or all) occurences of some substring with another one
+size_t wxString::Replace(const wxChar *szOld,
+ const wxChar *szNew, bool bReplaceAll)
+{
+ // if we tried to replace an empty string we'd enter an infinite loop below
+ wxCHECK_MSG( szOld && *szOld && szNew, 0,
+ _T("wxString::Replace(): invalid parameter") );
+
+ size_t uiCount = 0; // count of replacements made
+
+ size_t uiOldLen = wxStrlen(szOld);
+ size_t uiNewLen = wxStrlen(szNew);
+
+ size_t dwPos = 0;
+
+ while ( this->c_str()[dwPos] != wxT('\0') )
+ {
+ //DO NOT USE STRSTR HERE
+ //this string can contain embedded null characters,
+ //so strstr will function incorrectly
+ dwPos = find(szOld, dwPos);
+ if ( dwPos == npos )
+ break; // exit the loop
+ else
+ {
+ //replace this occurance of the old string with the new one
+ replace(dwPos, uiOldLen, szNew, uiNewLen);
+
+ //move up pos past the string that was replaced
+ dwPos += uiNewLen;
+
+ //increase replace count
+ ++uiCount;
+
+ // stop now?
+ if ( !bReplaceAll )
+ break; // exit the loop
+ }
+ }
+
+ return uiCount;
+}
+
+bool wxString::IsAscii() const
+{
+ const wxChar *s = (const wxChar*) *this;
+ while(*s){
+ if(!isascii(*s)) return(false);
+ s++;
+ }
+ return(true);
+}
+
+bool wxString::IsWord() const
+{
+ const wxChar *s = (const wxChar*) *this;
+ while(*s){
+ if(!wxIsalpha(*s)) return(false);
+ s++;
+ }
+ return(true);
+}
+
+bool wxString::IsNumber() const
+{
+ const wxChar *s = (const wxChar*) *this;
+ if (wxStrlen(s))
+ if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++;
+ while(*s){
+ if(!wxIsdigit(*s)) return(false);
+ s++;
+ }
+ return(true);
+}
+
+wxString wxString::Strip(stripType w) const
+{
+ wxString s = *this;
+ if ( w & leading ) s.Trim(false);
+ if ( w & trailing ) s.Trim(true);
+ return s;
+}
+
+// ---------------------------------------------------------------------------
+// case conversion
+// ---------------------------------------------------------------------------
+
+wxString& wxString::MakeUpper()
+{
+ for ( iterator it = begin(), en = end(); it != en; ++it )
+ *it = (wxChar)wxToupper(*it);
+
+ return *this;
+}
+
+wxString& wxString::MakeLower()
+{
+ for ( iterator it = begin(), en = end(); it != en; ++it )
+ *it = (wxChar)wxTolower(*it);
+
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+// trimming and padding
+// ---------------------------------------------------------------------------
+
+// some compilers (VC++ 6.0 not to name them) return true for a call to
+// isspace('ê') in the C locale which seems to be broken to me, but we have to
+// live with this by checking that the character is a 7 bit one - even if this
+// may fail to detect some spaces (I don't know if Unicode doesn't have
+// space-like symbols somewhere except in the first 128 chars), it is arguably
+// still better than trimming away accented letters
+inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
+
+// trims spaces (in the sense of isspace) from left or right side
+wxString& wxString::Trim(bool bFromRight)
+{
+ // first check if we're going to modify the string at all
+ if ( !empty() &&
+ (
+ (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
+ (!bFromRight && wxSafeIsspace(GetChar(0u)))
+ )
+ )
+ {
+ if ( bFromRight )
+ {
+ // find last non-space character
+ reverse_iterator psz = rbegin();
+ while ( (psz != rend()) && wxSafeIsspace(*psz) )
+ psz++;
+
+ // truncate at trailing space start
+ erase(psz.base(), end());
+ }
+ else
+ {
+ // find first non-space character
+ iterator psz = begin();
+ while ( (psz != end()) && wxSafeIsspace(*psz) )
+ psz++;
+
+ // fix up data and length
+ erase(begin(), psz);
+ }
+ }
+
+ return *this;
+}
+
+// adds nCount characters chPad to the string from either side
+wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
+{
+ wxString s(chPad, nCount);
+
+ if ( bFromRight )
+ *this += s;
+ else
+ {
+ s += *this;
+ swap(s);
+ }
+
+ return *this;
+}
+
+// truncate the string
+wxString& wxString::Truncate(size_t uiLen)
+{
+ if ( uiLen < length() )
+ {
+ erase(begin() + uiLen, end());
+ }
+ //else: nothing to do, string is already short enough
+
+ return *this;
+}
+
+// ---------------------------------------------------------------------------
+// finding (return wxNOT_FOUND if not found and index otherwise)
+// ---------------------------------------------------------------------------
+
+// find a character
+int wxString::Find(wxChar ch, bool bFromEnd) const
+{
+ size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
+
+ return (idx == npos) ? wxNOT_FOUND : (int)idx;
+}
+
+// find a sub-string (like strstr)
+int wxString::Find(const wxChar *pszSub) const
+{
+ size_type idx = find(pszSub);
+
+ return (idx == npos) ? wxNOT_FOUND : (int)idx;
+}
+
+// ----------------------------------------------------------------------------
+// conversion to numbers
+// ----------------------------------------------------------------------------
+
+bool wxString::ToLong(long *val, int base) const
+{
+ wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToLong") );
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+ const wxChar *start = c_str();
+ wxChar *end;
+ *val = wxStrtol(start, &end, base);
+
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with
+ return !*end && (end != start);
+}
+
+bool wxString::ToULong(unsigned long *val, int base) const
+{
+ wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToULong") );
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+ const wxChar *start = c_str();
+ wxChar *end;
+ *val = wxStrtoul(start, &end, base);
+
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with
+ return !*end && (end != start);
+}
+
+bool wxString::ToDouble(double *val) const
+{
+ wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
+
+ const wxChar *start = c_str();
+ wxChar *end;
+ *val = wxStrtod(start, &end);
+
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with
+ return !*end && (end != start);
+}
+
+// ---------------------------------------------------------------------------
+// formatted output
+// ---------------------------------------------------------------------------
+
+/* static */
+wxString wxString::Format(const wxChar *pszFormat, ...)
+{
+ va_list argptr;
+ va_start(argptr, pszFormat);
+
+ wxString s;
+ s.PrintfV(pszFormat, argptr);
+
+ va_end(argptr);
+
+ return s;
+}
+
+/* static */
+wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
+{
+ wxString s;
+ s.PrintfV(pszFormat, argptr);
+ return s;
+}
+
+int wxString::Printf(const wxChar *pszFormat, ...)
+{
+ va_list argptr;
+ va_start(argptr, pszFormat);
+
+ int iLen = PrintfV(pszFormat, argptr);
+
+ va_end(argptr);
+
+ return iLen;
+}
+
+int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
+{
+ int size = 1024;
+
+ for ( ;; )
+ {
+ wxStringBuffer tmp(*this, size + 1);
+ wxChar *buf = tmp;
+
+ if ( !buf )
+ {
+ // out of memory
+ return -1;
+ }
+
+ // wxVsnprintf() may modify the original arg pointer, so pass it
+ // only a copy
+ va_list argptrcopy;
+ wxVaCopy(argptrcopy, argptr);
+ int len = wxVsnprintf(buf, size, pszFormat, argptrcopy);
+ va_end(argptrcopy);
+
+ // some implementations of vsnprintf() don't NUL terminate
+ // the string if there is not enough space for it so
+ // always do it manually
+ buf[size] = _T('\0');
+
+ // vsnprintf() may return either -1 (traditional Unix behaviour) or the
+ // total number of characters which would have been written if the
+ // buffer were large enough (newer standards such as Unix98)
+ if ( len < 0 )
+ {
+ // still not enough, as we don't know how much we need, double the
+ // current size of the buffer
+ size *= 2;
+ }
+ else if ( len > size )
+ {
+ size = len;
+ }
+ else // ok, there was enough space
+ {
+ break;
+ }
+ }
+
+ // we could have overshot
+ Shrink();
+
+ return length();
+}
+
+// ----------------------------------------------------------------------------
+// misc other operations
+// ----------------------------------------------------------------------------
+
+// returns true if the string matches the pattern which may contain '*' and
+// '?' metacharacters (as usual, '?' matches any character and '*' any number
+// of them)
+bool wxString::Matches(const wxChar *pszMask) const
+{
+ // I disable this code as it doesn't seem to be faster (in fact, it seems
+ // to be much slower) than the old, hand-written code below and using it
+ // here requires always linking with libregex even if the user code doesn't
+ // use it
+#if 0 // wxUSE_REGEX
+ // first translate the shell-like mask into a regex
+ wxString pattern;
+ pattern.reserve(wxStrlen(pszMask));
+
+ pattern += _T('^');
+ while ( *pszMask )
+ {
+ switch ( *pszMask )
+ {
+ case _T('?'):
+ pattern += _T('.');
+ break;
+
+ case _T('*'):
+ pattern += _T(".*");
+ break;
+
+ case _T('^'):
+ case _T('.'):
+ case _T('$'):
+ case _T('('):
+ case _T(')'):
+ case _T('|'):
+ case _T('+'):
+ case _T('\\'):
+ // these characters are special in a RE, quote them
+ // (however note that we don't quote '[' and ']' to allow
+ // using them for Unix shell like matching)
+ pattern += _T('\\');
+ // fall through
+
+ default:
+ pattern += *pszMask;
+ }
+
+ pszMask++;
+ }
+ pattern += _T('$');
+
+ // and now use it
+ return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
+#else // !wxUSE_REGEX
+ // TODO: this is, of course, awfully inefficient...
+
+ // the char currently being checked
+ const wxChar *pszTxt = c_str();
+
+ // the last location where '*' matched
+ const wxChar *pszLastStarInText = NULL;
+ const wxChar *pszLastStarInMask = NULL;
+
+match:
+ for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
+ switch ( *pszMask ) {
+ case wxT('?'):
+ if ( *pszTxt == wxT('\0') )
+ return false;
+
+ // pszTxt and pszMask will be incremented in the loop statement
+
+ break;
+
+ case wxT('*'):
+ {
+ // remember where we started to be able to backtrack later
+ pszLastStarInText = pszTxt;
+ pszLastStarInMask = pszMask;
+
+ // ignore special chars immediately following this one
+ // (should this be an error?)
+ while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
+ pszMask++;
+
+ // if there is nothing more, match
+ if ( *pszMask == wxT('\0') )
+ return true;
+
+ // are there any other metacharacters in the mask?
+ size_t uiLenMask;
+ const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
+
+ if ( pEndMask != NULL ) {
+ // we have to match the string between two metachars
+ uiLenMask = pEndMask - pszMask;
+ }
+ else {
+ // we have to match the remainder of the string
+ uiLenMask = wxStrlen(pszMask);
+ }
+
+ wxString strToMatch(pszMask, uiLenMask);
+ const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
+ if ( pMatch == NULL )
+ return false;
+
+ // -1 to compensate "++" in the loop
+ pszTxt = pMatch + uiLenMask - 1;
+ pszMask += uiLenMask - 1;
+ }
+ break;