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:
Vadim Zeitlin 2007-01-07 16:17:28 +00:00
parent d2aa263fd1
commit f2bbe5b675
4 changed files with 78 additions and 17 deletions

View File

@ -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
/*

View File

@ -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
{

View File

@ -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, ...)

View File

@ -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;