From: Piotr Caban Subject: [PATCH] msvcrt: Use mbtowc/wctomb for string conversion in printf. Message-Id: Date: Thu, 14 Feb 2019 18:19:10 +0100 This changes printf behaviour for C locale. Signed-off-by: Piotr Caban --- dlls/msvcrt/msvcrt.h | 2 + dlls/msvcrt/printf.h | 97 ++++++++++++++++++++++++-------------- dlls/msvcrt/tests/printf.c | 12 +++++ 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 02b862832c..eba545f4bf 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -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); diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h index 077dafa550..b42dd73cbb 100644 --- a/dlls/msvcrt/printf.h +++ b/dlls/msvcrt/printf.h @@ -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; ilc_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; diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c index 80180ff8b2..9feee3289b 100644 --- a/dlls/msvcrt/tests/printf.c +++ b/dlls/msvcrt/tests/printf.c @@ -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, "r = %d\n", r); + if(!setlocale(LC_ALL, "Japanese_Japan.932")) { win_skip("Japanese_Japan.932 locale not available\n"); return;