+ if ( nStart == npos )
+ {
+ nStart = len - 1;
+ }
+ else
+ {
+ wxASSERT_MSG( nStart <= len, wxT("invalid index") );
+ }
+
+ size_t idx = nStart;
+ for ( const_reverse_iterator i = rbegin() + (len - nStart - 1);
+ i != rend(); --idx, ++i )
+ {
+ if ( *i != ch )
+ return idx;
+ }
+
+ return npos;
+}
+
+// the functions above were implemented for wchar_t* arguments in Unicode
+// build and char* in ANSI build; below are implementations for the other
+// version:
+#if wxUSE_UNICODE
+ #define wxOtherCharType char
+ #define STRCONV (const wxChar*)wxConvLibc.cMB2WC
+#else
+ #define wxOtherCharType wchar_t
+ #define STRCONV (const wxChar*)wxConvLibc.cWC2MB
+#endif
+
+size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart) const
+ { return find_first_of(STRCONV(sz), nStart); }
+
+size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart,
+ size_t n) const
+ { return find_first_of(STRCONV(sz, n, NULL), nStart, n); }
+size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart) const
+ { return find_last_of(STRCONV(sz), nStart); }
+size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart,
+ size_t n) const
+ { return find_last_of(STRCONV(sz, n, NULL), nStart, n); }
+size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart) const
+ { return find_first_not_of(STRCONV(sz), nStart); }
+size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart,
+ size_t n) const
+ { return find_first_not_of(STRCONV(sz, n, NULL), nStart, n); }
+size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart) const
+ { return find_last_not_of(STRCONV(sz), nStart); }
+size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
+ size_t n) const
+ { return find_last_not_of(STRCONV(sz, n, NULL), nStart, n); }
+
+#undef wxOtherCharType
+#undef STRCONV
+
+#endif // !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
+
+// ===========================================================================
+// other common string functions
+// ===========================================================================
+
+int wxString::CmpNoCase(const wxString& s) const
+{
+#if defined(__WXMSW__) && !wxUSE_UNICODE_UTF8
+ // Prefer to use CompareString() if available as it's more efficient than
+ // doing it manually or even using wxStricmp() (see #10375)
+ //
+ // Also note that not using NORM_STRINGSORT may result in not having a
+ // strict weak ordering (e.g. s1 < s2 and s2 < s3 but s3 < s1) and so break
+ // algorithms such as std::sort that rely on it. It's also more consistent
+ // with the fall back version below.
+ switch ( ::CompareString(LOCALE_USER_DEFAULT,
+ NORM_IGNORECASE | SORT_STRINGSORT,
+ m_impl.c_str(), m_impl.length(),
+ s.m_impl.c_str(), s.m_impl.length()) )
+ {
+ case CSTR_LESS_THAN:
+ return -1;
+
+ case CSTR_EQUAL:
+ return 0;
+
+ case CSTR_GREATER_THAN:
+ return 1;
+
+ default:
+ wxFAIL_MSG( "unexpected CompareString() return value" );
+ // fall through
+
+ case 0:
+ wxLogLastError("CompareString");
+ // use generic code below
+ }
+#endif // __WXMSW__ && !wxUSE_UNICODE_UTF8
+
+ // do the comparison manually: notice that we can't use wxStricmp() as it
+ // doesn't handle embedded NULs
+
+ // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
+ const_iterator i1 = begin();
+ const_iterator end1 = end();
+ const_iterator i2 = s.begin();
+ const_iterator end2 = s.end();
+
+ for ( ; i1 != end1 && i2 != end2; ++i1, ++i2 )
+ {
+ wxUniChar lower1 = (wxChar)wxTolower(*i1);
+ wxUniChar lower2 = (wxChar)wxTolower(*i2);
+ if ( lower1 != lower2 )
+ return lower1 < lower2 ? -1 : 1;
+ }
+
+ size_t len1 = length();
+ size_t len2 = s.length();
+
+ if ( len1 < len2 )
+ return -1;
+ else if ( len1 > len2 )
+ return 1;
+ return 0;
+}
+
+
+#if wxUSE_UNICODE
+
+#ifdef __MWERKS__
+#ifndef __SCHAR_MAX__
+#define __SCHAR_MAX__ 127
+#endif
+#endif
+
+wxString wxString::FromAscii(const char *ascii, size_t len)