+ wxStringBuffer buf(res, len);
+
+ wchar_t *dest = buf;
+
+ for ( ;; )
+ {
+ if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
+ break;
+ }
+ }
+
+ return res;
+}
+
+wxString wxString::FromAscii(const char ascii)
+{
+ // What do we do with '\0' ?
+
+ wxString res;
+ res += (wchar_t)(unsigned char) ascii;
+
+ return res;
+}
+
+const wxCharBuffer wxString::ToAscii() const
+{
+ // this will allocate enough space for the terminating NUL too
+ wxCharBuffer buffer(length());
+
+
+ char *dest = buffer.data();
+
+ const wchar_t *pwc = c_str();
+ for ( ;; )
+ {
+ *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
+
+ // the output string can't have embedded NULs anyhow, so we can safely
+ // stop at first of them even if we do have any
+ if ( !*pwc++ )
+ break;
+ }
+
+ return buffer;
+}
+
+#endif // Unicode
+
+// extract string of length nCount starting at nFirst
+wxString wxString::Mid(size_t nFirst, size_t nCount) const
+{
+ size_t nLen = length();
+
+ // default value of nCount is npos and means "till the end"
+ if ( nCount == npos )
+ {
+ nCount = nLen - nFirst;
+ }
+
+ // out-of-bounds requests return sensible things
+ if ( nFirst + nCount > nLen )
+ {
+ nCount = nLen - nFirst;
+ }
+
+ if ( nFirst > nLen )
+ {
+ // AllocCopy() will return empty string
+ return wxEmptyString;
+ }
+
+ wxString dest(*this, nFirst, nCount);
+ if ( dest.length() != nCount )
+ {
+ wxFAIL_MSG( _T("out of memory in wxString::Mid") );
+ }
+
+ return dest;
+}
+
+// check that the string starts with prefix and return the rest of the string
+// in the provided pointer if it is not NULL, otherwise return false
+bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
+{
+ wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
+
+ // first check if the beginning of the string matches the prefix: note
+ // that we don't have to check that we don't run out of this string as
+ // when we reach the terminating NUL, either prefix string ends too (and
+ // then it's ok) or we break out of the loop because there is no match
+ const wxChar *p = c_str();
+ while ( *prefix )
+ {
+ if ( *prefix++ != *p++ )
+ {
+ // no match
+ return false;
+ }
+ }
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ *rest = p;
+ }
+
+ 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
+// ----------------------------------------------------------------------------
+
+// the implementation of all the functions below is exactly the same so factor
+// it out
+#ifndef __WATCOMC__
+
+template <typename T>
+bool wxStringToIntType(const wxChar *start,
+ T *val,
+ int base,
+ T (*func)(const wxChar *, wxChar **, int))
+{
+ wxCHECK_MSG( val, false, _T("NULL output pointer") );
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+ errno = 0;
+
+ wxChar *end;
+ *val = (*func)(start, &end, base);
+
+ // return true only if scan was stopped by the terminating NUL and if the
+ // string was not empty to start with and no under/overflow occurred
+ return !*end && (end != start) && (errno != ERANGE);
+}
+
+#define wxSTR2INT(val, b, func) return wxStringToIntType(c_str(), val, b, func)
+
+#else // __WATCOMC__
+
+// FIXME, TODO, ASAP !!! - ugly trick to make release for Open Watcom possible
+// without changing code flow for other compilers
+
+#define wxSTR2INT(val, base, func) \
+ wxCHECK_MSG( val, false, _T("NULL output pointer") ); \
+ wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); \
+ \
+ errno = 0; \
+ \
+ wxChar *end; \
+ *val = (*func)(c_str(), &end, base); \
+ \
+ return !*end && (end != c_str()) && (errno != ERANGE)
+
+#endif // !__WATCOMC__/__WATCOMC__
+
+bool wxString::ToLong(long *val, int base) const
+{
+ wxSTR2INT(val, base, wxStrtol);
+}
+
+bool wxString::ToULong(unsigned long *val, int base) const
+{
+ wxSTR2INT(val, base, wxStrtoul);
+}
+
+bool wxString::ToLongLong(wxLongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+ wxSTR2INT(val, base, wxStrtoll);
+#else
+ // TODO: implement this ourselves
+ wxUnusedVar(val);
+ wxUnusedVar(base);
+ return false;
+#endif // wxHAS_STRTOLL
+}
+
+bool wxString::ToULongLong(wxULongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+ wxSTR2INT(val, base, wxStrtoull);
+#else
+ // TODO: implement this ourselves
+ wxUnusedVar(val);
+ wxUnusedVar(base);
+ return false;
+#endif
+}
+
+bool wxString::ToDouble(double *val) const
+{
+ wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
+
+ errno = 0;
+
+ 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 and no under/overflow occurred
+ return !*end && (end != start) && (errno != ERANGE);
+}
+
+// ---------------------------------------------------------------------------
+// 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 )
+ {
+ // some vsnprintf() implementations NUL-terminate the buffer and
+ // some don't in len == size case, to be safe always add 1
+ size = len + 1;
+ }
+ 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++;