Signed-off-by: Francois Gouget fgouget@codeweavers.com --- Note that the test for Swiss francs still fails because Wine uses "SFr." as the currency symbol instead of "CHF". The "SFr." symbol is obsolete and this is the subject of bug 51460. https://bugs.winehq.org/show_bug.cgi?id=51460 --- dlls/oleaut32/tests/vartest.c | 4 +-- dlls/oleaut32/variant.c | 46 +++++++++++++++++++++-------------- dlls/oleaut32/variant.h | 13 ---------- 3 files changed, 30 insertions(+), 33 deletions(-)
diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index fbcfba32c80..6dddc79e829 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -2439,10 +2439,10 @@ static void test_VarParseNumFromStrMisc(void) /* Windows 8.1 incorrectly doubles the right-to-left mark: * "\x62f.\x645.\x200f\x200f 5" */ - todo_wine ok(hres == S_OK || broken(hres == DISP_E_TYPEMISMATCH), "returned %08x\n", hres); + ok(hres == S_OK || broken(hres == DISP_E_TYPEMISMATCH), "returned %08x\n", hres); if (hres == S_OK) { - todo_wine EXPECT(1,NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_CURRENCY,6,0,0); + EXPECT(1,NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_CURRENCY,6,0,0); EXPECT2(5,FAILDIG); }
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 2ec07817460..fe4bdb41ed2 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -1499,6 +1499,19 @@ HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate) return S_OK; }
+/* The localised characters that make up a valid number */ +typedef struct tagVARIANT_NUMBER_CHARS +{ + WCHAR cNegativeSymbol; + WCHAR cPositiveSymbol; + WCHAR cDecimalPoint; + WCHAR cDigitSeparator; + DWORD sCurrencyLen; + WCHAR sCurrency[8]; + WCHAR cCurrencyDecimalPoint; + WCHAR cCurrencyDigitSeparator; +} VARIANT_NUMBER_CHARS; + #define GET_NUMBER_TEXT(fld,name) \ buff[0] = 0; \ if (!GetLocaleInfoW(lcid, lctype|fld, buff, 2)) \ @@ -1510,7 +1523,7 @@ HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate) /* Get the valid number characters for an lcid */ static void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags) { - static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',0,'$',0,'.',',' }; + static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',0,1,{'$',0},'.',',' }; LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE; WCHAR buff[4];
@@ -1522,17 +1535,16 @@ static void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint); GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeparator);
- /* Local currency symbols are often 2 characters */ - lpChars->cCurrencyLocal2 = '\0'; - switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, ARRAY_SIZE(buff))) + if (!GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, lpChars->sCurrency, ARRAY_SIZE(lpChars->sCurrency))) { - case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */ - case 2: lpChars->cCurrencyLocal = buff[0]; - break; - default: WARN("buffer too small for LOCALE_SCURRENCY\n"); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + WARN("buffer too small for LOCALE_SCURRENCY\n"); + *lpChars->sCurrency = 0; } - TRACE("lcid 0x%x, cCurrencyLocal=%d,%d %s\n", lcid, lpChars->cCurrencyLocal, - lpChars->cCurrencyLocal2, wine_dbgstr_w(buff)); + if (!*lpChars->sCurrency) + wcscpy(lpChars->sCurrency, L"$"); + lpChars->sCurrencyLen = wcslen(lpChars->sCurrency); + TRACE("lcid 0x%x, sCurrency=%u %s\n", lcid, lpChars->sCurrencyLen, wine_dbgstr_w(lpChars->sCurrency)); }
/* Number Parsing States */ @@ -1656,12 +1668,11 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla } else if (pNumprs->dwInFlags & NUMPRS_CURRENCY && !(pNumprs->dwOutFlags & NUMPRS_CURRENCY) && - *lpszStr == chars.cCurrencyLocal && - (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2)) + wcsncmp(lpszStr, chars.sCurrency, chars.sCurrencyLen) == 0) { pNumprs->dwOutFlags |= NUMPRS_CURRENCY; - cchUsed += chars.cCurrencyLocal2 ? 2 : 1; - lpszStr += chars.cCurrencyLocal2 ? 2 : 1; + cchUsed += chars.sCurrencyLen; + lpszStr += chars.sCurrencyLen; /* Only accept currency characters */ chars.cDecimalPoint = chars.cCurrencyDecimalPoint; } @@ -1972,12 +1983,11 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla pNumprs->dwOutFlags |= NUMPRS_NEG; } else if (pNumprs->dwInFlags & NUMPRS_CURRENCY && - *lpszStr == chars.cCurrencyLocal && - (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2)) + wcsncmp(lpszStr, chars.sCurrency, chars.sCurrencyLen) == 0) { pNumprs->dwOutFlags |= NUMPRS_CURRENCY; - cchUsed += chars.cCurrencyLocal2 ? 2 : 1; - lpszStr += chars.cCurrencyLocal2 ? 2 : 1; + cchUsed += chars.sCurrencyLen; + lpszStr += chars.sCurrencyLen; } else break; diff --git a/dlls/oleaut32/variant.h b/dlls/oleaut32/variant.h index 76444cf0514..1be8f8cdc79 100644 --- a/dlls/oleaut32/variant.h +++ b/dlls/oleaut32/variant.h @@ -101,19 +101,6 @@ #define VAR_BOOLYESNO 0x0800 /* Convert bool to "Yes"/"No" */ #define VAR_NEGATIVE 0x1000 /* Number is negative */
-/* The localised characters that make up a valid number */ -typedef struct tagVARIANT_NUMBER_CHARS -{ - WCHAR cNegativeSymbol; - WCHAR cPositiveSymbol; - WCHAR cDecimalPoint; - WCHAR cDigitSeparator; - WCHAR cCurrencyLocal; - WCHAR cCurrencyLocal2; - WCHAR cCurrencyDecimalPoint; - WCHAR cCurrencyDigitSeparator; -} VARIANT_NUMBER_CHARS; - unsigned int get_type_size(ULONG*, VARTYPE) DECLSPEC_HIDDEN; HRESULT VARIANT_ClearInd(VARIANTARG *) DECLSPEC_HIDDEN; BOOL get_date_format(LCID, DWORD, const SYSTEMTIME *,
They have no default, flag the value as a monetary amount, are unaffected by the presence / absence of a currency symbol, and are incompatible with hexadecimal / octal numbers.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/oleaut32/tests/vartest.c | 32 ++++++------------ dlls/oleaut32/variant.c | 61 ++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 42 deletions(-)
diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index 6dddc79e829..f6149005179 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -1548,11 +1548,8 @@ static void test_VarParseNumFromStrEn(void)
/* Only integers are allowed when using an alternative radix */ CONVERT("&ha.2", NUMPRS_HEX_OCT|NUMPRS_DECIMAL); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(1,NUMPRS_HEX_OCT|NUMPRS_DECIMAL,NUMPRS_HEX_OCT,3,4,0); - todo_wine ok(np.dwOutFlags == NUMPRS_HEX_OCT, "Got dwOutFlags=%08x\n", np.dwOutFlags); - EXPECTRGB(0,10); - todo_wine EXPECTRGB(1,FAILDIG); + EXPECT2(10,FAILDIG);
/* Except if it looks like a plain decimal number */ CONVERT("01.2", NUMPRS_HEX_OCT|NUMPRS_DECIMAL); @@ -2318,9 +2315,8 @@ static void test_VarParseNumFromStrMisc(void)
/* But not for their monetary equivalents */ hres = wconvert_str(L"~1", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY,NUMPRS_DECIMAL|NUMPRS_CURRENCY,2,0,-1); - todo_wine EXPECTRGB(0,1); - EXPECTRGB(1,FAILDIG); + EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY,NUMPRS_DECIMAL|NUMPRS_CURRENCY,2,0,-1); + EXPECT2(1,FAILDIG);
hres = wconvert_str(L"1~", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,2,0,0); @@ -2355,11 +2351,8 @@ static void test_VarParseNumFromStrMisc(void) EXPECTRGB(2,FAILDIG);
hres = wconvert_str(L"1,2", ARRAY_SIZE(rgb), NUMPRS_DECIMAL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(2,NUMPRS_DECIMAL,NUMPRS_DECIMAL|NUMPRS_CURRENCY,3,0,-1); - todo_wine ok(np.dwOutFlags == (NUMPRS_DECIMAL|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); - EXPECTRGB(0,1); - todo_wine EXPECTRGB(1,2); + EXPECT2(1,2); EXPECTRGB(2,FAILDIG);
hres = wconvert_str(L"1.2", ARRAY_SIZE(rgb), NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); @@ -2368,11 +2361,8 @@ static void test_VarParseNumFromStrMisc(void) EXPECTRGB(2,FAILDIG);
hres = wconvert_str(L"1,2", ARRAY_SIZE(rgb), NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(2,NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_DECIMAL|NUMPRS_CURRENCY,3,0,-1); - todo_wine ok(np.dwOutFlags == (NUMPRS_DECIMAL|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); - EXPECTRGB(0,1); - todo_wine EXPECTRGB(1,2); + EXPECT2(1,2); EXPECTRGB(2,FAILDIG);
hres = wconvert_str(L"1.2,3", ARRAY_SIZE(rgb), NUMPRS_DECIMAL|NUMPRS_CURRENCY, &np, rgb, LOCALE_USER_DEFAULT, 0); @@ -2381,11 +2371,8 @@ static void test_VarParseNumFromStrMisc(void) EXPECTRGB(2,FAILDIG);
hres = wconvert_str(L"1,2.3", ARRAY_SIZE(rgb), NUMPRS_DECIMAL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(2,NUMPRS_DECIMAL,NUMPRS_DECIMAL|NUMPRS_CURRENCY,3,0,-1); - todo_wine ok(np.dwOutFlags == (NUMPRS_DECIMAL|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); - EXPECTRGB(0,1); - todo_wine EXPECTRGB(1,2); + EXPECT2(1,2); EXPECTRGB(2,FAILDIG);
@@ -2394,10 +2381,9 @@ static void test_VarParseNumFromStrMisc(void) */ SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONDECIMALSEP, L"$"); hres = wconvert_str(L"1$99", ARRAY_SIZE(rgb), NUMPRS_DECIMAL|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECT(3,NUMPRS_DECIMAL|NUMPRS_USE_ALL,NUMPRS_DECIMAL|NUMPRS_CURRENCY,4,0,-2); - EXPECTRGB(0,1); - todo_wine EXPECTRGB(1,9); - todo_wine EXPECTRGB(2,9); + EXPECT(3,NUMPRS_DECIMAL|NUMPRS_USE_ALL,NUMPRS_DECIMAL|NUMPRS_CURRENCY,4,0,-2); + EXPECT2(1,9); + EXPECTRGB(2,9); EXPECTRGB(3,FAILDIG);
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index fe4bdb41ed2..09c6f9dcad6 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -1523,7 +1523,7 @@ typedef struct tagVARIANT_NUMBER_CHARS /* Get the valid number characters for an lcid */ static void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags) { - static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',0,1,{'$',0},'.',',' }; + static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',0,1,{'$',0},0,',' }; LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE; WCHAR buff[4];
@@ -1630,7 +1630,31 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla /* First consume all the leading symbols and space from the string */ while (1) { - if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && iswspace(*lpszStr)) + if (pNumprs->dwInFlags & NUMPRS_DECIMAL && + (*lpszStr == chars.cDecimalPoint || + *lpszStr == chars.cCurrencyDecimalPoint)) + { + pNumprs->dwOutFlags |= NUMPRS_DECIMAL; + if (*lpszStr == chars.cCurrencyDecimalPoint && + chars.cDecimalPoint != chars.cCurrencyDecimalPoint) + pNumprs->dwOutFlags |= NUMPRS_CURRENCY; + cchUsed++; + lpszStr++; + + /* If we have no digits so far, skip leading zeros */ + if (!pNumprs->cDig) + { + while (lpszStr[1] == '0') + { + dwState |= B_LEADING_ZERO; + cchUsed++; + lpszStr++; + pNumprs->nPwr10--; + } + } + break; + } + else if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && iswspace(*lpszStr)) { pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE; do @@ -1673,8 +1697,6 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla pNumprs->dwOutFlags |= NUMPRS_CURRENCY; cchUsed += chars.sCurrencyLen; lpszStr += chars.sCurrencyLen; - /* Only accept currency characters */ - chars.cDecimalPoint = chars.cCurrencyDecimalPoint; } else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' && !(pNumprs->dwOutFlags & NUMPRS_PARENS)) @@ -1687,27 +1709,24 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla break; }
- if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY)) - { - /* Only accept non-currency characters */ - chars.cCurrencyDecimalPoint = chars.cDecimalPoint; - } - - if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && - pNumprs->dwInFlags & NUMPRS_HEX_OCT) + if (!(pNumprs->dwOutFlags & NUMPRS_DECIMAL)) { + if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { dwState |= B_PROCESSING_HEX; pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; cchUsed=cchUsed+2; lpszStr=lpszStr+2; - } - else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) && - pNumprs->dwInFlags & NUMPRS_HEX_OCT) - { + } + else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { dwState |= B_PROCESSING_OCT; pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; cchUsed=cchUsed+2; lpszStr=lpszStr+2; + } }
/* Strip Leading zeros */ @@ -1796,11 +1815,15 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla pNumprs->dwOutFlags |= NUMPRS_THOUSANDS|NUMPRS_CURRENCY; cchUsed++; } - else if (*lpszStr == chars.cDecimalPoint && - pNumprs->dwInFlags & NUMPRS_DECIMAL && - !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT))) + else if (pNumprs->dwInFlags & NUMPRS_DECIMAL && + (*lpszStr == chars.cDecimalPoint || + *lpszStr == chars.cCurrencyDecimalPoint) && + !(pNumprs->dwOutFlags & (NUMPRS_HEX_OCT|NUMPRS_DECIMAL|NUMPRS_EXPONENT))) { pNumprs->dwOutFlags |= NUMPRS_DECIMAL; + if (*lpszStr == chars.cCurrencyDecimalPoint && + chars.cDecimalPoint != chars.cCurrencyDecimalPoint) + pNumprs->dwOutFlags |= NUMPRS_CURRENCY; cchUsed++;
/* If we have no digits so far, skip leading zeros */