VarRound implementation #2
Fabian Cenedese
Cenedese at indel.ch
Wed Feb 25 02:07:09 CST 2004
Hi
Some bugs fixed. The DECIMAL part is still missing. Some tests in test_VarRound
are commented out as compares on floats are not reliable. But I left them in
in case there's a way to check the rounding results.
bye Fabi
Changelog:
Fabian Cenedese <Cenedese at indel.ch>
VarRound implementation (without type DECIMAL yet) with test function
Index: wine/dlls/oleaut32/oleaut32.spec
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/oleaut32.spec,v
retrieving revision 1.64
diff -u -r1.64 oleaut32.spec
--- wine/dlls/oleaut32/oleaut32.spec 21 Jan 2004 22:24:08 -0000 1.64
+++ wine/dlls/oleaut32/oleaut32.spec 25 Feb 2004 07:50:14 -0000
@@ -170,7 +170,7 @@
172 stdcall VarInt(ptr ptr)
173 stdcall VarNeg(ptr ptr)
174 stdcall VarNot(ptr ptr)
-175 stub VarRound # stdcall (ptr long ptr)
+175 stdcall VarRound(ptr long ptr)
176 stdcall VarCmp(ptr ptr long long)
177 stdcall VarDecAdd(ptr ptr ptr)
178 stdcall VarDecDiv(ptr ptr ptr)
Index: wine/dlls/oleaut32/variant.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/variant.c,v
retrieving revision 1.88
diff -u -r1.88 variant.c
--- wine/dlls/oleaut32/variant.c 25 Feb 2004 01:35:01 -0000 1.88
+++ wine/dlls/oleaut32/variant.c 25 Feb 2004 08:00:10 -0000
@@ -3436,6 +3436,135 @@
return hRet;
}
+
+/**********************************************************************
+ * VarRound [OLEAUT32.175]
+ *
+ * Perform a round operation on a variant.
+ *
+ * PARAMS
+ * pVarIn [I] Source variant
+ * deci [I] Number of decimals to round to
+ * pVarOut [O] Destination for converted value
+ *
+ * RETURNS
+ * Success: S_OK. pVarOut contains the converted value.
+ * Failure: An HRESULT error code indicating the error.
+ *
+ * NOTES
+ * - Floating point values are rounded to the desired number of decimals.
+ * - Some integer types are just copied to the return variable.
+ * - Some other integer types are not handled and fail.
+ */
+HRESULT WINAPI VarRound(LPVARIANT pVarIn, int deci, LPVARIANT pVarOut)
+{
+ VARIANT varIn;
+ HRESULT hRet = S_OK;
+ float factor;
+
+ TRACE("(%p->(%s%s),%d)\n", pVarIn, debugstr_VT(pVarIn), debugstr_VF(pVarIn), deci);
+
+ switch (V_VT(pVarIn))
+ {
+ /* cases that fail on windows */
+ case VT_I1:
+ case VT_I8:
+ case VT_UI2:
+ case VT_UI4:
+ hRet = DISP_E_BADVARTYPE;
+ break;
+
+ /* cases just copying in to out */
+ case VT_UI1:
+ V_VT(pVarOut) = V_VT(pVarIn);
+ V_UI1(pVarOut) = V_UI1(pVarIn);
+ break;
+ case VT_I2:
+ V_VT(pVarOut) = V_VT(pVarIn);
+ V_I2(pVarOut) = V_I2(pVarIn);
+ break;
+ case VT_I4:
+ V_VT(pVarOut) = V_VT(pVarIn);
+ V_I4(pVarOut) = V_I4(pVarIn);
+ break;
+ case VT_NULL:
+ V_VT(pVarOut) = V_VT(pVarIn);
+ /* value unchanged */
+ break;
+
+ /* cases that change type */
+ case VT_EMPTY:
+ V_VT(pVarOut) = VT_I2;
+ V_I2(pVarOut) = 0;
+ break;
+ case VT_BOOL:
+ V_VT(pVarOut) = VT_I2;
+ V_I2(pVarOut) = V_BOOL(pVarIn);
+ break;
+ case VT_BSTR:
+ hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn));
+ if (FAILED(hRet))
+ break;
+ V_VT(&varIn)=VT_R8;
+ pVarIn = &varIn;
+ /* Fall through ... */
+
+ /* cases we need to do math */
+ case VT_R8:
+ if (V_R8(pVarIn)>0) {
+ V_R8(pVarOut)=floor(V_R8(pVarIn)*pow(10, deci)+0.5)/pow(10, deci);
+ } else {
+ V_R8(pVarOut)=ceil(V_R8(pVarIn)*pow(10, deci)-0.5)/pow(10, deci);
+ }
+ V_VT(pVarOut) = V_VT(pVarIn);
+ break;
+ case VT_R4:
+ if (V_R4(pVarIn)>0) {
+ V_R4(pVarOut)=floor(V_R4(pVarIn)*pow(10, deci)+0.5)/pow(10, deci);
+ } else {
+ V_R4(pVarOut)=ceil(V_R4(pVarIn)*pow(10, deci)-0.5)/pow(10, deci);
+ }
+ V_VT(pVarOut) = V_VT(pVarIn);
+ break;
+ case VT_DATE:
+ if (V_DATE(pVarIn)>0) {
+ V_DATE(pVarOut)=floor(V_DATE(pVarIn)*pow(10, deci)+0.5)/pow(10, deci);
+ } else {
+ V_DATE(pVarOut)=ceil(V_DATE(pVarIn)*pow(10, deci)-0.5)/pow(10, deci);
+ }
+ V_VT(pVarOut) = V_VT(pVarIn);
+ break;
+ case VT_CY:
+ if (deci>3)
+ factor=1;
+ else
+ factor=pow(10, 4-deci);
+
+ if (V_CY(pVarIn).int64>0) {
+ V_CY(pVarOut).int64=floor(V_CY(pVarIn).int64/factor)*factor;
+ } else {
+ V_CY(pVarOut).int64=ceil(V_CY(pVarIn).int64/factor)*factor;
+ }
+ V_VT(pVarOut) = V_VT(pVarIn);
+ break;
+
+ /* cases we don't know yet */
+ default:
+ FIXME("unimplemented part, V_VT(pVarIn) == 0x%X, deci == %d\n",
+ V_VT(pVarIn) & VT_TYPEMASK, deci);
+ hRet = DISP_E_BADVARTYPE;
+ }
+
+ if (FAILED(hRet))
+ V_VT(pVarOut) = VT_EMPTY;
+
+ TRACE("returning 0x%08lx (%s%s),%f\n", hRet, debugstr_VT(pVarOut),
+ debugstr_VF(pVarOut), (V_VT(pVarOut) == VT_R4) ? V_R4(pVarOut) :
+ (V_VT(pVarOut) == VT_R8) ? V_R8(pVarOut) : 0);
+
+ return hRet;
+}
+
/**********************************************************************
* VarMod [OLEAUT32.154]
Index: wine/dlls/oleaut32/tests/vartest.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/tests/vartest.c,v
retrieving revision 1.23
diff -u -r1.23 vartest.c
--- wine/dlls/oleaut32/tests/vartest.c 6 Feb 2004 05:23:48 -0000 1.23
+++ wine/dlls/oleaut32/tests/vartest.c 25 Feb 2004 08:00:13 -0000
@@ -2548,6 +2548,129 @@
"VarNeg: VT_CY wrong, hres=0x%lX\n", hres);
}
+static HRESULT (WINAPI *pVarRound)(LPVARIANT,int,LPVARIANT);
+
+#define VARROUND(vt,val,deci,rvt,rval) V_VT(&v) = VT_##vt; V_##vt(&v) = val; \
+ memset(&vDst,0,sizeof(vDst)); hres = pVarRound(&v,deci,&vDst); \
+ ok(hres == S_OK && V_VT(&vDst) == VT_##rvt && V_##rvt(&vDst) == (rval), \
+ "VarRound: expected 0x0,%d,%d, got 0x%lX,%d,%d\n", VT_##rvt, (int)(rval), \
+ hres, V_VT(&vDst), (int)V_##rvt(&vDst))
+
+#define VARROUNDF(vt,val,deci,rvt,rval) V_VT(&v) = VT_##vt; V_##vt(&v) = val; \
+ memset(&vDst,0,sizeof(vDst)); hres = pVarRound(&v,deci,&vDst); \
+ ok(hres == S_OK && V_VT(&vDst) == VT_##rvt && V_##rvt(&vDst) == (rval), \
+ "VarRound: expected 0x0,%d,%f, got 0x%lX,%d,%f\n", VT_##rvt, rval, \
+ hres, V_VT(&vDst), V_##rvt(&vDst))
+
+static void test_VarRound(void)
+{
+ static const WCHAR szNumMin[] = {'-','1','.','4','5','\0' };
+ static const WCHAR szNum[] = {'1','.','4','5','\0' };
+ HRESULT hres;
+ VARIANT v, vDst;
+ DECIMAL *pdec = &V_DECIMAL(&v);
+ CY *pcy = &V_CY(&v);
+
+ CHECKPTR(VarRound);
+
+ /* first check valid integer types */
+ VARROUND(BOOL,VARIANT_TRUE,0,I2,-1);
+ VARROUND(BOOL,VARIANT_FALSE,0,I2,0);
+ VARROUND(BOOL,1,0,I2,1);
+ VARROUND(UI1,1,0,UI1,1);
+ VARROUND(UI1,254,0,UI1,254);
+ VARROUND(I2,-32768,0,I2,-32768);
+ VARROUND(I2,-1,0,I2,-1);
+ VARROUND(I2,1,0,I2,1);
+ VARROUND(I4,-((int)(~0u >> 1)) - 1,0,I4,-((int)(~0u >> 1)) - 1);
+ VARROUND(I4,-1,0,I4,-1);
+ VARROUND(I4,1,0,I4,1);
+
+
+ /* MSDN states that rounding of R4/R8 is dependent on the underlying
+ * bit pattern of the number and so is architecture dependent. In this
+ * case Wine returns .2 (which is more correct) and Native returns .3
+ */
+
+ VARROUNDF(R4,1.0,0,R4,1.0);
+ VARROUNDF(R4,-1.0,0,R4,-1.0);
+ VARROUNDF(R8,1.0,0,R8,1.0);
+ VARROUNDF(R8,-1.0,0,R8,-1.0);
+
+ /* floating point numbers aren't exactly equal and we can't just
+ * compare the first few digits.
+ todo_wine {
+ VARROUNDF(DATE,1.451,1,DATE,1.5);
+ VARROUNDF(DATE,-1.45,1,DATE,-1.4);
+ VARROUNDF(BSTR,(BSTR)szNumMin,1,R8,-1.40);
+ VARROUNDF(BSTR,(BSTR)szNum,1,R8,1.50);
+
+ VARROUNDF(R4,1.23456,0,R4,1.0);
+ VARROUNDF(R4,1.23456,1,R4,1.2);
+ VARROUNDF(R4,1.23456,2,R4,1.23);
+ VARROUNDF(R4,1.23456,3,R4,1.235);
+ VARROUNDF(R4,1.23456,4,R4,1.2346);
+ VARROUNDF(R4,-1.23456,0,R4,-1.0);
+ VARROUNDF(R4,-1.23456,1,R4,-1.2);
+ VARROUNDF(R4,-1.23456,2,R4,-1.23);
+ VARROUNDF(R4,-1.23456,3,R4,-1.235);
+ VARROUNDF(R4,-1.23456,4,R4,-1.2346);
+
+ VARROUNDF(R8,1.23456,0,R8,1.0);
+ VARROUNDF(R8,1.23456,1,R8,1.2);
+ VARROUNDF(R8,1.23456,2,R8,1.23);
+ VARROUNDF(R8,1.23456,3,R8,1.235);
+ VARROUNDF(R8,1.23456,4,R8,1.2346);
+ VARROUNDF(R8,-1.23456,0,R8,-1.0);
+ VARROUNDF(R8,-1.23456,1,R8,-1.2);
+ VARROUNDF(R8,-1.23456,2,R8,-1.23);
+ VARROUNDF(R8,-1.23456,3,R8,-1.235);
+ VARROUNDF(R8,-1.23456,4,R8,-1.2346);
+ }
+ */
+
+ V_VT(&v) = VT_EMPTY;
+ hres = pVarRound(&v,0,&vDst);
+ ok(hres == S_OK && V_VT(&vDst) == VT_I2 && V_I2(&vDst) == 0,
+ "VarRound: expected 0x0,%d,0 got 0x%lX,%d,%d\n", VT_EMPTY,
+ hres, V_VT(&vDst), V_I2(&vDst));
+
+ V_VT(&v) = VT_NULL;
+ hres = pVarRound(&v,0,&vDst);
+ ok(hres == S_OK && V_VT(&vDst) == VT_NULL,
+ "VarRound: expected 0x0,%d got 0x%lX,%d\n", VT_NULL, hres, V_VT(&vDst));
+
+ /* not yet implemented so no use testing yet
+ todo_wine {
+ V_VT(&v) = VT_DECIMAL;
+ pdec->u.s.sign = DECIMAL_NEG;
+ pdec->u.s.scale = 0;
+ pdec->Hi32 = 0;
+ pdec->u1.s1.Mid32 = 0;
+ pdec->u1.s1.Lo32 = 1;
+ hres = pVarRound(&v,0,&vDst);
+ ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
+ V_DECIMAL(&vDst).u.s.sign == 0,
+ "VarRound: expected 0x0,%d,0x00, got 0x%lX,%d,%02x\n", VT_DECIMAL,
+ hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+
+ pdec->u.s.sign = 0;
+ hres = pVarRound(&v,0,&vDst);
+ ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
+ V_DECIMAL(&vDst).u.s.sign == DECIMAL_NEG,
+ "VarRound: expected 0x0,%d,0x7f, got 0x%lX,%d,%02x\n", VT_DECIMAL,
+ hres, V_VT(&vDst), V_DECIMAL(&vDst).u.s.sign);
+ }
+ */
+
+ V_VT(&v) = VT_CY;
+ pcy->int64 = 10000;
+ hres = pVarRound(&v,0,&vDst);
+ ok(hres == S_OK && V_VT(&vDst) == VT_CY && V_CY(&vDst).int64 == 10000,
+ "VarRound: VT_CY wrong, hres=0x%lX\n", hres);
+
+}
+
START_TEST(vartest)
{
hOleaut32 = LoadLibraryA("oleaut32.dll");
@@ -2573,4 +2696,5 @@
test_VarFix();
test_VarInt();
test_VarNeg();
+ test_VarRound();
}
More information about the wine-patches
mailing list