From d50f5f67c7b143ebc92d206ab78110da5a3efc4e Mon Sep 17 00:00:00 2001 From: Robert Wilhelm Date: Mon, 24 Aug 2020 11:43:57 +0200 Subject: [PATCH] vbscript: Implement Split. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47570 Signed-off-by: Robert Wilhelm Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/vbscript/global.c | 149 +++++++++++++++++++++++++++++++++++- dlls/vbscript/tests/api.vbs | 65 ++++++++++++++++ 2 files changed, 211 insertions(+), 3 deletions(-) diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 122f5c7b71a..00f74104dea 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -2291,10 +2291,153 @@ static HRESULT Global_Join(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, V return E_NOTIMPL; } -static HRESULT Global_Split(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Split(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR str, string, delimeter = NULL; + int count, max, mode, len, start, end, ret, delimeterlen = 1; + int i,*indices = NULL, indices_max = 8; + SAFEARRAYBOUND bounds; + SAFEARRAY *sa = NULL; + VARIANT *data, var; + HRESULT hres = S_OK; + + TRACE("%s %u...\n", debugstr_variant(args), args_cnt); + + assert(1 <= args_cnt && args_cnt <= 4); + + if(V_VT(args) == VT_NULL || (args_cnt > 1 && V_VT(args+1) == VT_NULL) || (args_cnt > 2 && V_VT(args+2) == VT_NULL) + || (args_cnt == 4 && V_VT(args+3) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if(V_VT(args) != VT_BSTR) { + hres = to_string(args, &string); + if(FAILED(hres)) + return hres; + }else { + string = V_BSTR(args); + } + + if(args_cnt > 1) { + if(V_VT(args+1) != VT_BSTR) { + hres = to_string(args+1, &delimeter); + if(FAILED(hres)) + goto error; + }else { + delimeter = V_BSTR(args+1); + } + delimeterlen = SysStringLen(delimeter); + } + + if(args_cnt > 2) { + hres = to_int(args+2, &max); + if(FAILED(hres)) + goto error; + if (max < -1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + }else { + max = -1; + } + + if(args_cnt == 4) { + hres = to_int(args+3, &mode); + if(FAILED(hres)) + goto error; + if (mode != 0 && mode != 1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + }else { + mode = 0; + } + + start = 0; + + len = SysStringLen(string); + count = 0; + + indices = heap_alloc( indices_max * sizeof(int)); + if(!indices) { + hres = E_OUTOFMEMORY; + goto error; + } + + while(1) { + ret = -1; + if (delimeterlen) { + ret = FindStringOrdinal(FIND_FROMSTART, string + start, len - start, + delimeter ? delimeter : L" ", delimeterlen, mode); + } + + if (ret == -1) { + end = len; + }else { + end = start + ret; + } + + if (count == indices_max) { + indices_max *= 2; + indices = heap_realloc( indices, indices_max * sizeof(int)); + if(!indices) { + hres = E_OUTOFMEMORY; + goto error; + } + } + indices[count++] = end; + + if (ret == -1 || count == max) break; + start = start + ret + delimeterlen; + if (start > len) break; + } + + bounds.lLbound = 0; + bounds.cElements = count; + sa = SafeArrayCreate( VT_VARIANT, 1, &bounds); + if (!sa) { + hres = E_OUTOFMEMORY; + goto error; + } + hres = SafeArrayAccessData(sa, (void**)&data); + if(FAILED(hres)) { + SafeArrayDestroy(sa); + goto error; + } + + start = 0; + for (i = 0; i < count; i++) { + str = SysAllocStringLen(string + start, indices[i] - start); + if (!str) { + hres = E_OUTOFMEMORY; + break; + } + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = str; + + hres = VariantCopyInd(data+i, &var); + if(FAILED(hres)) { + SafeArrayUnaccessData(sa); + SafeArrayDestroy(sa); + goto error; + } + start = indices[i]+delimeterlen; + } + SafeArrayUnaccessData(sa); + +error: + if(SUCCEEDED(hres) && res) { + V_VT(res) = VT_ARRAY|VT_VARIANT; + V_ARRAY(res) = sa; + }else { + if (sa) SafeArrayDestroy(sa); + } + + heap_free(indices); + if(V_VT(args) != VT_BSTR) + SysFreeString(string); + if(V_VT(args+1) != VT_BSTR) + SysFreeString(delimeter); + return hres; } static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index 6af49c849d3..787da7cd713 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -609,6 +609,71 @@ TestLCase 0.123, doubleAsString(0.123) TestLCase Empty, "" Call ok(getVT(LCase(Null)) = "VT_NULL", "getVT(LCase(Null)) = " & getVT(LCase(Null))) +x=Split("abc") +Call ok(x(0) = "abc", "Split(""abc"")(0)=" & x(0)) +x = Split("abc def") +Call ok(x(0) = "abc", "Split(""abc def"")(0)=" & x(0)) +Call ok(x(1) = "def", "Split(""abc def"")(1)=" & x(1)) +x = Split("abc def ghi") +Call ok(x(0) = "abc", "Split(""abc def ghi"")(0)=" & x(0)) +Call ok(x(1) = "def", "Split(""abc def ghi"")(1)=" & x(1)) +Call ok(x(2) = "ghi", "Split(""abc def ghi"")(2)=" & x(2)) +x = Split("abc def","") +Call ok(x(0) = "abc def", "Split(""abc def"","""")(0)=" & x(0)) +x = Split("abc-def","-") +Call ok(x(0) = "abc", "Split(""abc-def"",""-"")(0)=" & x(0)) +Call ok(x(1) = "def", "Split(""abc-def"",""-"")(1)=" & x(1)) +x = Split("abc--def","-") +Call ok(x(0) = "abc", "Split(""abc--def"",""-"")(0)=" & x(0)) +Call ok(x(1) = "", "Split(""abc--def"",""-"")(1)=" & x(1)) +Call ok(x(2) = "def", "Split(""abc--def"",""-"")(2)=" & x(2)) +x = Split("abcdefghi","def") +Call ok(x(0) = "abc", "Split(""abcdefghi"",""def"")(0)=" & x(0)) +Call ok(x(1) = "ghi", "Split(""abcdefghi"",""def"")(1)=" & x(1)) +x = Split("12345",3) +Call ok(x(0) = "12", "Split(""12345"",3)(0)=" & x(0)) +Call ok(x(1) = "45", "Split(""12345"",3)(1)=" & x(1)) +x = Split("12345",5) +Call ok(x(0) = "1234", "Split(""12345"",5)(0)=" & x(0)) +Call ok(x(1) = "", "Split(""12345"",5)(1)=" & x(1)) +x = Split("12345",12) +Call ok(x(0) = "", "Split(""12345"",12)(0)=" & x(0)) +Call ok(x(1) = "345", "Split(""12345"",12)(1)=" & x(1)) +x = Split("abc-def-ghi","-") +Call ok(UBound(x) = 2, "UBound(Split(""abc-def-ghi"",""-""))=" & UBound(x)) +x = Split("a b c d e f g h i j k l m n o p q") +Call ok(UBound(x) = 16, "UBound(Split(""a b c d e f g h i j k l m n o p q""))=" & UBound(x)) +x = Split("abc-def-ghi","-",2) +Call ok(UBound(x) = 1, "UBound(Split(""abc-def-ghi"",""-"",2))=" & UBound(x)) +x = Split("abc-def-ghi","-",4) +Call ok(UBound(x) = 2, "UBound(Split(""abc-def-ghi"",""-"",4))=" & UBound(x)) +x = Split("abc-def-ghi","-",-1) +Call ok(UBound(x) = 2, "UBound(Split(""abc-def-ghi"",""-"",-1))=" & UBound(x)) +x = Split("abc-def-ghi","-",-1) +Call ok(UBound(x) = 2, "UBound(Split(""abc-def-ghi"",""-"",-42))=" & UBound(x)) +x = Split("abcZdefZghi","Z",3,0) +Call ok(UBound(x) = 2, "UBound(Split(""abcZdefZghi"",""Z"",3,0))=" & UBound(x)) +x = Split("abcZdefZghi","z",3,0) +Call ok(UBound(x) = 0, "UBound(Split(""abcZdefZghi"",""z"",3,0))=" & UBound(x)) +x = Split("abcZdefZghi","z",3,1) +Call ok(UBound(x) = 2, "UBound(Split(""abcZdefZghi"",""z"",3,1))=" & UBound(x)) + +Sub testSplitError(arg1, arg2, arg3, arg4, error_num) + on error resume next + Dim x + + Call Err.clear() + x = Split(arg1, arg2, arg3, arg4) + Call ok(Err.number = error_num, "Err.number = " & Err.number) +End Sub + +call testSplitError("abc-def-ghi", "-", -1, 2, 5) +call testSplitError("abc-def-ghi", "-", -42, 0, 5) +call testSplitError(null, "-", -1, 0, 94) +call testSplitError("abc-def-ghi", null, -1, 0, 94) +call testSplitError("abc-def-ghi", "-", null, 0, 94) +call testSplitError("abc-def-ghi", "-", -1, null, 94) + Sub TestStrComp(str_left, str_right, mode, ex) x = StrComp(str_left, str_right, mode) Call ok(x = ex, "StrComp(" & str_left & ", " & str_right & ", " & mode & ") = " & x & " expected " & ex)