Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tests are basic because it depends on the user's locale, but observations have been noted in comments.
dlls/jscript/number.c | 77 ++++++++++++++++++++++++++++++++++++++- dlls/jscript/tests/api.js | 7 ++++ 2 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index be733fb..c487f10 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -17,6 +17,7 @@ */
#include <math.h> +#include <locale.h> #include <assert.h>
#include "jscript.h" @@ -344,8 +345,80 @@ static HRESULT Number_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns static HRESULT Number_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("\n"); - return E_NOTIMPL; + WCHAR buf[314], *numstr, *p, *frac = NULL; + BOOL remove_fraction = FALSE; + jsstr_t *str, *tmp; + _locale_t locale; + unsigned convlen; + HRESULT hres; + DOUBLE val; + int len; + + TRACE("\n"); + + hres = numberval_this(vthis, &val); + if(FAILED(hres)) + return hres; + + if(!r) + return S_OK; + + /* FIXME: Localize this? */ + if(!isfinite(val)) { + hres = to_string(ctx, jsval_number(val), &str); + if(FAILED(hres)) + return hres; + goto done; + } + + /* Native never uses an exponent, even if the number is very large, it will in fact + return all the digits (with thousands separators). jscript.dll uses two digits for + fraction even if they are zero (likely default numDigits) and always returns them, + while mshtml's jscript only if they are non-zero (on same locale settings); this + applies even for very small numbers, such as 0.0000999, which will simply be 0 */ + if(!(locale = _create_locale(LC_ALL, "C"))) + return E_OUTOFMEMORY; + len = _swprintf_l(buf, ARRAY_SIZE(buf), L"%.2f", locale, val); + _free_locale(locale); + + if(!(convlen = GetNumberFormatW(ctx->lcid, 0, buf, NULL, NULL, 0)) || + !(str = jsstr_alloc_buf(convlen - 1, &numstr))) + return E_OUTOFMEMORY; + + if(!GetNumberFormatW(ctx->lcid, 0, buf, NULL, numstr, convlen)) { + jsstr_release(str); + return E_OUTOFMEMORY; + } + + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + while(len--) { + if(buf[len] != '0') { + if(buf[len] == '.') + remove_fraction = TRUE; + break; + } + } + } + + if(remove_fraction && GetLocaleInfoW(ctx->lcid, LOCALE_SDECIMAL, buf, ARRAY_SIZE(buf))) { + p = numstr; + while(*p) { + if(!(p = wcsstr(p, buf))) + break; + frac = p++; + } + if(frac) { + tmp = jsstr_alloc_len(numstr, frac - numstr); + jsstr_release(str); + if(!tmp) + return E_OUTOFMEMORY; + str = tmp; + } + } + +done: + *r = jsval_string(str); + return S_OK; }
static HRESULT Number_toFixed(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 1efc023..8653946 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -1365,6 +1365,11 @@ ok(tmp === "0", "num().toString = " + tmp); tmp = (new Number(5.5)).toString(2); ok(tmp === "101.1", "num(5.5).toString(2) = " + tmp);
+tmp = (new Number(12)).toLocaleString(); +ok(tmp.indexOf(String.fromCharCode(0)) == -1, "invalid null byte"); +tmp = Number.prototype.toLocaleString.call(NaN); +ok(tmp.indexOf(String.fromCharCode(0)) == -1, "invalid null byte"); + tmp = (new Number(3)).toFixed(3); ok(tmp === "3.000", "num(3).toFixed(3) = " + tmp); tmp = (new Number(3)).toFixed(); @@ -2594,6 +2599,8 @@ testException(function() {arr.test();}, "E_NO_PROPERTY"); testException(function() {[1,2,3].sort(nullDisp);}, "E_JSCRIPT_EXPECTED"); testException(function() {Number.prototype.toString.call(arr);}, "E_NOT_NUM"); testException(function() {Number.prototype.toFixed.call(arr);}, "E_NOT_NUM"); +testException(function() {Number.prototype.toLocaleString.call(arr);}, "E_NOT_NUM"); +testException(function() {Number.prototype.toLocaleString.call(null);}, "E_NOT_NUM"); testException(function() {(new Number(3)).toString(1);}, "E_INVALID_CALL_ARG"); testException(function() {(new Number(3)).toFixed(21);}, "E_FRACTION_DIGITS_OUT_OF_RANGE"); testException(function() {(new Number(1)).toPrecision(0);}, "E_PRECISION_OUT_OF_RANGE");