Andrew Eikum : oleaut32: Implement VarDecRound.

Alexandre Julliard julliard at winehq.org
Wed Sep 18 15:49:59 CDT 2013


Module: wine
Branch: master
Commit: 87c459ab2359784f238c30073b1adc0111876987
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=87c459ab2359784f238c30073b1adc0111876987

Author: Andrew Eikum <aeikum at 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, &quotientscale, 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;
 }
 
 /************************************************************************




More information about the wine-cvs mailing list