diff options
| author | Aaron Spike <aaron@ekips.org> | 2006-04-12 13:20:54 +0000 |
|---|---|---|
| committer | acspike <acspike@users.sourceforge.net> | 2006-04-12 13:20:54 +0000 |
| commit | ddfaffe08d23e4663fe759d67ae33fd67fc9ce5b (patch) | |
| tree | 234f5425a7ef7058e69dc2ab77f89810e4f3ed91 /src/dom/js/jsdate.c | |
| parent | fix 1466070 (diff) | |
| download | inkscape-ddfaffe08d23e4663fe759d67ae33fd67fc9ce5b.tar.gz inkscape-ddfaffe08d23e4663fe759d67ae33fd67fc9ce5b.zip | |
Removed file/folder for ishmal
(bzr r478)
Diffstat (limited to 'src/dom/js/jsdate.c')
| -rw-r--r-- | src/dom/js/jsdate.c | 2234 |
1 files changed, 0 insertions, 2234 deletions
diff --git a/src/dom/js/jsdate.c b/src/dom/js/jsdate.c deleted file mode 100644 index a88df1830..000000000 --- a/src/dom/js/jsdate.c +++ /dev/null @@ -1,2234 +0,0 @@ -/* -*- 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): - * - * 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 date methods. - */ - -/* - * "For example, OS/360 devotes 26 bytes of the permanently - * resident date-turnover routine to the proper handling of - * December 31 on leap years (when it is Day 366). That - * might have been left to the operator." - * - * Frederick Brooks, 'The Second-System Effect'. - */ - -#include "jsstddef.h" -#include <ctype.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> -#include "jstypes.h" -#include "jsprf.h" -#include "prmjtime.h" -#include "jsutil.h" /* Added by JSIFY */ -#include "jsapi.h" -#include "jsconfig.h" -#include "jscntxt.h" -#include "jsdate.h" -#include "jsinterp.h" -#include "jsnum.h" -#include "jsobj.h" -#include "jsstr.h" - -/* - * The JS 'Date' object is patterned after the Java 'Date' object. - * Here is an script: - * - * today = new Date(); - * - * print(today.toLocaleString()); - * - * weekDay = today.getDay(); - * - * - * These Java (and ECMA-262) methods are supported: - * - * UTC - * getDate (getUTCDate) - * getDay (getUTCDay) - * getHours (getUTCHours) - * getMinutes (getUTCMinutes) - * getMonth (getUTCMonth) - * getSeconds (getUTCSeconds) - * getMilliseconds (getUTCMilliseconds) - * getTime - * getTimezoneOffset - * getYear - * getFullYear (getUTCFullYear) - * parse - * setDate (setUTCDate) - * setHours (setUTCHours) - * setMinutes (setUTCMinutes) - * setMonth (setUTCMonth) - * setSeconds (setUTCSeconds) - * setMilliseconds (setUTCMilliseconds) - * setTime - * setYear (setFullYear, setUTCFullYear) - * toGMTString (toUTCString) - * toLocaleString - * toString - * - * - * These Java methods are not supported - * - * setDay - * before - * after - * equals - * hashCode - */ - -/* - * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language - * definition and reduce dependence on NSPR. NSPR is used to get the current - * time in milliseconds, the time zone offset, and the daylight savings time - * offset for a given time. NSPR is also used for Date.toLocaleString(), for - * locale-specific formatting, and to get a string representing the timezone. - * (Which turns out to be platform-dependent.) - * - * To do: - * (I did some performance tests by timing how long it took to run what - * I had of the js ECMA conformance tests.) - * - * - look at saving results across multiple calls to supporting - * functions; the toString functions compute some of the same values - * multiple times. Although - I took a quick stab at this, and I lost - * rather than gained. (Fractionally.) Hard to tell what compilers/processors - * are doing these days. - * - * - look at tweaking function return types to return double instead - * of int; this seems to make things run slightly faster sometimes. - * (though it could be architecture-dependent.) It'd be good to see - * how this does on win32. (Tried it on irix.) Types could use a - * general going-over. - */ - -/* - * Supporting functions - ECMA 15.9.1.* - */ - -#define HalfTimeDomain 8.64e15 -#define HoursPerDay 24.0 -#define MinutesPerDay (HoursPerDay * MinutesPerHour) -#define MinutesPerHour 60.0 -#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) -#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) -#define SecondsPerMinute 60.0 - -#if defined(XP_WIN) || defined(XP_OS2) -/* Work around msvc double optimization bug by making these runtime values; if - * they're available at compile time, msvc optimizes division by them by - * computing the reciprocal and multiplying instead of dividing - this loses - * when the reciprocal isn't representable in a double. - */ -static jsdouble msPerSecond = 1000.0; -static jsdouble msPerDay = SecondsPerDay * 1000.0; -static jsdouble msPerHour = SecondsPerHour * 1000.0; -static jsdouble msPerMinute = SecondsPerMinute * 1000.0; -#else -#define msPerDay (SecondsPerDay * msPerSecond) -#define msPerHour (SecondsPerHour * msPerSecond) -#define msPerMinute (SecondsPerMinute * msPerSecond) -#define msPerSecond 1000.0 -#endif - -#define Day(t) floor((t) / msPerDay) - -static jsdouble -TimeWithinDay(jsdouble t) -{ - jsdouble result; - result = fmod(t, msPerDay); - if (result < 0) - result += msPerDay; - return result; -} - -#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \ - ? 366 : 365) - -/* math here has to be f.p, because we need - * floor((1968 - 1969) / 4) == -1 - */ -#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \ - - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0)) -#define TimeFromYear(y) (DayFromYear(y) * msPerDay) - -static jsint -YearFromTime(jsdouble t) -{ - jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970; - jsdouble t2 = (jsdouble) TimeFromYear(y); - - if (t2 > t) { - y--; - } else { - if (t2 + msPerDay * DaysInYear(y) <= t) - y++; - } - return y; -} - -#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366) - -#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year))) - -/* - * The following array contains the day of year for the first day of - * each month, where index 0 is January, and day 0 is January 1. - */ -static jsdouble firstDayOfMonth[2][12] = { - {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0}, - {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0} -}; - -#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m]; - -static intN -MonthFromTime(jsdouble t) -{ - intN d, step; - jsint year = YearFromTime(t); - d = DayWithinYear(t, year); - - if (d < (step = 31)) - return 0; - step += (InLeapYear(t) ? 29 : 28); - if (d < step) - return 1; - if (d < (step += 31)) - return 2; - if (d < (step += 30)) - return 3; - if (d < (step += 31)) - return 4; - if (d < (step += 30)) - return 5; - if (d < (step += 31)) - return 6; - if (d < (step += 31)) - return 7; - if (d < (step += 30)) - return 8; - if (d < (step += 31)) - return 9; - if (d < (step += 30)) - return 10; - return 11; -} - -static intN -DateFromTime(jsdouble t) -{ - intN d, step, next; - jsint year = YearFromTime(t); - d = DayWithinYear(t, year); - - if (d <= (next = 30)) - return d + 1; - step = next; - next += (InLeapYear(t) ? 29 : 28); - if (d <= next) - return d - step; - step = next; - if (d <= (next += 31)) - return d - step; - step = next; - if (d <= (next += 30)) - return d - step; - step = next; - if (d <= (next += 31)) - return d - step; - step = next; - if (d <= (next += 30)) - return d - step; - step = next; - if (d <= (next += 31)) - return d - step; - step = next; - if (d <= (next += 31)) - return d - step; - step = next; - if (d <= (next += 30)) - return d - step; - step = next; - if (d <= (next += 31)) - return d - step; - step = next; - if (d <= (next += 30)) - return d - step; - step = next; - return d - step; -} - -static intN -WeekDay(jsdouble t) -{ - jsint result; - result = (jsint) Day(t) + 4; - result = result % 7; - if (result < 0) - result += 7; - return (intN) result; -} - -/* LocalTZA gets set by js_InitDateClass() */ -static jsdouble LocalTZA; - -static jsdouble -DaylightSavingTA(jsdouble t) -{ - volatile int64 PR_t; - int64 ms2us; - int64 offset; - jsdouble result; - - /* abort if NaN */ - if (JSDOUBLE_IS_NaN(t)) - return t; - - /* put our t in an LL, and map it to usec for prtime */ - JSLL_D2L(PR_t, t); - JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC); - JSLL_MUL(PR_t, PR_t, ms2us); - - offset = PRMJ_DSTOffset(PR_t); - - JSLL_DIV(offset, offset, ms2us); - JSLL_L2D(result, offset); - return result; -} - - -#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay) - -#define LocalTime(t) ((t) + AdjustTime(t)) - -static jsdouble -UTC(jsdouble t) -{ - return t - AdjustTime(t - LocalTZA); -} - -static intN -HourFromTime(jsdouble t) -{ - intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay); - if (result < 0) - result += (intN)HoursPerDay; - return result; -} - -static intN -MinFromTime(jsdouble t) -{ - intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour); - if (result < 0) - result += (intN)MinutesPerHour; - return result; -} - -static intN -SecFromTime(jsdouble t) -{ - intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute); - if (result < 0) - result += (intN)SecondsPerMinute; - return result; -} - -static intN -msFromTime(jsdouble t) -{ - intN result = (intN) fmod(t, msPerSecond); - if (result < 0) - result += (intN)msPerSecond; - return result; -} - -#define MakeTime(hour, min, sec, ms) \ -(((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms) - -static jsdouble -MakeDay(jsdouble year, jsdouble month, jsdouble date) -{ - jsdouble result; - JSBool leap; - jsdouble yearday; - jsdouble monthday; - - year += floor(month / 12); - - month = fmod(month, 12.0); - if (month < 0) - month += 12; - - leap = (DaysInYear((jsint) year) == 366); - - yearday = floor(TimeFromYear(year) / msPerDay); - monthday = DayFromMonth(month, leap); - - result = yearday - + monthday - + date - 1; - return result; -} - -#define MakeDate(day, time) (day * msPerDay + time) - -#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ - && !((d < 0 ? -d : d) > HalfTimeDomain)) \ - ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN) - -/** - * end of ECMA 'support' functions - */ - -/* - * Other Support routines and definitions - */ - -static JSClass date_class = { - js_Date_str, - JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, - JSCLASS_NO_OPTIONAL_MEMBERS -}; - -/* for use by date_parse */ - -static const char* wtb[] = { - "am", "pm", - "monday", "tuesday", "wednesday", "thursday", "friday", - "saturday", "sunday", - "january", "february", "march", "april", "may", "june", - "july", "august", "september", "october", "november", "december", - "gmt", "ut", "utc", - "est", "edt", - "cst", "cdt", - "mst", "mdt", - "pst", "pdt" - /* time zone table needs to be expanded */ -}; - -static int ttb[] = { - -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */ - 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */ - 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */ - 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */ - 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */ -}; - -/* helper for date_parse */ -static JSBool -date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, - int count, int ignoreCase) -{ - JSBool result = JS_FALSE; - /* return true if matches, otherwise, false */ - - while (count > 0 && s1[s1off] && s2[s2off]) { - if (ignoreCase) { - if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) { - break; - } - } else { - if ((jschar)s1[s1off] != s2[s2off]) { - break; - } - } - s1off++; - s2off++; - count--; - } - - if (count == 0) { - result = JS_TRUE; - } - - return result; -} - -/* find UTC time from given date... no 1900 correction! */ -static jsdouble -date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, - jsdouble min, jsdouble sec, jsdouble msec) -{ - jsdouble day; - jsdouble msec_time; - jsdouble result; - - day = MakeDay(year, mon, mday); - msec_time = MakeTime(hour, min, sec, msec); - result = MakeDate(day, msec_time); - return result; -} - -/* - * See ECMA 15.9.4.[3-10]; - */ -/* XXX this function must be above date_parseString to avoid a - horrid bug in the Win16 1.52 compiler */ -#define MAXARGS 7 -static JSBool -date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble array[MAXARGS]; - uintN loop; - jsdouble d; - - for (loop = 0; loop < MAXARGS; loop++) { - if (loop < argc) { - if (!js_ValueToNumber(cx, argv[loop], &d)) - return JS_FALSE; - /* return NaN if any arg is NaN */ - if (!JSDOUBLE_IS_FINITE(d)) { - return js_NewNumberValue(cx, d, rval); - } - array[loop] = floor(d); - } else { - array[loop] = 0; - } - } - - /* adjust 2-digit years into the 20th century */ - if (array[0] >= 0 && array[0] <= 99) - array[0] += 1900; - - /* if we got a 0 for 'date' (which is out of range) - * pretend it's a 1. (So Date.UTC(1972, 5) works) */ - if (array[2] < 1) - array[2] = 1; - - d = date_msecFromDate(array[0], array[1], array[2], - array[3], array[4], array[5], array[6]); - d = TIMECLIP(d); - - return js_NewNumberValue(cx, d, rval); -} - -static JSBool -date_parseString(JSString *str, jsdouble *result) -{ - jsdouble msec; - - const jschar *s = JSSTRING_CHARS(str); - size_t limit = JSSTRING_LENGTH(str); - size_t i = 0; - int year = -1; - int mon = -1; - int mday = -1; - int hour = -1; - int min = -1; - int sec = -1; - int c = -1; - int n = -1; - jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */ - int prevc = 0; - JSBool seenplusminus = JS_FALSE; - - if (limit == 0) - goto syntax; - while (i < limit) { - c = s[i]; - i++; - if (c <= ' ' || c == ',' || c == '-') { - if (c == '-' && '0' <= s[i] && s[i] <= '9') { - prevc = c; - } - continue; - } - if (c == '(') { /* comments) */ - int depth = 1; - while (i < limit) { - c = s[i]; - i++; - if (c == '(') depth++; - else if (c == ')') - if (--depth <= 0) - break; - } - continue; - } - if ('0' <= c && c <= '9') { - n = c - '0'; - while (i < limit && '0' <= (c = s[i]) && c <= '9') { - n = n * 10 + c - '0'; - i++; - } - - /* allow TZA before the year, so - * 'Wed Nov 05 21:49:11 GMT-0800 1997' - * works */ - - /* uses of seenplusminus allow : in TZA, so Java - * no-timezone style of GMT+4:30 works - */ - - if ((prevc == '+' || prevc == '-')/* && year>=0 */) { - /* make ':' case below change tzoffset */ - seenplusminus = JS_TRUE; - - /* offset */ - if (n < 24) - n = n * 60; /* EG. "GMT-3" */ - else - n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ - if (prevc == '+') /* plus means east of GMT */ - n = -n; - if (tzoffset != 0 && tzoffset != -1) - goto syntax; - tzoffset = n; - } else if (n >= 70 || - (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) { - if (year >= 0) - goto syntax; - else if (c <= ' ' || c == ',' || c == '/' || i >= limit) - year = n < 100 ? n + 1900 : n; - else - goto syntax; - } else if (c == ':') { - if (hour < 0) - hour = /*byte*/ n; - else if (min < 0) - min = /*byte*/ n; - else - goto syntax; - } else if (c == '/') { - if (mon < 0) - mon = /*byte*/ n-1; - else if (mday < 0) - mday = /*byte*/ n; - else - goto syntax; - } else if (i < limit && c != ',' && c > ' ' && c != '-') { - goto syntax; - } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ - if (tzoffset < 0) - tzoffset -= n; - else - tzoffset += n; - } else if (hour >= 0 && min < 0) { - min = /*byte*/ n; - } else if (min >= 0 && sec < 0) { - sec = /*byte*/ n; - } else if (mday < 0) { - mday = /*byte*/ n; - } else { - goto syntax; - } - prevc = 0; - } else if (c == '/' || c == ':' || c == '+' || c == '-') { - prevc = c; - } else { - size_t st = i - 1; - int k; - while (i < limit) { - c = s[i]; - if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) - break; - i++; - } - if (i <= st + 1) - goto syntax; - for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;) - if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) { - int action = ttb[k]; - if (action != 0) { - if (action < 0) { - /* - * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as - * 12:30, instead of blindly adding 12 if PM. - */ - JS_ASSERT(action == -1 || action == -2); - if (hour > 12 || hour < 0) { - goto syntax; - } else { - if (action == -1 && hour == 12) { /* am */ - hour = 0; - } else if (action == -2 && hour != 12) { /* pm */ - hour += 12; - } - } - } else if (action <= 13) { /* month! */ - if (mon < 0) { - mon = /*byte*/ (action - 2); - } else { - goto syntax; - } - } else { - tzoffset = action - 10000; - } - } - break; - } - if (k < 0) - goto syntax; - prevc = 0; - } - } - if (year < 0 || mon < 0 || mday < 0) - goto syntax; - if (sec < 0) - sec = 0; - if (min < 0) - min = 0; - if (hour < 0) - hour = 0; - if (tzoffset == -1) { /* no time zone specified, have to use local */ - jsdouble msec_time; - msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); - - *result = UTC(msec_time); - return JS_TRUE; - } - - msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); - msec += tzoffset * msPerMinute; - *result = msec; - return JS_TRUE; - -syntax: - /* syntax error */ - *result = 0; - return JS_FALSE; -} - -static JSBool -date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - JSString *str; - jsdouble result; - - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - if (!date_parseString(str, &result)) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); - return JS_TRUE; - } - - result = TIMECLIP(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - int64 us, ms, us2ms; - jsdouble msec_time; - - us = PRMJ_Now(); - JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); - JSLL_DIV(ms, us, us2ms); - JSLL_L2D(msec_time, ms); - - return js_NewDoubleValue(cx, msec_time, rval); -} - -/* - * Check that obj is an object of class Date, and get the date value. - * Return NULL on failure. - */ -static jsdouble * -date_getProlog(JSContext *cx, JSObject *obj, jsval *argv) -{ - if (!JS_InstanceOf(cx, obj, &date_class, argv)) - return NULL; - return JSVAL_TO_DOUBLE(OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE)); -} - -/* - * See ECMA 15.9.5.4 thru 15.9.5.23 - */ -static JSBool -date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - return js_NewNumberValue(cx, *date, rval); -} - -static JSBool -date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = YearFromTime(LocalTime(result)); - - /* - * During the great date rewrite of 1.3, we tried to track the evolving ECMA - * standard, which then had a definition of getYear which always subtracted - * 1900. Which we implemented, not realizing that it was incompatible with - * the old behavior... now, rather than thrash the behavior yet again, - * we've decided to leave it with the - 1900 behavior and point people to - * the getFullYear method. But we try to protect existing scripts that - * have specified a version... - */ - if (cx->version == JSVERSION_1_0 || - cx->version == JSVERSION_1_1 || - cx->version == JSVERSION_1_2) - { - if (result >= 1900 && result < 2000) - result -= 1900; - } else { - result -= 1900; - } - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = YearFromTime(LocalTime(result)); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = YearFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = MonthFromTime(LocalTime(result)); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = MonthFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = LocalTime(result); - result = DateFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = DateFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = LocalTime(result); - result = WeekDay(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = WeekDay(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = HourFromTime(LocalTime(result)); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = HourFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = MinFromTime(LocalTime(result)); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = MinFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -/* Date.getSeconds is mapped to getUTCSeconds */ - -static JSBool -date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = SecFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -/* Date.getMilliseconds is mapped to getUTCMilliseconds */ - -static JSBool -date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - result = msFromTime(result); - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - result = *date; - - /* - * Return the time zone offset in minutes for the current locale - * that is appropriate for this time. This value would be a - * constant except for daylight savings time. - */ - result = (result - LocalTime(result)) / msPerMinute; - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble result; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - if (!js_ValueToNumber(cx, argv[0], &result)) - return JS_FALSE; - - result = TIMECLIP(result); - - *date = result; - return js_NewNumberValue(cx, result, rval); -} - -static JSBool -date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - uintN maxargs, JSBool local, jsval *rval) -{ - uintN i; - jsdouble args[4], *argp, *stop; - jsdouble hour, min, sec, msec; - jsdouble lorutime; /* Local or UTC version of *date */ - - jsdouble msec_time; - jsdouble result; - - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - result = *date; - - /* just return NaN if the date is already NaN */ - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); - - /* Satisfy the ECMA rule that if a function is called with - * fewer arguments than the specified formal arguments, the - * remaining arguments are set to undefined. Seems like all - * the Date.setWhatever functions in ECMA are only varargs - * beyond the first argument; this should be set to undefined - * if it's not given. This means that "d = new Date(); - * d.setMilliseconds()" returns NaN. Blech. - */ - if (argc == 0) - argc = 1; /* should be safe, because length of all setters is 1 */ - else if (argc > maxargs) - argc = maxargs; /* clamp argc */ - - for (i = 0; i < argc; i++) { - if (!js_ValueToNumber(cx, argv[i], &args[i])) - return JS_FALSE; - if (!JSDOUBLE_IS_FINITE(args[i])) { - *date = *cx->runtime->jsNaN; - return js_NewNumberValue(cx, *date, rval); - } - args[i] = js_DoubleToInteger(args[i]); - } - - if (local) - lorutime = LocalTime(result); - else - lorutime = result; - - argp = args; - stop = argp + argc; - if (maxargs >= 4 && argp < stop) - hour = *argp++; - else - hour = HourFromTime(lorutime); - - if (maxargs >= 3 && argp < stop) - min = *argp++; - else - min = MinFromTime(lorutime); - - if (maxargs >= 2 && argp < stop) - sec = *argp++; - else - sec = SecFromTime(lorutime); - - if (maxargs >= 1 && argp < stop) - msec = *argp; - else - msec = msFromTime(lorutime); - - msec_time = MakeTime(hour, min, sec, msec); - result = MakeDate(Day(lorutime), msec_time); - -/* fprintf(stderr, "%f\n", result); */ - - if (local) - result = UTC(result); - -/* fprintf(stderr, "%f\n", result); */ - - *date = TIMECLIP(result); - return js_NewNumberValue(cx, *date, rval); -} - -static JSBool -date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval); -} - -static JSBool -date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval); -} - -static JSBool -date_setSeconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval); -} - -static JSBool -date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval); -} - -static JSBool -date_setMinutes(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval); -} - -static JSBool -date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval); -} - -static JSBool -date_setHours(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval); -} - -static JSBool -date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval); -} - -static JSBool -date_makeDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, uintN maxargs, JSBool local, jsval *rval) -{ - uintN i; - jsdouble lorutime; /* local or UTC version of *date */ - jsdouble args[3], *argp, *stop; - jsdouble year, month, day; - jsdouble result; - - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - result = *date; - - /* see complaint about ECMA in date_MakeTime */ - if (argc == 0) - argc = 1; /* should be safe, because length of all setters is 1 */ - else if (argc > maxargs) - argc = maxargs; /* clamp argc */ - - for (i = 0; i < argc; i++) { - if (!js_ValueToNumber(cx, argv[i], &args[i])) - return JS_FALSE; - if (!JSDOUBLE_IS_FINITE(args[i])) { - *date = *cx->runtime->jsNaN; - return js_NewNumberValue(cx, *date, rval); - } - args[i] = js_DoubleToInteger(args[i]); - } - - /* return NaN if date is NaN and we're not setting the year, - * If we are, use 0 as the time. */ - if (!(JSDOUBLE_IS_FINITE(result))) { - if (argc < 3) - return js_NewNumberValue(cx, result, rval); - else - lorutime = +0.; - } else { - if (local) - lorutime = LocalTime(result); - else - lorutime = result; - } - - argp = args; - stop = argp + argc; - if (maxargs >= 3 && argp < stop) - year = *argp++; - else - year = YearFromTime(lorutime); - - if (maxargs >= 2 && argp < stop) - month = *argp++; - else - month = MonthFromTime(lorutime); - - if (maxargs >= 1 && argp < stop) - day = *argp++; - else - day = DateFromTime(lorutime); - - day = MakeDay(year, month, day); /* day within year */ - result = MakeDate(day, TimeWithinDay(lorutime)); - - if (local) - result = UTC(result); - - *date = TIMECLIP(result); - return js_NewNumberValue(cx, *date, rval); -} - -static JSBool -date_setDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval); -} - -static JSBool -date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval); -} - -static JSBool -date_setMonth(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval); -} - -static JSBool -date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval); -} - -static JSBool -date_setFullYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval); -} - -static JSBool -date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval); -} - -static JSBool -date_setYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - jsdouble t; - jsdouble year; - jsdouble day; - jsdouble result; - - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - result = *date; - - if (!js_ValueToNumber(cx, argv[0], &year)) - return JS_FALSE; - if (!JSDOUBLE_IS_FINITE(year)) { - *date = *cx->runtime->jsNaN; - return js_NewNumberValue(cx, *date, rval); - } - - year = js_DoubleToInteger(year); - - if (!JSDOUBLE_IS_FINITE(result)) { - t = +0.0; - } else { - t = LocalTime(result); - } - - if (year >= 0 && year <= 99) - year += 1900; - - day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); - result = MakeDate(day, TimeWithinDay(t)); - result = UTC(result); - - *date = TIMECLIP(result); - return js_NewNumberValue(cx, *date, rval); -} - -/* constants for toString, toUTCString */ -static char js_NaN_date_str[] = "Invalid Date"; -static const char* days[] = -{ - "Sun","Mon","Tue","Wed","Thu","Fri","Sat" -}; -static const char* months[] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static JSBool -date_toGMTString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - char buf[100]; - JSString *str; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - if (!JSDOUBLE_IS_FINITE(*date)) { - JS_snprintf(buf, sizeof buf, js_NaN_date_str); - } else { - jsdouble temp = *date; - - /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it - * requires a PRMJTime... which only has 16-bit years. Sub-ECMA. - */ - JS_snprintf(buf, sizeof buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", - days[WeekDay(temp)], - DateFromTime(temp), - months[MonthFromTime(temp)], - YearFromTime(temp), - HourFromTime(temp), - MinFromTime(temp), - SecFromTime(temp)); - } - str = JS_NewStringCopyZ(cx, buf); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -/* for Date.toLocaleString; interface to PRMJTime date struct. - * If findEquivalent is true, then try to map the year to an equivalent year - * that's in range. - */ -static void -new_explode(jsdouble timeval, PRMJTime *split, JSBool findEquivalent) -{ - jsint year = YearFromTime(timeval); - int16 adjustedYear; - - /* If the year doesn't fit in a PRMJTime, find something to do about it. */ - if (year > 32767 || year < -32768) { - if (findEquivalent) { - /* We're really just trying to get a timezone string; map the year - * to some equivalent year in the range 0 to 2800. Borrowed from - * A. D. Olsen. - */ - jsint cycles; -#define CYCLE_YEARS 2800L - cycles = (year >= 0) ? year / CYCLE_YEARS - : -1 - (-1 - year) / CYCLE_YEARS; - adjustedYear = (int16)(year - cycles * CYCLE_YEARS); - } else { - /* Clamp it to the nearest representable year. */ - adjustedYear = (int16)((year > 0) ? 32767 : - 32768); - } - } else { - adjustedYear = (int16)year; - } - - split->tm_usec = (int32) msFromTime(timeval) * 1000; - split->tm_sec = (int8) SecFromTime(timeval); - split->tm_min = (int8) MinFromTime(timeval); - split->tm_hour = (int8) HourFromTime(timeval); - split->tm_mday = (int8) DateFromTime(timeval); - split->tm_mon = (int8) MonthFromTime(timeval); - split->tm_wday = (int8) WeekDay(timeval); - split->tm_year = (int16) adjustedYear; - split->tm_yday = (int16) DayWithinYear(timeval, year); - - /* not sure how this affects things, but it doesn't seem - to matter. */ - split->tm_isdst = (DaylightSavingTA(timeval) != 0); -} - -typedef enum formatspec { - FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME -} formatspec; - -/* helper function */ -static JSBool -date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) -{ - char buf[100]; - JSString *str; - char tzbuf[100]; - JSBool usetz; - size_t i, tzlen; - PRMJTime split; - - if (!JSDOUBLE_IS_FINITE(date)) { - JS_snprintf(buf, sizeof buf, js_NaN_date_str); - } else { - jsdouble local = LocalTime(date); - - /* offset from GMT in minutes. The offset includes daylight savings, - if it applies. */ - jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute); - - /* map 510 minutes to 0830 hours */ - intN offset = (minutes / 60) * 100 + minutes % 60; - - /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is - * printed as 'GMT-0800' rather than as 'PST' to avoid - * operating-system dependence on strftime (which - * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints - * PST as 'Pacific Standard Time.' This way we always know - * what we're getting, and can parse it if we produce it. - * The OS TZA string is included as a comment. - */ - - /* get a timezone string from the OS to include as a - comment. */ - new_explode(date, &split, JS_TRUE); - if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { - - /* Decide whether to use the resulting timezone string. - * - * Reject it if it contains any non-ASCII, non-alphanumeric - * characters. It's then likely in some other character - * encoding, and we probably won't display it correctly. - */ - usetz = JS_TRUE; - tzlen = strlen(tzbuf); - if (tzlen > 100) { - usetz = JS_FALSE; - } else { - for (i = 0; i < tzlen; i++) { - jschar c = tzbuf[i]; - if (c > 127 || - !(isalpha(c) || isdigit(c) || - c == ' ' || c == '(' || c == ')')) { - usetz = JS_FALSE; - } - } - } - - /* Also reject it if it's not parenthesized or if it's '()'. */ - if (tzbuf[0] != '(' || tzbuf[1] == ')') - usetz = JS_FALSE; - } else - usetz = JS_FALSE; - - switch (format) { - case FORMATSPEC_FULL: - /* - * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it - * requires a PRMJTime... which only has 16-bit years. Sub-ECMA. - */ - /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */ - JS_snprintf(buf, sizeof buf, - "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s", - days[WeekDay(local)], - months[MonthFromTime(local)], - DateFromTime(local), - YearFromTime(local), - HourFromTime(local), - MinFromTime(local), - SecFromTime(local), - offset, - usetz ? " " : "", - usetz ? tzbuf : ""); - break; - case FORMATSPEC_DATE: - /* Tue Oct 31 2000 */ - JS_snprintf(buf, sizeof buf, - "%s %s %.2d %.4d", - days[WeekDay(local)], - months[MonthFromTime(local)], - DateFromTime(local), - YearFromTime(local)); - break; - case FORMATSPEC_TIME: - /* 09:41:40 GMT-0800 (PST) */ - JS_snprintf(buf, sizeof buf, - "%.2d:%.2d:%.2d GMT%+.4d%s%s", - HourFromTime(local), - MinFromTime(local), - SecFromTime(local), - offset, - usetz ? " " : "", - usetz ? tzbuf : ""); - break; - } - } - - str = JS_NewStringCopyZ(cx, buf); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -static JSBool -date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval, char *format) -{ - char buf[100]; - JSString *str; - PRMJTime split; - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - if (!JSDOUBLE_IS_FINITE(*date)) { - JS_snprintf(buf, sizeof buf, js_NaN_date_str); - } else { - intN result_len; - jsdouble local = LocalTime(*date); - new_explode(local, &split, JS_FALSE); - - /* let PRMJTime format it. */ - result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); - - /* If it failed, default to toString. */ - if (result_len == 0) - return date_format(cx, *date, FORMATSPEC_FULL, rval); - - /* Hacked check against undesired 2-digit year 00/00/00 form. */ - if (buf[result_len - 3] == '/' && - isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1])) { - JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), - "%d", js_DateGetYear(cx, obj)); - } - - } - - str = JS_NewStringCopyZ(cx, buf); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} - -static JSBool -date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - /* Use '%#c' for windows, because '%c' is - * backward-compatible and non-y2k with msvc; '%#c' requests that a - * full year be used in the result string. - */ - return date_toLocaleHelper(cx, obj, argc, argv, rval, -#if defined(_WIN32) && !defined(__MWERKS__) - "%#c" -#else - "%c" -#endif - ); -} - -static JSBool -date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - /* Use '%#x' for windows, because '%x' is - * backward-compatible and non-y2k with msvc; '%#x' requests that a - * full year be used in the result string. - */ - return date_toLocaleHelper(cx, obj, argc, argv, rval, -#if defined(_WIN32) && !defined(__MWERKS__) - "%#x" -#else - "%x" -#endif - ); -} - -static JSBool -date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X"); -} - -static JSBool -date_toTimeString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - return date_format(cx, *date, FORMATSPEC_TIME, rval); -} - -static JSBool -date_toDateString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - return date_format(cx, *date, FORMATSPEC_DATE, rval); -} - -#if JS_HAS_TOSOURCE -#include <string.h> -#include "jsdtoa.h" - -static JSBool -date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble *date; - char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes; - JSString *str; - - date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - - numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *date); - if (!numStr) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - bytes = JS_smprintf("(new %s(%s))", date_class.name, numStr); - if (!bytes) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - - str = JS_NewString(cx, bytes, strlen(bytes)); - if (!str) { - free(bytes); - return JS_FALSE; - } - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; -} -#endif - -static JSBool -date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble *date = date_getProlog(cx, obj, argv); - if (!date) - return JS_FALSE; - return date_format(cx, *date, FORMATSPEC_FULL, rval); -} - -#if JS_HAS_VALUEOF_HINT -static JSBool -date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - /* It is an error to call date_valueOf on a non-date object, but we don't - * need to check for that explicitly here because every path calls - * date_getProlog, which does the check. - */ - - /* If called directly with no arguments, convert to a time number. */ - if (argc == 0) - return date_getTime(cx, obj, argc, argv, rval); - - /* Convert to number only if the hint was given, otherwise favor string. */ - if (argc == 1) { - JSString *str, *str2; - - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); - if (!js_CompareStrings(str, str2)) - return date_getTime(cx, obj, argc, argv, rval); - } - return date_toString(cx, obj, argc, argv, rval); -} -#else -#define date_valueOf date_getTime -#endif - - -/* - * creation and destruction - */ - -static JSFunctionSpec date_static_methods[] = { - {"UTC", date_UTC, MAXARGS,0,0 }, - {"parse", date_parse, 1,0,0 }, - {"now", date_now, 0,0,0 }, - {0,0,0,0,0} -}; - -static JSFunctionSpec date_methods[] = { - {"getTime", date_getTime, 0,0,0 }, - {"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 }, - {"getYear", date_getYear, 0,0,0 }, - {"getFullYear", date_getFullYear, 0,0,0 }, - {"getUTCFullYear", date_getUTCFullYear, 0,0,0 }, - {"getMonth", date_getMonth, 0,0,0 }, - {"getUTCMonth", date_getUTCMonth, 0,0,0 }, - {"getDate", date_getDate, 0,0,0 }, - {"getUTCDate", date_getUTCDate, 0,0,0 }, - {"getDay", date_getDay, 0,0,0 }, - {"getUTCDay", date_getUTCDay, 0,0,0 }, - {"getHours", date_getHours, 0,0,0 }, - {"getUTCHours", date_getUTCHours, 0,0,0 }, - {"getMinutes", date_getMinutes, 0,0,0 }, - {"getUTCMinutes", date_getUTCMinutes, 0,0,0 }, - {"getSeconds", date_getUTCSeconds, 0,0,0 }, - {"getUTCSeconds", date_getUTCSeconds, 0,0,0 }, - {"getMilliseconds", date_getUTCMilliseconds,0,0,0 }, - {"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 }, - {"setTime", date_setTime, 1,0,0 }, - {"setYear", date_setYear, 1,0,0 }, - {"setFullYear", date_setFullYear, 3,0,0 }, - {"setUTCFullYear", date_setUTCFullYear, 3,0,0 }, - {"setMonth", date_setMonth, 2,0,0 }, - {"setUTCMonth", date_setUTCMonth, 2,0,0 }, - {"setDate", date_setDate, 1,0,0 }, - {"setUTCDate", date_setUTCDate, 1,0,0 }, - {"setHours", date_setHours, 4,0,0 }, - {"setUTCHours", date_setUTCHours, 4,0,0 }, - {"setMinutes", date_setMinutes, 3,0,0 }, - {"setUTCMinutes", date_setUTCMinutes, 3,0,0 }, - {"setSeconds", date_setSeconds, 2,0,0 }, - {"setUTCSeconds", date_setUTCSeconds, 2,0,0 }, - {"setMilliseconds", date_setMilliseconds, 1,0,0 }, - {"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 }, - {"toUTCString", date_toGMTString, 0,0,0 }, - {js_toLocaleString_str, date_toLocaleString, 0,0,0 }, - {"toLocaleDateString", date_toLocaleDateString,0,0,0 }, - {"toLocaleTimeString", date_toLocaleTimeString,0,0,0 }, - {"toDateString", date_toDateString, 0,0,0 }, - {"toTimeString", date_toTimeString, 0,0,0 }, -#if JS_HAS_TOSOURCE - {js_toSource_str, date_toSource, 0,0,0 }, -#endif - {js_toString_str, date_toString, 0,0,0 }, - {js_valueOf_str, date_valueOf, 0,0,0 }, - {0,0,0,0,0} -}; - -static jsdouble * -date_constructor(JSContext *cx, JSObject* obj) -{ - jsdouble *date; - - date = js_NewDouble(cx, 0.0); - if (!date) - return NULL; - OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date)); - return date; -} - -static JSBool -Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsdouble *date; - JSString *str; - jsdouble d; - - /* Date called as function */ - if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { - int64 us, ms, us2ms; - jsdouble msec_time; - - /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS', - * so compute ms from PRMJ_Now. - */ - us = PRMJ_Now(); - JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); - JSLL_DIV(ms, us, us2ms); - JSLL_L2D(msec_time, ms); - - return date_format(cx, msec_time, FORMATSPEC_FULL, rval); - } - - /* Date called as constructor */ - if (argc == 0) { - int64 us, ms, us2ms; - jsdouble msec_time; - - date = date_constructor(cx, obj); - if (!date) - return JS_FALSE; - - us = PRMJ_Now(); - JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); - JSLL_DIV(ms, us, us2ms); - JSLL_L2D(msec_time, ms); - - *date = msec_time; - } else if (argc == 1) { - if (!JSVAL_IS_STRING(argv[0])) { - /* the argument is a millisecond number */ - if (!js_ValueToNumber(cx, argv[0], &d)) - return JS_FALSE; - date = date_constructor(cx, obj); - if (!date) - return JS_FALSE; - *date = TIMECLIP(d); - } else { - /* the argument is a string; parse it. */ - date = date_constructor(cx, obj); - if (!date) - return JS_FALSE; - - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - - if (!date_parseString(str, date)) - *date = *cx->runtime->jsNaN; - *date = TIMECLIP(*date); - } - } else { - jsdouble array[MAXARGS]; - uintN loop; - jsdouble double_arg; - jsdouble day; - jsdouble msec_time; - - for (loop = 0; loop < MAXARGS; loop++) { - if (loop < argc) { - if (!js_ValueToNumber(cx, argv[loop], &double_arg)) - return JS_FALSE; - /* if any arg is NaN, make a NaN date object - and return */ - if (!JSDOUBLE_IS_FINITE(double_arg)) { - date = date_constructor(cx, obj); - if (!date) - return JS_FALSE; - *date = *cx->runtime->jsNaN; - return JS_TRUE; - } - array[loop] = js_DoubleToInteger(double_arg); - } else { - if (loop == 2) { - array[loop] = 1; /* Default the date argument to 1. */ - } else { - array[loop] = 0; - } - } - } - - date = date_constructor(cx, obj); - if (!date) - return JS_FALSE; - - /* adjust 2-digit years into the 20th century */ - if (array[0] >= 0 && array[0] <= 99) - array[0] += 1900; - - day = MakeDay(array[0], array[1], array[2]); - msec_time = MakeTime(array[3], array[4], array[5], array[6]); - msec_time = MakeDate(day, msec_time); - msec_time = UTC(msec_time); - *date = TIMECLIP(msec_time); - } - return JS_TRUE; -} - -JSObject * -js_InitDateClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto; - jsdouble *proto_date; - - /* set static LocalTZA */ - LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); - proto = JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS, - NULL, date_methods, NULL, date_static_methods); - if (!proto) - return NULL; - - /* Alias toUTCString with toGMTString. (ECMA B.2.6) */ - if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString")) - return NULL; - - /* Set the value of the Date.prototype date to NaN */ - proto_date = date_constructor(cx, proto); - if (!proto_date) - return NULL; - *proto_date = *cx->runtime->jsNaN; - - return proto; -} - -JS_FRIEND_API(JSObject *) -js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) -{ - JSObject *obj; - jsdouble *date; - - obj = js_NewObject(cx, &date_class, NULL, NULL); - if (!obj) - return NULL; - - date = date_constructor(cx, obj); - if (!date) - return NULL; - - *date = msec_time; - return obj; -} - -JS_FRIEND_API(JSObject *) -js_NewDateObject(JSContext* cx, int year, int mon, int mday, - int hour, int min, int sec) -{ - JSObject *obj; - jsdouble msec_time; - - msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); - obj = js_NewDateObjectMsec(cx, UTC(msec_time)); - return obj; -} - -JS_FRIEND_API(JSBool) -js_DateIsValid(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return JS_FALSE; - else - return JS_TRUE; -} - -JS_FRIEND_API(int) -js_DateGetYear(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - /* Preserve legacy API behavior of returning 0 for invalid dates. */ - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) YearFromTime(LocalTime(*date)); -} - -JS_FRIEND_API(int) -js_DateGetMonth(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) MonthFromTime(LocalTime(*date)); -} - -JS_FRIEND_API(int) -js_DateGetDate(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) DateFromTime(LocalTime(*date)); -} - -JS_FRIEND_API(int) -js_DateGetHours(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) HourFromTime(LocalTime(*date)); -} - -JS_FRIEND_API(int) -js_DateGetMinutes(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) MinFromTime(LocalTime(*date)); -} - -JS_FRIEND_API(int) -js_DateGetSeconds(JSContext *cx, JSObject* obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (int) SecFromTime(*date); -} - -JS_FRIEND_API(void) -js_DateSetYear(JSContext *cx, JSObject *obj, int year) -{ - jsdouble local; - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date) - return; - local = LocalTime(*date); - /* reset date if it was NaN */ - if (JSDOUBLE_IS_NaN(local)) - local = 0; - local = date_msecFromDate(year, - MonthFromTime(local), - DateFromTime(local), - HourFromTime(local), - MinFromTime(local), - SecFromTime(local), - msFromTime(local)); - *date = UTC(local); -} - -JS_FRIEND_API(void) -js_DateSetMonth(JSContext *cx, JSObject *obj, int month) -{ - jsdouble local; - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date) - return; - local = LocalTime(*date); - /* bail if date was NaN */ - if (JSDOUBLE_IS_NaN(local)) - return; - local = date_msecFromDate(YearFromTime(local), - month, - DateFromTime(local), - HourFromTime(local), - MinFromTime(local), - SecFromTime(local), - msFromTime(local)); - *date = UTC(local); -} - -JS_FRIEND_API(void) -js_DateSetDate(JSContext *cx, JSObject *obj, int date) -{ - jsdouble local; - jsdouble *datep = date_getProlog(cx, obj, NULL); - if (!datep) - return; - local = LocalTime(*datep); - if (JSDOUBLE_IS_NaN(local)) - return; - local = date_msecFromDate(YearFromTime(local), - MonthFromTime(local), - date, - HourFromTime(local), - MinFromTime(local), - SecFromTime(local), - msFromTime(local)); - *datep = UTC(local); -} - -JS_FRIEND_API(void) -js_DateSetHours(JSContext *cx, JSObject *obj, int hours) -{ - jsdouble local; - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date) - return; - local = LocalTime(*date); - if (JSDOUBLE_IS_NaN(local)) - return; - local = date_msecFromDate(YearFromTime(local), - MonthFromTime(local), - DateFromTime(local), - hours, - MinFromTime(local), - SecFromTime(local), - msFromTime(local)); - *date = UTC(local); -} - -JS_FRIEND_API(void) -js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes) -{ - jsdouble local; - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date) - return; - local = LocalTime(*date); - if (JSDOUBLE_IS_NaN(local)) - return; - local = date_msecFromDate(YearFromTime(local), - MonthFromTime(local), - DateFromTime(local), - HourFromTime(local), - minutes, - SecFromTime(local), - msFromTime(local)); - *date = UTC(local); -} - -JS_FRIEND_API(void) -js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds) -{ - jsdouble local; - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date) - return; - local = LocalTime(*date); - if (JSDOUBLE_IS_NaN(local)) - return; - local = date_msecFromDate(YearFromTime(local), - MonthFromTime(local), - DateFromTime(local), - HourFromTime(local), - MinFromTime(local), - seconds, - msFromTime(local)); - *date = UTC(local); -} - -JS_FRIEND_API(jsdouble) -js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj) -{ - jsdouble *date = date_getProlog(cx, obj, NULL); - if (!date || JSDOUBLE_IS_NaN(*date)) - return 0; - return (*date); -} |
