Code

fix 1243587 and misc fixes
[inkscape.git] / src / dom / js / jsnum.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *   IBM Corp.
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
41 /*
42  * JS number type and wrapper class.
43  */
44 #include "jsstddef.h"
45 #if defined(XP_WIN) || defined(XP_OS2)
46 #include <float.h>
47 #endif
48 #include <locale.h>
49 #include <limits.h>
50 #include <math.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "jstypes.h"
54 #include "jsutil.h" /* Added by JSIFY */
55 #include "jsapi.h"
56 #include "jsatom.h"
57 #include "jscntxt.h"
58 #include "jsconfig.h"
59 #include "jsdtoa.h"
60 #include "jsgc.h"
61 #include "jsinterp.h"
62 #include "jsnum.h"
63 #include "jsobj.h"
64 #include "jsopcode.h"
65 #include "jsprf.h"
66 #include "jsstr.h"
68 static JSBool
69 num_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
70 {
71     jsdouble x;
73     if (!js_ValueToNumber(cx, argv[0], &x))
74         return JS_FALSE;
75     *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
76     return JS_TRUE;
77 }
79 static JSBool
80 num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
81 {
82     jsdouble x;
84     if (!js_ValueToNumber(cx, argv[0], &x))
85         return JS_FALSE;
86     *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
87     return JS_TRUE;
88 }
90 static JSBool
91 num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
92 {
93     JSString *str;
94     jsdouble d;
95     const jschar *bp, *ep;
97     str = js_ValueToString(cx, argv[0]);
98     if (!str)
99         return JS_FALSE;
100     /* XXXbe js_strtod shouldn't require NUL termination */
101     bp = js_UndependString(cx, str);
102     if (!bp)
103         return JS_FALSE;
104     if (!js_strtod(cx, bp, &ep, &d))
105         return JS_FALSE;
106     if (ep == bp) {
107         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
108         return JS_TRUE;
109     }
110     return js_NewNumberValue(cx, d, rval);
113 /* See ECMA 15.1.2.2. */
114 static JSBool
115 num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
117     jsint radix;
118     JSString *str;
119     jsdouble d;
120     const jschar *bp, *ep;
122     if (argc > 1) {
123         if (!js_ValueToECMAInt32(cx, argv[1], &radix))
124             return JS_FALSE;
125     } else {
126         radix = 0;
127     }
128     if (radix != 0 && (radix < 2 || radix > 36)) {
129         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
130         return JS_TRUE;
131     }
133     str = js_ValueToString(cx, argv[0]);
134     if (!str)
135         return JS_FALSE;
136     /* XXXbe js_strtointeger shouldn't require NUL termination */
137     bp = js_UndependString(cx, str);
138     if (!bp)
139         return JS_FALSE;
140     if (!js_strtointeger(cx, bp, &ep, radix, &d))
141         return JS_FALSE;
142     if (ep == bp) {
143         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
144         return JS_TRUE;
145     }
146     return js_NewNumberValue(cx, d, rval);
149 const char js_Infinity_str[]   = "Infinity";
150 const char js_NaN_str[]        = "NaN";
151 const char js_isNaN_str[]      = "isNaN";
152 const char js_isFinite_str[]   = "isFinite";
153 const char js_parseFloat_str[] = "parseFloat";
154 const char js_parseInt_str[]   = "parseInt";
156 static JSFunctionSpec number_functions[] = {
157     {"isNaN",           num_isNaN,              1,0,0},
158     {"isFinite",        num_isFinite,           1,0,0},
159     {"parseFloat",      num_parseFloat,         1,0,0},
160     {"parseInt",        num_parseInt,           2,0,0},
161     {0,0,0,0,0}
162 };
164 JSClass js_NumberClass = {
165     "Number",
166     JSCLASS_HAS_PRIVATE,
167     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
168     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
169     JSCLASS_NO_OPTIONAL_MEMBERS
170 };
172 static JSBool
173 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
175     jsdouble d;
176     jsval v;
178     if (argc != 0) {
179         if (!js_ValueToNumber(cx, argv[0], &d))
180             return JS_FALSE;
181     } else {
182         d = 0.0;
183     }
184     if (!js_NewNumberValue(cx, d, &v))
185         return JS_FALSE;
186     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
187         *rval = v;
188         return JS_TRUE;
189     }
190     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
191     return JS_TRUE;
194 #if JS_HAS_TOSOURCE
195 static JSBool
196 num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
198     jsval v;
199     jsdouble d;
200     char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
201     char buf[64];
202     JSString *str;
204     if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv))
205         return JS_FALSE;
206     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
207     JS_ASSERT(JSVAL_IS_NUMBER(v));
208     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
209     numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
210     if (!numStr) {
211         JS_ReportOutOfMemory(cx);
212         return JS_FALSE;
213     }
214     JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
215     str = JS_NewStringCopyZ(cx, buf);
216     if (!str)
217         return JS_FALSE;
218     *rval = STRING_TO_JSVAL(str);
219     return JS_TRUE;
221 #endif
223 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
224 static char *
225 IntToString(jsint i, char *buf, size_t bufSize)
227     char *cp;
228     jsuint u;
230     u = (i < 0) ? -i : i;
232     cp = buf + bufSize; /* one past last buffer cell */
233     *--cp = '\0';       /* null terminate the string to be */
235     /*
236      * Build the string from behind. We use multiply and subtraction
237      * instead of modulus because that's much faster.
238      */
239     do {
240         jsuint newu = u / 10;
241         *--cp = (char)(u - newu * 10) + '0';
242         u = newu;
243     } while (u != 0);
245     if (i < 0)
246         *--cp = '-';
248     return cp;
251 static JSBool
252 num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
254     jsval v;
255     jsdouble d;
256     jsint base;
257     JSString *str;
259     if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv))
260         return JS_FALSE;
261     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
262     JS_ASSERT(JSVAL_IS_NUMBER(v));
263     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
264     base = 10;
265     if (argc != 0) {
266         if (!js_ValueToECMAInt32(cx, argv[0], &base))
267             return JS_FALSE;
268         if (base < 2 || base > 36) {
269             char numBuf[12];
270             char *numStr = IntToString(base, numBuf, sizeof numBuf);
271             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
272                                  numStr);
273             return JS_FALSE;
274         }
275     }
276     if (base == 10)
277         str = js_NumberToString(cx, d);
278     else {
279         char *dStr = JS_dtobasestr(base, d);
280         if (!dStr) {
281             JS_ReportOutOfMemory(cx);
282             return JS_FALSE;
283         }
284         str = JS_NewStringCopyZ(cx, dStr);
285         free(dStr);
286     }
287     if (!str)
288         return JS_FALSE;
289     *rval = STRING_TO_JSVAL(str);
290     return JS_TRUE;
293 static JSBool
294 num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
295                    jsval *argv, jsval *rval)
297     char thousandsLength, decimalLength;
298     const char *numGrouping, *tmpGroup;
299     JSRuntime *rt;
300     JSString *numStr, *str;
301     char *num, *buf, *dec, *end, *tmpSrc, *tmpDest;
302     int digits, size, remainder, nrepeat;
304     /*
305      * Create the string, move back to bytes to make string twiddling
306      * a bit easier and so we can insert platform charset seperators.
307      */
308     if (!num_toString(cx, obj, 0, argv, rval))
309         return JS_FALSE;
310     JS_ASSERT(JSVAL_IS_STRING(*rval));
311     numStr = JSVAL_TO_STRING(*rval);
312     num = js_GetStringBytes(numStr);
314     /* Find bit before the decimal. */
315     dec = strchr(num, '.');
316     digits = dec ? dec - num : (int)strlen(num);
317     end = num + digits;
319     rt = cx->runtime;
320     thousandsLength = strlen(rt->thousandsSeparator);
321     decimalLength = strlen(rt->decimalSeparator);
323     /* Figure out how long resulting string will be. */
324     size = digits + (dec ? decimalLength + strlen(dec + 1) : 0);
326     numGrouping = tmpGroup = rt->numGrouping;
327     remainder = digits;
328     if (*num == '-')
329         remainder--;
331     while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
332         if (*tmpGroup >= remainder)
333             break;
334         size += thousandsLength;
335         remainder -= *tmpGroup;
336         tmpGroup++;
337     }
338     if (*tmpGroup == '\0' && *numGrouping != '\0') {
339         nrepeat = (remainder - 1) / tmpGroup[-1];
340         size += thousandsLength * nrepeat;
341         remainder -= nrepeat * tmpGroup[-1];
342     } else {
343         nrepeat = 0;
344     }
345     tmpGroup--;
347     buf = (char *)JS_malloc(cx, size + 1);
348     if (!buf)
349         return JS_FALSE;
351     tmpDest = buf;
352     tmpSrc = num;
354     while (*tmpSrc == '-' || remainder--)
355         *tmpDest++ = *tmpSrc++;
356     while (tmpSrc < end) {
357         strcpy(tmpDest, rt->thousandsSeparator);
358         tmpDest += thousandsLength;
359         memcpy(tmpDest, tmpSrc, *tmpGroup);
360         tmpDest += *tmpGroup;
361         tmpSrc += *tmpGroup;
362         if (--nrepeat < 0)
363             tmpGroup--;
364     }
366     if (dec) {
367         strcpy(tmpDest, rt->decimalSeparator);
368         tmpDest += decimalLength;
369         strcpy(tmpDest, dec + 1);
370     } else {
371         *tmpDest++ = '\0';
372     }
374     str = JS_NewString(cx, buf, size);
375     if (!str) {
376         JS_free(cx, buf);
377         return JS_FALSE;
378     }
380     *rval = STRING_TO_JSVAL(str);
382     return JS_TRUE;
385 static JSBool
386 num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
388     if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv))
389         return JS_FALSE;
390     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
391     return JS_TRUE;
395 #if JS_HAS_NUMBER_FORMATS
396 #define MAX_PRECISION 100
398 static JSBool
399 num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode,
400        JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset)
402     jsval v;
403     jsdouble d, precision;
404     JSString *str;
405     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
407     if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv))
408         return JS_FALSE;
409     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
410     JS_ASSERT(JSVAL_IS_NUMBER(v));
411     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
413     if (JSVAL_IS_VOID(argv[0])) {
414         precision = 0.0;
415         oneArgMode = zeroArgMode;
416     } else {
417         if (!js_ValueToNumber(cx, argv[0], &precision))
418             return JS_FALSE;
419         precision = js_DoubleToInteger(precision);
420         if (precision < precisionMin || precision > precisionMax) {
421             numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
422             if (!numStr)
423                 JS_ReportOutOfMemory(cx);
424             else
425                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
426             return JS_FALSE;
427         }
428     }
430     numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
431     if (!numStr) {
432         JS_ReportOutOfMemory(cx);
433         return JS_FALSE;
434     }
435     str = JS_NewStringCopyZ(cx, numStr);
436     if (!str)
437         return JS_FALSE;
438     *rval = STRING_TO_JSVAL(str);
439     return JS_TRUE;
442 static JSBool
443 num_toFixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
445     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
446     return num_to(cx, obj, argc, argv, rval, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0);
449 static JSBool
450 num_toExponential(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
452     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
453     return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1);
456 static JSBool
457 num_toPrecision(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
459     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
460     return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0);
462 #endif /* JS_HAS_NUMBER_FORMATS */
465 static JSFunctionSpec number_methods[] = {
466 #if JS_HAS_TOSOURCE
467     {js_toSource_str,       num_toSource,       0,0,0},
468 #endif
469     {js_toString_str,       num_toString,       0,0,0},
470     {js_toLocaleString_str, num_toLocaleString, 0,0,0},
471     {js_valueOf_str,        num_valueOf,        0,0,0},
472 #if JS_HAS_NUMBER_FORMATS
473     {"toFixed",             num_toFixed,        1,0,0},
474     {"toExponential",       num_toExponential,  1,0,0},
475     {"toPrecision",         num_toPrecision,    1,0,0},
476 #endif
477     {0,0,0,0,0}
478 };
480 /* NB: Keep this in synch with number_constants[]. */
481 enum nc_slot {
482     NC_NaN,
483     NC_POSITIVE_INFINITY,
484     NC_NEGATIVE_INFINITY,
485     NC_MAX_VALUE,
486     NC_MIN_VALUE,
487     NC_LIMIT
488 };
490 /*
491  * Some to most C compilers forbid spelling these at compile time, or barf
492  * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
493  * using union jsdpun.
494  */
495 static JSConstDoubleSpec number_constants[] = {
496     {0,                         js_NaN_str,          0,{0,0,0}},
497     {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
498     {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
499     {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
500     {0,                         "MIN_VALUE",         0,{0,0,0}},
501     {0,0,0,{0,0,0}}
502 };
504 static jsdouble NaN;
507 #if (defined XP_WIN || defined XP_OS2) &&                                     \
508     !defined WINCE &&                                                         \
509     !defined __MWERKS__ &&                                                    \
510     (defined _M_IX86 ||                                                       \
511      (defined __GNUC__ && !defined __MINGW32__))
513 /*
514  * Set the exception mask to mask all exceptions and set the FPU precision
515  * to 53 bit mantissa.
516  * On Alpha platform this is handled via Compiler option.
517  */
518 #define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
520 #else
522 #define FIX_FPU() ((void)0)
524 #endif
526 JSBool
527 js_InitRuntimeNumberState(JSContext *cx)
529     JSRuntime *rt;
530     jsdpun u;
531     struct lconv *locale;
533     rt = cx->runtime;
534     JS_ASSERT(!rt->jsNaN);
536     FIX_FPU();
538     u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
539     u.s.lo = 0xffffffff;
540     number_constants[NC_NaN].dval = NaN = u.d;
541     rt->jsNaN = js_NewDouble(cx, NaN, GCF_LOCK);
542     if (!rt->jsNaN)
543         return JS_FALSE;
545     u.s.hi = JSDOUBLE_HI32_EXPMASK;
546     u.s.lo = 0x00000000;
547     number_constants[NC_POSITIVE_INFINITY].dval = u.d;
548     rt->jsPositiveInfinity = js_NewDouble(cx, u.d, GCF_LOCK);
549     if (!rt->jsPositiveInfinity)
550         return JS_FALSE;
552     u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
553     u.s.lo = 0x00000000;
554     number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
555     rt->jsNegativeInfinity = js_NewDouble(cx, u.d, GCF_LOCK);
556     if (!rt->jsNegativeInfinity)
557         return JS_FALSE;
559     u.s.hi = 0;
560     u.s.lo = 1;
561     number_constants[NC_MIN_VALUE].dval = u.d;
563     locale = localeconv();
564     rt->thousandsSeparator =
565         JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'");
566     rt->decimalSeparator =
567         JS_strdup(cx, locale->decimal_point ? locale->decimal_point : ".");
568     rt->numGrouping =
569         JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0");
571     return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
574 void
575 js_FinishRuntimeNumberState(JSContext *cx)
577     JSRuntime *rt = cx->runtime;
579     js_UnlockGCThingRT(rt, rt->jsNaN);
580     js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
581     js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
583     rt->jsNaN = NULL;
584     rt->jsNegativeInfinity = NULL;
585     rt->jsPositiveInfinity = NULL;
587     JS_free(cx, (void *)rt->thousandsSeparator);
588     JS_free(cx, (void *)rt->decimalSeparator);
589     JS_free(cx, (void *)rt->numGrouping);
590     rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
593 JSObject *
594 js_InitNumberClass(JSContext *cx, JSObject *obj)
596     JSObject *proto, *ctor;
597     JSRuntime *rt;
599     /* XXX must do at least once per new thread, so do it per JSContext... */
600     FIX_FPU();
602     if (!JS_DefineFunctions(cx, obj, number_functions))
603         return NULL;
605     proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
606                          NULL, number_methods, NULL, NULL);
607     if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
608         return NULL;
609     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_ZERO);
610     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
611         return NULL;
613     /* ECMA 15.1.1.1 */
614     rt = cx->runtime;
615     if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
616                            NULL, NULL, JSPROP_PERMANENT)) {
617         return NULL;
618     }
620     /* ECMA 15.1.1.2 */
621     if (!JS_DefineProperty(cx, obj, js_Infinity_str,
622                            DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
623                            NULL, NULL, JSPROP_PERMANENT)) {
624         return NULL;
625     }
626     return proto;
629 jsdouble *
630 js_NewDouble(JSContext *cx, jsdouble d, uintN gcflag)
632     jsdouble *dp;
634     dp = (jsdouble *) js_NewGCThing(cx, gcflag | GCX_DOUBLE, sizeof(jsdouble));
635     if (!dp)
636         return NULL;
637     *dp = d;
638     return dp;
641 void
642 js_FinalizeDouble(JSContext *cx, jsdouble *dp)
644     *dp = NaN;
647 JSBool
648 js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
650     jsdouble *dp;
652     dp = js_NewDouble(cx, d, 0);
653     if (!dp)
654         return JS_FALSE;
655     *rval = DOUBLE_TO_JSVAL(dp);
656     return JS_TRUE;
659 JSBool
660 js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
662     jsint i;
664     if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
665         *rval = INT_TO_JSVAL(i);
666     } else {
667         if (!js_NewDoubleValue(cx, d, rval))
668             return JS_FALSE;
669     }
670     return JS_TRUE;
673 JSObject *
674 js_NumberToObject(JSContext *cx, jsdouble d)
676     JSObject *obj;
677     jsval v;
679     obj = js_NewObject(cx, &js_NumberClass, NULL, NULL);
680     if (!obj)
681         return NULL;
682     if (!js_NewNumberValue(cx, d, &v)) {
683         cx->newborn[GCX_OBJECT] = NULL;
684         return NULL;
685     }
686     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
687     return obj;
690 JSString *
691 js_NumberToString(JSContext *cx, jsdouble d)
693     jsint i;
694     char buf[DTOSTR_STANDARD_BUFFER_SIZE];
695     char *numStr;
697     if (JSDOUBLE_IS_INT(d, i))
698         numStr = IntToString(i, buf, sizeof buf);
699     else {
700         numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
701         if (!numStr) {
702             JS_ReportOutOfMemory(cx);
703             return NULL;
704         }
705     }
706     return JS_NewStringCopyZ(cx, numStr);
709 JSBool
710 js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
712     JSObject *obj;
713     JSString *str;
714     const jschar *bp, *ep;
716     if (JSVAL_IS_OBJECT(v)) {
717         obj = JSVAL_TO_OBJECT(v);
718         if (!obj) {
719             *dp = 0;
720             return JS_TRUE;
721         }
722         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
723             return JS_FALSE;
724     }
725     if (JSVAL_IS_INT(v)) {
726         *dp = (jsdouble)JSVAL_TO_INT(v);
727     } else if (JSVAL_IS_DOUBLE(v)) {
728         *dp = *JSVAL_TO_DOUBLE(v);
729     } else if (JSVAL_IS_STRING(v)) {
730         str = JSVAL_TO_STRING(v);
731         /*
732          * Note that ECMA doesn't treat a string beginning with a '0' as an
733          * octal number here.  This works because all such numbers will be
734          * interpreted as decimal by js_strtod and will never get passed to
735          * js_strtointeger (which would interpret them as octal).
736          */
737         /* XXXbe js_strtod shouldn't require NUL termination */
738         bp = js_UndependString(cx, str);
739         if (!bp)
740             return JS_FALSE;
741         if ((!js_strtod(cx, bp, &ep, dp) ||
742              js_SkipWhiteSpace(ep) != bp + str->length) &&
743             (!js_strtointeger(cx, bp, &ep, 0, dp) ||
744              js_SkipWhiteSpace(ep) != bp + str->length)) {
745             goto badstr;
746         }
747     } else if (JSVAL_IS_BOOLEAN(v)) {
748         *dp = JSVAL_TO_BOOLEAN(v) ? 1 : 0;
749     } else {
750 #if JS_BUG_FALLIBLE_TONUM
751         str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
752 badstr:
753         if (str) {
754             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NAN,
755                                  JS_GetStringBytes(str));
757         }
758         return JS_FALSE;
759 #else
760 badstr:
761         *dp = *cx->runtime->jsNaN;
762 #endif
763     }
764     return JS_TRUE;
767 JSBool
768 js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
770     jsdouble d;
772     if (!js_ValueToNumber(cx, v, &d))
773         return JS_FALSE;
774     return js_DoubleToECMAInt32(cx, d, ip);
777 JSBool
778 js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip)
780     jsdouble two32 = 4294967296.0;
781     jsdouble two31 = 2147483648.0;
783     if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
784         *ip = 0;
785         return JS_TRUE;
786     }
787     d = fmod(d, two32);
788     d = (d >= 0) ? floor(d) : ceil(d) + two32;
789     if (d >= two31)
790         *ip = (int32)(d - two32);
791     else
792         *ip = (int32)d;
793     return JS_TRUE;
796 JSBool
797 js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
799     jsdouble d;
801     if (!js_ValueToNumber(cx, v, &d))
802         return JS_FALSE;
803     return js_DoubleToECMAUint32(cx, d, ip);
806 JSBool
807 js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip)
809     JSBool neg;
810     jsdouble two32 = 4294967296.0;
812     if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
813         *ip = 0;
814         return JS_TRUE;
815     }
817     neg = (d < 0);
818     d = floor(neg ? -d : d);
819     d = neg ? -d : d;
821     d = fmod(d, two32);
823     d = (d >= 0) ? d : d + two32;
824     *ip = (uint32)d;
825     return JS_TRUE;
828 JSBool
829 js_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
831     jsdouble d;
832     JSString *str;
834     if (JSVAL_IS_INT(v)) {
835         *ip = JSVAL_TO_INT(v);
836         return JS_TRUE;
837     }
838     if (!js_ValueToNumber(cx, v, &d))
839         return JS_FALSE;
840     if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
841         str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
842         if (str) {
843             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
844                                  JSMSG_CANT_CONVERT, JS_GetStringBytes(str));
846         }
847         return JS_FALSE;
848     }
849     *ip = (int32)floor(d + 0.5);     /* Round to nearest */
850     return JS_TRUE;
853 JSBool
854 js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
856     jsdouble d;
857     jsuint i, m;
858     JSBool neg;
860     if (!js_ValueToNumber(cx, v, &d))
861         return JS_FALSE;
862     if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
863         *ip = 0;
864         return JS_TRUE;
865     }
866     i = (jsuint)d;
867     if ((jsdouble)i == d) {
868         *ip = (uint16)i;
869         return JS_TRUE;
870     }
871     neg = (d < 0);
872     d = floor(neg ? -d : d);
873     d = neg ? -d : d;
874     m = JS_BIT(16);
875     d = fmod(d, (double)m);
876     if (d < 0)
877         d += m;
878     *ip = (uint16) d;
879     return JS_TRUE;
882 jsdouble
883 js_DoubleToInteger(jsdouble d)
885     JSBool neg;
887     if (d == 0)
888         return d;
889     if (!JSDOUBLE_IS_FINITE(d)) {
890         if (JSDOUBLE_IS_NaN(d))
891             return 0;
892         return d;
893     }
894     neg = (d < 0);
895     d = floor(neg ? -d : d);
896     return neg ? -d : d;
900 JSBool
901 js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
903     char cbuf[32];
904     size_t i;
905     char *cstr, *istr, *estr;
906     JSBool negative;
907     jsdouble d;
908     const jschar *s1 = js_SkipWhiteSpace(s);
909     size_t length = js_strlen(s1);
911     /* Use cbuf to avoid malloc */
912     if (length >= sizeof cbuf) {
913         cstr = (char *) JS_malloc(cx, length + 1);
914         if (!cstr)
915            return JS_FALSE;
916     } else {
917         cstr = cbuf;
918     }
920     for (i = 0; i <= length; i++) {
921         if (s1[i] >> 8) {
922             cstr[i] = 0;
923             break;
924         }
925         cstr[i] = (char)s1[i];
926     }
928     istr = cstr;
929     if ((negative = (*istr == '-')) != 0 || *istr == '+')
930         istr++;
931     if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
932         d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
933         estr = istr + 8;
934     } else {
935         int err;
936         d = JS_strtod(cstr, &estr, &err);
937         if (err == JS_DTOA_ENOMEM) {
938             JS_ReportOutOfMemory(cx);
939             if (cstr != cbuf)
940                 JS_free(cx, cstr);
941             return JS_FALSE;
942         }
943         if (err == JS_DTOA_ERANGE) {
944             if (d == HUGE_VAL)
945                 d = *cx->runtime->jsPositiveInfinity;
946             else if (d == -HUGE_VAL)
947                 d = *cx->runtime->jsNegativeInfinity;
948         }
949 #ifdef HPUX
950         if (d == 0.0 && negative) {
951             /*
952              * "-0", "-1e-2000" come out as positive zero
953              * here on HPUX. Force a negative zero instead.
954              */
955             JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
956             JSDOUBLE_LO32(d) = 0;
957         }
958 #endif
959     }
961     i = estr - cstr;
962     if (cstr != cbuf)
963         JS_free(cx, cstr);
964     *ep = i ? s1 + i : s;
965     *dp = d;
966     return JS_TRUE;
969 struct BinaryDigitReader
971     uintN base;                 /* Base of number; must be a power of 2 */
972     uintN digit;                /* Current digit value in radix given by base */
973     uintN digitMask;            /* Mask to extract the next bit from digit */
974     const jschar *digits;       /* Pointer to the remaining digits */
975     const jschar *end;          /* Pointer to first non-digit */
976 };
978 /* Return the next binary digit from the number or -1 if done */
979 static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
981     intN bit;
983     if (bdr->digitMask == 0) {
984         uintN c;
986         if (bdr->digits == bdr->end)
987             return -1;
989         c = *bdr->digits++;
990         if ('0' <= c && c <= '9')
991             bdr->digit = c - '0';
992         else if ('a' <= c && c <= 'z')
993             bdr->digit = c - 'a' + 10;
994         else bdr->digit = c - 'A' + 10;
995         bdr->digitMask = bdr->base >> 1;
996     }
997     bit = (bdr->digit & bdr->digitMask) != 0;
998     bdr->digitMask >>= 1;
999     return bit;
1002 JSBool
1003 js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
1005     JSBool negative;
1006     jsdouble value;
1007     const jschar *start;
1008     const jschar *s1 = js_SkipWhiteSpace(s);
1010     if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
1011         s1++;
1013     if (base == 0) {
1014         /* No base supplied, or some base that evaluated to 0. */
1015         if (*s1 == '0') {
1016             /* It's either hex or octal; only increment char if str isn't '0' */
1017             if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
1018                 s1 += 2;
1019                 base = 16;
1020             } else {    /* Octal */
1021                 base = 8;
1022             }
1023         } else {
1024             base = 10; /* Default to decimal. */
1025         }
1026     } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
1027         /* If base is 16, ignore hex prefix. */
1028         s1 += 2;
1029     }
1031     /*
1032      * Done with the preliminaries; find some prefix of the string that's
1033      * a number in the given base.
1034      */
1035     start = s1; /* Mark - if string is empty, we return NaN. */
1036     value = 0.0;
1037     for (;;) {
1038         uintN digit;
1039         jschar c = *s1;
1040         if ('0' <= c && c <= '9')
1041             digit = c - '0';
1042         else if ('a' <= c && c <= 'z')
1043             digit = c - 'a' + 10;
1044         else if ('A' <= c && c <= 'Z')
1045             digit = c - 'A' + 10;
1046         else
1047             break;
1048         if (digit >= (uintN)base)
1049             break;
1050         value = value * base + digit;
1051         s1++;
1052     }
1054     if (value >= 9007199254740992.0) {
1055         if (base == 10) {
1056             /*
1057              * If we're accumulating a decimal number and the number is >=
1058              * 2^53, then the result from the repeated multiply-add above may
1059              * be inaccurate.  Call JS_strtod to get the correct answer.
1060              */
1061             size_t i;
1062             size_t length = s1 - start;
1063             char *cstr = (char *) JS_malloc(cx, length + 1);
1064             char *estr;
1065             int err=0;
1067             if (!cstr)
1068                 return JS_FALSE;
1069             for (i = 0; i != length; i++)
1070                 cstr[i] = (char)start[i];
1071             cstr[length] = 0;
1073             value = JS_strtod(cstr, &estr, &err);
1074             if (err == JS_DTOA_ENOMEM) {
1075                 JS_ReportOutOfMemory(cx);
1076                 JS_free(cx, cstr);
1077                 return JS_FALSE;
1078             }
1079             if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
1080                 value = *cx->runtime->jsPositiveInfinity;
1081             JS_free(cx, cstr);
1082         } else if ((base & (base - 1)) == 0) {
1083             /*
1084              * The number may also be inaccurate for power-of-two bases.  This
1085              * happens if the addition in value * base + digit causes a round-
1086              * down to an even least significant mantissa bit when the first
1087              * dropped bit is a one.  If any of the following digits in the
1088              * number (which haven't been added in yet) are nonzero, then the
1089              * correct action would have been to round up instead of down.  An
1090              * example occurs when reading the number 0x1000000000000081, which
1091              * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1092              */
1093             struct BinaryDigitReader bdr;
1094             intN bit, bit2;
1095             intN j;
1097             bdr.base = base;
1098             bdr.digitMask = 0;
1099             bdr.digits = start;
1100             bdr.end = s1;
1101             value = 0.0;
1103             /* Skip leading zeros. */
1104             do {
1105                 bit = GetNextBinaryDigit(&bdr);
1106             } while (bit == 0);
1108             if (bit == 1) {
1109                 /* Gather the 53 significant bits (including the leading 1) */
1110                 value = 1.0;
1111                 for (j = 52; j; j--) {
1112                     bit = GetNextBinaryDigit(&bdr);
1113                     if (bit < 0)
1114                         goto done;
1115                     value = value*2 + bit;
1116                 }
1117                 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1118                 bit2 = GetNextBinaryDigit(&bdr);
1119                 if (bit2 >= 0) {
1120                     jsdouble factor = 2.0;
1121                     intN sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
1122                     intN bit3;
1124                     while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1125                         sticky |= bit3;
1126                         factor *= 2;
1127                     }
1128                     value += bit2 & (bit | sticky);
1129                     value *= factor;
1130                 }
1131               done:;
1132             }
1133         }
1134     }
1135     /* We don't worry about inaccurate numbers for any other base. */
1137     if (s1 == start) {
1138         *dp = 0.0;
1139         *ep = s;
1140     } else {
1141         *dp = negative ? -value : value;
1142         *ep = s1;
1143     }
1144     return JS_TRUE;