~vaifrax/inkscape/bugfix170049

« back to all changes in this revision

Viewing changes to src/dom/js/jsnum.c

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
{
 
69
    jsdouble x;
 
70
 
 
71
    if (!js_ValueToNumber(cx, argv[0], &x))
 
72
        return JS_FALSE;
 
73
    *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
 
74
    return JS_TRUE;
 
75
}
 
76
 
 
77
static JSBool
 
78
num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
79
{
 
80
    jsdouble x;
 
81
 
 
82
    if (!js_ValueToNumber(cx, argv[0], &x))
 
83
        return JS_FALSE;
 
84
    *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
 
85
    return JS_TRUE;
 
86
}
 
87
 
 
88
static JSBool
 
89
num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
90
{
 
91
    JSString *str;
 
92
    jsdouble d;
 
93
    const jschar *bp, *ep;
 
94
 
 
95
    str = js_ValueToString(cx, argv[0]);
 
96
    if (!str)
 
97
        return JS_FALSE;
 
98
    /* XXXbe js_strtod shouldn't require NUL termination */
 
99
    bp = js_UndependString(cx, str);
 
100
    if (!bp)
 
101
        return JS_FALSE;
 
102
    if (!js_strtod(cx, bp, &ep, &d))
 
103
        return JS_FALSE;
 
104
    if (ep == bp) {
 
105
        *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
 
106
        return JS_TRUE;
 
107
    }
 
108
    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
{
 
115
    JSString *str;
 
116
    jsint radix;
 
117
    jsdouble d;
 
118
    const jschar *bp, *ep;
 
119
 
 
120
    str = js_ValueToString(cx, argv[0]);
 
121
    if (!str)
 
122
        return JS_FALSE;
 
123
 
 
124
    if (argc > 1) {
 
125
        if (!js_ValueToECMAInt32(cx, argv[1], &radix))
 
126
            return JS_FALSE;
 
127
    } else
 
128
        radix = 0;
 
129
 
 
130
    if (radix != 0 && (radix < 2 || radix > 36)) {
 
131
        *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
 
132
        return JS_TRUE;
 
133
    }
 
134
    /* XXXbe js_strtointeger shouldn't require NUL termination */
 
135
    bp = js_UndependString(cx, str);
 
136
    if (!bp)
 
137
        return JS_FALSE;
 
138
    if (!js_strtointeger(cx, bp, &ep, radix, &d))
 
139
        return JS_FALSE;
 
140
    if (ep == bp) {
 
141
        *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
 
142
        return JS_TRUE;
 
143
    }
 
144
    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
{
 
173
    jsdouble d;
 
174
    jsval v;
 
175
 
 
176
    if (argc != 0) {
 
177
        if (!js_ValueToNumber(cx, argv[0], &d))
 
178
            return JS_FALSE;
 
179
    } else {
 
180
        d = 0.0;
 
181
    }
 
182
    if (!js_NewNumberValue(cx, d, &v))
 
183
        return JS_FALSE;
 
184
    if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
 
185
        *rval = v;
 
186
        return JS_TRUE;
 
187
    }
 
188
    OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
 
189
    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
{
 
196
    jsval v;
 
197
    jsdouble d;
 
198
    char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
 
199
    char buf[64];
 
200
    JSString *str;
 
201
 
 
202
    if (!JS_InstanceOf(cx, obj, &number_class, argv))
 
203
        return JS_FALSE;
 
204
    v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
 
205
    JS_ASSERT(JSVAL_IS_NUMBER(v));
 
206
    d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
 
207
    numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
 
208
    if (!numStr) {
 
209
        JS_ReportOutOfMemory(cx);
 
210
        return JS_FALSE;
 
211
    }
 
212
    JS_snprintf(buf, sizeof buf, "(new %s(%s))", number_class.name, numStr);
 
213
    str = JS_NewStringCopyZ(cx, buf);
 
214
    if (!str)
 
215
        return JS_FALSE;
 
216
    *rval = STRING_TO_JSVAL(str);
 
217
    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
{
 
225
    char *cp;
 
226
    jsuint u;
 
227
    
 
228
    u = (i < 0) ? -i : i;
 
229
 
 
230
    cp = buf + bufSize; /* one past last buffer cell */
 
231
    *--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
    do {
 
238
        jsuint newu = u / 10;
 
239
        *--cp = (char)(u - newu * 10) + '0';
 
240
        u = newu;
 
241
    } while (u != 0);
 
242
    
 
243
    if (i < 0)
 
244
        *--cp = '-';
 
245
 
 
246
    return cp;
 
247
}
 
248
 
 
249
static JSBool
 
250
num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
251
{
 
252
    jsval v;
 
253
    jsdouble d;
 
254
    jsint base;
 
255
    JSString *str;
 
256
 
 
257
    if (!JS_InstanceOf(cx, obj, &number_class, argv))
 
258
        return JS_FALSE;
 
259
    v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
 
260
    JS_ASSERT(JSVAL_IS_NUMBER(v));
 
261
    d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
 
262
    base = 10;
 
263
    if (argc != 0) {
 
264
        if (!js_ValueToECMAInt32(cx, argv[0], &base))
 
265
            return JS_FALSE;
 
266
        if (base < 2 || base > 36) {
 
267
            char numBuf[12];
 
268
            char *numStr = IntToString(base, numBuf, sizeof numBuf);
 
269
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
 
270
                                 numStr);
 
271
            return JS_FALSE;
 
272
        }
 
273
    }
 
274
    if (base == 10)
 
275
        str = js_NumberToString(cx, d);
 
276
    else {
 
277
        char *dStr = JS_dtobasestr(base, d);
 
278
        if (!dStr) {
 
279
            JS_ReportOutOfMemory(cx);
 
280
            return JS_FALSE;
 
281
        }
 
282
        str = JS_NewStringCopyZ(cx, dStr);
 
283
        free(dStr);
 
284
    }
 
285
    if (!str)
 
286
        return JS_FALSE;
 
287
    *rval = STRING_TO_JSVAL(str);
 
288
    return JS_TRUE;
 
289
}
 
290
 
 
291
static JSBool
 
292
num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
 
293
                   jsval *argv, jsval *rval)
 
294
{
 
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
    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
{
 
307
    if (!JS_InstanceOf(cx, obj, &number_class, argv))
 
308
        return JS_FALSE;
 
309
    *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
 
310
    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
{
 
321
    jsval v;
 
322
    jsdouble d, precision;
 
323
    JSString *str;
 
324
    char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */
 
325
 
 
326
    if (!JS_InstanceOf(cx, obj, &number_class, argv))
 
327
        return JS_FALSE;
 
328
    v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
 
329
    JS_ASSERT(JSVAL_IS_NUMBER(v));
 
330
    d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
 
331
 
 
332
    if (JSVAL_IS_VOID(argv[0])) {
 
333
        precision = 0.0;
 
334
        oneArgMode = zeroArgMode;
 
335
    } else {
 
336
        if (!js_ValueToNumber(cx, argv[0], &precision))
 
337
            return JS_FALSE;
 
338
        precision = js_DoubleToInteger(precision);
 
339
        if (precision < precisionMin || precision > precisionMax) {
 
340
            numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
 
341
            if (!numStr)
 
342
                JS_ReportOutOfMemory(cx);
 
343
            else
 
344
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
 
345
            return JS_FALSE;
 
346
        }
 
347
    }
 
348
 
 
349
    numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
 
350
    if (!numStr) {
 
351
        JS_ReportOutOfMemory(cx);
 
352
        return JS_FALSE;
 
353
    }
 
354
    str = JS_NewStringCopyZ(cx, numStr);
 
355
    if (!str)
 
356
        return JS_FALSE;
 
357
    *rval = STRING_TO_JSVAL(str);
 
358
    return JS_TRUE;
 
359
}
 
360
 
 
361
static JSBool
 
362
num_toFixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
363
{
 
364
    /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
 
365
    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
{
 
371
    /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
 
372
    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
{
 
378
    /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */
 
379
    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
{
 
447
    JSRuntime *rt;
 
448
    jsdpun u;
 
449
 
 
450
    rt = cx->runtime;
 
451
    JS_ASSERT(!rt->jsNaN);
 
452
 
 
453
    FIX_FPU();
 
454
 
 
455
    u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
 
456
    u.s.lo = 0xffffffff;
 
457
    number_constants[NC_NaN].dval = NaN = u.d;
 
458
    rt->jsNaN = js_NewDouble(cx, NaN);
 
459
    if (!rt->jsNaN || !js_LockGCThing(cx, rt->jsNaN))
 
460
        return JS_FALSE;
 
461
 
 
462
    u.s.hi = JSDOUBLE_HI32_EXPMASK;
 
463
    u.s.lo = 0x00000000;
 
464
    number_constants[NC_POSITIVE_INFINITY].dval = u.d;
 
465
    rt->jsPositiveInfinity = js_NewDouble(cx, u.d);
 
466
    if (!rt->jsPositiveInfinity ||
 
467
        !js_LockGCThing(cx, rt->jsPositiveInfinity)) {
 
468
        return JS_FALSE;
 
469
    }
 
470
 
 
471
    u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
 
472
    u.s.lo = 0x00000000;
 
473
    number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
 
474
    rt->jsNegativeInfinity = js_NewDouble(cx, u.d);
 
475
    if (!rt->jsNegativeInfinity ||
 
476
        !js_LockGCThing(cx, rt->jsNegativeInfinity)) {
 
477
        return JS_FALSE;
 
478
    }
 
479
 
 
480
    u.s.hi = 0;
 
481
    u.s.lo = 1;
 
482
    number_constants[NC_MIN_VALUE].dval = u.d;
 
483
 
 
484
    return JS_TRUE;
 
485
}
 
486
 
 
487
void
 
488
js_FinishRuntimeNumberState(JSContext *cx)
 
489
{
 
490
    JSRuntime *rt = cx->runtime;
 
491
 
 
492
    js_UnlockGCThingRT(rt, rt->jsNaN);
 
493
    js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
 
494
    js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
 
495
 
 
496
    rt->jsNaN = NULL;
 
497
    rt->jsNegativeInfinity = NULL;
 
498
    rt->jsPositiveInfinity = NULL;
 
499
}
 
500
 
 
501
JSObject *
 
502
js_InitNumberClass(JSContext *cx, JSObject *obj)
 
503
{
 
504
    JSObject *proto, *ctor;
 
505
    JSRuntime *rt;
 
506
 
 
507
    /* XXX must do at least once per new thread, so do it per JSContext... */
 
508
    FIX_FPU();
 
509
 
 
510
    if (!JS_DefineFunctions(cx, obj, number_functions))
 
511
        return NULL;
 
512
 
 
513
    proto = JS_InitClass(cx, obj, NULL, &number_class, Number, 1,
 
514
                         NULL, number_methods, NULL, NULL);
 
515
    if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
 
516
        return NULL;
 
517
    OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE, JSVAL_ZERO);
 
518
    if (!JS_DefineConstDoubles(cx, ctor, number_constants))
 
519
        return NULL;
 
520
 
 
521
    /* ECMA 15.1.1.1 */
 
522
    rt = cx->runtime;
 
523
    if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
 
524
                           NULL, NULL, JSPROP_PERMANENT)) {
 
525
        return NULL;
 
526
    }
 
527
 
 
528
    /* ECMA 15.1.1.2 */
 
529
    if (!JS_DefineProperty(cx, obj, js_Infinity_str,
 
530
                           DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
 
531
                           NULL, NULL, JSPROP_PERMANENT)) {
 
532
        return NULL;
 
533
    }
 
534
    return proto;
 
535
}
 
536
 
 
537
jsdouble *
 
538
js_NewDouble(JSContext *cx, jsdouble d)
 
539
{
 
540
    jsdouble *dp;
 
541
 
 
542
    dp = (jsdouble *) js_AllocGCThing(cx, GCX_DOUBLE);
 
543
    if (!dp)
 
544
        return NULL;
 
545
    *dp = d;
 
546
    return dp;
 
547
}
 
548
 
 
549
void
 
550
js_FinalizeDouble(JSContext *cx, jsdouble *dp)
 
551
{
 
552
    *dp = NaN;
 
553
}
 
554
 
 
555
JSBool
 
556
js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
 
557
{
 
558
    jsdouble *dp;
 
559
 
 
560
    dp = js_NewDouble(cx, d);
 
561
    if (!dp)
 
562
        return JS_FALSE;
 
563
    *rval = DOUBLE_TO_JSVAL(dp);
 
564
    return JS_TRUE;
 
565
}
 
566
 
 
567
JSBool
 
568
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
 
569
{
 
570
    jsint i;
 
571
    JSBool ok;
 
572
 
 
573
    SET_FPU();
 
574
 
 
575
    if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
 
576
        *rval = INT_TO_JSVAL(i);
 
577
        ok = JS_TRUE;
 
578
    } else {
 
579
        ok = js_NewDoubleValue(cx, d, rval);
 
580
    }
 
581
    
 
582
    RESTORE_FPU();
 
583
    return ok;
 
584
}
 
585
 
 
586
JSObject *
 
587
js_NumberToObject(JSContext *cx, jsdouble d)
 
588
{
 
589
    JSObject *obj;
 
590
    jsval v;
 
591
 
 
592
    obj = js_NewObject(cx, &number_class, NULL, NULL);
 
593
    if (!obj)
 
594
        return NULL;
 
595
    if (!js_NewNumberValue(cx, d, &v)) {
 
596
        cx->newborn[GCX_OBJECT] = NULL;
 
597
        return NULL;
 
598
    }
 
599
    OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
 
600
    return obj;
 
601
}
 
602
 
 
603
JSString *
 
604
js_NumberToString(JSContext *cx, jsdouble d)
 
605
{
 
606
    jsint i;
 
607
    char buf[DTOSTR_STANDARD_BUFFER_SIZE];
 
608
    char *numStr;
 
609
 
 
610
    if (JSDOUBLE_IS_INT(d, i))
 
611
        numStr = IntToString(i, buf, sizeof buf);
 
612
    else {
 
613
        numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
 
614
        if (!numStr) {
 
615
            JS_ReportOutOfMemory(cx);
 
616
            return NULL;
 
617
        }
 
618
    }
 
619
    return JS_NewStringCopyZ(cx, numStr);
 
620
}
 
621
 
 
622
JSBool
 
623
js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
 
624
{
 
625
    JSObject *obj;
 
626
    JSString *str;
 
627
    const jschar *bp, *ep;
 
628
 
 
629
    if (JSVAL_IS_OBJECT(v)) {
 
630
        obj = JSVAL_TO_OBJECT(v);
 
631
        if (!obj) {
 
632
            *dp = 0;
 
633
            return JS_TRUE;
 
634
        }
 
635
        if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
 
636
            return JS_FALSE;
 
637
    }
 
638
    if (JSVAL_IS_INT(v)) {
 
639
        *dp = (jsdouble)JSVAL_TO_INT(v);
 
640
    } else if (JSVAL_IS_DOUBLE(v)) {
 
641
        *dp = *JSVAL_TO_DOUBLE(v);
 
642
    } else if (JSVAL_IS_STRING(v)) {
 
643
        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
        bp = js_UndependString(cx, str);
 
652
        if (!bp)
 
653
            return JS_FALSE;
 
654
        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
            goto badstr;
 
659
        }
 
660
    } else if (JSVAL_IS_BOOLEAN(v)) {
 
661
        *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
        *dp = *cx->runtime->jsNaN;
 
675
#endif
 
676
    }
 
677
    return JS_TRUE;
 
678
}
 
679
 
 
680
JSBool
 
681
js_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
 
682
{
 
683
    jsdouble d;
 
684
 
 
685
    if (!js_ValueToNumber(cx, v, &d))
 
686
        return JS_FALSE;
 
687
    return js_DoubleToECMAInt32(cx, d, ip);
 
688
}
 
689
 
 
690
JSBool
 
691
js_DoubleToECMAInt32(JSContext *cx, jsdouble d, int32 *ip)
 
692
{
 
693
    jsdouble two32 = 4294967296.0;
 
694
    jsdouble two31 = 2147483648.0;
 
695
 
 
696
    if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
 
697
        *ip = 0;
 
698
        return JS_TRUE;
 
699
    }
 
700
    d = fmod(d, two32);
 
701
    d = (d >= 0) ? floor(d) : ceil(d) + two32;
 
702
    if (d >= two31)
 
703
        *ip = (int32)(d - two32);
 
704
    else
 
705
        *ip = (int32)d;
 
706
    return JS_TRUE;
 
707
}
 
708
 
 
709
JSBool
 
710
js_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
 
711
{
 
712
    jsdouble d;
 
713
 
 
714
    if (!js_ValueToNumber(cx, v, &d))
 
715
        return JS_FALSE;
 
716
    return js_DoubleToECMAUint32(cx, d, ip);
 
717
}
 
718
 
 
719
JSBool
 
720
js_DoubleToECMAUint32(JSContext *cx, jsdouble d, uint32 *ip)
 
721
{
 
722
    JSBool neg;
 
723
    jsdouble two32 = 4294967296.0;
 
724
 
 
725
    if (!JSDOUBLE_IS_FINITE(d) || d == 0) {
 
726
        *ip = 0;
 
727
        return JS_TRUE;
 
728
    }
 
729
 
 
730
    neg = (d < 0);
 
731
    d = floor(neg ? -d : d);
 
732
    d = neg ? -d : d;
 
733
 
 
734
    d = fmod(d, two32);
 
735
 
 
736
    d = (d >= 0) ? d : d + two32;
 
737
    *ip = (uint32)d;
 
738
    return JS_TRUE;
 
739
}
 
740
 
 
741
JSBool
 
742
js_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
 
743
{
 
744
    jsdouble d;
 
745
    JSString *str;
 
746
 
 
747
    if (JSVAL_IS_INT(v)) {
 
748
        *ip = JSVAL_TO_INT(v);
 
749
        return JS_TRUE;
 
750
    }
 
751
    if (!js_ValueToNumber(cx, v, &d))
 
752
        return JS_FALSE;
 
753
    if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
 
754
        str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
 
755
        if (str) {
 
756
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
757
                                 JSMSG_CANT_CONVERT, JS_GetStringBytes(str));
 
758
 
 
759
        }
 
760
        return JS_FALSE;
 
761
    }
 
762
    *ip = (int32)floor(d + 0.5);     /* Round to nearest */
 
763
    return JS_TRUE;
 
764
}
 
765
 
 
766
JSBool
 
767
js_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
 
768
{
 
769
    jsdouble d;
 
770
    jsuint i, m;
 
771
    JSBool neg;
 
772
 
 
773
    if (!js_ValueToNumber(cx, v, &d))
 
774
        return JS_FALSE;
 
775
    if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
 
776
        *ip = 0;
 
777
        return JS_TRUE;
 
778
    }
 
779
    i = (jsuint)d;
 
780
    if ((jsdouble)i == d) {
 
781
        *ip = (uint16)i;
 
782
        return JS_TRUE;
 
783
    }
 
784
    neg = (d < 0);
 
785
    d = floor(neg ? -d : d);
 
786
    d = neg ? -d : d;
 
787
    m = JS_BIT(16);
 
788
    d = fmod(d, (double)m);
 
789
    if (d < 0)
 
790
        d += m;
 
791
    *ip = (uint16) d;
 
792
    return JS_TRUE;
 
793
}
 
794
 
 
795
jsdouble
 
796
js_DoubleToInteger(jsdouble d)
 
797
{
 
798
    JSBool neg;
 
799
 
 
800
    if (d == 0)
 
801
        return d;
 
802
    if (!JSDOUBLE_IS_FINITE(d)) {
 
803
        if (JSDOUBLE_IS_NaN(d))
 
804
            return 0;
 
805
        return d;
 
806
    }
 
807
    neg = (d < 0);
 
808
    d = floor(neg ? -d : d);
 
809
    return neg ? -d : d;
 
810
}
 
