Commit 30f33e7a authored by David Flynn's avatar David Flynn Committed by Jean-Baptiste Kempf

win32: make vlc_vsnprintf more like c99 vsnprintf

Fixes following issues using MSVCRT _snprintf:
 - Failure to null terminate all strings
 - Failure to return number of characters that would've been
   printed had the buffer been sufficiently large
 - Failure to accept size = 0 (and str = NULL) to determine
   final output length.

NB, the third issue above is fixed on *some* win32 implementations,
however it is not officially documented as being so.
Signed-off-by: default avatarDavid Flynn <davidf@rd.bbc.co.uk>
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 3779d5bd
...@@ -123,6 +123,7 @@ static inline int vlc_vsprintf (char *str, const char *format, va_list ap) ...@@ -123,6 +123,7 @@ static inline int vlc_vsprintf (char *str, const char *format, va_list ap)
} }
# define vsprintf vlc_vsprintf # define vsprintf vlc_vsprintf
static inline int vasprintf (char **strp, const char *fmt, va_list ap);
static inline int vlc_vsnprintf (char *str, size_t size, const char *format, va_list ap) static inline int vlc_vsnprintf (char *str, size_t size, const char *format, va_list ap)
{ {
int must_free = vlc_fix_format_string (&format); int must_free = vlc_fix_format_string (&format);
...@@ -130,7 +131,18 @@ static inline int vlc_vsnprintf (char *str, size_t size, const char *format, va_ ...@@ -130,7 +131,18 @@ static inline int vlc_vsnprintf (char *str, size_t size, const char *format, va_
* to 'aid' portability/standards compliance, mingw provides a * to 'aid' portability/standards compliance, mingw provides a
* static version of vsnprintf that is buggy. Be sure to use * static version of vsnprintf that is buggy. Be sure to use
* MSVCRT version, at least it behaves as expected */ * MSVCRT version, at least it behaves as expected */
int ret = _vsnprintf (str, size, format, ap); /* MSVCRT _vsnprintf does not:
* - null terminate string if insufficient storage
* - return the number of characters that would've been written
*/
int ret = _vsnprintf (str, size-1, format, ap);
str[size-1] = 0; /* ensure the null gets written */
if (ret == -1)
{
/* work out the number of chars that should've been written */
ret = vasprintf (&str, format, ap);
if (ret >= 0 && str) free (str);
}
if (must_free) free ((char *)format); if (must_free) free ((char *)format);
return ret; return ret;
} }
...@@ -195,7 +207,7 @@ static inline int vlc_snprintf (char *str, size_t size, const char *format, ...) ...@@ -195,7 +207,7 @@ static inline int vlc_snprintf (char *str, size_t size, const char *format, ...)
# include <stdarg.h> # include <stdarg.h>
static inline int vasprintf (char **strp, const char *fmt, va_list ap) static inline int vasprintf (char **strp, const char *fmt, va_list ap)
{ {
#ifndef UNDER_CE #ifndef WIN32
int len = vsnprintf (NULL, 0, fmt, ap) + 1; int len = vsnprintf (NULL, 0, fmt, ap) + 1;
char *res = (char *)malloc (len); char *res = (char *)malloc (len);
if (res == NULL) if (res == NULL)
...@@ -203,27 +215,31 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap) ...@@ -203,27 +215,31 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap)
*strp = res; *strp = res;
return vsnprintf (res, len, fmt, ap); return vsnprintf (res, len, fmt, ap);
#else #else
/* HACK: vsnprintf in the WinCE API behaves like /* HACK: vsnprintf in the Win32 API behaves like
* the one in glibc 2.0 and doesn't return the number of characters * the one in glibc 2.0 and doesn't return the number of characters
* it needed to copy the string. * it needed to copy the string.
* cf http://msdn.microsoft.com/en-us/library/1kt27hek.aspx * cf http://msdn.microsoft.com/en-us/library/1kt27hek.aspx
* and cf the man page of vsnprintf * and cf the man page of vsnprintf
* */
Guess we need no more than 50 bytes. */ int must_free = vlc_fix_format_string (&fmt);
int n, size = 50; int n, size = 2 * strlen (fmt);
char *res, *np; char *res, *np;
if ((res = (char *) malloc (size)) == NULL) if ((res = (char *) malloc (size)) == NULL)
{
if (must_free) free ((char *)fmt);
return -1; return -1;
}
while (1) while (1)
{ {
n = vsnprintf (res, size, fmt, ap); n = _vsnprintf (res, size, fmt, ap);
/* If that worked, return the string. */ /* If that worked, return the string. */
if (n > -1 && n < size) if (n > -1 && n < size)
{ {
*strp = res; *strp = res;
if (must_free) free ((char *)fmt);
return n; return n;
} }
...@@ -233,6 +249,7 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap) ...@@ -233,6 +249,7 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap)
if ((np = (char *) realloc (res, size)) == NULL) if ((np = (char *) realloc (res, size)) == NULL)
{ {
free(res); free(res);
if (must_free) free ((char *)fmt);
return -1; return -1;
} }
else else
...@@ -241,7 +258,7 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap) ...@@ -241,7 +258,7 @@ static inline int vasprintf (char **strp, const char *fmt, va_list ap)
} }
} }
#endif /* UNDER_CE */ #endif /* WIN32 */
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment