]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wxchar.cpp
added wxString::operator=(const wxCStrData&) to make it possible to compile code...
[wxWidgets.git] / src / common / wxchar.cpp
index eaab6699ac854c9d63c4242c9fad617aebbcec98..9afb608e493a59fd47b9ef5abf74a7ea31abdb3d 100644 (file)
@@ -20,6 +20,8 @@
     #pragma hdrstop
 #endif
 
+#include "wx/wxchar.h"
+
 #define _ISOC9X_SOURCE 1 // to get vsscanf()
 #define _BSD_SOURCE    1 // to still get strdup()
 
 #endif
 
 #ifndef WX_PRECOMP
-    #include "wx/wxchar.h"
     #include "wx/string.h"
     #include "wx/hash.h"
+    #include "wx/utils.h"     // for wxMin and wxMax
+    #include "wx/log.h"
 #endif
-  #include "wx/utils.h"     // for wxMin and wxMax
 
 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
   #include <windef.h>
@@ -165,6 +167,10 @@ bool WXDLLEXPORT wxOKlibc()
 
 #if !defined(wxVsnprintf_)
 
+#if !wxUSE_WXVSNPRINTF
+    #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used
+#endif
+
 // wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to
 // use wxStrlen and wxStrncpy functions over one-char processing loops.
 //
@@ -183,68 +189,35 @@ bool WXDLLEXPORT wxOKlibc()
 #endif
 
 // some limits of our implementation
-#define wxMAX_SVNPRINTF_ARGUMENTS         16
+#define wxMAX_SVNPRINTF_ARGUMENTS         64
 #define wxMAX_SVNPRINTF_FLAGBUFFER_LEN    32
 #define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN   512
 
-
-// wxVsnprintf() needs to use a *system* implementation of swnprintf()
-// in order to perform some internal tasks.
-// NB: we cannot just use wxSnprintf() because for some systems it maybe
-//     implemented later in this file using wxVsnprintf() and that would
-//     result in an endless recursion and thus in a stack overflow
-#if wxUSE_UNICODE
-
-    #if defined(__WXWINCE__) || ( defined(__VISUALC__) && __VISUALC__ <= 1200 )
-        #define HAVE_BROKEN_SWPRINTF_DECL
-    #endif
-
-
-    // problem: on some systems swprintf takes the 'max' argument while on others
-    //          it doesn't
-    #if defined(HAVE_BROKEN_SWPRINTF_DECL)
-
-        // like when using sprintf(), since 'max' is not used, wxVsnprintf() should
-        // always ensure that 'buff' is big enough for all common needs
-        #define system_sprintf(buff, max, flags, data)      \
-            ::swprintf(buff, flags, data)
-    #else
-
-        #if !defined(HAVE_SWPRINTF)
-            #error wxVsnprintf() needs a system swprintf() implementation!
-        #endif
-
-        #define system_sprintf(buff, max, flags, data)      \
-            ::swprintf(buff, max, flags, data)
-    #endif
-
-#else
-
-    #if defined(HAVE_SNPRINTF)
-
-        #define system_sprintf(buff, max, flags, data)      \
-            ::snprintf(buff, max, flags, data)
-
-    #else       // NB: at least sprintf() should *always* be available
-
-        // since 'max' is not used in this case, wxVsnprintf() should always ensure
-        // that 'buff' is big enough for all common needs
-        // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN)
-        #define system_sprintf(buff, max, flags, data)      \
-            ::sprintf(buff, flags, data)
-
-    #endif
+// prefer snprintf over sprintf
+#if defined(__VISUALC__) || \
+        (defined(__BORLANDC__) && __BORLANDC__ >= 0x540)
+    #define system_sprintf(buff, max, flags, data)      \
+        ::_snprintf(buff, max, flags, data)
+#elif defined(HAVE_SNPRINTF)
+    #define system_sprintf(buff, max, flags, data)      \
+        ::snprintf(buff, max, flags, data)
+#else       // NB: at least sprintf() should always be available
+    // since 'max' is not used in this case, wxVsnprintf() should always
+    // ensure that 'buff' is big enough for all common needs
+    // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN)
+    #define system_sprintf(buff, max, flags, data)      \
+        ::sprintf(buff, flags, data)
+
+    #define SYSTEM_SPRINTF_IS_UNSAFE
 #endif
 
