<html><head></head><body><div style="font-family: Verdana;font-size: 12.0px;"><div> </div>

<div>
<div>Hi Nikolay,</div>

<div> </div>

<div>Thanks for working on vbs builtin.</div>

<div> </div>

<div>On minor nit:</div>

<div> </div>

<div>If we pass NULL as argument, we get error type mismatch instead of illegal null usage.</div>

<div> </div>

<div>In some builtins, we explicitely check for NULL like following:</div>

<div> </div>

<div>  if(V_VT(arg) == VT_NULL)<br/>
        return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);</div>

<div>
<div> </div>

<div>Quite a few builtins lack these checks...</div>

<div> </div>

<div>Best regards,</div>

<div>Robert</div>

<div name="quote" style="margin:10px 5px 5px 10px; padding: 10px 0 10px 10px; border-left:2px solid #C3D9E5; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">
<div style="margin:0 0 10px 0;"><b>Gesendet:</b> Sonntag, 15. Mai 2022 um 14:50 Uhr<br/>
<b>Von:</b> "Nikolay Sivov" <nsivov@codeweavers.com><br/>
<b>An:</b> wine-devel@winehq.org<br/>
<b>Betreff:</b> [PATCH 2/2] vbscript: Implement DateAdd().</div>

<div name="quoted-content">Wine-Bug: <a href="https://bugs.winehq.org/show_bug.cgi?id=52686" target="_blank">https://bugs.winehq.org/show_bug.cgi?id=52686</a><br/>
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com><br/>
---<br/>
dlls/vbscript/global.c | 57 +++++++++++++++++++++++++++++++++++--<br/>
dlls/vbscript/tests/api.vbs | 29 +++++++++++++++++++<br/>
2 files changed, 83 insertions(+), 3 deletions(-)<br/>
<br/>
diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c<br/>
index da3da1f04d8..f8770093f0e 100644<br/>
--- a/dlls/vbscript/global.c<br/>
+++ b/dlls/vbscript/global.c<br/>
@@ -2209,10 +2209,61 @@ static HRESULT Global_GetObject(BuiltinDisp *This, VARIANT *args, unsigned args_<br/>
return hres;<br/>
}<br/>
<br/>
-static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)<br/>
+static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)<br/>
{<br/>
- FIXME("\n");<br/>
- return E_NOTIMPL;<br/>
+ BSTR interval = NULL;<br/>
+ UDATE ud = { 0 };<br/>
+ HRESULT hres;<br/>
+ double date;<br/>
+ int count;<br/>
+<br/>
+ TRACE("\n");<br/>
+<br/>
+ assert(args_cnt == 3);<br/>
+<br/>
+ hres = to_string(args, &interval);<br/>
+ if (SUCCEEDED(hres))<br/>
+ hres = to_int(args + 1, &count);<br/>
+ if (SUCCEEDED(hres))<br/>
+ hres = to_system_time(args + 2, &ud.st);<br/>
+ if (SUCCEEDED(hres))<br/>
+ {<br/>
+ if (!wcscmp(interval, L"yyyy"))<br/>
+ ud.st.wYear += count;<br/>
+ else if (!wcscmp(interval, L"q"))<br/>
+ ud.st.wMonth += 3 * count;<br/>
+ else if (!wcscmp(interval, L"m"))<br/>
+ ud.st.wMonth += count;<br/>
+ else if (!wcscmp(interval, L"y")<br/>
+ || !wcscmp(interval, L"d")<br/>
+ || !wcscmp(interval, L"w"))<br/>
+ {<br/>
+ ud.st.wDay += count;<br/>
+ }<br/>
+ else if (!wcscmp(interval, L"ww"))<br/>
+ ud.st.wDay += 7 * count;<br/>
+ else if (!wcscmp(interval, L"h"))<br/>
+ ud.st.wHour += count;<br/>
+ else if (!wcscmp(interval, L"n"))<br/>
+ ud.st.wMinute += count;<br/>
+ else if (!wcscmp(interval, L"s"))<br/>
+ ud.st.wSecond += count;<br/>
+ else<br/>
+ {<br/>
+ WARN("Unrecognized interval %s.\n", debugstr_w(interval));<br/>
+ hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);<br/>
+ }<br/>
+ }<br/>
+<br/>
+ SysFreeString(interval);<br/>
+<br/>
+ if (SUCCEEDED(hres))<br/>
+ hres = VarDateFromUdateEx(&ud, 0, 0, &date);<br/>
+<br/>
+ if (SUCCEEDED(hres))<br/>
+ hres = return_date(res, date);<br/>
+<br/>
+ return hres;<br/>
}<br/>
<br/>
static HRESULT Global_DateDiff(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)<br/>
diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs<br/>
index f65789184e0..d8b8578be2e 100644<br/>
--- a/dlls/vbscript/tests/api.vbs<br/>
+++ b/dlls/vbscript/tests/api.vbs<br/>
@@ -1986,4 +1986,33 @@ call testDateSerial(2000, 14, 2, 2001, 2, 2)<br/>
call testDateSerial(9999, 12, 1, 9999, 12, 1)<br/>
call testDateSerialError()<br/>
<br/>
+sub testDateAdd(d, interval, number, expected_date)<br/>
+ dim x<br/>
+ x = DateAdd(interval, number, d)<br/>
+ call ok(Year(x) = Year(expected_date), "year = " & Year(x) & " expected " & Year(expected_date))<br/>
+ call ok(Month(x) = Month(expected_date), "month = " & Month(x) & " expected " & Month(expected_date))<br/>
+ call ok(Day(x) = Day(expected_date), "day = " & Day(x) & " expected " & Day(expected_date))<br/>
+ call ok(getVT(x) = "VT_DATE*", "getVT = " & getVT(x))<br/>
+end sub<br/>
+<br/>
+sub testDateAddError()<br/>
+ on error resume next<br/>
+ call Err.clear()<br/>
+ call DateAdd("k", 1, DateSerial(2000, 2, 1))<br/>
+ call ok(Err.number = 5, "Err.number = " & Err.number)<br/>
+end sub<br/>
+<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "yyyy", 1, DateSerial(2001, 1, 1))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "q", 1, DateSerial(2000, 4, 1))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "m", -1, DateSerial(1999, 12, 1))<br/>
+call testDateAdd(DateSerial(2000, 12, 31), "y", 1, DateSerial(2001, 1, 1))<br/>
+call testDateAdd(DateSerial(2000, 12, 31), "d", 1, DateSerial(2001, 1, 1))<br/>
+call testDateAdd(DateSerial(2000, 12, 31), "w", 1, DateSerial(2001, 1, 1))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "y", -1, DateSerial(1999, 12, 31))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "d", -1, DateSerial(1999, 12, 31))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "w", -1, DateSerial(1999, 12, 31))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "ww", 1, DateSerial(2000, 1, 8))<br/>
+call testDateAdd(DateSerial(2000, 1, 1), "ww", -1, DateSerial(1999, 12, 25))<br/>
+call testDateAddError()<br/>
+<br/>
Call reportSuccess()<br/>
--<br/>
2.35.1<br/>
<br/>
 </div>
</div>
</div>
</div></div></body></html>