Piotr Caban : jscript: Added implementation of Date constructor with more then one argument.
Alexandre Julliard
julliard at winehq.org
Tue Jun 23 10:02:46 CDT 2009
Module: wine
Branch: master
Commit: b529cdb65ea879c59ab8f428164fc6f35b0efaa9
URL: http://source.winehq.org/git/wine.git/?a=commit;h=b529cdb65ea879c59ab8f428164fc6f35b0efaa9
Author: Piotr Caban <piotr.caban at gmail.com>
Date: Mon Jun 22 20:40:01 2009 +0200
jscript: Added implementation of Date constructor with more then one argument.
---
dlls/jscript/date.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 219 insertions(+), 9 deletions(-)
diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c
index 3fd856e..52eac08 100644
--- a/dlls/jscript/date.c
+++ b/dlls/jscript/date.c
@@ -35,6 +35,10 @@ typedef struct {
DOUBLE time;
LONG bias;
+ SYSTEMTIME standardDate;
+ LONG standardBias;
+ SYSTEMTIME daylightDate;
+ LONG daylightBias;
} DateInstance;
static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
@@ -112,14 +116,42 @@ static inline DOUBLE days_in_year(DOUBLE year)
/* ECMA-262 3th Edition 15.9.1.3 */
static inline DOUBLE day_from_year(DOUBLE year)
{
- int y;
-
if(year != (int)year)
return ret_nan();
- y = year;
- return 365*(y-1970) + floor((y-1969)/4)
- - floor((y-1901)/100) + floor((y-1601)/400);
+ return floor(365.0*(year-1970) + floor((year-1969)/4)
+ - floor((year-1901)/100) + floor((year-1601)/400));
+}
+
+static inline int day_from_month(int month, int in_leap_year)
+{
+ switch(month)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return 31;
+ case 2:
+ return 59+in_leap_year;
+ case 3:
+ return 90+in_leap_year;
+ case 4:
+ return 120+in_leap_year;
+ case 5:
+ return 151+in_leap_year;
+ case 6:
+ return 181+in_leap_year;
+ case 7:
+ return 212+in_leap_year;
+ case 8:
+ return 243+in_leap_year;
+ case 9:
+ return 273+in_leap_year;
+ case 10:
+ return 304+in_leap_year;
+ default:
+ return 334+in_leap_year;
+ }
}
/* ECMA-262 3th Edition 15.9.1.3 */
@@ -221,6 +253,74 @@ static inline DOUBLE week_day(DOUBLE time)
return ret;
}
+static inline DOUBLE convert_time(int year, SYSTEMTIME st)
+{
+ DOUBLE time;
+ int set_week_day;
+
+ if(st.wMonth == 0)
+ return ret_nan();
+
+ if(st.wYear != 0)
+ year = st.wYear;
+
+ time = time_from_year(year);
+ time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
+
+ if(st.wYear == 0) {
+ set_week_day = st.wDayOfWeek-week_day(time);
+ if(set_week_day < 0)
+ set_week_day += 7;
+ time += set_week_day * MS_PER_DAY;
+
+ time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
+ if(month_from_time(time) != st.wMonth-1)
+ time -= 7 * MS_PER_DAY;
+ }
+ else
+ time += st.wDay * MS_PER_DAY;
+
+ time += st.wHour * MS_PER_HOUR;
+ time += st.wMinute * MS_PER_MINUTE;
+
+ return time;
+}
+
+/* ECMA-262 3rd Edition 15.9.1.9 */
+static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
+{
+ int year = year_from_time(time);
+ DOUBLE standardTime, daylightTime;
+
+ if(isnan(time))
+ return 0;
+
+ standardTime = convert_time(year, date->standardDate);
+ daylightTime = convert_time(year, date->daylightDate);
+
+ if(isnan(standardTime) || isnan(daylightTime))
+ return 0;
+ else if(standardTime > daylightTime) {
+ if(daylightTime <= time && time < standardTime)
+ return date->daylightBias;
+
+ return date->standardBias;
+ }
+ else {
+ if(standardTime <= time && time < daylightTime)
+ return date->standardBias;
+
+ return date->daylightBias;
+ }
+}
+
+/* ECMA-262 3rd Edition 15.9.1.9 */
+static inline DOUBLE utc(DOUBLE time, DateInstance *date)
+{
+ time += date->bias * MS_PER_MINUTE;
+ return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
+}
+
/* ECMA-262 3th Edition 15.9.1.10 */
static inline DOUBLE hour_from_time(DOUBLE time)
{
@@ -277,6 +377,36 @@ static inline DOUBLE ms_from_time(DOUBLE time)
return ret;
}
+/* ECMA-262 3rd Edition 15.9.1.11 */
+static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
+{
+ return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
+}
+
+/* ECMA-262 3rd Edition 15.9.1.12 */
+static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
+{
+ DOUBLE time;
+
+ year += floor(month/12);
+
+ month = fmod(month, 12);
+ if(month<0) month += 12;
+
+ time = time_from_year(year);
+
+ day += floor(time / MS_PER_DAY);
+ day += day_from_month(month, in_leap_year(time));
+
+ return day-1;
+}
+
+/* ECMA-262 3rd Edition 15.9.1.13 */
+static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
+{
+ return day*MS_PER_DAY + time;
+}
+
/* ECMA-262 3rd Edition 15.9.1.14 */
static inline DOUBLE time_clip(DOUBLE time)
{
@@ -1022,8 +1152,9 @@ static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, Disp
DateInstance *date;
HRESULT hres;
TIME_ZONE_INFORMATION tzi;
+ DWORD dret;
- GetTimeZoneInformation(&tzi);
+ dret = GetTimeZoneInformation(&tzi);
date = heap_alloc_zero(sizeof(DateInstance));
if(!date)
@@ -1040,6 +1171,10 @@ static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, Disp
date->time = time;
date->bias = tzi.Bias;
+ date->standardDate = tzi.StandardDate;
+ date->standardBias = tzi.StandardBias;
+ date->daylightDate = tzi.DaylightDate;
+ date->daylightBias = tzi.DaylightBias;
*ret = &date->dispex;
return S_OK;
@@ -1095,9 +1230,84 @@ static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPP
break;
}
- default:
- FIXME("unimplemented argcnt %d\n", arg_cnt(dp));
- return E_NOTIMPL;
+ /* ECMA-262 3rd Edition 15.9.3.1 */
+ default: {
+ VARIANT year, month, vdate, hours, minutes, seconds, ms;
+ DateInstance *di;
+ int arg_no = arg_cnt(dp), y;
+
+ hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &year);
+ if(FAILED(hres))
+ return hres;
+ y = num_val(&year);
+ if(0<=y && y<=99)
+ y += 1900;
+
+
+ hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &month);
+ if(FAILED(hres))
+ return hres;
+
+ if(arg_no>2) {
+ hres = to_number(dispex->ctx, get_arg(dp, 2), ei, &vdate);
+ if(FAILED(hres))
+ return hres;
+ }
+ else {
+ V_VT(&vdate) = VT_R8;
+ V_R8(&vdate) = 1;
+ }
+
+ if(arg_no>3) {
+ hres = to_number(dispex->ctx, get_arg(dp, 3), ei, &hours);
+ if(FAILED(hres))
+ return hres;
+ }
+ else {
+ V_VT(&hours) = VT_R8;
+ V_R8(&hours) = 0;
+ }
+
+ if(arg_no>4) {
+ hres = to_number(dispex->ctx, get_arg(dp, 4), ei, &minutes);
+ if(FAILED(hres))
+ return hres;
+ }
+ else {
+ V_VT(&minutes) = VT_R8;
+ V_R8(&minutes) = 0;
+ }
+
+ if(arg_no>5) {
+ hres = to_number(dispex->ctx, get_arg(dp, 5), ei, &seconds);
+ if(FAILED(hres))
+ return hres;
+ }
+ else {
+ V_VT(&seconds) = VT_R8;
+ V_R8(&seconds) = 0;
+ }
+
+ if(arg_no>6) {
+ hres = to_number(dispex->ctx, get_arg(dp, 6), ei, &ms);
+ if(FAILED(hres))
+ return hres;
+ }
+ else {
+ V_VT(&ms) = VT_R8;
+ V_R8(&ms) = 0;
+ }
+
+ hres = create_date(dispex->ctx, TRUE, time_clip(
+ make_date(make_day(y, num_val(&month), num_val(&vdate)),
+ make_time(num_val(&hours), num_val(&minutes),
+ num_val(&seconds), num_val(&ms)))), &date);
+ if(FAILED(hres))
+ return hres;
+
+ di = (DateInstance*)date;
+ di->time = utc(di->time, di);
+ }
}
V_VT(retv) = VT_DISPATCH;
More information about the wine-cvs
mailing list