}
#endif
-#if wxUSE_UNICODE
+#if wxUSE_UNICODE && defined(HAVE_WOSTREAM)
wxSTD wostream& operator<<(wxSTD wostream& wos, const wxString& str)
{
return wos << str.data();
}
-#endif // wxUSE_UNICODE
+#endif // wxUSE_UNICODE && defined(HAVE_WOSTREAM)
#endif // wxUSE_STD_IOSTREAM
}
#endif // wxUSE_UNICODE_UTF8
+/*
+ Uses wxVsnprintf and places the result into the this string.
+
+ In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build
+ it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in
+ the ISO C99 (and thus SUSv3) standard the return value for the case of
+ an undersized buffer is inconsistent. For conforming vsnprintf
+ implementations the function must return the number of characters that
+ would have been printed had the buffer been large enough. For conforming
+ vswprintf implementations the function must return a negative number
+ and set errno.
+
+ What vswprintf sets errno to is undefined but Darwin seems to set it to
+ EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of
+ those are defined in the standard and backed up by several conformance
+ statements. Note that ENOMEM mentioned in the manual page does not
+ apply to swprintf, only wprintf and fwprintf.
+
+ Official manual page:
+ http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html
+
+ Some conformance statements (AIX, Solaris):
+ http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3
+ http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10
+
+ Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since
+ EILSEQ and EINVAL are specifically defined to mean the error is other than
+ an undersized buffer and no other errno are defined we treat those two
+ as meaning hard errors and everything else gets the old behavior which
+ is to keep looping and increasing buffer size until the function succeeds.
+
+ In practice it's impossible to determine before compilation which behavior
+ may be used. The vswprintf function may have vsnprintf-like behavior or
+ vice-versa. Behavior detected on one release can theoretically change
+ with an updated release. Not to mention that configure testing for it
+ would require the test to be run on the host system, not the build system
+ which makes cross compilation difficult. Therefore, we make no assumptions
+ about behavior and try our best to handle every known case, including the
+ case where wxVsnprintf returns a negative number and fails to set errno.
+
+ There is yet one more non-standard implementation and that is our own.
+ Fortunately, that can be detected at compile-time.
+
+ On top of all that, ISO C99 explicitly defines snprintf to write a null
+ character to the last position of the specified buffer. That would be at
+ at the given buffer size minus 1. It is supposed to do this even if it
+ turns out that the buffer is sized too small.
+
+ Darwin (tested on 10.5) follows the C99 behavior exactly.
+
+ Glibc 2.6 almost follows the C99 behavior except vswprintf never sets
+ errno even when it fails. However, it only seems to ever fail due
+ to an undersized buffer.
+*/
#if wxUSE_UNICODE_UTF8
template<typename BufferType>
#else
// only a copy
va_list argptrcopy;
wxVaCopy(argptrcopy, argptr);
+
+#ifndef __WXWINCE__
+ // Set errno to 0 to make it determinate if wxVsnprintf fails to set it.
+ errno = 0;
+#endif
int len = wxVsnprintf(buf, size, format, argptrcopy);
va_end(argptrcopy);
// some implementations of vsnprintf() don't NUL terminate
// the string if there is not enough space for it so
// always do it manually
+ // FIXME: This really seems to be the wrong and would be an off-by-one
+ // bug except the code above allocates an extra character.
buf[size] = _T('\0');
// vsnprintf() may return either -1 (traditional Unix behaviour) or the
// assume it only returns error if there is not enough space, but
// as we don't know how much we need, double the current size of
// the buffer
- size *= 2;
+#ifndef __WXWINCE__
+ if( (errno == EILSEQ) || (errno == EINVAL) )
+ // If errno was set to one of the two well-known hard errors
+ // then fail immediately to avoid an infinite loop.
+ return -1;
+ else
+#endif // __WXWINCE__
+ // 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 )
#else
// some vsnprintf() implementations NUL-terminate the buffer and
// some don't in len == size case, to be safe always add 1
+ // FIXME: I don't quite understand this comment. The vsnprintf
+ // function is specifically defined to return the number of
+ // characters printed not including the null terminator.
+ // So OF COURSE you need to add 1 to get the right buffer size.
+ // The following line is definitely correct, no question.
size = len + 1;
#endif
}