fixes and workarounds to return value of our own wxVsnprintf_() implementation: handle -1 as error and not an indication that there is not enough space (patch 1623077)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44122 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
d2aa263fd1
commit
f2bbe5b675
@ -982,13 +982,18 @@ WXDLLIMPEXP_BASE bool wxOKlibc(); /* for internal use */
|
||||
#endif /* wxUSE_PRINTF_POS_PARAMS/!wxUSE_PRINTF_POS_PARAMS */
|
||||
|
||||
#ifndef wxSnprintf_
|
||||
/* no [v]snprintf(), cook our own */
|
||||
/* no snprintf(), cook our own */
|
||||
WXDLLIMPEXP_BASE int
|
||||
wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...) ATTRIBUTE_PRINTF_3;
|
||||
#endif
|
||||
#ifndef wxVsnprintf_
|
||||
/* no (suitable) vsnprintf(), cook our own */
|
||||
WXDLLIMPEXP_BASE int
|
||||
wxVsnprintf_(wxChar *buf, size_t len, const wxChar *format, va_list argptr);
|
||||
|
||||
#define wxUSE_WXVSNPRINTF 1
|
||||
#else
|
||||
#define wxUSE_WXVSNPRINTF 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1837,15 +1837,29 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
|
||||
// buffer were large enough (newer standards such as Unix98)
|
||||
if ( len < 0 )
|
||||
{
|
||||
#if wxUSE_WXVSNPRINTF
|
||||
// we know that our own implementation of wxVsnprintf() returns -1
|
||||
// only for a format error - thus there's something wrong with
|
||||
// the user's format string
|
||||
return -1;
|
||||
#else // assume that system version only returns error if not enough space
|
||||
// still not enough, as we don't know how much we need, double the
|
||||
// current size of the buffer
|
||||
size *= 2;
|
||||
#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
|
||||
}
|
||||
else if ( len >= size )
|
||||
{
|
||||
#if wxUSE_WXVSNPRINTF
|
||||
// we know that our own implementation of wxVsnprintf() returns
|
||||
// size+1 when there's not enough space but that's not the size
|
||||
// of the required buffer!
|
||||
size *= 2; // so we just double the current size of the buffer
|
||||
#else
|
||||
// some vsnprintf() implementations NUL-terminate the buffer and
|
||||
// some don't in len == size case, to be safe always add 1
|
||||
size = len + 1;
|
||||
#endif
|
||||
}
|
||||
else // ok, there was enough space
|
||||
{
|
||||
|
@ -167,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.
|
||||
//
|
||||
@ -1124,6 +1128,7 @@ 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;
|
||||
@ -1143,7 +1148,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
|
||||
if (lenCur == lenMax)
|
||||
{
|
||||
buf[lenMax - 1] = 0;
|
||||
return -1;
|
||||
return lenMax+1; // not enough space in the output buffer !
|
||||
}
|
||||
|
||||
// process this specifier directly in the output buffer
|
||||
@ -1151,7 +1156,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
|
||||
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;
|
||||
|
||||
@ -1171,7 +1176,7 @@ int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
|
||||
if (buf[lenCur])
|
||||
{
|
||||
buf[lenCur] = 0;
|
||||
return -1;
|
||||
return lenMax+1; // not enough space in the output buffer !
|
||||
}
|
||||
|
||||
wxASSERT(lenCur == wxStrlen(buf));
|
||||
@ -1182,7 +1187,13 @@ 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, ...)
|
||||
|
@ -31,35 +31,36 @@
|
||||
|
||||
// temporary buffers
|
||||
static wxChar buf[MAX_TEST_LEN];
|
||||
int r;
|
||||
|
||||
// these macros makes it possible to write all tests without repeating a lot of times wxT() macro
|
||||
|
||||
#define ASSERT_STR_EQUAL( a, b ) \
|
||||
CPPUNIT_ASSERT_EQUAL( wxString(a), wxString(b) );
|
||||
|
||||
#define CMP5(expected, x, y, z, w) \
|
||||
wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z, w); \
|
||||
\
|
||||
#define CMP5(expected, x, y, z, w) \
|
||||
r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z, w); \
|
||||
CPPUNIT_ASSERT( r > 0 ); \
|
||||
ASSERT_STR_EQUAL( wxT(expected), buf );
|
||||
|
||||
#define CMP4(expected, x, y, z) \
|
||||
wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z); \
|
||||
\
|
||||
r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z); \
|
||||
CPPUNIT_ASSERT( r > 0 ); \
|
||||
ASSERT_STR_EQUAL( wxT(expected), buf );
|
||||
|
||||
#define CMP3(expected, x, y) \
|
||||
wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y); \
|
||||
\
|
||||
r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y); \
|
||||
CPPUNIT_ASSERT( r > 0 ); \
|
||||
ASSERT_STR_EQUAL( wxT(expected), buf );
|
||||
|
||||
#define CMP2(expected, x) \
|
||||
wxSnprintf(buf, MAX_TEST_LEN, wxT(x)); \
|
||||
\
|
||||
r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x)); \
|
||||
CPPUNIT_ASSERT( r > 0 ); \
|
||||
ASSERT_STR_EQUAL( wxT(expected), buf );
|
||||
|
||||
#define CMPTOSIZE(buffer, size, expected, fmt, x, y, z, w) \
|
||||
wxSnprintf(buffer, size, wxT(fmt), x, y, z, w); \
|
||||
\
|
||||
r=wxSnprintf(buffer, size, wxT(fmt), x, y, z, w); \
|
||||
CPPUNIT_ASSERT( r > 0 ); \
|
||||
CPPUNIT_ASSERT_EQUAL( wxString(wxT(expected)).Left(size - 1), \
|
||||
wxString(buffer) )
|
||||
|
||||
@ -92,6 +93,7 @@ private:
|
||||
#endif
|
||||
|
||||
CPPUNIT_TEST( BigToSmallBuffer );
|
||||
CPPUNIT_TEST( WrongFormatStrings );
|
||||
CPPUNIT_TEST( Miscellaneous );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
@ -112,6 +114,7 @@ private:
|
||||
void Unicode();
|
||||
|
||||
void BigToSmallBuffer();
|
||||
void WrongFormatStrings();
|
||||
void Miscellaneous();
|
||||
void Misc(wxChar *buffer, int size);
|
||||
|
||||
@ -321,9 +324,12 @@ void VsnprintfTestCase::Misc(wxChar *buffer, int size)
|
||||
// value can be the number of characters required for the output buffer
|
||||
// (conforming to ISO C99; implemented in e.g. GNU libc >= 2.1), or
|
||||
// just a negative number, usually -1; (this is how e.g. MSVC's
|
||||
// *printf() behaves). Fortunately, in all implementations, when the
|
||||
// *printf() behaves). Luckily, in all implementations, when the
|
||||
// output buffer is too small, it's nonetheless filled up to its max
|
||||
// size.
|
||||
//
|
||||
// Note that in the second case (i.e. when we're using our own implementation),
|
||||
// wxVsnprintf() will always return the number of characters which
|
||||
|
||||
// test without positionals
|
||||
CMPTOSIZE(buffer, size, "123 444444444 - test - 555 -0.666",
|
||||
@ -350,6 +356,31 @@ void VsnprintfTestCase::Misc(wxChar *buffer, int size)
|
||||
L"unicode!!", L'W', "ansi!!", 'w');
|
||||
}
|
||||
|
||||
void VsnprintfTestCase::WrongFormatStrings()
|
||||
{
|
||||
// test how wxVsnprintf() behaves with wrong format string:
|
||||
|
||||
#if wxUSE_PRINTF_POS_PARAMS
|
||||
|
||||
// two positionals with the same index:
|
||||
r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$s %1$s"), "hello");
|
||||
CPPUNIT_ASSERT(r == -1);
|
||||
|
||||
// three positionals with the same index mixed with other pos args:
|
||||
r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%4$d %2$f %1$s %2$s %3$d"), "hello", "world", 3, 4);
|
||||
CPPUNIT_ASSERT(r == -1);
|
||||
|
||||
// a missing positional arg:
|
||||
r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %3$d"), 1, 2, 3);
|
||||
CPPUNIT_ASSERT(r == -1);
|
||||
|
||||
// positional and non-positionals in the same format string:
|
||||
r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %d %3$d"), 1, 2, 3);
|
||||
CPPUNIT_ASSERT(r == -1);
|
||||
|
||||
#endif // wxUSE_PRINTF_POS_PARAMS
|
||||
}
|
||||
|
||||
void VsnprintfTestCase::BigToSmallBuffer()
|
||||
{
|
||||
wxChar buf[1024], buf2[16], buf3[4], buf4;
|
||||
|
Loading…
Reference in New Issue
Block a user