mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
347aaac8d3
- Switch improvements: - JSOP_CONDSWITCH is a 1 byte nop, not variable length with the same kind of immediate operand as JSOP_LOOKUPSWITCH (which is useless except for decompilation). New scheme uses SRC_COMMA notes on each JSOP_CASE opcode, usually 2 bytes per note, and a typically-1-byte 2nd offset on SRC_SWITCH: 1 + 2 * ncases vs. the previous JSOP_LOOKUPSWITCH immediate, which consumed: 4 * ncases bytes after the switch opcode just for decompilation. - SRC_SWITCH has two offsets, first to end of switch as before, the second to first case if JSOP_CONDSWITCH, for decompilation. - Optimize switches with all-constant cases using JSOP_TABLESWITH, or if that can't be used, JSOP_LOOKUPSWITCH, before falling back on ECMAv2's JSOP_CONDSWITCH. - Use cx->gcDisabled when evaluating case exprs at compile time for old, pre-ECMAv2 switches, to prevent branch-callback-based GC invocations from ripping apart the unrooted temporary script for each case expr. - Fixed up stale SRC_SWITCH comments in jsemit.h. jsemit.c jsemit.h - TREE_CONTEXT_INIT to match ATOM_LIST_INIT, not English word order. - Reorganized JSCodeGenerator to sort of match argument order to js_InitCodeGenerator. - Got rid of confusing CG_RESET* macros and used memset(cg, 0, sizeof *cg) and non-zero-default init in js_InitCodeGenerator. js_ResetCodeGenerator just releases the code and temp arena pools and leaves the cg in a state where it must be re-initialized (as before, but more obvious). - In the same spirit, don't do partial "resets" or src and trynotes in their js_FinishTaking*Notes functions -- those are friends of jsscript.c and are not general, idempotent functions. jsapi.c jsapi.h jsarray.c jsatom.c jsatom.h jscntxt.c jsemit.c jsmsg.def jsnum.c jsobj.c jsopcode.c jsregexp.c jsscan.c jsstr.c jsxdrapi. - Use PR_snprintf rather than sprintf always, so we don't have to worry about systems with 64-bit longs that overflow 12-byte buffers and open Morris-Worm-type security holes. - Trim extra spaces, fix hanging indentation, and similar anal retention. - Renamed JSMSG_BAD_PROTO_SORT to JSMSG_BAD_SORT_ARG cuz that's what it is complaining about. - SRC_CATCHGUARD still lived in comments, but it's SRC_CATCH in code. jscntxt.c jscntxt.h jsinterp.c - Packed nearby JSPackedBools and added a new one: gcDisabled, for use by jsemit.c's pre-ECMAv2 switch case expr eval. - Rip out old js_InterpreterHooks stuff from original liveconnect (moja). - Remove javaData and savedErrors from JSContext. Leaving it to fur or shaver to remove javaData from jsscript.h.
2023 lines
50 KiB
C
2023 lines
50 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
/*
|
||
* JS date methods.
|
||
*/
|
||
#include "jsstddef.h"
|
||
#include <math.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "prtypes.h"
|
||
#include "prprintf.h"
|
||
#include "prtime.h"
|
||
#include "prassert.h"
|
||
#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
|
||
|
||
#ifdef XP_PC
|
||
/* 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 lo = (jsint) floor((t / msPerDay) / 366) + 1970;
|
||
jsint hi = (jsint) floor((t / msPerDay) / 365) + 1970;
|
||
jsint mid;
|
||
|
||
/* above doesn't work for negative dates... */
|
||
if (hi < lo) {
|
||
jsint temp = lo;
|
||
lo = hi;
|
||
hi = temp;
|
||
}
|
||
|
||
/* Use a simple binary search algorithm to find the right
|
||
year. This seems like brute force... but the computation
|
||
of hi and lo years above lands within one year of the
|
||
correct answer for years within a thousand years of
|
||
1970; the loop below only requires six iterations
|
||
for year 270000. */
|
||
while (hi > lo) {
|
||
mid = (hi + lo) / 2;
|
||
if (TimeFromYear(mid) > t) {
|
||
hi = mid - 1;
|
||
} else {
|
||
if (TimeFromYear(mid) <= t) {
|
||
jsint temp = mid + 1;
|
||
if (TimeFromYear(temp) > t) {
|
||
return mid;
|
||
}
|
||
lo = mid + 1;
|
||
}
|
||
}
|
||
}
|
||
return lo;
|
||
}
|
||
|
||
#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)
|
||
{
|
||
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 */
|
||
LL_D2L(PR_t, t);
|
||
LL_I2L(ms2us, PR_USEC_PER_MSEC);
|
||
LL_MUL(PR_t, PR_t, ms2us);
|
||
|
||
offset = PR_DSTOffset(PR_t);
|
||
|
||
LL_DIV(offset, offset, ms2us);
|
||
LL_L2D(result, offset);
|
||
return result;
|
||
}
|
||
|
||
#define LocalTime(t) ((t) + LocalTZA + DaylightSavingTA(t))
|
||
|
||
static jsdouble
|
||
UTC(jsdouble t)
|
||
{
|
||
return t - LocalTZA - DaylightSavingTA(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);
|
||
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 = {
|
||
"Date",
|
||
JSCLASS_HAS_PRIVATE,
|
||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
||
};
|
||
|
||
/* for use by date_parse */
|
||
|
||
static 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[] = {
|
||
0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||
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 time;
|
||
jsdouble result;
|
||
|
||
day = MakeDay(year, mon, mday);
|
||
time = MakeTime(hour, min, sec, msec);
|
||
result = MakeDate(day, 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(const jschar *s, jsdouble *result)
|
||
{
|
||
jsdouble msec;
|
||
|
||
int year = -1;
|
||
int mon = -1;
|
||
int mday = -1;
|
||
int hour = -1;
|
||
int min = -1;
|
||
int sec = -1;
|
||
int c = -1;
|
||
int i = 0;
|
||
int n = -1;
|
||
jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */
|
||
int prevc = 0;
|
||
int limit = 0;
|
||
JSBool seenplusminus = JS_FALSE;
|
||
|
||
if (s == 0)
|
||
goto syntax;
|
||
limit = js_strlen(s);
|
||
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 {
|
||
int 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 == 1) { /* pm */
|
||
if (hour > 12 || hour < 0) {
|
||
goto syntax;
|
||
} else {
|
||
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 time;
|
||
time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
||
|
||
*result = UTC(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->chars, &result)) {
|
||
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
|
||
return JS_TRUE;
|
||
}
|
||
|
||
result = TIMECLIP(result);
|
||
return js_NewNumberValue(cx, result, 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));
|
||
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 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 settors 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);
|
||
|
||
time = MakeTime(hour, min, sec, msec);
|
||
result = MakeDate(Day(lorutime), 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 settors 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)) {
|
||
PR_snprintf(buf, sizeof buf, js_NaN_date_str);
|
||
} else {
|
||
jsdouble temp = *date;
|
||
|
||
/* Avoid dependence on PR_FormatTimeUSEnglish, because it
|
||
* requires a PRTime... which only has 16-bit years. Sub-ECMA.
|
||
*/
|
||
PR_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 PRTime 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 time, PRTime *split, JSBool findEquivalent)
|
||
{
|
||
jsint year = YearFromTime(time);
|
||
int16 adjustedYear;
|
||
|
||
/* If the year doesn't fit in a PRTime, 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(time) * 1000;
|
||
split->tm_sec = (int8) SecFromTime(time);
|
||
split->tm_min = (int8) MinFromTime(time);
|
||
split->tm_hour = (int8) HourFromTime(time);
|
||
split->tm_mday = (int8) DateFromTime(time);
|
||
split->tm_mon = (int8) MonthFromTime(time);
|
||
split->tm_wday = (int8) WeekDay(time);
|
||
split->tm_year = (int16) adjustedYear;
|
||
split->tm_yday = (int16) DayWithinYear(time, year);
|
||
|
||
/* not sure how this affects things, but it doesn't seem
|
||
to matter. */
|
||
split->tm_isdst = (DaylightSavingTA(time) != 0);
|
||
}
|
||
|
||
/* helper function */
|
||
static JSBool
|
||
date_format(JSContext *cx, jsdouble date, jsval *rval)
|
||
{
|
||
char buf[100];
|
||
JSString *str;
|
||
char tzbuf[100];
|
||
PRTime split;
|
||
|
||
if (!JSDOUBLE_IS_FINITE(date)) {
|
||
PR_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((LocalTZA + DaylightSavingTA(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
|
||
* PR_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);
|
||
PR_FormatTime(tzbuf, sizeof tzbuf, "(%Z) ", &split);
|
||
|
||
/* Avoid dependence on PR_FormatTimeUSEnglish, because it
|
||
* requires a PRTime... which only has 16-bit years. Sub-ECMA.
|
||
*/
|
||
PR_snprintf(buf, sizeof buf, "%s %s %.2d %.2d:%.2d:%.2d GMT%+.4d %s%.4d",
|
||
days[WeekDay(local)],
|
||
months[MonthFromTime(local)],
|
||
DateFromTime(local),
|
||
HourFromTime(local),
|
||
MinFromTime(local),
|
||
SecFromTime(local),
|
||
offset,
|
||
|
||
/* don't print anything for the TZA comment if we got '()'
|
||
* or something non-parenthesized from the OS.
|
||
*/
|
||
((tzbuf[0] == '(' && tzbuf[1] != ')') ? tzbuf : ""),
|
||
|
||
YearFromTime(local));
|
||
}
|
||
|
||
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)
|
||
{
|
||
char buf[100];
|
||
JSString *str;
|
||
PRTime split;
|
||
jsdouble *date = date_getProlog(cx, obj, argv);
|
||
if (!date)
|
||
return JS_FALSE;
|
||
|
||
if (!JSDOUBLE_IS_FINITE(*date)) {
|
||
PR_snprintf(buf, sizeof buf, js_NaN_date_str);
|
||
} else {
|
||
intN result_len;
|
||
jsdouble local = LocalTime(*date);
|
||
new_explode(local, &split, JS_FALSE);
|
||
|
||
/* let PRTime format it. 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.
|
||
*/
|
||
result_len = PR_FormatTime(buf, sizeof buf,
|
||
#ifdef _WIN32
|
||
"%#c",
|
||
#else
|
||
"%c",
|
||
#endif
|
||
&split);
|
||
|
||
/* If it failed, default to toString. */
|
||
if (result_len == 0)
|
||
return date_format(cx, *date, rval);
|
||
}
|
||
|
||
str = JS_NewStringCopyZ(cx, buf);
|
||
if (!str)
|
||
return JS_FALSE;
|
||
*rval = STRING_TO_JSVAL(str);
|
||
return JS_TRUE;
|
||
}
|
||
|
||
#if JS_HAS_TOSOURCE
|
||
#include "prdtoa.h"
|
||
|
||
static JSBool
|
||
date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||
jsval *rval)
|
||
{
|
||
jsdouble *date;
|
||
char buf[32], *bytes;
|
||
JSString *str;
|
||
|
||
date = date_getProlog(cx, obj, argv);
|
||
if (!date)
|
||
return JS_FALSE;
|
||
|
||
PR_cnvtf(buf, sizeof buf, 20, *date);
|
||
bytes = PR_smprintf("(new %s(%s))", date_class.name, buf);
|
||
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, 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 },
|
||
{"parse", date_parse, 1 },
|
||
{0}
|
||
};
|
||
|
||
static JSFunctionSpec date_methods[] = {
|
||
{"getTime", date_getTime, 0 },
|
||
{"getTimezoneOffset", date_getTimezoneOffset, 0 },
|
||
{"getYear", date_getYear, 0 },
|
||
{"getFullYear", date_getFullYear, 0 },
|
||
{"getUTCFullYear", date_getUTCFullYear, 0 },
|
||
{"getMonth", date_getMonth, 0 },
|
||
{"getUTCMonth", date_getUTCMonth, 0 },
|
||
{"getDate", date_getDate, 0 },
|
||
{"getUTCDate", date_getUTCDate, 0 },
|
||
{"getDay", date_getDay, 0 },
|
||
{"getUTCDay", date_getUTCDay, 0 },
|
||
{"getHours", date_getHours, 0 },
|
||
{"getUTCHours", date_getUTCHours, 0 },
|
||
{"getMinutes", date_getMinutes, 0 },
|
||
{"getUTCMinutes", date_getUTCMinutes, 0 },
|
||
{"getSeconds", date_getUTCSeconds, 0 },
|
||
{"getUTCSeconds", date_getUTCSeconds, 0 },
|
||
{"getMilliseconds", date_getUTCMilliseconds,0 },
|
||
{"getUTCMilliseconds",date_getUTCMilliseconds,0 },
|
||
{"setTime", date_setTime, 1 },
|
||
{"setYear", date_setYear, 1 },
|
||
{"setFullYear", date_setFullYear, 3 },
|
||
{"setUTCFullYear", date_setUTCFullYear, 3 },
|
||
{"setMonth", date_setMonth, 2 },
|
||
{"setUTCMonth", date_setUTCMonth, 2 },
|
||
{"setDate", date_setDate, 1 },
|
||
{"setUTCDate", date_setUTCDate, 1 },
|
||
{"setHours", date_setHours, 4 },
|
||
{"setUTCHours", date_setUTCHours, 4 },
|
||
{"setMinutes", date_setMinutes, 3 },
|
||
{"setUTCMinutes", date_setUTCMinutes, 3 },
|
||
{"setSeconds", date_setSeconds, 2 },
|
||
{"setUTCSeconds", date_setUTCSeconds, 2 },
|
||
{"setMilliseconds", date_setMilliseconds, 1 },
|
||
{"setUTCMilliseconds",date_setUTCMilliseconds,1 },
|
||
{"toGMTString", date_toGMTString, 0 },
|
||
{"toUTCString", date_toGMTString, 0 },
|
||
{"toLocaleString", date_toLocaleString, 0 },
|
||
#if JS_HAS_TOSOURCE
|
||
{js_toSource_str, date_toSource, 0 },
|
||
#endif
|
||
{js_toString_str, date_toString, 0 },
|
||
{js_valueOf_str, date_valueOf, 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->constructing) {
|
||
int64 us, ms, us2ms;
|
||
jsdouble time;
|
||
|
||
/* NSPR 2.0 docs say 'We do not support PR_NowMS and PR_NowS',
|
||
* so compute ms from PR_Now.
|
||
*/
|
||
us = PR_Now();
|
||
LL_UI2L(us2ms, PR_USEC_PER_MSEC);
|
||
LL_DIV(ms, us, us2ms);
|
||
LL_L2D(time, ms);
|
||
|
||
return date_format(cx, time, rval);
|
||
}
|
||
|
||
/* Date called as constructor */
|
||
if (argc == 0) {
|
||
int64 us, ms, us2ms;
|
||
jsdouble time;
|
||
|
||
date = date_constructor(cx, obj);
|
||
if (!date)
|
||
return JS_FALSE;
|
||
|
||
us = PR_Now();
|
||
LL_UI2L(us2ms, PR_USEC_PER_MSEC);
|
||
LL_DIV(ms, us, us2ms);
|
||
LL_L2D(time, ms);
|
||
|
||
*date = 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->chars, date))
|
||
*date = *(cx->runtime->jsNaN);
|
||
*date = TIMECLIP(*date);
|
||
}
|
||
} else {
|
||
jsdouble array[MAXARGS];
|
||
uintN loop;
|
||
jsdouble d;
|
||
jsdouble day;
|
||
jsdouble time;
|
||
|
||
for (loop = 0; loop < MAXARGS; loop++) {
|
||
if (loop < argc) {
|
||
if (!js_ValueToNumber(cx, argv[loop], &d))
|
||
return JS_FALSE;
|
||
/* if any arg is NaN, make a NaN date object
|
||
and return */
|
||
if (!JSDOUBLE_IS_FINITE(d)) {
|
||
date = date_constructor(cx, obj);
|
||
if (!date)
|
||
return JS_FALSE;
|
||
*date = *(cx->runtime->jsNaN);
|
||
return JS_TRUE;
|
||
}
|
||
array[loop] = js_DoubleToInteger(d);
|
||
} 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;
|
||
|
||
/* if we got a 0 for 'date' (which is out of range)
|
||
* pretend it's a 1 */
|
||
if (array[2] < 1)
|
||
array[2] = 1;
|
||
|
||
day = MakeDay(array[0], array[1], array[2]);
|
||
time = MakeTime(array[3], array[4], array[5], array[6]);
|
||
time = MakeDate(day, time);
|
||
time = UTC(time);
|
||
*date = TIMECLIP(time);
|
||
}
|
||
return JS_TRUE;
|
||
}
|
||
|
||
JSObject *
|
||
js_InitDateClass(JSContext *cx, JSObject *obj)
|
||
{
|
||
JSObject *proto;
|
||
jsdouble *proto_date;
|
||
|
||
/* set static LocalTZA */
|
||
LocalTZA = -(PR_LocalGMTDifference() * msPerSecond);
|
||
proto = JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS,
|
||
NULL, date_methods, NULL, date_static_methods);
|
||
if (!proto)
|
||
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_NewDateObject(JSContext* cx, int year, int mon, int mday,
|
||
int hour, int min, int sec)
|
||
{
|
||
JSObject *obj;
|
||
jsdouble *date;
|
||
jsdouble time;
|
||
|
||
obj = js_NewObject(cx, &date_class, NULL, NULL);
|
||
if (!obj)
|
||
return NULL;
|
||
|
||
JS_DefineFunctions(cx, obj, date_methods);
|
||
|
||
date = date_constructor(cx, obj);
|
||
if (!date)
|
||
return NULL;
|
||
|
||
time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
||
*date = UTC(time);
|
||
return obj;
|
||
}
|
||
|
||
JS_FRIEND_API(int)
|
||
js_DateGetYear(JSContext *cx, JSObject* obj)
|
||
{
|
||
jsdouble *date = date_getProlog(cx, obj, NULL);
|
||
|
||
if (!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)
|
||
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)
|
||
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)
|
||
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)
|
||
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)
|
||
return 0;
|
||
return (int) SecFromTime(*date);
|
||
}
|
||
|
||
extern 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);
|
||
}
|
||
|
||
extern 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);
|
||
}
|
||
|
||
extern 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);
|
||
}
|
||
|
||
extern 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);
|
||
}
|
||
|
||
extern 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);
|
||
}
|
||
|
||
extern 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);
|
||
}
|