-
-
 // the conversion specifiers accepted by wxVsnprintf_
 enum wxPrintfArgType {
     wxPAT_INVALID = -1,
 
     wxPAT_INT,          // %d, %i, %o, %u, %x, %X
     wxPAT_LONGINT,      // %ld, etc
-#if SIZEOF_LONG_LONG
+#ifdef wxLongLong_t
     wxPAT_LONGLONGINT,  // %Ld, etc
 #endif
     wxPAT_SIZET,        // %Zd, etc
@@ -269,8 +242,8 @@ enum wxPrintfArgType {
 typedef union {
     int pad_int;                        //  %d, %i, %o, %u, %x, %X
     long int pad_longint;               // %ld, etc
-#if SIZEOF_LONG_LONG
-    long long int pad_longlongint;      // %Ld, etc
+#ifdef wxLongLong_t
+    wxLongLong_t pad_longlongint;      // %Ld, etc
 #endif
     size_t pad_sizet;                   // %Zd, etc
 
@@ -330,7 +303,7 @@ public:
     //     thus could be safely declared as a char[] buffer, we want it to be wxChar
     //     so that in Unicode builds we can avoid to convert its contents to Unicode
     //     chars when copying it in user's buffer.
-    wxChar m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
+    char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
 
 
 public:
@@ -348,7 +321,7 @@ public:
     // Process this conversion specifier and puts the result in the given
     // buffer. Returns the number of characters written in 'buf' or -1 if
     // there's not enough space.
-    int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p);
+    int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written);
 
     // Loads the argument of this conversion specifier from given va_list.
     bool LoadArg(wxPrintfArg *p, va_list &argptr);
@@ -369,7 +342,7 @@ void wxPrintfConvSpec::Init()
 
     // this character will never be removed from m_szFlags array and
     // is important when calling sprintf() in wxPrintfConvSpec::Process() !
-    m_szFlags[0] = wxT('%');
+    m_szFlags[0] = '%';
 }
 
 bool wxPrintfConvSpec::Parse(const wxChar *format)
@@ -378,7 +351,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
 
     // temporary parse data
     size_t flagofs = 1;
-    bool in_prec, prec_dot;
+    bool in_prec,       // true if we found the dot in some previous iteration
+         prec_dot;      // true if the dot has been already added to m_szFlags
     int ilen = 0;
 
     m_bAlignLeft = in_prec = prec_dot = false;
@@ -408,13 +382,13 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
             case wxT('+'):
             case wxT('\''):
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('-'):
                 CHECK_PREC
                 m_bAlignLeft = true;
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('.'):
@@ -429,7 +403,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
             case wxT('h'):
                 ilen = -1;
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('l'):
@@ -439,20 +413,39 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
                 else
                 ilen = 1;
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('q'):
             case wxT('L'):
                 ilen = 2;
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
+#ifdef __WXMSW__
+            // under Windows we support the special '%I64' notation as longlong
+            // integer conversion specifier for MSVC compatibility
+            // (it behaves exactly as '%lli' or '%Li' or '%qi')
+            case wxT('I'):
+                if (*(m_pArgEnd+1) != wxT('6') ||
+                    *(m_pArgEnd+2) != wxT('4'))
+                    return false;       // bad format
+
+                m_pArgEnd++;
+                m_pArgEnd++;
+
+                ilen = 2;
+                CHECK_PREC
+                m_szFlags[flagofs++] = char(ch);
+                m_szFlags[flagofs++] = '6';
+                m_szFlags[flagofs++] = '4';
+                break;
+#endif      // __WXMSW__
 
             case wxT('Z'):
                 ilen = 3;
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('*'):
@@ -473,7 +466,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
 
                 // save the * in our formatting buffer...
                 // will be replaced later by Process()
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 break;
 
             case wxT('1'): case wxT('2'): case wxT('3'):
