📄 jsnum.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * IBM Corp. * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS number type and wrapper class. */#include "jsstddef.h"#if defined(XP_WIN) || defined(XP_OS2)#include <float.h>#endif#include <locale.h>#include <limits.h>#include <math.h>#include <stdlib.h>#include <string.h>#include "jstypes.h"#include "jsutil.h" /* Added by JSIFY */#include "jsapi.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsdtoa.h"#include "jsgc.h"#include "jsinterp.h"#include "jsnum.h"#include "jsobj.h"#include "jsopcode.h"#include "jsprf.h"#include "jsstr.h"static JSBoolnum_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsdouble x; if (!js_ValueToNumber(cx, argv[0], &x)) return JS_FALSE; *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x)); return JS_TRUE;}static JSBoolnum_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsdouble x; if (!js_ValueToNumber(cx, argv[0], &x)) return JS_FALSE; *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x)); return JS_TRUE;}static JSBoolnum_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ JSString *str; jsdouble d; const jschar *bp, *ep; str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; /* XXXbe js_strtod shouldn't require NUL termination */ bp = js_UndependString(cx, str); if (!bp) return JS_FALSE; if (!js_strtod(cx, bp, &ep, &d)) return JS_FALSE; if (ep == bp) { *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } return js_NewNumberValue(cx, d, rval);}/* See ECMA 15.1.2.2. */static JSBoolnum_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsint radix; JSString *str; jsdouble d; const jschar *bp, *ep; if (argc > 1) { if (!js_ValueToECMAInt32(cx, argv[1], &radix)) return JS_FALSE; } else { radix = 0; } if (radix != 0 && (radix < 2 || radix > 36)) { *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; /* XXXbe js_strtointeger shouldn't require NUL termination */ bp = js_UndependString(cx, str); if (!bp) return JS_FALSE; if (!js_strtointeger(cx, bp, &ep, radix, &d)) return JS_FALSE; if (ep == bp) { *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } return js_NewNumberValue(cx, d, rval);}const char js_Infinity_str[] = "Infinity";const char js_NaN_str[] = "NaN";const char js_isNaN_str[] = "isNaN";const char js_isFinite_str[] = "isFinite";const char js_parseFloat_str[] = "parseFloat";const char js_parseInt_str[] = "parseInt";static JSFunctionSpec number_functions[] = { {js_isNaN_str, num_isNaN, 1,0,0}, {js_isFinite_str, num_isFinite, 1,0,0}, {js_parseFloat_str, num_parseFloat, 1,0,0}, {js_parseInt_str, num_parseInt, 2,0,0}, {0,0,0,0,0}};JSClass js_NumberClass = { js_Number_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};static JSBoolNumber(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsdouble d; jsval v; if (argc != 0) { if (!js_ValueToNumber(cx, argv[0], &d)) return JS_FALSE; } else { d = 0.0; } if (!js_NewNumberValue(cx, d, &v)) return JS_FALSE; if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { *rval = v; return JS_TRUE; } OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v); return JS_TRUE;}#if JS_HAS_TOSOURCEstatic JSBoolnum_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval v; jsdouble d; char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr; char buf[64]; JSString *str; if (JSVAL_IS_NUMBER((jsval)obj)) { v = (jsval)obj; } else { if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) return JS_FALSE; v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); JS_ASSERT(JSVAL_IS_NUMBER(v)); } d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); if (!numStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; } JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); return JS_TRUE;}#endif/* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */static char *IntToString(jsint i, char *buf, size_t bufSize){ char *cp; jsuint u; u = (i < 0) ? -i : i; cp = buf + bufSize; /* one past last buffer cell */ *--cp = '\0'; /* null terminate the string to be */ /* * Build the string from behind. We use multiply and subtraction * instead of modulus because that's much faster. */ do { jsuint newu = u / 10; *--cp = (char)(u - newu * 10) + '0'; u = newu; } while (u != 0); if (i < 0) *--cp = '-'; return cp;}static JSBoolnum_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval v; jsdouble d; jsint base; JSString *str; if (JSVAL_IS_NUMBER((jsval)obj)) { v = (jsval)obj; } else { if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) return JS_FALSE; v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); JS_ASSERT(JSVAL_IS_NUMBER(v)); } d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); base = 10; if (argc != 0) { if (!js_ValueToECMAInt32(cx, argv[0], &base)) return JS_FALSE; if (base < 2 || base > 36) { char numBuf[12]; char *numStr = IntToString(base, numBuf, sizeof numBuf); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX, numStr); return JS_FALSE; } } if (base == 10) { str = js_NumberToString(cx, d); } else { char *dStr = JS_dtobasestr(base, d); if (!dStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; } str = JS_NewStringCopyZ(cx, dStr); free(dStr); } if (!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); return JS_TRUE;}static JSBoolnum_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ char thousandsLength, decimalLength; const char *numGrouping, *tmpGroup; JSRuntime *rt; JSString *numStr, *str; char *num, *buf, *dec, *end, *tmpSrc, *tmpDest; int digits, size, remainder, nrepeat; /* * Create the string, move back to bytes to make string twiddling * a bit easier and so we can insert platform charset seperators. */ if (!num_toString(cx, obj, 0, argv, rval)) return JS_FALSE; JS_ASSERT(JSVAL_IS_STRING(*rval)); numStr = JSVAL_TO_STRING(*rval); num = js_GetStringBytes(cx->runtime, numStr); /* Find bit before the decimal. */ dec = strchr(num, '.'); digits = dec ? dec - num : (int)strlen(num); end = num + digits; rt = cx->runtime; thousandsLength = strlen(rt->thousandsSeparator); decimalLength = strlen(rt->decimalSeparator); /* Figure out how long resulting string will be. */ size = digits + (dec ? decimalLength + strlen(dec + 1) : 0); numGrouping = tmpGroup = rt->numGrouping; remainder = digits; if (*num == '-') remainder--; while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { if (*tmpGroup >= remainder) break; size += thousandsLength; remainder -= *tmpGroup; tmpGroup++; } if (*tmpGroup == '\0' && *numGrouping != '\0') { nrepeat = (remainder - 1) / tmpGroup[-1]; size += thousandsLength * nrepeat; remainder -= nrepeat * tmpGroup[-1]; } else { nrepeat = 0; } tmpGroup--; buf = (char *)JS_malloc(cx, size + 1); if (!buf) return JS_FALSE; tmpDest = buf; tmpSrc = num; while (*tmpSrc == '-' || remainder--) *tmpDest++ = *tmpSrc++; while (tmpSrc < end) { strcpy(tmpDest, rt->thousandsSeparator); tmpDest += thousandsLength; memcpy(tmpDest, tmpSrc, *tmpGroup); tmpDest += *tmpGroup; tmpSrc += *tmpGroup; if (--nrepeat < 0) tmpGroup--; } if (dec) { strcpy(tmpDest, rt->decimalSeparator); tmpDest += decimalLength; strcpy(tmpDest, dec + 1); } else { *tmpDest++ = '\0'; } if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) return cx->localeCallbacks->localeToUnicode(cx, buf, rval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -