Module: wine Branch: master Commit: 87c459ab2359784f238c30073b1adc0111876987 URL: http://source.winehq.org/git/wine.git/?a=commit;h=87c459ab2359784f238c30073b...
Author: Andrew Eikum aeikum@codeweavers.com Date: Tue Sep 17 13:01:45 2013 -0500
oleaut32: Implement VarDecRound.
---
dlls/oleaut32/tests/vartype.c | 35 +++++++++++++++++ dlls/oleaut32/vartype.c | 86 ++++++++++++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 23 deletions(-)
diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c index 4c823c6..e296e77 100644 --- a/dlls/oleaut32/tests/vartype.c +++ b/dlls/oleaut32/tests/vartype.c @@ -455,6 +455,7 @@ static HRESULT (WINAPI *pVarDecDiv)(const DECIMAL*,const DECIMAL*,DECIMAL*); static HRESULT (WINAPI *pVarDecCmp)(const DECIMAL*,const DECIMAL*); static HRESULT (WINAPI *pVarDecCmpR8)(const DECIMAL*,double); static HRESULT (WINAPI *pVarDecNeg)(const DECIMAL*,DECIMAL*); +static HRESULT (WINAPI *pVarDecRound)(const DECIMAL*,int,DECIMAL*);
static HRESULT (WINAPI *pVarBoolFromUI1)(BYTE,VARIANT_BOOL*); static HRESULT (WINAPI *pVarBoolFromI2)(SHORT,VARIANT_BOOL*); @@ -4545,6 +4546,39 @@ static void test_VarDecCmpR8(void) SETDEC(l,0,DECIMAL_NEG,-1,-1); r = DECIMAL_NEG; MATH3(VarDecCmpR8); EXPECT_LT; }
+#define CLEAR(x) memset(&(x), 0xBB, sizeof(x)) + +static void test_VarDecRound(void) +{ + HRESULT hres; + DECIMAL l, out; + + CHECKPTR(VarDecRound); + + CLEAR(out); SETDEC(l, 0, 0, 0, 1); hres = pVarDecRound(&l, 3, &out); EXPECTDEC(0, 0, 0, 1); + + CLEAR(out); SETDEC(l, 0, 0, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, 0, 0, 1); + CLEAR(out); SETDEC(l, 1, 0, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, 0, 0, 0); + CLEAR(out); SETDEC(l, 1, 0, 0, 1); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 1); + CLEAR(out); SETDEC(l, 2, 0, 0, 11); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 1); + CLEAR(out); SETDEC(l, 2, 0, 0, 15); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 2); + CLEAR(out); SETDEC(l, 6, 0, 0, 550001); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 6); + + CLEAR(out); SETDEC(l, 0, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 1, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, DECIMAL_NEG, 0, 0); + CLEAR(out); SETDEC(l, 1, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 2, DECIMAL_NEG, 0, 11); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 2, DECIMAL_NEG, 0, 15); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 2); + CLEAR(out); SETDEC(l, 6, DECIMAL_NEG, 0, 550001); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 6); + + CLEAR(out); SETDEC64(l, 0, 0, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, 0, 0xffffffff, 0xffffffff, 0xffffffff); + CLEAR(out); SETDEC64(l, 28, 0, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, 0, 0, 0, 8); + CLEAR(out); SETDEC64(l, 0, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); + CLEAR(out); SETDEC64(l, 28, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, DECIMAL_NEG, 0, 0, 8); + + CLEAR(out); SETDEC(l, 2, 0, 0, 0); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 0); +} + /* * VT_BOOL */ @@ -6334,6 +6368,7 @@ START_TEST(vartype) test_VarDecCmpR8(); test_VarDecMul(); test_VarDecDiv(); + test_VarDecRound();
test_VarBoolFromI1(); test_VarBoolFromUI1(); diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c index 74f66de..e1672a1 100644 --- a/dlls/oleaut32/vartype.c +++ b/dlls/oleaut32/vartype.c @@ -5137,7 +5137,7 @@ static int VARIANT_int_addlossy( in case of quotient overflow. */ static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor, - VARIANT_DI * quotient) + VARIANT_DI * quotient, BOOL round_remainder) { HRESULT r_overflow = S_OK;
@@ -5180,8 +5180,21 @@ static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * di underflow = VARIANT_int_addlossy( quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD), remainderplusquotient, &tempquotientscale, 4); - VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10); - memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD)); + if (round_remainder) { + if(remainderplusquotient[4] >= 5){ + unsigned int i; + unsigned char remainder = 1; + for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) { + ULONGLONG digit = quotient->bitsnum[i] + 1; + remainder = (digit > 0xFFFFFFFF) ? 1 : 0; + quotient->bitsnum[i] = digit & 0xFFFFFFFF; + } + } + memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); + } else { + VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10); + memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD)); + } tempquotientscale = ++remainderscale; } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
@@ -5485,31 +5498,16 @@ static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest) return hres; }
-/************************************************************************ - * VarDecDiv (OLEAUT32.178) - * - * Divide one DECIMAL by another. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] Value to divide by - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut, + BOOL round) { HRESULT hRet = S_OK; VARIANT_DI di_left, di_right, di_result; HRESULT divresult;
- if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG; - VARIANT_DIFromDec(pDecLeft, &di_left); VARIANT_DIFromDec(pDecRight, &di_right); - divresult = VARIANT_DI_div(&di_left, &di_right, &di_result); + divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round); if (divresult != S_OK) { /* division actually overflowed */ @@ -5557,6 +5555,27 @@ HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECI }
/************************************************************************ + * VarDecDiv (OLEAUT32.178) + * + * Divide one DECIMAL by another. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] Value to divide by + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +{ + if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG; + + return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE); +} + +/************************************************************************ * VarDecMul (OLEAUT32.179) * * Multiply one DECIMAL by another. @@ -5765,6 +5784,10 @@ HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) */ HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) { + DECIMAL divisor, tmp; + HRESULT hr; + unsigned int i; + if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) return E_INVALIDARG;
@@ -5774,9 +5797,26 @@ HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOu return S_OK; }
- FIXME("semi-stub!\n"); + /* truncate significant digits and rescale */ + memset(&divisor, 0, sizeof(divisor)); + DEC_LO64(&divisor) = 1;
- return DISP_E_OVERFLOW; + memset(&tmp, 0, sizeof(tmp)); + DEC_LO64(&tmp) = 10; + for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i) + { + hr = VarDecMul(&divisor, &tmp, &divisor); + if (FAILED(hr)) + return hr; + } + + hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE); + if (FAILED(hr)) + return hr; + + DEC_SCALE(pDecOut) = cDecimals; + + return S_OK; }
/************************************************************************