Commit b09aadd2 authored by Martin Storsjo's avatar Martin Storsjo Committed by Alexandre Julliard

ucrtbase: Handle the swprintf style termination and return values.

When neither the "legacy vsprintf null termination" nor the "standard snprintf behaviour" flags are specified, the functions return -2 when the output string didn't fit (similar to old style msvcrt _snprintf that returned -1), but they are null terminated (similar to the C99 snprintf style behaviour). This is the same way as the C99 swprintf function behaves. Signed-off-by: 's avatarMartin Storsjo <martin@martin.st> Signed-off-by: 's avatarPiotr Caban <piotr@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent cc0420ac
...@@ -1130,6 +1130,9 @@ extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t, ...@@ -1130,6 +1130,9 @@ extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t,
#define UCRTBASE_PRINTF_LEGACY_MSVCRT_COMPATIBILITY (0x0008) #define UCRTBASE_PRINTF_LEGACY_MSVCRT_COMPATIBILITY (0x0008)
#define UCRTBASE_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS (0x0010) #define UCRTBASE_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS (0x0010)
#define UCRTBASE_PRINTF_TERMINATION_MASK (UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION | \
UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR)
#define UCRTBASE_SCANF_SECURECRT (0x0001) #define UCRTBASE_SCANF_SECURECRT (0x0001)
#define UCRTBASE_SCANF_LEGACY_WIDE_SPECIFIERS (0x0002) #define UCRTBASE_SCANF_LEGACY_WIDE_SPECIFIERS (0x0002)
#define UCRTBASE_SCANF_LEGACY_MSVCRT_COMPATIBILITY (0x0004) #define UCRTBASE_SCANF_LEGACY_MSVCRT_COMPATIBILITY (0x0004)
......
...@@ -701,10 +701,10 @@ static int puts_clbk_str_c99_a(void *ctx, int len, const char *str) ...@@ -701,10 +701,10 @@ static int puts_clbk_str_c99_a(void *ctx, int len, const char *str)
if(!out->buf) if(!out->buf)
return len; return len;
if(out->len - 1 < len) { if(out->len < len) {
memcpy(out->buf, str, out->len - 1); memcpy(out->buf, str, out->len);
out->buf += out->len - 1; out->buf += out->len;
out->len = 1; out->len = 0;
return len; return len;
} }
...@@ -724,12 +724,18 @@ int CDECL MSVCRT__stdio_common_vsprintf( unsigned __int64 options, char *str, MS ...@@ -724,12 +724,18 @@ int CDECL MSVCRT__stdio_common_vsprintf( unsigned __int64 options, char *str, MS
struct _str_ctx_a ctx = {len, str}; struct _str_ctx_a ctx = {len, str};
int ret; int ret;
if (options != UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION && if (options & ~UCRTBASE_PRINTF_TERMINATION_MASK)
options != UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR)
FIXME("options %s not handled\n", wine_dbgstr_longlong(options)); FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
ret = pf_printf_a(options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR ? puts_clbk_str_c99_a : puts_clbk_str_a, ret = pf_printf_a(puts_clbk_str_c99_a,
&ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist); &ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
puts_clbk_str_a(&ctx, 1, &nullbyte); puts_clbk_str_a(&ctx, 1, &nullbyte);
if(options & UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
return ret>len ? -1 : ret;
if(ret>=len) {
if(len) str[len-1] = 0;
return (options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) ? ret : -2;
}
return ret; return ret;
} }
...@@ -1148,10 +1154,10 @@ static int puts_clbk_str_c99_w(void *ctx, int len, const MSVCRT_wchar_t *str) ...@@ -1148,10 +1154,10 @@ static int puts_clbk_str_c99_w(void *ctx, int len, const MSVCRT_wchar_t *str)
if(!out->buf) if(!out->buf)
return len; return len;
if(out->len - 1 < len) { if(out->len < len) {
memcpy(out->buf, str, (out->len - 1)*sizeof(MSVCRT_wchar_t)); memcpy(out->buf, str, out->len*sizeof(MSVCRT_wchar_t));
out->buf += out->len - 1; out->buf += out->len;
out->len = 1; out->len = 0;
return len; return len;
} }
...@@ -1171,12 +1177,18 @@ int CDECL MSVCRT__stdio_common_vswprintf( unsigned __int64 options, MSVCRT_wchar ...@@ -1171,12 +1177,18 @@ int CDECL MSVCRT__stdio_common_vswprintf( unsigned __int64 options, MSVCRT_wchar
struct _str_ctx_w ctx = {len, str}; struct _str_ctx_w ctx = {len, str};
int ret; int ret;
if (options != UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION && if (options & ~UCRTBASE_PRINTF_TERMINATION_MASK)
options != UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR)
FIXME("options %s not handled\n", wine_dbgstr_longlong(options)); FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
ret = pf_printf_w(options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR ? puts_clbk_str_c99_w : puts_clbk_str_w, ret = pf_printf_w(puts_clbk_str_c99_w,
&ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist); &ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
puts_clbk_str_w(&ctx, 1, &nullbyte); puts_clbk_str_w(&ctx, 1, &nullbyte);
if(options & UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
return ret>len ? -1 : ret;
if(ret>=len) {
if(len) str[len-1] = 0;
return (options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) ? ret : -2;
}
return ret; return ret;
} }
......
...@@ -120,6 +120,21 @@ static void test_snprintf (void) ...@@ -120,6 +120,21 @@ static void test_snprintf (void)
ok (buffer[valid] == '\0', ok (buffer[valid] == '\0',
"\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]); "\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]);
} }
/* swprintf style termination */
for (i = 0; i < sizeof tests / sizeof tests[0]; i++) {
const char *fmt = tests[i];
const int expect = strlen(fmt) >= bufsiz ? -2 : strlen(fmt);
const int n = vsprintf_wrapper (0, buffer, bufsiz, fmt);
const int valid = n < 0 ? bufsiz - 1 : n;
ok (n == expect, "\"%s\": expected %d, returned %d\n",
fmt, expect, n);
ok (!memcmp (fmt, buffer, valid),
"\"%s\": rendered \"%.*s\"\n", fmt, valid, buffer);
ok (buffer[valid] == '\0',
"\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]);
}
} }
static int __cdecl vswprintf_wrapper(unsigned __int64 options, wchar_t *str, static int __cdecl vswprintf_wrapper(unsigned __int64 options, wchar_t *str,
...@@ -177,6 +192,23 @@ static void test_swprintf (void) ...@@ -177,6 +192,23 @@ static void test_swprintf (void)
ok (buffer[valid] == '\0', ok (buffer[valid] == '\0',
"\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]); "\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]);
} }
/* swprintf style termination */
for (i = 0; i < sizeof tests / sizeof tests[0]; i++) {
const wchar_t *fmt = tests[i];
const int expect = wcslen(fmt) >= bufsiz ? -2 : wcslen(fmt);
const int n = vswprintf_wrapper (0, buffer, bufsiz, fmt);
const int valid = n < 0 ? bufsiz - 1 : n;
WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL);
WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL);
ok (n == expect, "\"%s\": expected %d, returned %d\n",
narrow_fmt, expect, n);
ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)),
"\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow);
ok (buffer[valid] == '\0',
"\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]);
}
} }
static int __cdecl vfprintf_wrapper(FILE *file, static int __cdecl vfprintf_wrapper(FILE *file,
......
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