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