811
 
 
812
 
 
813
JSBool
 
814
js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
 
815
{
 
816
    char cbuf[32];
 
817
    size_t i;
 
818
    char *cstr, *istr, *estr;
 
819
    JSBool negative;
 
820
    jsdouble d;
 
821
    const jschar *s1 = js_SkipWhiteSpace(s);
 
822
    size_t length = js_strlen(s1);
 
823
 
 
824
    /* Use cbuf to avoid malloc */
 
825
    if (length >= sizeof cbuf) {
 
826
        cstr = (char *) JS_malloc(cx, length + 1);
 
827
        if (!cstr)
 
828
           return JS_FALSE;
 
829
    } else {
 
830
        cstr = cbuf;
 
831
    }
 
832
   
 
833
    for (i = 0; i <= length; i++) {
 
834
        if (s1[i] >> 8) {
 
835
            cstr[i] = 0;
 
836
            break;
 
837
        }
 
838
        cstr[i] = (char)s1[i];
 
839
    }
 
840
 
 
841
    istr = cstr;
 
842
    if ((negative = (*istr == '-')) != 0 || *istr == '+')
 
843
        istr++;
 
844
    if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
 
845
        d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
 
846
        estr = istr + 8;
 
847
    } else {
 
848
        int err;
 
849
        d = JS_strtod(cstr, &estr, &err);
 
850
        if (err == JS_DTOA_ENOMEM) {
 
851
            JS_ReportOutOfMemory(cx);
 
852
            if (cstr != cbuf)
 
853
                JS_free(cx, cstr);
 
854
            return JS_FALSE;
 
855
        }
 
856
        if (err == JS_DTOA_ERANGE) {
 
857
            if (d == HUGE_VAL)
 
858
                d = *cx->runtime->jsPositiveInfinity;
 
859
            else if (d == -HUGE_VAL)
 
860
                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
    i = estr - cstr;
 
875
    if (cstr != cbuf)
 
876
        JS_free(cx, cstr);
 
877
    *ep = i ? s1 + i : s;
 
878
    *dp = d;
 
879
    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
{
 
894
    intN bit;
 
895
 
 
896
    if (bdr->digitMask == 0) {
 
897
        uintN c;
 
898
 
 
899
        if (bdr->digits == bdr->end)
 
900
            return -1;
 
901
 
 
902
        c = *bdr->digits++;
 
903
        if ('0' <= c && c <= '9')
 
904
            bdr->digit = c - '0';
 
905
        else if ('a' <= c && c <= 'z')
 
906
            bdr->digit = c - 'a' + 10;
 
907
        else bdr->digit = c - 'A' + 10;
 
908
        bdr->digitMask = bdr->base >> 1;
 
909
    }
 
910
    bit = (bdr->digit & bdr->digitMask) != 0;
 
911
    bdr->digitMask >>= 1;
 
912
    return bit;
 
913
}
 
914
 
 
915
JSBool
 
916
js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
 
917
{
 
918
    JSBool negative;
 
919
    jsdouble value;
 
920
    const jschar *start;
 
921
    const jschar *s1 = js_SkipWhiteSpace(s);
 
922
 
 
923
    if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
 
924
        s1++;
 
925
 
 
926
    if (base == 0) {
 
927
        /* No base supplied, or some base that evaluated to 0. */
 
928
        if (*s1 == '0') {
 
929
            /* It's either hex or octal; only increment char if str isn't '0' */
 
930
            if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
 
931
                s1 += 2;
 
932
                base = 16;
 
933
            } else {    /* Octal */
 
934
                base = 8;
 
935
            }
 
936
        } else {
 
937
            base = 10; /* Default to decimal. */
 
938
        }
 
939
    } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
 
940
        /* If base is 16, ignore hex prefix. */
 
941
        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
    start = s1; /* Mark - if string is empty, we return NaN. */
 
949
    value = 0.0;
 
950
    for (;;) {
 
951
        uintN digit;
 
952
        jschar c = *s1;
 
953
        if ('0' <= c && c <= '9')
 
954
            digit = c - '0';
 
955
        else if ('a' <= c && c <= 'z')
 
956
            digit = c - 'a' + 10;
 
957
        else if ('A' <= c && c <= 'Z')
 
958
            digit = c - 'A' + 10;
 
959
        else
 
960
            break;
 
961
        if (digit >= (uintN)base)
 
962
            break;
 
963
        value = value * base + digit;
 
964
        s1++;
 
965
    }
 
966
 
 
967
    if (value >= 9007199254740992.0) {
 
968
        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
            size_t i;
 
975
            size_t length = s1 - start;
 
976
            char *cstr = (char *) JS_malloc(cx, length + 1);
 
977
            char *estr;
 
978
            int err=0;
 
979
 
 
980
            if (!cstr)
 
981
                return JS_FALSE;
 
982
            for (i = 0; i != length; i++)
 
983
                cstr[i] = (char)start[i];
 
984
            cstr[length] = 0;
 
985
 
 
986
            value = JS_strtod(cstr, &estr, &err);
 
987
            if (err == JS_DTOA_ENOMEM) {
 
988
                JS_ReportOutOfMemory(cx);
 
989
                JS_free(cx, cstr);
 
990
                return JS_FALSE;
 
991
            }
 
992
            if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
 
993
                value = *cx->runtime->jsPositiveInfinity;
 
994
            JS_free(cx, cstr);
 
995
        } 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
            struct BinaryDigitReader bdr;
 
1007
            intN bit, bit2;
 
1008
            intN j;
 
1009
 
 
1010
            bdr.base = base;
 
1011
            bdr.digitMask = 0;
 
1012
            bdr.digits = start;
 
1013
            bdr.end = s1;
 
1014
            value = 0.0;
 
1015
 
 
1016
            /* Skip leading zeros. */
 
1017
            do {
 
1018
                bit = GetNextBinaryDigit(&bdr);
 
1019
            } while (bit == 0);
 
1020
 
 
1021
            if (bit == 1) {
 
1022
                /* Gather the 53 significant bits (including the leading 1) */
 
1023
                value = 1.0;
 
1024
                for (j = 52; j; j--) {
 
1025
                    bit = GetNextBinaryDigit(&bdr);
 
1026
                    if (bit < 0)
 
1027
                        goto done;
 
1028
                    value = value*2 + bit;
 
1029
                }
 
1030
                /* bit2 is the 54th bit (the first dropped from the mantissa) */
 
1031
                bit2 = GetNextBinaryDigit(&bdr);
 
1032
                if (bit2 >= 0) {
 
1033
                    jsdouble factor = 2.0;
 
1034
                    intN sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
 
1035
                    intN bit3;
 
1036
 
 
1037
                    while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
 
1038
                        sticky |= bit3;
 
1039
                        factor *= 2;
 
1040
                    }
 
1041
                    value += bit2 & (bit | sticky);
 
1042
                    value *= factor;
 
1043
                }
 
1044
              done:;
 
1045
            }
 
1046
        }
 
1047
    }
 
1048
    /* We don't worry about inaccurate numbers for any other base. */
 
1049
 
 
1050
    if (s1 == start) {
 
1051
        *dp = 0.0;
 
1052
        *ep = s;
 
1053
    } else {
 
1054
        *dp = negative ? -value : value;
 
1055
        *ep = s1;
 
1056
    }
 
1057
    return JS_TRUE;
 
1058
}