]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/string.h
added missing #include "wx/buffer.h"
[wxWidgets.git] / include / wx / string.h
index d60073694c437e1321546d234cde87c56ff8a82c..43bde5e5c1636290927bcc2a4c8d31af5a98f00b 100644 (file)
     #include <StringMgr.h>
 #endif
 
-#include "wx/wxchar.h"      // for wxChar, wxStrlen() etc.
+#include "wx/wxcrt.h"       // for wxChar, wxStrlen() etc.
 #include "wx/strvararg.h"
 #include "wx/buffer.h"      // for wxCharBuffer
 #include "wx/strconv.h"     // for wxConvertXXX() macros and wxMBConv classes
 #include "wx/stringimpl.h"
+#include "wx/stringops.h"
 #include "wx/unichar.h"
 
 class WXDLLIMPEXP_BASE wxString;
@@ -185,8 +186,9 @@ private:
 public:
     // Ctor constructs the object from char literal; they are needed to make
     // operator?: compile and they intentionally take char*, not const char*
-    wxCStrData(char *buf);
-    wxCStrData(wchar_t *buf);
+    inline wxCStrData(char *buf);
+    inline wxCStrData(wchar_t *buf);
+    inline wxCStrData(const wxCStrData& data);
 
     inline ~wxCStrData();
 
@@ -199,8 +201,6 @@ public:
     const wchar_t* AsWChar() const;
     operator const wchar_t*() const { return AsWChar(); }
 
-    inline operator bool() const;
-
 #if !wxUSE_UNICODE
     inline
 #endif
@@ -217,6 +217,10 @@ public:
 
     inline wxString AsString() const;
 
+    // returns the value as C string in internal representation (equivalent
+    // to AsString().wx_str(), but more efficient)
+    const wxStringCharType *AsInternal() const;
+
     // allow expressions like "c_str()[0]":
     inline wxUniChar operator[](size_t n) const;
     wxUniChar operator[](int n) const { return operator[](size_t(n)); }
@@ -293,8 +297,8 @@ class WXDLLIMPEXP_BASE wxStringPrintfMixinBase
 protected:
     wxStringPrintfMixinBase() {}
 
-    int DoPrintf(const wxChar *format, ...) ATTRIBUTE_PRINTF_2;
-    static wxString DoFormat(const wxChar *format, ...) ATTRIBUTE_PRINTF_1;
+    int DoPrintf(const wxString& format, ...);
+    static wxString DoFormat(const wxString& format, ...);
 };
 
 // this class contains template wrappers for wxString's vararg methods, it's
@@ -317,13 +321,27 @@ public:
     // these are duplicated wxString methods, they're also declared below
     // if !wxNEEDS_WXSTRING_PRINTF_MIXIN:
 
-    // int Printf(const wxChar *pszFormat, ...);
-    WX_DEFINE_VARARG_FUNC(int, Printf, DoPrintf)
-    // static wxString Format(const wxChar *pszFormat, ...) ATTRIBUTE_PRINTF_1;
-    WX_DEFINE_VARARG_FUNC(static typename StringReturnType<T1>::type,
-                          Format, DoFormat)
-    // int sprintf(const wxChar *pszFormat, ...) ATTRIBUTE_PRINTF_2;
-    WX_DEFINE_VARARG_FUNC(int, sprintf, DoPrintf)
+    // static wxString Format(const wString& format, ...) ATTRIBUTE_PRINTF_1;
+    WX_DEFINE_VARARG_FUNC2_SANS_N0(static typename StringReturnType<T1>::type,
+                                   Format, 1, (const wxString&),
+                                   DoFormat, DoFormat)
+    // We have to implement the version without template arguments manually
+    // because of the StringReturnType<> hack, although WX_DEFINE_VARARG_FUNC
+    // normally does it itself. It has to be a template so that we can use
+    // the hack, even though there's no real template parameter:
+    struct FormatDummyArg {} ;
+
+    template<typename T>
+    inline static typename StringReturnType<T>::type
+    Format(const wxString& fmt, FormatDummyArg dummy = FormatDummyArg())
+    {
+        return DoFormat(fmt);
+    }
+
+    // int Printf(const wxString& format, ...);
+    WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const wxString&), DoPrintf)
+    // int sprintf(const wxString& format, ...) ATTRIBUTE_PRINTF_2;
+    WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const wxString&), DoPrintf)
 
 protected:
     wxStringPrintfMixin() : wxStringPrintfMixinBase() {}
@@ -373,7 +391,6 @@ private:
 
   // buffer for holding temporary substring when using any of the methods
   // that take (char*,size_t) or (wchar_t*,size_t) arguments:
