#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,
// 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:
// 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)
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('.'):
case wxT('h'):
ilen = -1;
CHECK_PREC
- m_szFlags[flagofs++] = ch;
+ m_szFlags[flagofs++] = char(ch);
break;
case wxT('l'):
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;
case wxT('Z'):
ilen = 3;
CHECK_PREC
- m_szFlags[flagofs++] = ch;
+ m_szFlags[flagofs++] = char(ch);
break;
case wxT('*'):
// 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'):
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++;
}
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;
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;
case wxT('p'):
m_type = wxPAT_POINTER;
+ m_szFlags[flagofs++] = char(ch);
+ m_szFlags[flagofs] = '\0';
done = true;
break;
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('*'));
+ char *pwidth = strchr(m_szFlags, '*');
wxASSERT(pwidth);
// 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('-');
}
// 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)
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 '...'
// 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) \
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
}
#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;