msvcrt: Use mbtowc/wctomb for string conversion in printf.

This changes printf behaviour for C locale.

Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Piotr Caban 2019-02-14 18:27:59 +01:00 committed by Alexandre Julliard
parent 3fc1180623
commit a808235e45
3 changed files with 75 additions and 36 deletions

View File

@ -1103,6 +1103,7 @@ int __cdecl _ismbblead_l(unsigned int, MSVCRT__locale_t);
int __cdecl _ismbclegal(unsigned int c);
int __cdecl _ismbstrail(const unsigned char* start, const unsigned char* str);
int __cdecl MSVCRT_mbtowc(MSVCRT_wchar_t*,const char*,MSVCRT_size_t);
int __cdecl MSVCRT_mbtowc_l(MSVCRT_wchar_t*,const char*,MSVCRT_size_t,MSVCRT__locale_t);
MSVCRT_size_t __cdecl MSVCRT_mbstowcs(MSVCRT_wchar_t*,const char*,MSVCRT_size_t);
MSVCRT_size_t __cdecl MSVCRT__mbstowcs_l(MSVCRT_wchar_t*, const char*, MSVCRT_size_t, MSVCRT__locale_t);
MSVCRT_size_t __cdecl MSVCRT_wcstombs(char*,const MSVCRT_wchar_t*,MSVCRT_size_t);
@ -1128,6 +1129,7 @@ MSVCRT_size_t __cdecl MSVCRT_strnlen(const char *,MSVCRT_size_t);
MSVCRT_size_t __cdecl MSVCRT_wcsnlen(const MSVCRT_wchar_t*,MSVCRT_size_t);
MSVCRT_wchar_t*** __cdecl MSVCRT___p__wenviron(void);
INT __cdecl MSVCRT_wctomb(char*,MSVCRT_wchar_t);
int __cdecl MSVCRT__wctomb_l(char*, MSVCRT_wchar_t, MSVCRT__locale_t);
char* __cdecl MSVCRT__strdate(char* date);
char* __cdecl MSVCRT__strtime(char* date);
int __cdecl _setmbcp(int);

View File