-  // FIXME-UTF8: This will need changes when UTF8 build is introduced
   template<typename T>
   struct SubstrBufFromType
   {
@@ -441,28 +458,6 @@ private:
     { return ConvertStr(str, n, wxConvLibc); }
   #endif
 
-  // moves the iterator to the next Unicode character
-  static void IncIter(wxStringImpl::iterator& i) { ++i; }
-  static void IncIter(wxStringImpl::const_iterator& i) { ++i; }
-  // moves the iterator to the previous Unicode character
-  static void DecIter(wxStringImpl::iterator& i) { --i; }
-  static void DecIter(wxStringImpl::const_iterator& i) { --i; }
-  // moves the iterator by n Unicode characters
-  static wxStringImpl::iterator AddToIter(wxStringImpl::iterator i, int n)
-    { return i + n; }
-  static wxStringImpl::const_iterator AddToIter(wxStringImpl::const_iterator i, int n)
-    { return i + n; }
-  // returns distance of the two iterators in Unicode characters
-  static int DiffIters(wxStringImpl::iterator i1, wxStringImpl::iterator i2)
-    { return i1 - i2; }
-  static int DiffIters(wxStringImpl::const_iterator i1, wxStringImpl::const_iterator i2)
-    { return i1 - i2; }
-
-  // encodes the character to a form used to represent it in internal
-  // representation (returns a string in UTF8 version)
-  static wxChar EncodeChar(wxUniChar ch) { return (wxChar)ch; }
-  static wxUniChar DecodeChar(wxStringImpl::const_iterator i) { return *i; }
-
   // translates position index in wxString to/from index in underlying
   // wxStringImpl:
   static size_t PosToImpl(size_t pos) { return pos; }
@@ -474,55 +469,20 @@ private:
 
 #else // wxUSE_UNICODE_UTF8
 
-  // checks correctness of UTF-8 sequence
-  static bool IsValidUtf8String(const char *c);
-#ifdef __WXDEBUG__
-  static bool IsValidUtf8LeadByte(unsigned char c);
-#endif
-
-  // table of offsets to skip forward when iterating
-  static unsigned char ms_utf8IterTable[256];
-
-  static void IncIter(wxStringImpl::iterator& i)
-  {
-      wxASSERT( IsValidUtf8LeadByte(*i) );
-      i += ms_utf8IterTable[(unsigned char)*i];
-  }
-  static void IncIter(wxStringImpl::const_iterator& i)
-  {
-      wxASSERT( IsValidUtf8LeadByte(*i) );
-      i += ms_utf8IterTable[(unsigned char)*i];
-  }
-
-  static void DecIter(wxStringImpl::iterator& i);
-  static void DecIter(wxStringImpl::const_iterator& i);
-  static wxStringImpl::iterator AddToIter(wxStringImpl::iterator i, int n);
-  static wxStringImpl::const_iterator AddToIter(wxStringImpl::const_iterator i, int n);
-  static int DiffIters(wxStringImpl::const_iterator i1, wxStringImpl::const_iterator i2);
-  static int DiffIters(wxStringImpl::iterator i1, wxStringImpl::iterator i2);
-
-  struct Utf8CharBuffer
-  {
-      char data[5];
-      operator const char*() const { return data; }
-  };
-  static Utf8CharBuffer EncodeChar(wxUniChar ch);
-  // returns n copies of ch encoded in UTF-8 string
-  static wxCharBuffer EncodeNChars(size_t n, wxUniChar ch);
-
-  // returns the length of UTF-8 encoding of the character with lead byte 'c'
-  static size_t GetUtf8CharLength(char c)
-  {
-      wxASSERT( IsValidUtf8LeadByte(c) );
-      return ms_utf8IterTable[(unsigned char)c];
-  }
+  // FIXME-UTF8: return as-is without copying under UTF8 locale, return
+  //             converted string under other locales - needs wxCharBuffer
+  //             changes
+  static wxCharBuffer ImplStr(const char* str,
+                              const wxMBConv& conv = wxConvLibc)
+    { return ConvertStr(str, npos, conv).data; }
+  static SubstrBufFromMB ImplStr(const char* str, size_t n,
+                                 const wxMBConv& conv = wxConvLibc)
+    { return ConvertStr(str, n, conv); }
 
-  // decodes single UTF-8 character from UTF-8 string
-  // FIXME-UTF8: move EncodeChar/DecodeChar and other operations to separate
-  //             class
-  static wxUniChar DecodeChar(wxStringImpl::const_iterator i)
-    { return wxUniCharRef::DecodeChar(i); }
-  friend class WXDLLIMPEXP_BASE wxUniCharRef;
+  static wxCharBuffer ImplStr(const wchar_t* str)
+    { return ConvertStr(str, npos, wxConvUTF8).data; }
+  static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n)
+    { return ConvertStr(str, n, wxConvUTF8); }
 
   size_t PosToImpl(size_t pos) const
   {
@@ -548,21 +508,6 @@ private:
       else
           return const_iterator(m_impl.begin() + pos) - begin();
   }
-
-  // FIXME-UTF8: return as-is without copying under UTF8 locale, return
-  //             converted string under other locales - needs wxCharBuffer
-  //             changes
-  static wxCharBuffer ImplStr(const char* str,
-                              const wxMBConv& conv = wxConvLibc)
-    { return ConvertStr(str, npos, conv).data; }
-  static SubstrBufFromMB ImplStr(const char* str, size_t n,
-                                 const wxMBConv& conv = wxConvLibc)
-    { return ConvertStr(str, n, conv); }
-
-  static wxCharBuffer ImplStr(const wchar_t* str)
-    { return ConvertStr(str, npos, wxConvUTF8).data; }
-  static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n)
-    { return ConvertStr(str, n, wxConvUTF8); }
 #endif // !wxUSE_UNICODE_UTF8/wxUSE_UNICODE_UTF8
 
 public:
@@ -602,33 +547,45 @@ public:
           reference operator[](size_t n) const { return *(*this + n); }     \
                                                                             \
           iterator_name& operator++()                                       \
