Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52686 Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
v2: changed string argument to case-insensitive comparison, improved error handling.
dlls/vbscript/global.c | 63 +++++++++++++++++++++++++++++++++++-- dlls/vbscript/tests/api.vbs | 48 ++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 18da8e4991f..1d3929ba249 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -2205,10 +2205,67 @@ static HRESULT Global_GetObject(BuiltinDisp *This, VARIANT *args, unsigned args_ return hres; }
-static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR interval = NULL; + UDATE ud = {{ 0 }}; + HRESULT hres; + double date; + int count; + + TRACE("\n"); + + assert(args_cnt == 3); + + if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if (V_VT(args + 2) == VT_NULL) + return return_null(res); + + hres = to_string(args, &interval); + if (SUCCEEDED(hres)) + hres = to_int(args + 1, &count); + if (SUCCEEDED(hres)) + hres = to_system_time(args + 2, &ud.st); + if (SUCCEEDED(hres)) + { + if (!wcsicmp(interval, L"yyyy")) + ud.st.wYear += count; + else if (!wcsicmp(interval, L"q")) + ud.st.wMonth += 3 * count; + else if (!wcsicmp(interval, L"m")) + ud.st.wMonth += count; + else if (!wcsicmp(interval, L"y") + || !wcsicmp(interval, L"d") + || !wcsicmp(interval, L"w")) + { + ud.st.wDay += count; + } + else if (!wcsicmp(interval, L"ww")) + ud.st.wDay += 7 * count; + else if (!wcsicmp(interval, L"h")) + ud.st.wHour += count; + else if (!wcsicmp(interval, L"n")) + ud.st.wMinute += count; + else if (!wcsicmp(interval, L"s")) + ud.st.wSecond += count; + else + { + WARN("Unrecognized interval %s.\n", debugstr_w(interval)); + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + } + + SysFreeString(interval); + + if (SUCCEEDED(hres)) + hres = VarDateFromUdateEx(&ud, 0, 0, &date); + + if (SUCCEEDED(hres)) + hres = return_date(res, date); + + return hres; }
static HRESULT Global_DateDiff(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index 3bc64d74193..a765eb1fcda 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -1988,4 +1988,52 @@ call testDateSerial(2000, 14, 2, 2001, 2, 2) call testDateSerial(9999, 12, 1, 9999, 12, 1) call testDateSerialError()
+sub testDateAdd(d, interval, number, expected_date) + dim x + x = DateAdd(interval, number, d) + call ok(Year(x) = Year(expected_date), "year = " & Year(x) & " expected " & Year(expected_date)) + call ok(Month(x) = Month(expected_date), "month = " & Month(x) & " expected " & Month(expected_date)) + call ok(Day(x) = Day(expected_date), "day = " & Day(x) & " expected " & Day(expected_date)) + call ok(getVT(x) = "VT_DATE*", "getVT = " & getVT(x)) +end sub + +sub testDateAddError() + on error resume next + dim x + call Err.clear() + x = DateAdd("k", 1, DateSerial(2000, 2, 1)) + call ok(Err.number = 5, "Err.number = " & Err.number) + call ok(getVT(x) = "VT_EMPTY*", "getVT = " & getVT(x)) + call Err.clear() + call DateAdd(null, 1, DateSerial(2000, 2, 1)) + call ok(Err.number = 94, "Err.number = " & Err.number) + call Err.clear() + call DateAdd("q", null, DateSerial(2000, 2, 1)) + call ok(Err.number = 94, "Err.number = " & Err.number) + call Err.clear() + x = DateAdd("q", 1, null) + call ok(getVT(x) = "VT_NULL*", "getVT = " & getVT(x)) + call ok(Err.number = 0, "Err.number = " & Err.number) +end sub + +call testDateAdd(DateSerial(2000, 1, 1), "yyyy", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "yYyy", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "q", 1, DateSerial(2000, 4, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "Q", 1, DateSerial(2000, 4, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "m", -1, DateSerial(1999, 12, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "M", -1, DateSerial(1999, 12, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "y", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "Y", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "d", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "D", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "w", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 12, 31), "W", 1, DateSerial(2001, 1, 1)) +call testDateAdd(DateSerial(2000, 1, 1), "y", -1, DateSerial(1999, 12, 31)) +call testDateAdd(DateSerial(2000, 1, 1), "d", -1, DateSerial(1999, 12, 31)) +call testDateAdd(DateSerial(2000, 1, 1), "w", -1, DateSerial(1999, 12, 31)) +call testDateAdd(DateSerial(2000, 1, 1), "ww", 1, DateSerial(2000, 1, 8)) +call testDateAdd(DateSerial(2000, 1, 1), "ww", -1, DateSerial(1999, 12, 25)) +call testDateAdd(DateSerial(2000, 1, 1), "Ww", -1, DateSerial(1999, 12, 25)) +call testDateAddError() + Call reportSuccess()
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/vbscript/global.c | 43 ++++++++++++++++++++++++++++++--- dlls/vbscript/tests/api.vbs | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 1d3929ba249..62b41cea39d 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -1982,10 +1982,47 @@ static HRESULT Global_Month(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, return FAILED(hres) ? hres : return_short(res, st.wMonth); }
-static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + int first_day = 0; + SYSTEMTIME st; + HRESULT hres; + + TRACE("(%s)\n", debugstr_variant(args)); + + assert(args_cnt == 1 || args_cnt == 2); + + /* [vbSunday = 1, vbSaturday = 7] -> wDayOfWeek [0, 6] */ + if (args_cnt == 2) + { + if (V_VT(args + 1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args + 1, &first_day); + if (SUCCEEDED(hres)) + { + if (!first_day) + { + /* vbUseSystemDayOfWeek */ + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IFIRSTDAYOFWEEK, (LPWSTR)&first_day, + sizeof(&first_day) / sizeof(WCHAR)); + first_day = (first_day + 1) % 7; + } + else if (first_day >= 1 && first_day <= 7) + { + first_day--; + } + else + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + } + + if (V_VT(args) == VT_NULL) + return return_null(res); + + if (FAILED(hres = to_system_time(args, &st))) return hres; + + return FAILED(hres) ? hres : return_short(res, 1 + (7 - first_day + st.wDayOfWeek) % 7); }
static HRESULT Global_Year(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index a765eb1fcda..657cec9195f 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -2036,4 +2036,52 @@ call testDateAdd(DateSerial(2000, 1, 1), "ww", -1, DateSerial(1999, 12, 25)) call testDateAdd(DateSerial(2000, 1, 1), "Ww", -1, DateSerial(1999, 12, 25)) call testDateAddError()
+sub testWeekday(d, firstday, wd) + dim x, x2 + x = Weekday(d, firstday) + call ok(x = wd, "weekday = " & x & " expected " & wd) + call ok(getVT(x) = "VT_I2*", "getVT = " & getVT(x)) + if firstday = vbSunday then + x = Weekday(d) + call ok(x = wd, "weekday = " & x & " expected " & wd) + end if + x = Weekday(d, vbUseSystemDayOfWeek) + x2 = Weekday(d, firstDayOfWeek) + call ok(x = x2, "weekday = " & x & " expected " & x2) +end sub + +sub testWeekdayError() + on error resume next + dim x + call Err.clear() + call Weekday(DateSerial(1000, 1, 1), 10) + call ok(Err.number = 5, "Err.number = " & Err.number) + call Err.clear() + call Weekday(DateSerial(1000, 1, 1), -1) + call ok(Err.number = 5, "Err.number = " & Err.number) + call Err.clear() + call Weekday(null, -1) + call ok(Err.number = 5, "Err.number = " & Err.number) + call Err.clear() + call Weekday(DateSerial(1000, 1, 1), null) + call ok(Err.number = 94, "Err.number = " & Err.number) + call Err.clear() + x = Weekday(null, vbSunday) + call ok(Err.number = 0, "Err.number = " & Err.number) + call ok(getVT(x) = "VT_NULL*", "getVT = " & getVT(x)) + call Err.clear() + call Weekday(null, null) + call ok(Err.number = 94, "Err.number = " & Err.number) +end sub + +call testWeekday(DateSerial(2000, 1, 1), vbSunday, 7) +call testWeekday(DateSerial(2000, 1, 1), vbMonday, 6) +call testWeekday(DateSerial(2000, 1, 1), vbTuesday, 5) +call testWeekday(DateSerial(2000, 1, 1), vbWednesday, 4) +call testWeekday(DateSerial(2000, 1, 1), vbThursday, 3) +call testWeekday(DateSerial(2000, 1, 1), vbFriday, 2) +call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1) +call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1) +call testWeekdayError() + Call reportSuccess()
Hi Nikolay,
+call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1) +call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1)
You have this line twice. Is this intentional?
Maybe you could add a test where second argument of Weekday is omitted.
Thanks, Robert
On 5/17/22 10:48, Robert Wilhelm wrote:
Hi Nikolay,
+call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1) +call testWeekday(DateSerial(2000, 1, 1), vbSaturday, 1)
You have this line twice. Is this intentional?
It was not intentional, I'll resend after first patch gets in (or doesn't).
Maybe you could add a test where second argument of Weekday is omitted.
It's there, within testWeekday().
Thanks, Robert