@@ -485,7 +478,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
                     while ( (*m_pArgEnd >= wxT('0')) &&
                             (*m_pArgEnd <= wxT('9')) )
                     {
-                        m_szFlags[flagofs++] = (*m_pArgEnd);
+                        m_szFlags[flagofs++] = char(*m_pArgEnd);
                         len = len*10 + (*m_pArgEnd - wxT('0'));
                         m_pArgEnd++;
                     }
@@ -527,7 +520,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
             case wxT('x'):
             case wxT('X'):
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 m_szFlags[flagofs] = '\0';
                 if (ilen == 0)
                     m_type = wxPAT_INT;
@@ -539,11 +532,11 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
                 else if (ilen == 1)
                     m_type = wxPAT_LONGINT;
                 else if (ilen == 2)
-#if SIZEOF_LONG_LONG
+#ifdef wxLongLong_t
                     m_type = wxPAT_LONGLONGINT;
-#else // !long long
+#else // !wxLongLong_t
                     m_type = wxPAT_LONGINT;
-#endif // long long/!long long
+#endif // wxLongLong_t/!wxLongLong_t
                 else if (ilen == 3)
                     m_type = wxPAT_SIZET;
                 done = true;
@@ -555,7 +548,7 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
             case wxT('g'):
             case wxT('G'):
                 CHECK_PREC
-                m_szFlags[flagofs++] = ch;
+                m_szFlags[flagofs++] = char(ch);
                 m_szFlags[flagofs] = '\0';
                 if (ilen == 2)
                     m_type = wxPAT_LONGDOUBLE;
@@ -566,6 +559,8 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
 
             case wxT('p'):
                 m_type = wxPAT_POINTER;
+                m_szFlags[flagofs++] = char(ch);
+                m_szFlags[flagofs] = '\0';
                 done = true;
                 break;
 
@@ -649,14 +644,14 @@ bool wxPrintfConvSpec::Parse(const wxChar *format)
 
 void wxPrintfConvSpec::ReplaceAsteriskWith(int width)
 {
-    wxChar temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
+    char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
 
     // find the first * in our flag buffer
-    wxChar *pwidth = wxStrchr(m_szFlags, wxT('*'));
-    wxASSERT(pwidth);
+    char *pwidth = strchr(m_szFlags, '*');
+    wxCHECK_RET(pwidth, _T("field width must be specified"));
 
     // save what follows the * (the +1 is to skip the asterisk itself!)
-    wxStrcpy(temp, pwidth+1);
+    strcpy(temp, pwidth+1);
     if (width < 0)
     {
         pwidth[0] = wxT('-');
@@ -664,11 +659,14 @@ void wxPrintfConvSpec::ReplaceAsteriskWith(int width)
     }
 
     // replace * with the actual integer given as width
-    int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) / sizeof(wxChar);
-    int offset = system_sprintf(pwidth, maxlen, wxT("%d"), abs(width));
+#ifndef SYSTEM_SPRINTF_IS_UNSAFE
+    int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) /
+                        sizeof(*m_szFlags);
+#endif
+    int offset = system_sprintf(pwidth, maxlen, "%d", abs(width));
 
     // restore after the expanded * what was following it
-    wxStrcpy(pwidth+offset, temp);
+    strcpy(pwidth+offset, temp);
 }
 
 bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
@@ -704,11 +702,11 @@ bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
         case wxPAT_LONGINT:
             p->pad_longint = va_arg(argptr, long int);
             break;
-#if SIZEOF_LONG_LONG
+#ifdef wxLongLong_t
         case wxPAT_LONGLONGINT:
-            p->pad_longlongint = va_arg(argptr, long long int);
+            p->pad_longlongint = va_arg(argptr, wxLongLong_t);
             break;