-            { wxString::IncIter(m_cur); return *this; }                     \
+            { wxStringOperations::IncIter(m_cur); return *this; }           \
           iterator_name& operator--()                                       \
-            { wxString::DecIter(m_cur); return *this; }                     \
+            { wxStringOperations::DecIter(m_cur); return *this; }           \
           iterator_name operator++(int)                                     \
           {                                                                 \
               iterator_name tmp = *this;                                    \
-              wxString::IncIter(m_cur);                                     \
+              wxStringOperations::IncIter(m_cur);                           \
               return tmp;                                                   \
           }                                                                 \
           iterator_name operator--(int)                                     \
           {                                                                 \
               iterator_name tmp = *this;                                    \
-              wxString::DecIter(m_cur);                                     \
+              wxStringOperations::DecIter(m_cur);                           \
               return tmp;                                                   \
           }                                                                 \
                                                                             \
           iterator_name& operator+=(int n)                                  \
-            { m_cur = wxString::AddToIter(m_cur, n); return *this; }        \
+          {                                                                 \
+              m_cur = wxStringOperations::AddToIter(m_cur, n);              \
+              return *this;                                                 \
+          }                                                                 \
           iterator_name& operator+=(size_t n)                               \
-            { m_cur = wxString::AddToIter(m_cur, (int)n); return *this; }   \
+          {                                                                 \
+              m_cur = wxStringOperations::AddToIter(m_cur, (int)n);         \
+              return *this;                                                 \
+          }                                                                 \
           iterator_name& operator-=(int n)                                  \
-            { m_cur = wxString::AddToIter(m_cur, -n); return *this; }       \
+          {                                                                 \
+              m_cur = wxStringOperations::AddToIter(m_cur, -n);             \
+              return *this;                                                 \
+          }                                                                 \
           iterator_name& operator-=(size_t n)                               \
-            { m_cur = wxString::AddToIter(m_cur, -(int)n); return *this; }  \
+          {                                                                 \
+              m_cur = wxStringOperations::AddToIter(m_cur, -(int)n);        \
+              return *this;                                                 \
+          }                                                                 \
                                                                             \
           difference_type operator-(const iterator_name& i) const           \
-            { return wxString::DiffIters(m_cur, i.m_cur); }                 \
+            { return wxStringOperations::DiffIters(m_cur, i.m_cur); }       \
                                                                             \
           bool operator==(const iterator_name& i) const                     \
             { return m_cur == i.m_cur; }                                    \
@@ -672,13 +629,13 @@ public:
       iterator(const iterator& i) : m_cur(i.m_cur), m_str(i.m_str) {}
 
       iterator operator+(int n) const
-        { return iterator(m_str, wxString::AddToIter(m_cur, n)); }
+        { return iterator(m_str, wxStringOperations::AddToIter(m_cur, n)); }
       iterator operator+(size_t n) const
-        { return iterator(m_str, wxString::AddToIter(m_cur, (int)n)); }
+        { return iterator(m_str, wxStringOperations::AddToIter(m_cur, (int)n)); }
       iterator operator-(int n) const
-        { return iterator(m_str, wxString::AddToIter(m_cur, -n)); }
+        { return iterator(m_str, wxStringOperations::AddToIter(m_cur, -n)); }
       iterator operator-(size_t n) const
-        { return iterator(m_str, wxString::AddToIter(m_cur, -(int)n)); }
+        { return iterator(m_str, wxStringOperations::AddToIter(m_cur, -(int)n)); }
 
   private:
       iterator(wxString *str, underlying_iterator ptr)
@@ -705,13 +662,13 @@ public:
       iterator(const iterator& i) : m_cur(i.m_cur) {}
 
       iterator operator+(int n) const
-        { return iterator(wxString::AddToIter(m_cur, n)); }
+        { return iterator(wxStringOperations::AddToIter(m_cur, n)); }
       iterator operator+(size_t n) const
-        { return iterator(wxString::AddToIter(m_cur, (int)n)); }
+        { return iterator(wxStringOperations::AddToIter(m_cur, (int)n)); }
       iterator operator-(int n) const
-        { return iterator(wxString::AddToIter(m_cur, -n)); }
+        { return iterator(wxStringOperations::AddToIter(m_cur, -n)); }
       iterator operator-(size_t n) const
-        { return iterator(wxString::AddToIter(m_cur, -(int)n)); }
+        { return iterator(wxStringOperations::AddToIter(m_cur, -(int)n)); }
 
   private:
       // for internal wxString use only:
@@ -727,20 +684,20 @@ public:
       // NB: reference_type is intentionally value, not reference, the character
       //     may be encoded differently in wxString data:
       WX_STR_ITERATOR_IMPL(const_iterator, const wxChar*, wxUniChar,
-                           wxString::DecodeChar(m_cur));
+                           wxStringOperations::DecodeChar(m_cur));
 
   public:
       const_iterator(const const_iterator& i) : m_cur(i.m_cur) {}
       const_iterator(const iterator& i) : m_cur(i.m_cur) {}
 
       const_iterator operator+(int n) const
-        { return const_iterator(wxString::AddToIter(m_cur, n)); }
+        { return const_iterator(wxStringOperations::AddToIter(m_cur, n)); }
       const_iterator operator+(size_t n) const
-        { return const_iterator(wxString::AddToIter(m_cur, (int)n)); }
+        { return const_iterator(wxStringOperations::AddToIter(m_cur, (int)n)); }
       const_iterator operator-(int n) const