@ -115,25 +115,53 @@ static inline int FUNC_NAME(pf_fill)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ct
return r>=0 ? written : r;
}
#ifndef PRINTF_HELPERS
#define PRINTF_HELPERS
static inline int wcstombs_len(char *mbstr, const MSVCRT_wchar_t *wcstr,
int len, MSVCRT__locale_t locale)
{
char buf[MSVCRT_MB_LEN_MAX];
int i, r, mblen = 0;
for(i=0; i<len; i++) {
r = MSVCRT__wctomb_l(mbstr ? mbstr+mblen : buf, wcstr[i], locale);
if(r < 0) return r;
mblen += r;
}
return mblen;
}
static inline int mbstowcs_len(MSVCRT_wchar_t *wcstr, const char *mbstr,
int len, MSVCRT__locale_t locale)
{
int i, r, wlen = 0;
WCHAR buf;
for(i=0; i<len; wlen++) {
r = MSVCRT_mbtowc_l(wcstr ? wcstr+wlen : &buf, mbstr+i, len-i, locale);
if(r < 0) return r;
i += r ? r : 1;
}
return wlen;
}
#endif
static inline int FUNC_NAME(pf_output_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
const MSVCRT_wchar_t *str, int len, MSVCRT_pthreadlocinfo locinfo)
const MSVCRT_wchar_t *str, int len, MSVCRT__locale_t locale)
{
#ifdef PRINTF_WIDE
return pf_puts(puts_ctx, len, str);
#else
LPSTR out;
BOOL def_char;
int len_a = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
str, len, NULL, 0, NULL, &def_char);
if(def_char)
return 0;
int len_a = wcstombs_len(NULL, str, len, locale);
if(len_a < 0)
return -1;
out = HeapAlloc(GetProcessHeap(), 0, len_a);
if(!out)
return -1;
WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
str, len, out, len_a, NULL, NULL);
wcstombs_len(out, str, len, locale);
len = pf_puts(puts_ctx, len_a, out);
HeapFree(GetProcessHeap(), 0, out);
return len;
@ -141,17 +169,19 @@ static inline int FUNC_NAME(pf_output_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *
}
static inline int FUNC_NAME(pf_output_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
const char *str, int len, MSVCRT_pthreadlocinfo locinfo)
const char *str, int len, MSVCRT__locale_t locale)
{
#ifdef PRINTF_WIDE
LPWSTR out;
int len_w = MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, NULL, 0);
int len_w = mbstowcs_len(NULL, str, len, locale);
if(len_w < 0)
return -1;
out = HeapAlloc(GetProcessHeap(), 0, len_w*sizeof(WCHAR));
if(!out)
return -1;
MultiByteToWideChar(locinfo->lc_codepage, 0, str, len, out, len_w);
mbstowcs_len(out, str, len, locale);
len = pf_puts(puts_ctx, len_w, out);
HeapFree(GetProcessHeap(), 0, out);
return len;
@ -161,7 +191,7 @@ static inline int FUNC_NAME(pf_output_str)(FUNC_NAME(puts_clbk) pf_puts, void *p
}
static inline int FUNC_NAME(pf_output_format_wstr)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
const MSVCRT_wchar_t *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
const MSVCRT_wchar_t *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT__locale_t locale)
{
int r, ret;
@ -179,7 +209,7 @@ static inline int FUNC_NAME(pf_output_format_wstr)(FUNC_NAME(puts_clbk) pf_puts,
r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
ret = r;
if(r >= 0) {
r = FUNC_NAME(pf_output_wstr)(pf_puts, puts_ctx, str, len, locinfo);
r = FUNC_NAME(pf_output_wstr)(pf_puts, puts_ctx, str, len, locale);
ret += r;
}
if(r >= 0) {
@ -191,7 +221,7 @@ static inline int FUNC_NAME(pf_output_format_wstr)(FUNC_NAME(puts_clbk) pf_puts,
}
static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
const char *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo)
const char *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT__locale_t locale)
{
int r, ret;
@ -209,7 +239,7 @@ static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts,
r = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, flags, TRUE);
ret = r;
if(r >= 0) {
r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, str, len, locinfo);
r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, str, len, locale);
ret += r;
}
if(r >= 0) {
@ -221,7 +251,7 @@ static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts,
}
static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
const void *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT_pthreadlocinfo locinfo, BOOL legacy_wide)
const void *str, int len, FUNC_NAME(pf_flags) *flags, MSVCRT__locale_t locale, BOOL legacy_wide)
{
BOOL api_is_wide = sizeof(APICHAR) == sizeof(MSVCRT_wchar_t);
BOOL complement_is_narrow = legacy_wide ? api_is_wide : FALSE;
@ -229,21 +259,21 @@ static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void
static const MSVCRT_wchar_t nullW[] = {'(','n','u','l','l',')',0};
if(!str)
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, nullW, 6, flags, locinfo);
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, nullW, 6, flags, locale);
#else
if(!str)
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locinfo);
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locale);
#endif
if((flags->NaturalString && api_is_wide) || flags->WideString || flags->IntegerLength=='l')
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale);
if((flags->NaturalString && !api_is_wide) || flags->IntegerLength == 'h')
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale);
if((flags->Format=='S' || flags->Format=='C') == complement_is_narrow)
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locinfo);
return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale);
else
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locinfo);
return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale);
}
static inline void FUNC_NAME(pf_rebuild_format_string)(char *p, FUNC_NAME(pf_flags) *flags)
@ -359,7 +389,6 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
MSVCRT__locale_t locale, DWORD options,
args_clbk pf_args, void *args_ctx, __ms_va_list *valist)
{
MSVCRT_pthreadlocinfo locinfo;
const APICHAR *q, *p = fmt;
APICHAR buf[32];
int written = 0, pos, i;
@ -379,11 +408,6 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
if (!MSVCRT_CHECK_PMT(fmt != NULL))
return -1;
if(!locale)
locinfo = get_locinfo();
else
locinfo = locale->locinfo;
while(*p) {
/* output characters before '%' */
for(q=p; *q && *q!='%'; q++);
@ -508,11 +532,12 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
if(flags.Format == 's' || flags.Format == 'S') {
i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx,
pf_args(args_ctx, pos, VT_PTR, valist).get_ptr,
-1, &flags, locinfo, legacy_wide);
-1, &flags, locale, legacy_wide);
} else if(flags.Format == 'c' || flags.Format == 'C') {
int ch = pf_args(args_ctx, pos, VT_INT, valist).get_int;
i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locinfo, legacy_wide);
i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locale, legacy_wide);
if(i < 0) i = 0; /* ignore conversion error */
} else if(flags.Format == 'p') {
flags.Format = 'X';
flags.PadZero = '0';
@ -524,9 +549,9 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
flags.Precision = i;
#ifdef PRINTF_WIDE
i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, buf, -1, &flags, locale);
#else
i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, buf, -1, &flags, locinfo);
i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, buf, -1, &flags, locale);
#endif
} else if(flags.Format == 'n') {
int *used;
@ -567,9 +592,9 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
(unsigned short)pf_args(args_ctx, pos, VT_INT, valist).get_int);
#ifdef PRINTF_WIDE
i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
i = FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, tmp, -1, &flags, locale);
#else
i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, tmp, -1, &flags, locinfo);
i = FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, tmp, -1, &flags, locale);
#endif
if(tmp != buf)
HeapFree(GetProcessHeap(), 0, tmp);
@ -648,7 +673,7 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
decimal_point = strchr(tmp, '.');
if(decimal_point) {
*decimal_point = *locinfo->lconv->decimal_point;
*decimal_point = *(locale ? locale->locinfo : get_locinfo())->lconv->decimal_point;
if(inf || nan || ind) {
static const char inf_str[] = "#INF";
@ -685,7 +710,7 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
i = FUNC_NAME(pf_fill)(pf_puts, puts_ctx, len, &flags, TRUE);
if(i < 0)
return i;
r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, tmp, len, locinfo);
r = FUNC_NAME(pf_output_str)(pf_puts, puts_ctx, tmp, len, locale);
if(r < 0)
return r;
i += r;

View File

@ -106,6 +106,7 @@ static void test_sprintf( void )
double pnumber=789456123;
int x, r;
WCHAR wide[] = { 'w','i','d','e',0};
WCHAR buf_w[2];
format = "%+#23.15e";
r = sprintf(buffer,format,pnumber);
@ -786,6 +787,17 @@ static void test_sprintf( void )
ok(r==0, "r = %d\n", r);
ok(!strcmp(buffer, ""), "failed: \"%s\"\n", buffer);
format = "a%Cb";
r = sprintf(buffer, format, 0x3042);
ok(r==2, "r = %d\n", r);
ok(!strcmp(buffer, "ab"), "failed: \"%s\"\n", buffer);
format = "%S";
buf_w[0] = 0x3042;
buf_w[1] = 0;
r = sprintf(buffer, format, buf_w);
ok(r==-1 || broken(!r), "r = %d\n", r);
if(!setlocale(LC_ALL, "Japanese_Japan.932")) {
win_skip("Japanese_Japan.932 locale not available\n");
return;