-#endif
+#endif // wxLongLong_t
         case wxPAT_SIZET:
             p->pad_sizet = va_arg(argptr, size_t);
             break;
@@ -723,7 +721,7 @@ bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
             break;
 
         case wxPAT_CHAR:
-            p->pad_char = va_arg(argptr, int);  // char is promoted to int when passed through '...'
+            p->pad_char = (char)va_arg(argptr, int);  // char is promoted to int when passed through '...'
             break;
         case wxPAT_WCHAR:
             p->pad_wchar = (wchar_t)va_arg(argptr, int);  // char is promoted to int when passed through '...'
@@ -754,12 +752,12 @@ bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
     return true;    // loading was successful
 }
 
-int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
+int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written)
 {
     // buffer to avoid dynamic memory allocation each time for small strings;
     // note that this buffer is used only to hold results of number formatting,
     // %s directly writes user's string in buf, without using szScratch
-    wxChar szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN];
+    char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN];
     size_t lenScratch = 0, lenCur = 0;
 
 #define APPEND_CH(ch) \
@@ -788,7 +786,7 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
             lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint);
             break;
 
-#if SIZEOF_LONG_LONG
+#ifdef wxLongLong_t
         case wxPAT_LONGLONGINT:
             lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint);
             break;
@@ -932,15 +930,15 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
             break;
 
         case wxPAT_NINT:
-            *p->pad_nint = lenCur;
+            *p->pad_nint = written;
             break;
 
         case wxPAT_NSHORTINT:
-            *p->pad_nshortint = (short int)lenCur;
+            *p->pad_nshortint = (short int)written;
             break;
 
         case wxPAT_NLONGINT:
-            *p->pad_nlongint = lenCur;
+            *p->pad_nlongint = written;
             break;
 
         case wxPAT_INVALID:
@@ -954,16 +952,16 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
     {
         case wxPAT_INT:
         case wxPAT_LONGINT:
-#if SIZEOF_LONG_LONG
+#ifdef wxLongLong_t
         case wxPAT_LONGLONGINT:
 #endif
         case wxPAT_SIZET:
         case wxPAT_LONGDOUBLE:
         case wxPAT_DOUBLE:
         case wxPAT_POINTER:
-#if wxUSE_STRUTILS
+            wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN);
+#if !wxUSE_UNICODE
             {
-                wxASSERT(lenScratch >= 0 && lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN);
                 if (lenMax < lenScratch)
                 {
                     // fill output buffer and then return -1
@@ -975,7 +973,39 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
             }
 #else
             {
-                APPEND_STR(szScratch);
+                // Copy the char scratch to the wide output. This requires
+                // conversion, but we can optimise by making use of the fact
+                // that we are formatting numbers, this should mean only 7-bit
+                // ascii characters are involved.
+                wxChar *bufptr = buf;
+                const wxChar *bufend = buf + lenMax;
+                const char *scratchptr = szScratch;
+
+                // Simply copy each char to a wxChar, stopping on the first
+                // null or non-ascii byte. Checking '(signed char)*scratchptr
+                // > 0' is an extra optimisation over '*scratchptr != 0 &&
+                // isascii(*scratchptr)', though it assumes signed char is
+                // 8-bit 2 complement.
+                while ((signed char)*scratchptr > 0 && bufptr != bufend)
+                    *bufptr++ = *scratchptr++;
+
+                if (bufptr == bufend)
+                    return -1;
+
+                lenCur += bufptr - buf;
+
+                // check if the loop stopped on a non-ascii char, if yes then
+                // fall back to wxMB2WX
+                if (*scratchptr)
+                {
+                    size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr);
+
+                    if (len && len != (size_t)(-1))
+                        if (bufptr[len - 1])
+                            return -1;
+                        else
+                            lenCur += len;
+                }
             }
 #endif
             break;
@@ -987,19 +1017,23 @@ int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
     return lenCur;
 }
 