-        { return const_iterator(wxString::AddToIter(m_cur, -n)); }
+        { return const_iterator(wxStringOperations::AddToIter(m_cur, -n)); }
       const_iterator operator-(size_t n) const
-        { return const_iterator(wxString::AddToIter(m_cur, -(int)n)); }
+        { return const_iterator(wxStringOperations::AddToIter(m_cur, -(int)n)); }
 
   private:
       // for internal wxString use only:
@@ -833,15 +790,33 @@ private:
       return const_iterator(data.m_str->begin() + data.m_offset);
   }
 
+  // in UTF-8 STL build, creation from std::string requires conversion under
+  // non-UTF8 locales, so we can't have and use wxString(wxStringImpl) ctor;
+  // instead we define dummy type that lets us have wxString ctor for creation
+  // from wxStringImpl that couldn't be used by user code (in all other builds,
+  // "standard" ctors can be used):
+#if wxUSE_UNICODE_UTF8 && wxUSE_STL_BASED_WXSTRING
+  struct CtorFromStringImplTag {};
+
+  wxString(CtorFromStringImplTag* WXUNUSED(dummy), const wxStringImpl& src)
+      : m_impl(src) {}
+
+  static wxString FromImpl(const wxStringImpl& src)
+      { return wxString((CtorFromStringImplTag*)NULL, src); }
+#else
+  #if !wxUSE_STL_BASED_WXSTRING
+  wxString(const wxStringImpl& src) : m_impl(src) { }
+  // else: already defined as wxString(wxStdString) below
+  #endif
+  static wxString FromImpl(const wxStringImpl& src) { return wxString(src); }
+#endif
+
 public:
   // constructors and destructor
     // ctor for an empty string
   wxString() {}
 
     // copy ctor
-  // FIXME-UTF8: this one needs to do UTF-8 conversion in UTF-8 build!
-  wxString(const wxStringImpl& stringSrc) : m_impl(stringSrc) { }
-
   wxString(const wxString& stringSrc) : m_impl(stringSrc.m_impl) { }
 
     // string containing nRepeat copies of ch
@@ -917,17 +892,49 @@ public:
       : m_impl(str.Mid(0, nLength).m_impl) {}
 
   // even if we're not built with wxUSE_STL == 1 it is very convenient to allow
-  // implicit conversions from std::string to wxString as this allows to use
-  // the same strings in non-GUI and GUI code, however we don't want to
-  // unconditionally add this ctor as it would make wx lib dependent on
+  // implicit conversions from std::string to wxString and vice verse as this
+  // allows to use the same strings in non-GUI and GUI code, however we don't
+  // want to unconditionally add this ctor as it would make wx lib dependent on
   // libstdc++ on some Linux versions which is bad, so instead we ask the
   // client code to define this wxUSE_STD_STRING symbol if they need it
-#if wxUSE_STD_STRING && !wxUSE_STL_BASED_WXSTRING
-  wxString(const wxStdString& s)
-      // FIXME-UTF8: this one needs to do UTF-8 conversion in UTF-8 build!
-      : m_impl(s.c_str()) { } // FIXME-UTF8: this is broken for embedded 0s
-#endif // wxUSE_STD_STRING && !wxUSE_STL_BASED_WXSTRING
+#if wxUSE_STD_STRING
+  #if wxUSE_UNICODE_WCHAR
+    wxString(const wxStdWideString& str) : m_impl(str) {}
+  #else // UTF-8 or ANSI
+    wxString(const wxStdWideString& str)
+        { assign(str.c_str(), str.length()); }
+  #endif
+
+  #if !wxUSE_UNICODE // ANSI build
+    // FIXME-UTF8: do this in UTF8 build #if wxUSE_UTF8_LOCALE_ONLY, too
+    wxString(const std::string& str) : m_impl(str) {}
+  #else // Unicode
+    wxString(const std::string& str)
+        { assign(str.c_str(), str.length()); }
+  #endif
 
+  #if wxUSE_UNICODE_WCHAR && wxUSE_STL_BASED_WXSTRING
+    // wxStringImpl is std::string in the encoding we want
+    operator const wxStdWideString&() const { return m_impl; }
+  #else
+    // wxStringImpl is either not std::string or needs conversion
+    operator wxStdWideString() const
+        // FIXME-UTF8: broken for embedded NULs
+        { return wxStdWideString(wc_str()); }
+  #endif
+
+  #if !wxUSE_UNICODE && wxUSE_STL_BASED_WXSTRING
+    // FIXME-UTF8: do this in UTF8 build #if wxUSE_UTF8_LOCALE_ONLY, too
+    // wxStringImpl is std::string in the encoding we want
+    operator const std::string&() const { return m_impl; }
+  #else
+    // wxStringImpl is either not std::string or needs conversion
+    operator std::string() const
+        // FIXME-UTF8: broken for embedded NULs
+        { return std::string(mb_str()); }
+  #endif
+
+#endif // wxUSE_STD_STRING
 
   // first valid index position
   const_iterator begin() const { return const_iterator(m_impl.begin()); }
@@ -984,7 +991,7 @@ public:
   {
     size_t pos, len;
     PosLenToImpl(nStart, nLen, &pos, &len);
-    return m_impl.substr(pos, len);
+    return FromImpl(m_impl.substr(pos, len));
   }
 
   // generic attributes & operations
