From: Francis De Brabandere francisdb@gmail.com
--- dlls/vbscript/global.c | 113 +++++++++++++++++++++++++++++++++++- dlls/vbscript/tests/api.vbs | 75 ++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 972d0d2ea0b..e58c8534054 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -2581,10 +2581,117 @@ static HRESULT Global_Filter(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, return E_NOTIMPL; }
-static HRESULT Global_Join(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Join(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR string, tmp, str, conv_str = NULL, delimiter = NULL; + SAFEARRAY *sa; + HRESULT hres; + INT i; + UINT string_len, str_len, delimiter_len; + LONG lbound, ubound; + VARIANT *data; + + TRACE("%s %u...\n", debugstr_variant(args), args_cnt); + + assert(1 <= args_cnt && args_cnt <= 2); + + switch(V_VT(args)) { + case VT_NULL: + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + case VT_DISPATCH: + return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD); + case VT_VARIANT|VT_ARRAY: + sa = V_ARRAY(args); + break; + case VT_VARIANT|VT_ARRAY|VT_BYREF: + sa = *V_ARRAYREF(args); + break; + default: + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + } + + if (args_cnt == 2) + { + if ( V_VT(args+1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + if(V_VT(args+1) != VT_BSTR) + { + hres = to_string(args+1, &delimiter); + if(FAILED(hres)) { + return hres; + } + } + else + delimiter = V_BSTR(args+1); + } + else + delimiter = SysAllocString(L" "); + + if (SafeArrayGetDim(sa) != 1) + return E_NOTIMPL; + + hres = SafeArrayGetLBound(sa, 1, &lbound); + if(FAILED(hres)) + return hres; + + hres = SafeArrayGetUBound(sa, 1, &ubound); + if(FAILED(hres)) + return hres; + + hres = SafeArrayAccessData(sa, (void**)&data); + if (FAILED(hres)) + return hres; + + delimiter_len = SysStringLen(delimiter); + + string = SysAllocString(L""); + + for (i = lbound; i <= ubound; i++) { + if(V_VT(&data[i]) != VT_BSTR) { + hres = to_string(&data[i], &conv_str); + if(FAILED(hres)) { + SafeArrayUnaccessData(sa); + SysFreeString(string); + + if (args_cnt == 2) + if(V_VT(args+1) != VT_BSTR) + SysFreeString(delimiter); + + return hres; + } + str = conv_str; + } + else + str = V_BSTR(&data[i]); + + if (i > lbound) { + string_len = SysStringLen(string); + tmp = SysAllocStringLen(string, string_len + delimiter_len); + memcpy(tmp + string_len, delimiter, delimiter_len * sizeof(WCHAR)); + SysFreeString(string); + string = tmp; + } + + string_len = SysStringLen(string); + str_len = SysStringLen(str); + tmp = SysAllocStringLen(string, string_len + str_len); + memcpy(tmp + string_len, str, str_len * sizeof(WCHAR)); + SysFreeString(string); + string = tmp; + + if (conv_str) { + SysFreeString(conv_str); + conv_str = NULL; + } + } + + SafeArrayUnaccessData(sa); + + if (args_cnt == 2) + if(V_VT(args+1) != VT_BSTR) + SysFreeString(delimiter); + + return return_bstr(res, string); }
static HRESULT Global_Split(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index dfa2816bec5..70f6a23c569 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -22,6 +22,28 @@ Dim x Class EmptyClass End Class
+' Helper function to print a variable +Function ToString(x) + If IsEmpty(x) Then + ToString = "Empty" + ElseIf IsNull(x) Then + ToString = "Null" + ElseIf IsObject(x) Then + ToString = "Object" + ElseIf IsArray(x) Then + Dim i, arrStr + arrStr = "Array(" + For i = LBound(x) To UBound(x) + arrStr = arrStr & ToString(x(i)) + If i < UBound(x) Then arrStr = arrStr & ", " + Next + arrStr = arrStr & ")" + ToString = arrStr + Else + ToString = CStr(x) + End If +End Function + Call ok(vbSunday = 1, "vbSunday = " & vbSunday) Call ok(getVT(vbSunday) = "VT_I2", "getVT(vbSunday) = " & getVT(vbSunday)) Call ok(vbMonday = 2, "vbMonday = " & vbMonday) @@ -713,6 +735,59 @@ TestLCase 0.123, doubleAsString(0.123) TestLCase Empty, "" Call ok(getVT(LCase(Null)) = "VT_NULL", "getVT(LCase(Null)) = " & getVT(LCase(Null)))
+' Join + +Sub TestJoin(arg, ex) + x = Join(arg) + Call ok(x = ex, "Join(" & ToString(arg) & ") = " & x & " expected " & ex) +End Sub + +Sub TestJoin2(arg1, arg2, ex) + x = Join(arg1, arg2) + Call ok(x = ex, "Join(" & ToString(arg1) & "," & arg2 & ") = " & x & " expected " & ex) +End Sub + +Sub TestJoinError(arg, num) + On Error Resume Next + Call Join(arg) + Dim err_num: err_num = Err.number + Call Err.clear() + On Error GoTo 0 + Call ok(err_num = num, "Join(" & ToString(arg) & ") expected Err.number = " & num & " got " & err_num) +End Sub + +TestJoin Array(), "" +TestJoin Array("a", "b", "c"), "a b c" +TestJoin Array("a", "b", "c", 1, 2, 3), "a b c 1 2 3" +TestJoin Array(1, Empty), "1 " + +TestJoin2 Array(), "", "" +TestJoin2 Array("a"), "-", "a" +TestJoin2 Array("a", "b"), "-", "a-b" +TestJoin2 Array("a", "b", "c"), "", "abc" +TestJoin2 Array(1, "Hello"), "-", "1-Hello" +TestJoin2 Array("a", "b", "c"), Empty, "abc" + +TestJoinError Null , 94 +TestJoinError Empty, 13 +TestJoinError 1, 13 +TestJoinError "test", 13 +TestJoinError 1.2, 13 +TestJoinError New EmptyClass, 438 +TestJoinError Array(1, Null), 13 + +On Error Resume Next +Call Join(Array(), Null) +Call ok(Err.number = 94, "Join(Array(), Null) expected Err.number = 94 got " & Err.number) +Call Err.clear +On Error GoTo 0 + +On Error Resume Next +Call Join(Array(), "a", "b") +Call ok(Err.number = 450, "Join(Array(), ""a"", ""b"") expected Err.number = 450 got " & Err.number) +Call Err.clear +On Error GoTo 0 + x=Split("abc") Call ok(x(0) = "abc", "Split(""abc"")(0)=" & x(0)) x = Split("abc def")