-// differences from standard strncpy:
-// 1) copies everything from 'source' except for '%%' sequence which is copied as '%'
-// 2) returns the number of written characters in 'dest' as it could differ from given 'n'
-// 3) much less optimized, unfortunately...
-static int wxCopyStrWithPercents(wxChar *dest, const wxChar *source, size_t n)
+// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn
+// chars from source and write at most outMax chars to dest, returns the
+// number of chars actually written. Does not treat null specially.
+//
+static int wxCopyStrWithPercents(
+        size_t maxOut,
+        wxChar *dest,
+        size_t maxIn,
+        const wxChar *source)
 {
     size_t written = 0;
 
-    if (n == 0)
+    if (maxIn == 0)
         return 0;
 
     size_t i;
-    for ( i = 0; i < n-1; source++, i++)
+    for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++)
     {
         dest[written++] = *source;
         if (*(source+1) == wxT('%'))
@@ -1010,7 +1044,7 @@ static int wxCopyStrWithPercents(wxChar *dest, const wxChar *source, size_t n)
         }
     }
 
-    if (i < n)
+    if (i < maxIn && written < maxOut)
         // copy last character inconditionally
         dest[written++] = *source;
 
@@ -1091,8 +1125,10 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
     }
 
     if (posarg_present && nonposarg_present)
+    {
+        buf[0] = 0;
         return -1;      // format strings with both positional and
-                        // non-positional conversion specifier are unsupported !!
+    }                   // non-positional conversion specifier are unsupported !!
 
     // on platforms where va_list is an array type, it is necessary to make a
     // copy to be able to pass it to LoadArg as a reference.
@@ -1112,8 +1148,12 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
     va_end(ap);
 
     // something failed while loading arguments from the variable list...
+    // (e.g. the user repeated twice the same positional argument)
     if (!ok)
+    {
+        buf[0] = 0;
         return -1;
+    }
 
     // finally, process each conversion specifier with its own argument
     toparse = format;
@@ -1122,23 +1162,21 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
         // copy in the output buffer the portion of the format string between
         // last specifier and the current one
         size_t tocopy = ( arg[i].m_pArgPos - toparse );
-        if (lenCur+tocopy >= lenMax)
+
+        lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
+                                        tocopy, toparse);
+        if (lenCur == lenMax)
         {
-            // not enough space in the output buffer !
-            // copy until the end of remaining space and then stop
-            wxCopyStrWithPercents(buf+lenCur, toparse, lenMax - lenCur - 1);
-            buf[lenMax-1] = wxT('\0');
-            return -1;
+            buf[lenMax - 1] = 0;
+            return lenMax+1;      // not enough space in the output buffer !
         }
 
-        lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy);
-
         // process this specifier directly in the output buffer
-        int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos]);
+        int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur);
         if (n == -1)
         {
             buf[lenMax-1] = wxT('\0');  // be sure to always NUL-terminate the string
-            return -1;      // not enough space in the output buffer !
+            return lenMax+1;      // not enough space in the output buffer !
         }
         lenCur += n;
 
@@ -1152,13 +1190,20 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
     //       conversion specifier
     // NOTE2: the +1 is because we want to copy also the '\0'
     size_t tocopy = wxStrlen(format) + 1  - ( toparse - format ) ;
-    if (lenCur+tocopy >= lenMax)
-        return -1;      // not enough space in the output buffer !
 
-    // the -1 is because of the '\0'
-    lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy) - 1;
+    lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, 
+                                    tocopy, toparse) - 1;
+    if (buf[lenCur])
+    {
+        buf[lenCur] = 0;
+        return lenMax+1;     // not enough space in the output buffer !
+    }
+
+    // Don't do:
+    //      wxASSERT(lenCur == wxStrlen(buf));
+    // in fact if we embedded NULLs in the output buffer (using %c with a '\0')
+    // such check would fail
 
-    wxASSERT(lenCur == wxStrlen(buf));
     return lenCur;
 }
 
@@ -1166,10 +1211,16 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
 #undef APPEND_STR
 #undef CHECK_PREC
 