@@ -1084,6 +1091,11 @@ public:
     operator const char*() const { return c_str(); }
     operator const wchar_t*() const { return c_str(); }
 
+    // implicit conversion to untyped pointer for compatibility with previous
+    // wxWidgets versions: this is the same as conversion to const char * so it
+    // may fail!
+    operator const void*() const { return c_str(); }
+
     // identical to c_str(), for MFC compatibility
     const wxCStrData GetData() const { return c_str(); }
 
@@ -1094,7 +1106,8 @@ public:
     // conversion to *non-const* multibyte or widestring buffer; modifying
     // returned buffer won't affect the string, these methods are only useful
     // for passing values to const-incorrect functions
-    wxWritableCharBuffer char_str() const { return mb_str(); }
+    wxWritableCharBuffer char_str(const wxMBConv& conv = wxConvLibc) const
+        { return mb_str(conv); }
     wxWritableWCharBuffer wchar_str() const { return wc_str(); }
 
     // conversion to/from plain (i.e. 7 bit) ASCII: this is useful for
@@ -1168,7 +1181,7 @@ public:
     { return *this = cstr.AsString(); }
     // from a character
   wxString& operator=(wxUniChar ch)
-    { m_impl = EncodeChar(ch); return *this; }
+    { m_impl = wxStringOperations::EncodeChar(ch); return *this; }
   wxString& operator=(wxUniCharRef ch)
     { return operator=((wxUniChar)ch); }
   wxString& operator=(char ch)
@@ -1489,16 +1502,27 @@ public:
   // formatted input/output
     // as sprintf(), returns the number of characters written or < 0 on error
     // (take 'this' into account in attribute parameter count)
-  // int Printf(const wxChar *pszFormat, ...);
-  WX_DEFINE_VARARG_FUNC(int, Printf, DoPrintf)
+  // int Printf(const wxString& format, ...);
+  WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const wxString&), DoPrintf)
+#ifdef __WATCOMC__
+  WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const char*), DoPrintf)
+  WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const wchar_t*), DoPrintf)
+  WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const wxCStrData&), DoPrintf)
+#endif
 #endif // !wxNEEDS_WXSTRING_PRINTF_MIXIN
     // as vprintf(), returns the number of characters written or < 0 on error
   int PrintfV(const wxString& format, va_list argptr);
 
 #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN
     // returns the string containing the result of Printf() to it
-  // static wxString Format(const wxChar *pszFormat, ...) ATTRIBUTE_PRINTF_1;
-  WX_DEFINE_VARARG_FUNC(static wxString, Format, DoFormat)
+  // static wxString Format(const wxString& format, ...) ATTRIBUTE_PRINTF_1;
+  WX_DEFINE_VARARG_FUNC(static wxString, Format, 1, (const wxString&), DoFormat)
+#ifdef __WATCOMC__
+  // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
+  WX_DEFINE_VARARG_FUNC(static wxString, Format, 1, (const char*), DoFormat)
+  WX_DEFINE_VARARG_FUNC(static wxString, Format, 1, (const wchar_t*), DoFormat)
+  WX_DEFINE_VARARG_FUNC(static wxString, Format, 1, (const wxCStrData&), DoFormat)
+#endif
 #endif
     // the same as above, but takes a va_list
   static wxString FormatV(const wxString& format, va_list argptr);
@@ -1515,7 +1539,7 @@ public:
     //
     // get writable buffer of at least nLen bytes. Unget() *must* be called
     // a.s.a.p. to put string back in a reasonable state!
-  wxDEPRECATED( wxChar *GetWriteBuf(size_t nLen) );
+  wxDEPRECATED( wxStringCharType *GetWriteBuf(size_t nLen) );
     // call this immediately after GetWriteBuf() has been used
   wxDEPRECATED( void UngetWriteBuf() );
   wxDEPRECATED( void UngetWriteBuf(size_t nLen) );
@@ -1534,8 +1558,14 @@ public:
 #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN
   // use Printf()
   // (take 'this' into account in attribute parameter count)
-  // int sprintf(const wxChar *pszFormat, ...) ATTRIBUTE_PRINTF_2;
-  WX_DEFINE_VARARG_FUNC(int, sprintf, DoPrintf)
+  // int sprintf(const wxString& format, ...) ATTRIBUTE_PRINTF_2;
+  WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const wxString&), DoPrintf)
+#ifdef __WATCOMC__
+  // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351
+  WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const char*), DoPrintf)
+  WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const wchar_t*), DoPrintf)
+  WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const wxCStrData&), DoPrintf)
+#endif
 #endif // wxNEEDS_WXSTRING_PRINTF_MIXIN
 
     // use Cmp()
