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 ***** */
40
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 <math.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include "jstypes.h"
52 #include "jsutil.h" /* Added by JSIFY */
53 #include "jsapi.h"
54 #include "jsatom.h"
55 #include "jscntxt.h"
56 #include "jsconfig.h"
57 #include "jsdtoa.h"
58 #include "jsgc.h"
59 #include "jsinterp.h"
60 #include "jsnum.h"
61 #include "jsobj.h"
62 #include "jsopcode.h"
63 #include "jsprf.h"
64 #include "jsstr.h"
65
66 static JSBool
67 num_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
68 0 {
69 0     jsdouble x;
70
71 0     if (!js_ValueToNumber(cx, argv[0], &x))
72 0 return JS_FALSE;
73 0     *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
74 0     return JS_TRUE;
75 }
76
77 static JSBool
78 num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
79 0 {
80 0     jsdouble x;
81
82 0     if (!js_ValueToNumber(cx, argv[0], &x))
83 0 return JS_FALSE;
84 0     *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
85 0     return JS_TRUE;
86 }
87
88 static JSBool
89 num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
90 0 {
91 0     JSString *str;
92 0     jsdouble d;
93 0     const jschar *bp, *ep;
94
95 0     str = js_ValueToString(cx, argv[0]);
96 0     if (!str)
97 0 return JS_FALSE;
98     /* XXXbe js_strtod shouldn't require NUL termination */
99 0     bp = js_UndependString(cx, str);
100 0     if (!bp)
101 0 return JS_FALSE;
102 0     if (!js_strtod(cx, bp, &ep, &d))
103 0 return JS_FALSE;
104 0     if (ep == bp) {
105 0 *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
106 0 return JS_TRUE;
107     }
108 0     return js_NewNumberValue(cx, d, rval);
109 }
110
111 /* See ECMA 15.1.2.2. */
112 static JSBool
113 num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
114 0 {
115 0     JSString *str;
116 0     jsint radix;
117 0     jsdouble d;
118 0     const jschar *bp, *ep;
119
120 0     str = js_ValueToString(cx, argv[0]);
121 0     if (!str)
122 0 return JS_FALSE;
123
124 0     if (argc > 1) {
125 0 if (!js_ValueToECMAInt32(cx, argv[1], &radix))
126 0     return JS_FALSE;
127     } else
128 0 radix = 0;
129
130 0     if (radix != 0 && (radix < 2 || radix > 36)) {
131 0 *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
132 0 return JS_TRUE;
133     }
134     /* XXXbe js_strtointeger shouldn't require NUL termination */
135 0     bp = js_UndependString(cx, str);
136 0     if (!bp)
137 0 return JS_FALSE;
138 0     if (!js_strtointeger(cx, bp, &ep, radix, &d))
139 0 return JS_FALSE;
140 0     if (ep == bp) {
141 0 *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
142 0 return JS_TRUE;
143     }
144 0     return js_NewNumberValue(cx, d, rval);
145 }
146
147 const char js_Infinity_str[]   = "Infinity";
148 const char js_NaN_str[]        = "NaN";
149 const char js_isNaN_str[]      = "isNaN";
150 const char js_isFinite_str[]   = "isFinite";
151 const char js_parseFloat_str[] = "parseFloat";
152 const char js_parseInt_str[]   = "parseInt";
153
154 static JSFunctionSpec number_functions[] = {
155     {"isNaN",           num_isNaN,              1,0,0},
156     {"isFinite",        num_isFinite,           1,0,0},
157     {"parseFloat",      num_parseFloat,         1,0,0},
158     {"parseInt",        num_parseInt,           2,0,0},
159     {0,0,0,0,0}
160 };
161
162 static JSClass number_class = {
163     "Number",
164     JSCLASS_HAS_PRIVATE,
165     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
166     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
167     JSCLASS_NO_OPTIONAL_MEMBERS
168 };
169
170 static JSBool
171 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
172 0 {
173 0     jsdouble d;
174 0     jsval v;
175
176 0     if (argc != 0) {
177 0 if (!js_ValueToNumber(cx, argv[0], &d))
178 0     return JS_FALSE;
179     } else {
180 0 d = 0.0;
181     }
182 0     if (!js_NewNumberValue(cx, d, &v))
183 0 return JS_FALSE;
184 0     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
185 0 *rval = v;
186 0 return JS_TRUE;
187     }
188 0     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
189 0     return JS_TRUE;
190 }
191
192 #if JS_HAS_TOSOURCE
193 static JSBool
194 num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
195 0 {
196 0     jsval v;
197 0     jsdouble d;
198 0     char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
199 0     char buf[64];
200 0     JSString *str;
201
202 0     if (!JS_InstanceOf(cx, obj, &number_class, argv))
203 0 return JS_FALSE;
204 0     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
205 0     JS_ASSERT(JSVAL_IS_NUMBER(v));
206 0     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
207 0     numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
208 0     if (!numStr) {
209 0 JS_ReportOutOfMemory(cx);
210 0 return JS_FALSE;
211     }
212 0     JS_snprintf(buf, sizeof buf, "(new %s(%s))", number_class.name, numStr);
213 0     str = JS_NewStringCopyZ(cx, buf);
214 0     if (!str)
215 0 return JS_FALSE;
216 0     *rval = STRING_TO_JSVAL(str);
217 0     return JS_TRUE;
218 }
219 #endif
220
221 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
222 static char *
223 IntToString(jsint i, char *buf, size_t bufSize)
224 0 {
225 0     char *cp;
226 0     jsuint u;
227     
228 0     u = (i < 0) ? -i : i;
229
230 0     cp = buf + bufSize; /* one past last buffer cell */
231 0     *--cp = '\0';       /* null terminate the string to be */
232     
233     /*
234      * Build the string from behind. We use multiply and subtraction
235      * instead of modulus because that's much faster.
236      */
237 0     do {
238 0         jsuint newu = u / 10;
239 0         *--cp = (char)(u - newu * 10) + '0';
240 0         u = newu;
241 0     } while (u != 0);
242     
243 0     if (i < 0)
244 0         *--cp = '-';
245
246 0     return cp;
247 }
248
249 static JSBool
250 num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
251 0 {
252 0     jsval v;
253 0     jsdouble d;
254 0     jsint base;
255 0     JSString *str;
256
257 0     if (!JS_InstanceOf(cx, obj, &number_class, argv))
258 0 return JS_FALSE;
259 0     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
260 0     JS_ASSERT(JSVAL_IS_NUMBER(v));
261 0     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
262 0     base = 10;
263 0     if (argc != 0) {
264 0 if (!js_ValueToECMAInt32(cx, argv[0], &base))
265 0     return JS_FALSE;
266 0 if (base < 2 || base > 36) {
267 0     char numBuf[12];
268 0     char *numStr = IntToString(base, numBuf, sizeof numBuf);
269 0     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
270       numStr);
271 0     return JS_FALSE;
272 }
273     }
274 0     if (base == 10)
275 0 str = js_NumberToString(cx, d);
276     else {
277 0 char *dStr = JS_dtobasestr(base, d);
278 0 if (!dStr) {
279 0     JS_ReportOutOfMemory(cx);
280 0     return JS_FALSE;
281 }
282 0 str = JS_NewStringCopyZ(cx, dStr);
283 0 free(dStr);
284     }
285 0     if (!str)
286 0 return JS_FALSE;
287 0     *rval = STRING_TO_JSVAL(str);
288 0     return JS_TRUE;
289 }
290
291 static JSBool
292 num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
293                    jsval *argv, jsval *rval)
294 0 {
295 /*
296  *  For now, forcibly ignore the first (or any) argument and return toString().
297  *  ECMA allows this, although it doesn't 'encourage it'.
298  *  [The first argument is being reserved by ECMA and we don't want it confused
299  *  with a radix]
300  */
301 0     return num_toString(cx, obj, 0, argv, rval);
302 }
303
304 static JSBool
305 num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
306 0 {
307 0     if (!JS_InstanceOf(cx, obj, &number_class, argv))
308 0 return JS_FALSE;
309 0     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
310 0     return JS_TRUE;
311 }
312
313
314 #if JS_HAS_NUMBER_FORMATS
315 #define MAX_PRECISION 100
316
317 static JSBool
318 num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode,
319        JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset)
320 0 {
321 0     jsval v;
322 0     jsdouble d, precision;
323 0     JSString *str;
324 0     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
325
326 0     if (!JS_InstanceOf(cx, obj, &number_class, argv))
327 0 return JS_FALSE;
328 0     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
329 0     JS_ASSERT(JSVAL_IS_NUMBER(v));
330 0     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
331
332 0     if (JSVAL_IS_VOID(argv[0])) {
333 0 precision = 0.0;
334 0 oneArgMode = zeroArgMode;
335     } else {
336 0 if (!js_ValueToNumber(cx, argv[0], &precision))
337 0     return JS_FALSE;
338 0 precision = js_DoubleToInteger(precision);
339 0         if (precision < precisionMin || precision > precisionMax) {
340 0             numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
341 0             if (!numStr)
342 0                 JS_ReportOutOfMemory(cx);
343             else
344 0                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
345 0             return JS_FALSE;
346         }
347     }
348
349 0     numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
350 0     if (!numStr) {
351 0 JS_ReportOutOfMemory(cx);
352 0 return JS_FALSE;
353     }
354 0     str = JS_NewStringCopyZ(cx, numStr);
355 0     if (!str)
356 0 return JS_FALSE;
357 0     *rval = STRING_TO_JSVAL(str);
358 0     return JS_TRUE;
359 }
360
361 static JSBool
362 num_toFixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
363 0 {
364     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
365 0     return num_to(cx, obj, argc, argv, rval, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0);
366 }
367
368 static JSBool
369 num_toExponential(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
370 0 {
371     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
372 0     return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1);
373 }
374
375 static JSBool
376 num_toPrecision(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
377 0 {
378     /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
379 0     return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0);
380 }
381 #endif /* JS_HAS_NUMBER_FORMATS */
382
383
384 static JSFunctionSpec number_methods[] = {
385 #if JS_HAS_TOSOURCE
386     {js_toSource_str,       num_toSource,       0,0,0},
387 #endif
388     {js_toString_str,     num_toString,       0,0,0},
389     {js_toLocaleString_str, num_toLocaleString, 0,0,0},
390     {js_valueOf_str,     num_valueOf,        0,0,0},
391 #if JS_HAS_NUMBER_FORMATS
392     {"toFixed",             num_toFixed,        1,0,0},
393     {"toExponential",       num_toExponential,  1,0,0},
394     {"toPrecision",         num_toPrecision,    1,0,0},
395 #endif
396     {0,0,0,0,0}
397 };
398
399 /* NB: Keep this in synch with number_constants[]. */
400 enum nc_slot {
401     NC_NaN,
402     NC_POSITIVE_INFINITY,
403     NC_NEGATIVE_INFINITY,
404     NC_MAX_VALUE,
405     NC_MIN_VALUE,
406     NC_LIMIT
407 };
408
409 /*
410  * Some to most C compilers forbid spelling these at compile time, or barf
411  * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
412  * using union jsdpun.
413  */
414 static JSConstDoubleSpec number_constants[] = {
415     {0,                         js_NaN_str,          0,{0,0,0}},
416     {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
417     {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
418     {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
419     {0,                         "MIN_VALUE",         0,{0,0,0}},
420     {0,0,0,{0,0,0}}
421 };
422
423 static jsdouble NaN;
424
425
426 #if defined XP_WIN &&                                                         \
427     !defined __MWERKS__ &&                                                    \
428     (defined _M_IX86 ||                                                       \
429      (defined __GNUC__ && !defined __MINGW32__))
430
431 /*
432  * Set the exception mask to mask all exceptions and set the FPU precision
433  * to 53 bit mantissa.
434  * On Alpha platform this is handled via Compiler option.
435  */
436 #define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
437
438 #else
439
440 #define FIX_FPU() ((void)0)
441
442 #endif
443
444 JSBool
445 js_InitRuntimeNumberState(JSContext *cx)
446 0 {
447 0     JSRuntime *rt;
448 0     jsdpun u;
449
450 0     rt = cx->runtime;
451 0     JS_ASSERT(!rt->jsNaN);
452
453 0     FIX_FPU();
454
455 0     u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
456 0     u.s.lo = 0xffffffff;
457 0     number_constants[NC_NaN].dval = NaN = u.d;
458 0     rt->jsNaN = js_NewDouble(cx, NaN);
459 0     if (!rt->jsNaN || !js_LockGCThing(cx, rt->jsNaN))
460 0         return JS_FALSE;
461
462 0     u.s.hi = JSDOUBLE_HI32_EXPMASK;
463 0     u.s.lo = 0x00000000;
464 0     number_constants[NC_POSITIVE_INFINITY].dval = u.d;
465 0     rt->jsPositiveInfinity = js_NewDouble(cx, u.d);
466 0     if (!rt->jsPositiveInfinity ||
467         !js_LockGCThing(cx, rt->jsPositiveInfinity)) {
468 0         return JS_FALSE;
469     }
470
471 0     u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
472 0     u.s.lo = 0x00000000;
473 0     number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
474 0     rt->jsNegativeInfinity = js_NewDouble(cx, u.d);
475 0     if (!rt->jsNegativeInfinity ||
476         !js_LockGCThing(cx, rt->jsNegativeInfinity)) {
477 0         return JS_FALSE;
478     }
479
480 0     u.s.hi = 0;
481 0     u.s.lo = 1;
482 0     number_constants[NC_MIN_VALUE].dval = u.d;
483
484 0     return JS_TRUE;
485 }
486
487 void
488 js_FinishRuntimeNumberState(JSContext *cx)
489 0 {
490 0     JSRuntime *rt = cx->runtime;
491
492 0     js_UnlockGCThingRT(rt, rt->jsNaN);
493 0     js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
494 0     js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
495
496 0     rt->jsNaN = NULL;
497 0     rt->jsNegativeInfinity = NULL;
498 0     rt->jsPositiveInfinity = NULL;
499 }
500
501 JSObject *
502 js_InitNumberClass(JSContext *cx, JSObject *obj)
503 0 {
504 0     JSObject *proto, *ctor;
505 0     JSRuntime *rt;
506
507     /* XXX must do at least once per new thread, so do it per JSContext... */
508 0     FIX_FPU();
509
510 0     if (!JS_DefineFunctions(cx, obj, number_functions))
511 0 return NULL;
512
513 0     proto = JS_InitClass(cx, obj, NULL, &number_class, Number, 1,
514  NULL, number_methods, NULL, NULL);
515 0     if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
516 0 return NULL;
517 0     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_ZERO);
518 0     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
519 0 return NULL;
520
521     /* ECMA 15.1.1.1 */
522 0     rt = cx->runtime;
523 0     if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
524    NULL, NULL, JSPROP_PERMANENT)) {
525 0 return NULL;
526     }
527
528     /* ECMA 15.1.1.2 */
529 0     if (!JS_DefineProperty(cx, obj, js_Infinity_str,
530    DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
531    NULL, NULL, JSPROP_PERMANENT)) {
532 0 return NULL;
533     }
534 0     return proto;
535 }
536
537 jsdouble *
538 js_NewDouble(JSContext *cx, jsdouble d)
539 0 {
540 0     jsdouble *dp;
541
542 0     dp = (jsdouble *) js_AllocGCThing(cx, GCX_DOUBLE);
543 0     if (!dp)
544 0 return NULL;
545 0     *dp = d;
546 0     return dp;
547 }
548
549 void
550 js_FinalizeDouble(JSContext *cx, jsdouble *dp)
551 0 {
552 0     *dp = NaN;
553 }
554
555 JSBool
556 js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
557 0 {
558 0     jsdouble *dp;
559
560 0     dp = js_NewDouble(cx, d);
561 0     if (!dp)
562 0 return JS_FALSE;
563 0     *rval = DOUBLE_TO_JSVAL(dp);
564 0     return JS_TRUE;
565 }
566
567 JSBool
568 js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
569 0 {
570 0     jsint i;
571 0     JSBool ok;
572
573 0     SET_FPU();
574
575 0     if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
576 0 *rval = INT_TO_JSVAL(i);
577 0         ok = JS_TRUE;
578     } else {
579 0         ok = js_NewDoubleValue(cx, d, rval);
580     }
581     
582 0     RESTORE_FPU();
583 0     return ok;
584 }
585
586 JSObject *
587 js_NumberToObject(JSContext *cx, jsdouble d)
588 0 {
589 0     JSObject *obj;
590 0     jsval v;
591
592 0     obj = js_NewObject(cx, &number_class, NULL, NULL);
593 0     if (!obj)
594 0 return NULL;
595 0     if (!js_NewNumberValue(cx, d, &v)) {
596 0 cx->newborn[GCX_OBJECT] = NULL;
597 0 return NULL;
598     }
599 0     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
600 0     return obj;
601 }
602
603 JSString *
604 js_NumberToString(JSContext *cx, jsdouble d)
605 0 {
606 0     jsint i;
607 0     char buf[DTOSTR_STANDARD_BUFFER_SIZE];
608 0     char *numStr;
609
610 0     if (JSDOUBLE_IS_INT(d, i))
611 0 numStr = IntToString(i, buf, sizeof buf);
612     else {
613 0 numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
614 0 if (!numStr) {
615 0     JS_ReportOutOfMemory(cx);
616 0     return NULL;
617 }
618     }
619 0     return JS_NewStringCopyZ(cx, numStr);
620 }
621
622 JSBool
623 js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
624 0 {
625 0     JSObject *obj;
626 0     JSString *str;
627 0     const jschar *bp, *ep;
628
629 0     if (JSVAL_IS_OBJECT(v)) {
630 0 obj = JSVAL_TO_OBJECT(v);
631 0 if (!obj) {
632 0     *dp = 0;
633 0     return JS_TRUE;
634 }
635 0 if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
636 0     return JS_FALSE;
637     }
638 0     if (JSVAL_IS_INT(v)) {
639 0 *dp = (jsdouble)JSVAL_TO_INT(v);
640 0     } else if (JSVAL_IS_DOUBLE(v)) {
641 0 *dp = *JSVAL_TO_DOUBLE(v);
642 0     } else if (JSVAL_IS_STRING(v)) {
643 0 str = JSVAL_TO_STRING(v);
644 /*
645          * Note that ECMA doesn't treat a string beginning with a '0' as an
646          * octal number here.  This works because all such numbers will be
647          * interpreted as decimal by js_strtod and will never get passed to
648          * js_strtointeger (which would interpret them as octal).
649          */
650         /* XXXbe js_strtod shouldn't require NUL termination */
651 0         bp = js_UndependString(cx, str);
652 0         if (!bp)
653 0             return JS_FALSE;
654 0         if ((!js_strtod(cx, bp, &ep, dp) ||
655              js_SkipWhiteSpace(ep) != bp + str->length) &&
656     (!js_strtointeger(cx, bp, &ep, 0, dp) ||
657              js_SkipWhiteSpace(ep) != bp + str->length)) {
658 0     goto badstr;
659 }
660 0     } else if (JSVAL_IS_BOOLEAN(v)) {
661 0 *dp = JSVAL_TO_BOOLEAN(v) ? 1 : 0;
662     } else {
663 #if JS_BUG_FALLIBLE_TONUM
664 str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
665 badstr:
666 if (str) {
667     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NAN,
668  JS_GetStringBytes(str));
669
670 }
671 return JS_FALSE;
672 #else
673 badstr:
674 0 *dp = *cx->runtime->jsNaN;
675 #endif
676     }
677 0     return JS_TRUE;
678 }
679
680 JSBool
681 js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
682 0 {
683 0     jsdouble d;
684
685 0     if (!js_ValueToNumber(cx, v, &d))
686 0 return JS_FALSE;
687 0     return js_DoubleToECMAInt32(cx, d, ip);
688 }
689
690 JSBool
691 js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip)
692 0 {
693 0     jsdouble two32 = 4294967296.0;
694 0     jsdouble two31 = 2147483648.0;
695
696 0     if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
697 0         *ip = 0;
698 0         return JS_TRUE;
699     }
700 0     d = fmod(d, two32);
701 0     d = (d >= 0) ? floor(d) : ceil(d) + two32;
702 0     if (d >= two31)
703 0         *ip = (int32)(d - two32);
704     else
705 0         *ip = (int32)d;
706 0     return JS_TRUE;
707 }
708
709 JSBool
710 js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
711 0 {
712 0     jsdouble d;
713
714 0     if (!js_ValueToNumber(cx, v, &d))
715 0 return JS_FALSE;
716 0     return js_DoubleToECMAUint32(cx, d, ip);
717 }
718
719 JSBool
720 js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip)
721 0 {
722 0     JSBool neg;
723 0     jsdouble two32 = 4294967296.0;
724
725 0     if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
726 0 *ip = 0;
727 0 return JS_TRUE;
728     }
729
730 0     neg = (d < 0);
731 0     d = floor(neg ? -d : d);
732 0     d = neg ? -d : d;
733
734 0     d = fmod(d, two32);
735
736 0     d = (d >= 0) ? d : d + two32;
737 0     *ip = (uint32)d;
738 0     return JS_TRUE;
739 }
740
741 JSBool
742 js_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
743 0 {
744 0     jsdouble d;
745 0     JSString *str;
746
747 0     if (JSVAL_IS_INT(v)) {
748 0         *ip = JSVAL_TO_INT(v);
749 0         return JS_TRUE;
750     }
751 0     if (!js_ValueToNumber(cx, v, &d))
752 0 return JS_FALSE;
753 0     if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
754 0 str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
755 0 if (str) {
756 0     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
757  JSMSG_CANT_CONVERT, JS_GetStringBytes(str));
758
759 }
760 0 return JS_FALSE;
761     }
762 0     *ip = (int32)floor(d + 0.5);     /* Round to nearest */
763 0     return JS_TRUE;
764 }
765
766 JSBool
767 js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
768 0 {
769 0     jsdouble d;
770 0     jsuint i, m;
771 0     JSBool neg;
772
773 0     if (!js_ValueToNumber(cx, v, &d))
774 0 return JS_FALSE;
775 0     if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
776 0 *ip = 0;
777 0 return JS_TRUE;
778     }
779 0     i = (jsuint)d;
780 0     if ((jsdouble)i == d) {
781 0 *ip = (uint16)i;
782 0 return JS_TRUE;
783     }
784 0     neg = (d < 0);
785 0     d = floor(neg ? -d : d);
786 0     d = neg ? -d : d;
787 0     m = JS_BIT(16);
788 0     d = fmod(d, (double)m);
789 0     if (d < 0)
790 0 d += m;
791 0     *ip = (uint16) d;
792 0     return JS_TRUE;
793 }
794
795 jsdouble
796 js_DoubleToInteger(jsdouble d)
797 0 {
798 0     JSBool neg;
799
800 0     if (d == 0)
801 0 return d;
802 0     if (!JSDOUBLE_IS_FINITE(d)) {
803 0 if (JSDOUBLE_IS_NaN(d))
804 0     return 0;
805 0 return d;
806     }
807 0     neg = (d < 0);
808 0     d = floor(neg ? -d : d);
809 0     return neg ? -d : d;
810 }
811
812
813 JSBool
814 js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
815 0 {
816 0     char cbuf[32];
817 0     size_t i;
818 0     char *cstr, *istr, *estr;
819 0     JSBool negative;
820 0     jsdouble d;
821 0     const jschar *s1 = js_SkipWhiteSpace(s);
822 0     size_t length = js_strlen(s1);
823
824     /* Use cbuf to avoid malloc */
825 0     if (length >= sizeof cbuf) {
826 0         cstr = (char *) JS_malloc(cx, length + 1);
827 0         if (!cstr)
828 0            return JS_FALSE;
829     } else {
830 0         cstr = cbuf;
831     }
832    
833 0     for (i = 0; i <= length; i++) {
834 0         if (s1[i] >> 8) {
835 0             cstr[i] = 0;
836 0             break;
837         }
838 0         cstr[i] = (char)s1[i];
839     }
840
841 0     istr = cstr;
842 0     if ((negative = (*istr == '-')) != 0 || *istr == '+')
843 0         istr++;
844 0     if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
845 0         d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
846 0         estr = istr + 8;
847     } else {
848 0         int err;
849 0         d = JS_strtod(cstr, &estr, &err);
850 0         if (err == JS_DTOA_ENOMEM) {
851 0             JS_ReportOutOfMemory(cx);
852 0             if (cstr != cbuf)
853 0                 JS_free(cx, cstr);
854 0             return JS_FALSE;
855         }
856 0         if (err == JS_DTOA_ERANGE) {
857 0             if (d == HUGE_VAL)
858 0                 d = *cx->runtime->jsPositiveInfinity;
859 0             else if (d == -HUGE_VAL)
860 0                 d = *cx->runtime->jsNegativeInfinity;
861         }
862 #ifdef HPUX
863         if (d == 0.0 && negative) {
864             /*
865              * "-0", "-1e-2000" come out as positive zero
866              * here on HPUX. Force a negative zero instead.
867              */
868             JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
869             JSDOUBLE_LO32(d) = 0;
870         }
871 #endif
872     }
873
874 0     i = estr - cstr;
875 0     if (cstr != cbuf)
876 0         JS_free(cx, cstr);
877 0     *ep = i ? s1 + i : s;
878 0     *dp = d;
879 0     return JS_TRUE;
880 }
881
882 struct BinaryDigitReader
883 {
884     uintN base;                 /* Base of number; must be a power of 2 */
885     uintN digit;                /* Current digit value in radix given by base */
886     uintN digitMask;            /* Mask to extract the next bit from digit */
887     const jschar *digits;       /* Pointer to the remaining digits */
888     const jschar *end;          /* Pointer to first non-digit */
889 };
890
891 /* Return the next binary digit from the number or -1 if done */
892 static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
893 0 {
894 0     intN bit;
895
896 0     if (bdr->digitMask == 0) {
897 0         uintN c;
898
899 0         if (bdr->digits == bdr->end)
900 0             return -1;
901
902 0         c = *bdr->digits++;
903 0         if ('0' <= c && c <= '9')
904 0             bdr->digit = c - '0';
905 0         else if ('a' <= c && c <= 'z')
906 0             bdr->digit = c - 'a' + 10;
907 0         else bdr->digit = c - 'A' + 10;
908 0         bdr->digitMask = bdr->base >> 1;
909     }
910 0     bit = (bdr->digit & bdr->digitMask) != 0;
911 0     bdr->digitMask >>= 1;
912 0     return bit;
913 }
914
915 JSBool
916 js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
917 0 {
918 0     JSBool negative;
919 0     jsdouble value;
920 0     const jschar *start;
921 0     const jschar *s1 = js_SkipWhiteSpace(s);
922
923 0     if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
924 0         s1++;
925
926 0     if (base == 0) {
927         /* No base supplied, or some base that evaluated to 0. */
928 0         if (*s1 == '0') {
929             /* It's either hex or octal; only increment char if str isn't '0' */
930 0             if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
931 0                 s1 += 2;
932 0                 base = 16;
933             } else {    /* Octal */
934 0                 base = 8;
935             }
936         } else {
937 0             base = 10; /* Default to decimal. */
938         }
939 0     } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
940         /* If base is 16, ignore hex prefix. */
941 0         s1 += 2;
942     }
943
944     /*
945      * Done with the preliminaries; find some prefix of the string that's
946      * a number in the given base.
947      */
948 0     start = s1; /* Mark - if string is empty, we return NaN. */
949 0     value = 0.0;
950 0     for (;;) {
951 0         uintN digit;
952 0         jschar c = *s1;
953 0         if ('0' <= c && c <= '9')
954 0             digit = c - '0';
955 0         else if ('a' <= c && c <= 'z')
956 0             digit = c - 'a' + 10;
957 0         else if ('A' <= c && c <= 'Z')
958 0             digit = c - 'A' + 10;
959         else
960 0             break;
961 0         if (digit >= (uintN)base)
962 0             break;
963 0         value = value * base + digit;
964 0         s1++;
965     }
966
967 0     if (value >= 9007199254740992.0) {
968 0         if (base == 10) {
969             /*
970              * If we're accumulating a decimal number and the number is >=
971              * 2^53, then the result from the repeated multiply-add above may
972              * be inaccurate.  Call JS_strtod to get the correct answer.
973              */
974 0             size_t i;
975 0             size_t length = s1 - start;
976 0             char *cstr = (char *) JS_malloc(cx, length + 1);
977 0             char *estr;
978 0             int err=0;
979
980 0             if (!cstr)
981 0                 return JS_FALSE;
982 0             for (i = 0; i != length; i++)
983 0                 cstr[i] = (char)start[i];
984 0             cstr[length] = 0;
985
986 0             value = JS_strtod(cstr, &estr, &err);
987 0             if (err == JS_DTOA_ENOMEM) {
988 0                 JS_ReportOutOfMemory(cx);
989 0                 JS_free(cx, cstr);
990 0                 return JS_FALSE;
991             }
992 0             if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
993 0                 value = *cx->runtime->jsPositiveInfinity;
994 0             JS_free(cx, cstr);
995 0         } else if ((base & (base - 1)) == 0) {
996             /*
997              * The number may also be inaccurate for power-of-two bases.  This
998              * happens if the addition in value * base + digit causes a round-
999              * down to an even least significant mantissa bit when the first
1000              * dropped bit is a one.  If any of the following digits in the
1001              * number (which haven't been added in yet) are nonzero, then the
1002              * correct action would have been to round up instead of down.  An
1003              * example occurs when reading the number 0x1000000000000081, which
1004              * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1005              */
1006 0             struct BinaryDigitReader bdr;
1007 0             intN bit, bit2;
1008 0             intN j;
1009
1010 0             bdr.base = base;
1011 0             bdr.digitMask = 0;
1012 0             bdr.digits = start;
1013 0             bdr.end = s1;
1014 0             value = 0.0;
1015
1016             /* Skip leading zeros. */
1017 0             do {
1018 0                 bit = GetNextBinaryDigit(&bdr);
1019 0             } while (bit == 0);
1020
1021 0             if (bit == 1) {
1022                 /* Gather the 53 significant bits (including the leading 1) */
1023 0                 value = 1.0;
1024 0                 for (j = 52; j; j--) {
1025 0                     bit = GetNextBinaryDigit(&bdr);
1026 0                     if (bit < 0)
1027 0                         goto done;
1028 0                     value = value*2 + bit;
1029                 }
1030                 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1031 0                 bit2 = GetNextBinaryDigit(&bdr);
1032 0                 if (bit2 >= 0) {
1033 0                     jsdouble factor = 2.0;
1034 0                     intN sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
1035 0                     intN bit3;
1036
1037 0                     while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1038 0                         sticky |= bit3;
1039 0                         factor *= 2;
1040                     }
1041 0                     value += bit2 & (bit | sticky);
1042 0                     value *= factor;
1043                 }
1044               done:;
1045             }
1046         }
1047     }
1048     /* We don't worry about inaccurate numbers for any other base. */
1049
1050 0     if (s1 == start) {
1051 0         *dp = 0.0;
1052 0         *ep = s;
1053     } else {
1054 0         *dp = negative ? -value : value;
1055 0         *ep = s1;
1056     }
1057 0     return JS_TRUE;