[PATCH 2/8] jscript: Implement Number.prototype.toLocaleString.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Fri Apr 15 08:00:22 CDT 2022
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at 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");
--
2.34.1
More information about the wine-devel
mailing list