@@ -1644,7 +1674,7 @@ public:
   {
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.append(EncodeNChars(n, ch));
+        m_impl.append(wxStringOperations::EncodeNChars(n, ch));
     else
 #endif
         m_impl.append(n, (wxStringCharType)ch);
@@ -1700,7 +1730,7 @@ public:
   {
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.assign(EncodeNChars(n, ch));
+        m_impl.assign(wxStringOperations::EncodeNChars(n, ch));
     else
 #endif
         m_impl.assign(n, (wxStringCharType)ch);
@@ -1777,7 +1807,7 @@ public:
   {
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.insert(PosToImpl(nPos), EncodeNChars(n, ch));
+        m_impl.insert(PosToImpl(nPos), wxStringOperations::EncodeNChars(n, ch));
     else
 #endif
         m_impl.insert(PosToImpl(nPos), n, (wxStringCharType)ch);
@@ -1789,7 +1819,7 @@ public:
     if ( !ch.IsAscii() )
     {
         size_t pos = IterToImplPos(it);
-        m_impl.insert(pos, EncodeChar(ch));
+        m_impl.insert(pos, wxStringOperations::EncodeChar(ch));
         return iterator(this, m_impl.begin() + pos);
     }
     else
@@ -1811,7 +1841,7 @@ public:
   {
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.insert(IterToImplPos(it), EncodeNChars(n, ch));
+        m_impl.insert(IterToImplPos(it), wxStringOperations::EncodeNChars(n, ch));
     else
 #endif
         m_impl.insert(it.impl(), n, (wxStringCharType)ch);
@@ -1867,7 +1897,7 @@ public:
     PosLenToImpl(nStart, nLen, &from, &len);
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.replace(from, len, EncodeNChars(nCount, ch));
+        m_impl.replace(from, len, wxStringOperations::EncodeNChars(nCount, ch));
     else
 #endif
         m_impl.replace(from, len, nCount, (wxStringCharType)ch);
@@ -1940,7 +1970,8 @@ public:
   {
 #if wxUSE_UNICODE_UTF8
     if ( !ch.IsAscii() )
-        m_impl.replace(first.impl(), last.impl(), EncodeNChars(n, ch));
+        m_impl.replace(first.impl(), last.impl(),
+                       wxStringOperations::EncodeNChars(n, ch));
     else
 #endif
         m_impl.replace(first.impl(), last.impl(), n, (wxStringCharType)ch);
@@ -1981,7 +2012,10 @@ public:
 
     // find the first occurence of character ch after nStart
   size_t find(wxUniChar ch, size_t nStart = 0) const
-    { return PosFromImpl(m_impl.find(EncodeChar(ch), PosToImpl(nStart))); }
+  {
+    return PosFromImpl(m_impl.find(wxStringOperations::EncodeChar(ch),
+                                   PosToImpl(nStart)));
+  }
   size_t find(wxUniCharRef ch, size_t nStart = 0) const
     {  return find(wxUniChar(ch), nStart); }
   size_t find(char ch, size_t nStart = 0) const
@@ -2010,7 +2044,10 @@ public:
   }
     // as find, but from the end
   size_t rfind(wxUniChar ch, size_t nStart = npos) const
-    { return PosFromImpl(m_impl.rfind(EncodeChar(ch), PosToImpl(nStart))); }
+  {
+    return PosFromImpl(m_impl.rfind(wxStringOperations::EncodeChar(ch),
+                                    PosToImpl(nStart)));
+  }
   size_t rfind(wxUniCharRef ch, size_t nStart = npos) const
     {  return rfind(wxUniChar(ch), nStart); }
   size_t rfind(char ch, size_t nStart = npos) const
@@ -2190,7 +2227,7 @@ public:
     { m_impl += s.AsString().m_impl; return *this; }
       // string += char
   wxString& operator+=(wxUniChar ch)
-    { m_impl += EncodeChar(ch); return *this; }
+    { m_impl += wxStringOperations::EncodeChar(ch); return *this; }
   wxString& operator+=(wxUniCharRef ch) { return *this += wxUniChar(ch); }
   wxString& operator+=(int ch) { return *this += wxUniChar(ch); }
   wxString& operator+=(char ch) { return *this += wxUniChar(ch); }
@@ -2198,7 +2235,7 @@ public:
   wxString& operator+=(wchar_t ch) { return *this += wxUniChar(ch); }
 
 private:
-#if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
+#if !wxUSE_STL_BASED_WXSTRING
   // helpers for wxStringBuffer and wxStringBufferLength
   wxStringCharType *DoGetWriteBuf(size_t nLen)
     { return m_impl.DoGetWriteBuf(nLen); }
@@ -2206,14 +2243,11 @@ private:
     { m_impl.DoUngetWriteBuf(); }
   void DoUngetWriteBuf(size_t nLen)
     { m_impl.DoUngetWriteBuf(nLen); }
-
-  friend class WXDLLIMPEXP_BASE wxStringBuffer;
-  friend class WXDLLIMPEXP_BASE wxStringBufferLength;
-#endif // !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
+#endif // !wxUSE_STL_BASED_WXSTRING
 
 #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN
-  int DoPrintf(const wxChar *format, ...) ATTRIBUTE_PRINTF_2;
-  static wxString DoFormat(const wxChar *format, ...) ATTRIBUTE_PRINTF_1;
+  int DoPrintf(const wxString& format, ...);
+  static wxString DoFormat(const wxString& format, ...);
 #endif
 
 #if !wxUSE_STL_BASED_WXSTRING
@@ -2251,7 +2285,10 @@ private:
 #if !wxUSE_UNICODE_WCHAR
   ConvertedBuffer<wchar_t> m_convertedToWChar;
 #endif
+
   friend class WXDLLIMPEXP_BASE wxCStrData;
+  friend class wxImplStringBuffer;
+  friend class wxImplStringBufferLength;
 };
 
 #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
@@ -2319,114 +2356,177 @@ inline wxString operator+(wchar_t ch, const wxString& string)
 // wxStringBuffer: a tiny class allowing to get a writable pointer into string
 // ----------------------------------------------------------------------------
 
-#if wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
+#if !wxUSE_STL_BASED_WXSTRING
+// string buffer for direct access to string data in their native
+// representation:
+class wxImplStringBuffer
+{
+public:
+    typedef wxStringCharType CharType;
 
-class WXDLLIMPEXP_BASE wxStringBuffer
+    wxImplStringBuffer(wxString& str, size_t lenWanted = 1024)
+        : m_str(str), m_buf(NULL)
+        { m_buf = m_str.DoGetWriteBuf(lenWanted); }
+
+    ~wxImplStringBuffer() { m_str.DoUngetWriteBuf(); }
+
+    operator wxStringCharType*() const { return m_buf; }
+
+private:
+    wxString&         m_str;
+    wxStringCharType *m_buf;
+
+    DECLARE_NO_COPY_CLASS(wxImplStringBuffer)
+};
+
+class wxImplStringBufferLength
+{
+public:
+    typedef wxStringCharType CharType;
+
+    wxImplStringBufferLength(wxString& str, size_t lenWanted = 1024)
+        : m_str(str), m_buf(NULL), m_len(0), m_lenSet(false)
+    {
+        m_buf = m_str.DoGetWriteBuf(lenWanted);
+        wxASSERT(m_buf != NULL);
+    }
+
+    ~wxImplStringBufferLength()
+    {
+        wxASSERT(m_lenSet);
+        m_str.DoUngetWriteBuf(m_len);
+    }
+
+    operator wxStringCharType*() const { return m_buf; }
+    void SetLength(size_t length) { m_len = length; m_lenSet = true; }
+
+private:
+    wxString&         m_str;
+    wxStringCharType *m_buf;
+    size_t            m_len;
+    bool              m_lenSet;
+
+    DECLARE_NO_COPY_CLASS(wxImplStringBufferLength)
+};
+
+#endif // !wxUSE_STL_BASED_WXSTRING
+
+template<typename T>
+class wxStringTypeBufferBase
 {
 public:
-    wxStringBuffer(wxString& str, size_t lenWanted = 1024)
+    typedef T CharType;
+
+    wxStringTypeBufferBase(wxString& str, size_t lenWanted = 1024)
         : m_str(str), m_buf(lenWanted)
         { }
 
-    ~wxStringBuffer() { m_str.assign(m_buf.data(), wxStrlen(m_buf.data())); }
 
-    operator wxChar*() { return m_buf.data(); }
+    operator CharType*() { return m_buf.data(); }
 
-private:
+protected:
     wxString& m_str;
-#if wxUSE_UNICODE
-    wxWCharBuffer m_buf;
-#else
-    wxCharBuffer m_buf;
-#endif
-
-    DECLARE_NO_COPY_CLASS(wxStringBuffer)
+    wxCharTypeBuffer<CharType> m_buf;
 };
 
-class WXDLLIMPEXP_BASE wxStringBufferLength
+template<typename T>
+class wxStringTypeBufferLengthBase
 {
 public:
-    wxStringBufferLength(wxString& str, size_t lenWanted = 1024)
+    typedef T CharType;
+
+    wxStringTypeBufferLengthBase(wxString& str, size_t lenWanted = 1024)
         : m_str(str), m_buf(lenWanted), m_len(0), m_lenSet(false)
         { }
 
-    ~wxStringBufferLength()
+    ~wxStringTypeBufferLengthBase()
     {
         wxASSERT(m_lenSet);
         m_str.assign(m_buf.data(), m_len);
     }
 
-    operator wxChar*() { return m_buf.data(); }
+    operator CharType*() { return m_buf.data(); }
     void SetLength(size_t length) { m_len = length; m_lenSet = true; }
 
-private:
+protected:
     wxString& m_str;
-#if wxUSE_UNICODE
-    wxWCharBuffer m_buf;
-#else
-    wxCharBuffer  m_buf;
-#endif
+    wxCharTypeBuffer<CharType> m_buf;
     size_t        m_len;
     bool          m_lenSet;
-
-    DECLARE_NO_COPY_CLASS(wxStringBufferLength)
 };
 
-#else // if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
+template<typename T>
+class wxStringTypeBuffer : public wxStringTypeBufferBase<T>
+{
+public:
+    wxStringTypeBuffer(wxString& str, size_t lenWanted = 1024)
+        : wxStringTypeBufferBase<T>(str, lenWanted) {}
+    ~wxStringTypeBuffer()
+    {
+        this->m_str.assign(this->m_buf.data());
+    }
 
-class WXDLLIMPEXP_BASE wxStringBuffer
+    DECLARE_NO_COPY_CLASS(wxStringTypeBuffer)
+};
+
+template<typename T>
+class wxStringTypeBufferLength : public wxStringTypeBufferLengthBase<T>
 {
 public:
-    wxStringBuffer(wxString& str, size_t lenWanted = 1024)
-        : m_str(str), m_buf(NULL)
-        { m_buf = m_str.DoGetWriteBuf(lenWanted); }
+    wxStringTypeBufferLength(wxString& str, size_t lenWanted = 1024)
+        : wxStringTypeBufferLengthBase<T>(str, lenWanted) {}
 
-    ~wxStringBuffer() { m_str.DoUngetWriteBuf(); }
+    ~wxStringTypeBufferLength()
+    {
+        wxASSERT(this->m_lenSet);
+        this->m_str.assign(this->m_buf.data(), this->m_len);
+    }
 
-    operator wxChar*() const { return m_buf; }
+    DECLARE_NO_COPY_CLASS(wxStringTypeBufferLength)
+};
 
-private:
-    wxString& m_str;
-    wxChar   *m_buf;
+#if wxUSE_STL_BASED_WXSTRING
+class wxImplStringBuffer : public wxStringTypeBufferBase<wxStringCharType>
+{
+public:
+    wxImplStringBuffer(wxString& str, size_t lenWanted = 1024)
+        : wxStringTypeBufferBase<wxStringCharType>(str, lenWanted) {}
+    ~wxImplStringBuffer()
+        { m_str.m_impl.assign(m_buf.data()); }
 
-    DECLARE_NO_COPY_CLASS(wxStringBuffer)
+    DECLARE_NO_COPY_CLASS(wxImplStringBuffer)
 };
 
-class WXDLLIMPEXP_BASE wxStringBufferLength
+class wxImplStringBufferLength : public wxStringTypeBufferLengthBase<wxStringCharType>
 {
 public:
-    wxStringBufferLength(wxString& str, size_t lenWanted = 1024)
-        : m_str(str), m_buf(NULL), m_len(0), m_lenSet(false)
-    {
-        m_buf = m_str.DoGetWriteBuf(lenWanted);
-        wxASSERT(m_buf != NULL);
-    }
+    wxImplStringBufferLength(wxString& str, size_t lenWanted = 1024)
+        : wxStringTypeBufferLengthBase<wxStringCharType>(str, lenWanted) {}
 
-    ~wxStringBufferLength()
+    ~wxImplStringBufferLength()
     {
         wxASSERT(m_lenSet);
-        m_str.DoUngetWriteBuf(m_len);
+        m_str.m_impl.assign(m_buf.data(), m_len);
     }
 
-    operator wxChar*() const { return m_buf; }
-    void SetLength(size_t length) { m_len = length; m_lenSet = true; }
-
-private:
-    wxString& m_str;
-    wxChar   *m_buf;
-    size_t    m_len;
-    bool      m_lenSet;
-
-    DECLARE_NO_COPY_CLASS(wxStringBufferLength)
+    DECLARE_NO_COPY_CLASS(wxImplStringBufferLength)
 };
+#endif // wxUSE_STL_BASED_WXSTRING
 
+
+#if wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8
+typedef wxStringTypeBuffer<wxChar>        wxStringBuffer;
+typedef wxStringTypeBufferLength<wxChar>  wxStringBufferLength;
+#else // if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
+typedef wxImplStringBuffer                wxStringBuffer;
+typedef wxImplStringBufferLength          wxStringBufferLength;
 #endif // !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8
 
 // ---------------------------------------------------------------------------
 // wxString comparison functions: operator versions are always case sensitive
 // ---------------------------------------------------------------------------
 
-#define wxCMP_WXCHAR_STRING(p, s, op) s.Cmp(p) op 0
+#define wxCMP_WXCHAR_STRING(p, s, op) 0 op s.Cmp(p)
 
 wxDEFINE_ALL_COMPARISONS(const wxChar *, const wxString&, wxCMP_WXCHAR_STRING)
 
@@ -2550,15 +2650,17 @@ inline wxCStrData::wxCStrData(char *buf)
 inline wxCStrData::wxCStrData(wchar_t *buf)
     : m_str(new wxString(buf)), m_offset(0), m_owned(true) {}
 
-inline wxCStrData::~wxCStrData()
+inline wxCStrData::wxCStrData(const wxCStrData& data)
+    : m_str(data.m_owned ? new wxString(*data.m_str) : data.m_str),
+      m_offset(data.m_offset),
+      m_owned(data.m_owned)
 {
-    if ( m_owned )
-        delete m_str;
 }
 
-inline wxCStrData::operator bool() const
+inline wxCStrData::~wxCStrData()
 {
-    return !m_str->empty();
+    if ( m_owned )
+        delete m_str;
 }
 
 // simple cases for AsChar() and AsWChar(), the complicated ones are
@@ -2603,6 +2705,11 @@ inline wxString wxCStrData::AsString() const
         return m_str->Mid(m_offset);
 }
 
+inline const wxStringCharType *wxCStrData::AsInternal() const
+{
+    return wxStringOperations::AddToIter(m_str->wx_str(), m_offset);
+}
+
 inline wxUniChar wxCStrData::operator*() const
 {
     if ( m_str->empty() )
@@ -2613,7 +2720,9 @@ inline wxUniChar wxCStrData::operator*() const
 
 inline wxUniChar wxCStrData::operator[](size_t n) const
 {
-    return m_str->at(m_offset + n);
+    // NB: we intentionally use operator[] and not at() here because the former
+    //     works for the terminating NUL while the latter does not
+    return (*m_str)[m_offset + n];
 }
 
 // ----------------------------------------------------------------------------
@@ -2647,4 +2756,12 @@ inline wxWCharBuffer::wxWCharBuffer(const wxCStrData& cstr)
 {
 }
 
+#if WXWIN_COMPATIBILITY_2_8
+    // lot of code out there doesn't explicitly include wx/wxchar.h, but uses
+    // CRT wrappers that are now declared in wx/wxcrt.h and wx/wxcrtvararg.h,
+    // so let's include this header now that wxString is defined and it's safe
+    // to do it:
+    #include "wx/wxchar.h"
+#endif
+
 #endif  // _WX_WXSTRING_H_