+  Reinit();
+  for (size_t n = 0; pszFormat[n]; n++)
+    if (pszFormat[n] == wxT('%')) {
+      static char s_szFlags[256] = "%";
+      size_t flagofs = 1;
+      bool adj_left = FALSE, in_prec = FALSE,
+           prec_dot = FALSE, done = FALSE;
+      int ilen = 0;
+      size_t min_width = 0, max_width = wxSTRING_MAXLEN;
+      do {
+#define CHECK_PREC if (in_prec && !prec_dot) { s_szFlags[flagofs++] = '.'; prec_dot = TRUE; }
+        switch (pszFormat[++n]) {
+        case wxT('\0'):
+          done = TRUE;
+          break;
+        case wxT('%'):
+          *this += wxT('%');
+          done = TRUE;
+          break;
+        case wxT('#'):
+        case wxT('0'):
+        case wxT(' '):
+        case wxT('+'):
+        case wxT('\''):
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('-'):
+          CHECK_PREC
+          adj_left = TRUE;
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('.'):
+          CHECK_PREC
+          in_prec = TRUE;
+          prec_dot = FALSE;
+          max_width = 0;
+          // dot will be auto-added to s_szFlags if non-negative number follows
+          break;
+        case wxT('h'):
+          ilen = -1;
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('l'):
+          ilen = 1;
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('q'):
+        case wxT('L'):
+          ilen = 2;
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('Z'):
+          ilen = 3;
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          break;
+        case wxT('*'):
+          {
+            int len = va_arg(argptr, int);
+            if (in_prec) {
+              if (len<0) break;
+              CHECK_PREC
+              max_width = len;
+            } else {
+              if (len<0) {
+                adj_left = !adj_left;
+                s_szFlags[flagofs++] = '-';
+                len = -len;
+              }
+              min_width = len;
+            }
+            flagofs += ::sprintf(s_szFlags+flagofs,"%d",len);
+          }
+          break;
+        case wxT('1'): case wxT('2'): case wxT('3'):
+        case wxT('4'): case wxT('5'): case wxT('6'):
+        case wxT('7'): case wxT('8'): case wxT('9'):
+          {
+            int len = 0;
+            CHECK_PREC
+            while ((pszFormat[n]>=wxT('0')) && (pszFormat[n]<=wxT('9'))) {
+              s_szFlags[flagofs++] = pszFormat[n];
+              len = len*10 + (pszFormat[n] - wxT('0'));
+              n++;
+            }
+            if (in_prec) max_width = len;
+            else min_width = len;
+            n--; // the main loop pre-increments n again
+          }
+          break;
+        case wxT('d'):
+        case wxT('i'):
+        case wxT('o'):
+        case wxT('u'):
+        case wxT('x'):
+        case wxT('X'):
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          s_szFlags[flagofs] = '\0';
+          if (ilen == 0 ) {
+            int val = va_arg(argptr, int);
+            ::sprintf(szScratch, s_szFlags, val);
+          }
+          else if (ilen == -1) {
+            short int val = va_arg(argptr, short int);
+            ::sprintf(szScratch, s_szFlags, val);
+          }
+          else if (ilen == 1) {
+            long int val = va_arg(argptr, long int);
+            ::sprintf(szScratch, s_szFlags, val);
+          }
+          else if (ilen == 2) {
+#if SIZEOF_LONG_LONG
+            long long int val = va_arg(argptr, long long int);
+            ::sprintf(szScratch, s_szFlags, val);
+#else
+            long int val = va_arg(argptr, long int);
+            ::sprintf(szScratch, s_szFlags, val);
+#endif
+          }
+          else if (ilen == 3) {
+            size_t val = va_arg(argptr, size_t);
+            ::sprintf(szScratch, s_szFlags, val);
+          }
+          *this += wxString(szScratch);
+          done = TRUE;
+          break;
+        case wxT('e'):
+        case wxT('E'):
+        case wxT('f'):
+        case wxT('g'):
+        case wxT('G'):
+          CHECK_PREC
+          s_szFlags[flagofs++] = pszFormat[n];
+          s_szFlags[flagofs] = '\0';
+          if (ilen == 2) {
+            long double val = va_arg(argptr, long double);
+            ::sprintf(szScratch, s_szFlags, val);
+          } else {
+            double val = va_arg(argptr, double);
+            ::sprintf(szScratch, s_szFlags, val);
+          }
+          *this += wxString(szScratch);
+          done = TRUE;
+          break;
+        case wxT('p'):
+          {
+            void *val = va_arg(argptr, void *);
+            CHECK_PREC
+            s_szFlags[flagofs++] = pszFormat[n];
+            s_szFlags[flagofs] = '\0';
+            ::sprintf(szScratch, s_szFlags, val);
+            *this += wxString(szScratch);
+            done = TRUE;
+          }
+          break;
+        case wxT('c'):
+          {
+            wxChar val = va_arg(argptr, int);
+            // we don't need to honor padding here, do we?
+            *this += val;
+            done = TRUE;
+          }
+          break;
+        case wxT('s'):
+          if (ilen == -1) {
+            // wx extension: we'll let %hs mean non-Unicode strings
+            char *val = va_arg(argptr, char *);
+#if wxUSE_UNICODE
+            // ASCII->Unicode constructor handles max_width right
+            wxString s(val, wxConvLibc, max_width);
+#else
+            size_t len = wxSTRING_MAXLEN;
+            if (val) {
+              for (len = 0; val[len] && (len<max_width); len++);
+            } else val = wxT("(null)");
+            wxString s(val, len);
+#endif
+            if (s.Len() < min_width)
+              s.Pad(min_width - s.Len(), wxT(' '), adj_left);
+            *this += s;
+          } else {
+            wxChar *val = va_arg(argptr, wxChar *);
+            size_t len = wxSTRING_MAXLEN;
+            if (val) {
+              for (len = 0; val[len] && (len<max_width); len++);
+            } else val = wxT("(null)");
+            wxString s(val, len);
+            if (s.Len() < min_width)
+              s.Pad(min_width - s.Len(), wxT(' '), adj_left);
+            *this += s;
+          }
+          done = TRUE;
+          break;
+        case wxT('n'):
+          if (ilen == 0) {
+            int *val = va_arg(argptr, int *);
+            *val = Len();
+          }
+          else if (ilen == -1) {
+            short int *val = va_arg(argptr, short int *);
+            *val = Len();
+          }
+          else if (ilen >= 1) {
+            long int *val = va_arg(argptr, long int *);
+            *val = Len();
+          }
+          done = TRUE;
+          break;
+        default:
+          if (wxIsalpha(pszFormat[n]))
+            // probably some flag not taken care of here yet
+            s_szFlags[flagofs++] = pszFormat[n];
+          else {
+            // bad format
+            *this += wxT('%'); // just to pass the glibc tst-printf.c
+            n--;
+            done = TRUE;
+          }
+          break;
+        }
+#undef CHECK_PREC
+      } while (!done);
+    } else *this += pszFormat[n];
+
+#else
+  // buffer to avoid dynamic memory allocation each time for small strings
+  char szScratch[1024];
+
+  // NB: wxVsnprintf() may return either less than the buffer size or -1 if
+  //     there is not enough place depending on implementation
+  int iLen = wxVsnprintfA(szScratch, WXSIZEOF(szScratch), (char *)pszFormat, argptr);
+  if ( iLen != -1 ) {
+    // the whole string is in szScratch
+    *this = szScratch;