Piotr Caban : jscript: Improve Number_toString implementation.

Alexandre Julliard julliard at winehq.org
Wed Jul 15 09:46:44 CDT 2009


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

Author: Piotr Caban <piotr.caban at gmail.com>
Date:   Wed Jul 15 12:51:21 2009 +0200

jscript: Improve Number_toString implementation.

---

 dlls/jscript/number.c     |  113 ++++++++++++++++++++++++++++++++++++++++++--
 dlls/jscript/tests/api.js |   50 +++++++++++++++++--
 2 files changed, 151 insertions(+), 12 deletions(-)

diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c
index d6591d0..5399c91 100644
--- a/dlls/jscript/number.c
+++ b/dlls/jscript/number.c
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <math.h>
+
 #include "jscript.h"
 
 #include "wine/debug.h"
@@ -39,11 +41,14 @@ static const WCHAR propertyIsEnumerableW[] =
     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
 
+#define NUMBER_TOSTRING_BUF_SIZE 64
 /* ECMA-262 3rd Edition    15.7.4.2 */
 static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
     NumberInstance *number;
+    INT radix = 10;
+    DOUBLE val;
     BSTR str;
     HRESULT hres;
 
@@ -56,14 +61,110 @@ static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPA
 
     number = (NumberInstance*)dispex;
 
-    if(arg_cnt(dp) != 0) {
-        FIXME("unsupported args\n");
-        return E_NOTIMPL;
+    if(arg_cnt(dp)) {
+        hres = to_int32(dispex->ctx, get_arg(dp, 0), ei, &radix);
+        if(FAILED(hres))
+            return hres;
+
+        if(radix<2 || radix>36) {
+            FIXME("throw TypeError\n");
+            return E_FAIL;
+        }
     }
 
-    hres = to_string(dispex->ctx, &number->num, ei, &str);
-    if(FAILED(hres))
-        return hres;
+    if(V_VT(&number->num) == VT_I4)
+        val = V_I4(&number->num);
+    else
+        val = V_R8(&number->num);
+
+    if(radix==10 || isnan(val) || isinf(val)) {
+        hres = to_string(dispex->ctx, &number->num, ei, &str);
+        if(FAILED(hres))
+            return hres;
+    }
+    else {
+        INT idx = 0;
+        DOUBLE integ, frac, log_radix = 0;
+        WCHAR buf[NUMBER_TOSTRING_BUF_SIZE+16];
+        BOOL exp = FALSE;
+
+        if(val<0) {
+            val = -val;
+            buf[idx++] = '-';
+        }
+
+        while(1) {
+            integ = floor(val);
+            frac = val-integ;
+
+            if(integ == 0)
+                buf[idx++] = '0';
+            while(integ>=1 && idx<NUMBER_TOSTRING_BUF_SIZE) {
+                buf[idx] = fmod(integ, radix);
+                if(buf[idx]<10) buf[idx] += '0';
+                else buf[idx] += 'a'-10;
+                integ /= radix;
+                idx++;
+            }
+
+            if(idx<NUMBER_TOSTRING_BUF_SIZE) {
+                INT beg = buf[0]=='-'?1:0;
+                INT end = idx-1;
+                WCHAR wch;
+
+                while(end > beg) {
+                    wch = buf[beg];
+                    buf[beg++] = buf[end];
+                    buf[end--] = wch;
+                }
+            }
+
+            if(idx != NUMBER_TOSTRING_BUF_SIZE) buf[idx++] = '.';
+
+            while(frac>0 && idx<NUMBER_TOSTRING_BUF_SIZE) {
+                frac *= radix;
+                buf[idx] = fmod(frac, radix);
+                frac -= buf[idx];
+                if(buf[idx]<10) buf[idx] += '0';
+                else buf[idx] += 'a'-10;
+                idx++;
+            }
+
+            if(idx==NUMBER_TOSTRING_BUF_SIZE && !exp) {
+                exp = TRUE;
+                idx = (buf[0]=='-') ? 1 : 0;
+                log_radix = floor(log(val)/log(radix));
+                val *= pow(radix, -log_radix);
+                continue;
+            }
+
+            break;
+        }
+
+        while(buf[idx-1] == '0') idx--;
+        if(buf[idx-1] == '.') idx--;
+
+        if(exp) {
+            if(log_radix==0)
+                buf[idx++] = '\0';
+            else {
+                static const WCHAR formatW[] = {'(','e','%','c','%','d',')',0};
+                WCHAR ch;
+
+                if(log_radix<0) {
+                    log_radix = -log_radix;
+                    ch = '-';
+                }
+                else ch = '+';
+                sprintfW(&buf[idx], formatW, ch, (int)log_radix);
+            }
+        }
+        else buf[idx] = '\0';
+
+        str = SysAllocString(buf);
+        if(!str)
+            return E_OUTOFMEMORY;
+    }
 
     if(retv) {
         V_VT(retv) = VT_BSTR;
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index f4dd74b..b347846 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -566,12 +566,50 @@ ok(tmp === 0, "(new Number()).valueOf = " + tmp);
 tmp = Number.prototype.valueOf();
 ok(tmp === 0, "Number.prototype.valueOf = " + tmp);
 
-num = new Number(NaN);
-ok(num.toString() === "NaN", "num.toString() = " + num.toString());
-num = new Number(-Infinity);
-ok(num.toString() === "-Infinity", "num.toString() = " + num.toString());
-num = new Number(Infinity);
-ok(num.toString() === "Infinity", "num.toString() = " + num.toString());
+function equals(val, base) {
+    var i;
+    var num = 0;
+    var str = val.toString(base);
+
+    for(i=0; i<str.length; i++) {
+        if(str.substring(i, i+1) == '(') break;
+        if(str.substring(i, i+1) == '.') break;
+        num = num*base + parseInt(str.substring(i, i+1));
+    }
+
+    if(str.substring(i, i+1) == '.') {
+        var mult = base;
+        for(i++; i<str.length; i++) {
+            if(str.substring(i, i+1) == '(') break;
+            num += parseInt(str.substring(i, i+1))/mult;
+            mult *= base;
+        }
+    }
+
+    if(str.substring(i, i+1) == '(') {
+        exp = parseInt(str.substring(i+2));
+        num *= Math.pow(base, exp);
+    }
+
+    ok(num>val-val/1000 && num<val+val/1000, "equals: num = " + num);
+}
+
+ok((10).toString(11) === "a", "(10).toString(11) = " + (10).toString(11));
+ok((213213433).toString(17) === "8e2ddcb", "(213213433).toString(17) = " + (213213433).toString(17));
+ok((-3254343).toString(33) === "-2oicf", "(-3254343).toString(33) = " + (-3254343).toString(33));
+ok((NaN).toString(12) === "NaN", "(NaN).toString(11) = " + (NaN).toString(11));
+ok((Infinity).toString(13) === "Infinity", "(Infinity).toString(11) = " + (Infinity).toString(11));
+for(i=2; i<10; i++) {
+    equals(1.123, i);
+    equals(2305843009200000000, i);
+    equals(5.123, i);
+    equals(1/(1024*1024*1024*1024*1024*1024*1.9), i);
+    equals(1024*1024*1024*1024*1024*1024*1.9999, i);
+    equals(0.0000000000000000001, i);
+    equals(0.6, i);
+    equals(4.65661287308e-10, i);
+    ok((0).toString(i) === "0", "(0).toString("+i+") = " + (0).toString(i));
+}
 
 tmp = Math.min(1);
 ok(tmp === 1, "Math.min(1) = " + tmp);




More information about the wine-cvs mailing list