From: Gabriel Ivăncescu gabrielopcode@gmail.com
Fixes a regression introduced by 56099a31242dcc522fb94643e70553e152c522ec.
LOCALE_SGROUPING's string and the `Grouping` field in NUMBERFMTW are confusingly different. The former, which is what is fixed here, treats a '0' as a repeat of the previous grouping. But a 0 at the end of the `Grouping` field prevents it from repeating (it repeats by default otherwise) so it's the opposite. Note that without a '0' in the LOCALE_SGROUPING string, it shouldn't even repeat in the first place.
This fixes the typical "3;0" default grouping, for example.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/kernelbase/locale.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 1e96e49622e..cb1b460090d 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -7245,11 +7245,16 @@ BOOL WINAPI SetUserGeoName(PWSTR geo_name)
static void grouping_to_string( UINT grouping, WCHAR *buffer ) { + UINT last_digit = grouping % 10; WCHAR tmp[10], *p = tmp;
+ /* The string is confusingly different when it comes to repetitions (trailing zeros). For a string, + * a 0 signals that the format needs to be repeat, which is the opposite of the grouping integer. */ while (grouping) { - *p++ = '0' + grouping % 10; + UINT digit = grouping % 10; + if (digit) + *p++ = '0' + digit; grouping /= 10; } while (p > tmp) @@ -7257,6 +7262,11 @@ static void grouping_to_string( UINT grouping, WCHAR *buffer ) *buffer++ = *(--p); if (p > tmp) *buffer++ = ';'; } + if (last_digit != 0) + { + *buffer++ = ';'; + *buffer++ = '0'; + } *buffer = 0; }
@@ -7272,9 +7282,9 @@ static WCHAR *prepend_str( WCHAR *end, const WCHAR *str ) static WCHAR *format_number( WCHAR *end, const WCHAR *value, const WCHAR *decimal_sep, const WCHAR *thousand_sep, const WCHAR *grouping, UINT digits, BOOL lzero ) { + UINT i, len = 0, limit = ~0, repeat = ~0; const WCHAR *frac = NULL; BOOL round = FALSE; - UINT i, len = 0;
*(--end) = 0;
@@ -7327,9 +7337,10 @@ static WCHAR *format_number( WCHAR *end, const WCHAR *value, const WCHAR *decima } if (len) lzero = FALSE;
+ if (*grouping >= '1' && *grouping <= '9') + limit = repeat = *grouping - '0'; while (len) { - UINT limit = *grouping == '0' ? ~0u : *grouping - '0'; while (len && limit--) { WCHAR ch = value[--len]; @@ -7345,7 +7356,16 @@ static WCHAR *format_number( WCHAR *end, const WCHAR *value, const WCHAR *decima *(--end) = ch; } if (len) end = prepend_str( end, thousand_sep ); - if (grouping[1] == ';') grouping += 2; + if (*grouping == '0') + limit = repeat; + else if (grouping[1] == ';') + { + grouping += 2; + if (*grouping == '0') + limit = repeat; + else if (*grouping >= '1' && *grouping <= '9') + limit = repeat = *grouping - '0'; + } } if (round) *(--end) = '1'; else if (lzero) *(--end) = '0'; @@ -7356,7 +7376,7 @@ static WCHAR *format_number( WCHAR *end, const WCHAR *value, const WCHAR *decima static int get_number_format( const NLS_LOCALE_DATA *locale, DWORD flags, const WCHAR *value, const NUMBERFMTW *format, WCHAR *buffer, int len ) { - WCHAR *num, fmt_decimal[4], fmt_thousand[4], fmt_neg[5], grouping[20], output[256]; + WCHAR *num, fmt_decimal[4], fmt_thousand[4], fmt_neg[5], grouping[22], output[256]; const WCHAR *decimal_sep = fmt_decimal, *thousand_sep = fmt_thousand; DWORD digits, lzero, order; int ret = 0;