-#endif // !wxVsnprintfA
+#else    // wxVsnprintf_ is defined
+
+#if wxUSE_WXVSNPRINTF
+    #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used
+#endif
+
+#endif // !wxVsnprintf_
 
 #if !defined(wxSnprintf_)
-int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
+int WXDLLEXPORT wxDoSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1185,7 +1236,7 @@ int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
 #if defined(__DMC__)
     /* Digital Mars adds count to _stprintf (C99) so convert */
     #if wxUSE_UNICODE
-        int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
+        int wxDoSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
         {
             va_list arglist;
 
@@ -1206,9 +1257,13 @@ int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
 #ifdef wxNEED_FPUTS
 int wxFputs(const wchar_t *ws, FILE *stream)
 {
+    wxCharBuffer buf(wxConvLibc.cWC2MB(ws));
+    if ( !buf )
+        return -1;
+
     // counting the number of wide characters written isn't worth the trouble,
     // simply distinguish between ok and error
-    return fputs(wxConvLibc.cWC2MB(ws), stream) == -1 ? -1 : 0;
+    return fputs(buf, stream) == -1 ? -1 : 0;
 }
 #endif // wxNEED_FPUTS
 
@@ -1521,7 +1576,7 @@ wxString wxConvertFormat(const wxChar *format)
 
 #if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
 
-int wxScanf( const wxChar *format, ... )
+int wxDoScanf( const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1533,7 +1588,7 @@ int wxScanf( const wxChar *format, ... )
     return ret;
 }
 
-int wxSscanf( const wxChar *str, const wxChar *format, ... )
+int wxDoSscanf( const wxChar *str, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1545,7 +1600,7 @@ int wxSscanf( const wxChar *str, const wxChar *format, ... )
     return ret;
 }
 
-int wxFscanf( FILE *stream, const wxChar *format, ... )
+int wxDoFscanf( FILE *stream, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1556,7 +1611,7 @@ int wxFscanf( FILE *stream, const wxChar *format, ... )
     return ret;
 }
 
-int wxPrintf( const wxChar *format, ... )
+int wxDoPrintf( const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1569,7 +1624,7 @@ int wxPrintf( const wxChar *format, ... )
 }
 
 #ifndef wxSnprintf
-int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
+int wxDoSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1586,7 +1641,7 @@ int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
 }
 #endif // wxSnprintf
 
-int wxSprintf( wxChar *str, const wxChar *format, ... )
+int wxDoSprintf( wxChar *str, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -1601,7 +1656,7 @@ int wxSprintf( wxChar *str, const wxChar *format, ... )
     return s.length();
 }
 
-int wxFprintf( FILE *stream, const wxChar *format, ... )
+int wxDoFprintf( FILE *stream, const wxChar *format, ... )
 {
     va_list argptr;
     va_start( argptr, format );
@@ -2210,3 +2265,34 @@ int wxRemove(const wxChar *path)
 }
 
 #endif
+
+// ----------------------------------------------------------------------------
+// wxUniChar
+// ----------------------------------------------------------------------------
+
+/* static */
+wxUniChar::unicode_type wxUniChar::From8bit(char c)
+{
+    // all supported charsets have the first 128 characters same as ASCII:
+    if ( (unsigned char)c < 0x80 )
+        return c;
+
+    wchar_t buf[2];
+    if ( wxConvLibc.ToWChar(buf, 2, &c, 1) != 2 )
+        return wxT('?'); // FIXME-UTF8: what to use as failure character?
+    return buf[0];
+}
+
+/* static */
+char wxUniChar::To8bit(wxUniChar::unicode_type c)
+{
+    // all supported charsets have the first 128 characters same as ASCII:
+    if ( c < 0x80 )
+        return c;
+
+    wchar_t in = c;
+    char buf[2];
+    if ( wxConvLibc.FromWChar(buf, 2, &in, 1) != 2 )
+        return '?'; // FIXME-UTF8: what to use as failure character?
+    return buf[0];
+}