oleaut32: use the locale settings for digit group sizes
Damjan Jovanovic
damjan.jov at gmail.com
Mon Jul 4 22:05:55 CDT 2011
Changelog:
* oleaut32: use the locale settings for digit group sizes
Definitely fixes digit grouping in Indic locales and might close
#25263. Either way it's one step closer to world domination ;-).
Damjan Jovanovic
-------------- next part --------------
diff --git a/dlls/oleaut32/tests/varformat.c b/dlls/oleaut32/tests/varformat.c
index ae74429..2c75868 100644
--- a/dlls/oleaut32/tests/varformat.c
+++ b/dlls/oleaut32/tests/varformat.c
@@ -249,6 +249,7 @@ static void test_VarFormat(void)
int fd = 0, fw = 0;
ULONG flags = 0;
BSTR bstrin, out = NULL;
+ WCHAR origSGrouping[10];
HRESULT hres;
CHECKPTR(VarFormat);
@@ -420,6 +421,14 @@ static void test_VarFormat(void)
VARFMT(VT_R8,V_R8,1.00,"#,##0.00",S_OK,"1.00");
VARFMT(VT_R8,V_R8,0.0995,"#.###",S_OK,".1");
+ if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, origSGrouping, sizeof(origSGrouping)/sizeof(WCHAR)))
+ {
+ SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, "3;2;0");
+ VARFMT(VT_I4,V_I4,123456789,"#,#",S_OK,"12,34,56,789");
+ SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, origSGrouping);
+ }
+ else
+ skip("getting LOCALE_SGROUPING failed, skipping test\n");
/* 'out' is not cleared */
out = (BSTR)0x1;
diff --git a/dlls/oleaut32/varformat.c b/dlls/oleaut32/varformat.c
index 351529c..dbf0417 100644
--- a/dlls/oleaut32/varformat.c
+++ b/dlls/oleaut32/varformat.c
@@ -1184,6 +1184,70 @@ HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok,
#define NUM_WRITE_ON 0x02 /* Started to write the number */
#define NUM_WROTE_SIGN 0x04 /* Written the negative sign */
+struct grouping_state
+{
+ int digitGroupCount;
+ int digitGroupOffsets[10];
+ BOOL recurs;
+ int recurringOffset;
+ int recurringLength;
+};
+
+static void parse_sgrouping(WCHAR *sgrouping, struct grouping_state *state)
+{
+ WCHAR *prev;
+ WCHAR *digit;
+ int total = 0;
+ int secondLastGroup = 0;
+ int lastGroup;
+
+ prev = digit = sgrouping;
+ state->digitGroupCount = 0;
+ while (*digit)
+ {
+ if (*digit == ';')
+ {
+ *digit = 0;
+ secondLastGroup = atoiW(prev);
+ total += secondLastGroup;
+ state->digitGroupOffsets[state->digitGroupCount++] = total;
+ prev = ++digit;
+ }
+ else
+ digit++;
+ }
+ lastGroup = atoiW(prev);
+ if (lastGroup == 0)
+ {
+ state->recurs = TRUE;
+ state->recurringOffset = total + secondLastGroup;
+ state->recurringLength = secondLastGroup;
+ }
+ else
+ {
+ state->recurs = FALSE;
+ state->digitGroupOffsets[state->digitGroupCount++] = total + lastGroup;
+ }
+}
+
+static BOOL needs_separator(struct grouping_state *grouping, int position)
+{
+ if (position <= 0)
+ return FALSE;
+ if (grouping->digitGroupCount > 0 &&
+ grouping->digitGroupOffsets[grouping->digitGroupCount - 1] == position)
+ {
+ grouping->digitGroupCount--;
+ return TRUE;
+ }
+ if (grouping->recurs && position >= grouping->recurringOffset)
+ {
+ if ((position - grouping->recurringOffset) % grouping->recurringLength == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* Format a variant using a number format */
static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat,
LPBYTE rgbTok, ULONG dwFlags,
@@ -1194,6 +1258,7 @@ static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat,
int have_int, need_int = 0, have_frac, need_frac, exponent = 0, pad = 0;
WCHAR buff[256], *pBuff = buff;
WCHAR thousandSeparator[32];
+ struct grouping_state digitGrouping;
VARIANT vString, vBool;
DWORD dwState = 0;
FMT_HEADER *header = (FMT_HEADER*)rgbTok;
@@ -1330,12 +1395,21 @@ static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat,
if (numHeader->flags & FMT_FLAG_THOUSANDS)
{
+ WCHAR sgrouping[10];
if (!GetLocaleInfoW(lcid, LOCALE_STHOUSAND, thousandSeparator,
sizeof(thousandSeparator)/sizeof(WCHAR)))
{
thousandSeparator[0] = ',';
thousandSeparator[1] = 0;
}
+ if (GetLocaleInfoW(lcid, LOCALE_SGROUPING, sgrouping,
+ sizeof(sgrouping)/sizeof(WCHAR)))
+ parse_sgrouping(sgrouping, &digitGrouping);
+ else
+ {
+ digitGrouping.digitGroupCount = 0;
+ digitGrouping.recurs = FALSE;
+ }
}
pToken = (const BYTE*)numHeader + sizeof(FMT_NUMBER_HEADER);
@@ -1513,7 +1587,7 @@ VARIANT_FormatNumber_Bool:
{
*pBuff++ = '0';
if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
- position > 1 && (--position % 3) == 0)
+ needs_separator(&digitGrouping, --position))
{
int k;
TRACE("write thousand separator\n");
@@ -1534,7 +1608,7 @@ VARIANT_FormatNumber_Bool:
dwState |= NUM_WRITE_ON;
*pBuff++ = '0' + *prgbDig++;
if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
- position > 1 && (--position % 3) == 0)
+ needs_separator(&digitGrouping, --position))
{
int k;
TRACE("write thousand separator\n");
@@ -1550,7 +1624,7 @@ VARIANT_FormatNumber_Bool:
{
*pBuff++ = '0';
if ((numHeader->flags & FMT_FLAG_THOUSANDS) &&
- position > 1 && (--position % 3) == 0)
+ needs_separator(&digitGrouping, --position))
{
int k;
TRACE("write thousand separator\n");
More information about the wine-patches
mailing list