[PATCH v3] vbscript: Implement Split.

Robert Wilhelm robert.wilhelm at gmx.net
Mon Aug 17 16:08:24 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47570
Signed-off-by: Robert Wilhelm <robert.wilhelm at gmx.net>
---
v3: Try to address comments from Jacek's review: Fix some corner cases, avoid memory leaks and add more tests.
---
 dlls/vbscript/global.c      | 128 +++++++++++++++++++++++++++++++++++-
 dlls/vbscript/tests/api.vbs |  42 ++++++++++++
 2 files changed, 167 insertions(+), 3 deletions(-)

diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c
index 122f5c7b71..d697c63be2 100644
--- a/dlls/vbscript/global.c
+++ b/dlls/vbscript/global.c
@@ -2291,10 +2291,132 @@ 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;
+    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_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;;
+    }else {
+        max = -1;
+    }
+
+    if(args_cnt == 4) {
+        hres = to_int(args+3, &mode);
+        if(FAILED(hres))
+            goto error;
+        if (mode != 0 && mode != 1) {
+            FIXME("unknown compare mode = %d\n", mode);
+            hres = E_FAIL;
+            goto error;
+        }
+    }
+    else {
+        mode = 0;
+    }
+
+    start = 0;
+    bounds.lLbound = 0;
+    bounds.cElements = 0;
+    sa = SafeArrayCreate( VT_VARIANT, 1, &bounds);
+    if (!sa)
+    {
+        hres = E_OUTOFMEMORY;
+        goto error;
+    }
+    len = SysStringLen(string);
+    count = 0;
+
+    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 (end-start) {
+            str = SysAllocStringLen(string + start, end - start);
+            if (!str) {
+                hres = E_OUTOFMEMORY;
+                break;
+            }
+            V_VT(&var) = VT_BSTR;
+            V_BSTR(&var) = str;
+            bounds.cElements++;
+            SafeArrayRedim(sa, &bounds);
+            hres = SafeArrayAccessData(sa, (void**)&data);
+            if(FAILED(hres)) {
+                SafeArrayDestroy(sa);
+                break;
+            }
+
+            hres = VariantCopyInd(data+count, &var);
+            if(FAILED(hres)) {
+                SafeArrayUnaccessData(sa);
+                SafeArrayDestroy(sa);
+                break;
+            }
+
+            SafeArrayUnaccessData(sa);
+            count++;
+        }
+
+        if (ret == -1) break;
+        start = start + ret + delimeterlen;
+        if (count == max) break;
+        if (start >= len) break;
+    }
+
+error:
+    if(res) {
+        V_VT(res) = VT_ARRAY|VT_VARIANT;
+        V_ARRAY(res) = sa;
+    }else {
+        if (sa) SafeArrayDestroy(sa);
+    }
+
+    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 6af49c849d..440c2e38d5 100644
--- a/dlls/vbscript/tests/api.vbs
+++ b/dlls/vbscript/tests/api.vbs
@@ -609,6 +609,48 @@ 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 returned " & x(0))
+x = Split("abc def")
+Call ok(x(0) = "abc", "Split returned " & x(0))
+Call ok(x(1) = "def", "Split returned " & x(1))
+x = Split("abc def ghi")
+Call ok(x(0) = "abc", "Split returned " & x(0))
+Call ok(x(1) = "def", "Split returned " & x(1))
+Call ok(x(2) = "ghi", "Split returned " & x(2))
+x = Split("abc def","")
+Call ok(x(0) = "abc def", "Split returned " & x(0))
+x = Split("abc-def","-")
+Call ok(x(0) = "abc", "Split returned " & x(0))
+Call ok(x(1) = "def", "Split returned " & x(1))
+x = Split("abc--def","-")
+Call ok(x(0) = "abc", "Split returned " & x(0))
+Call ok(x(1) = "def", "Split returned " & x(1))
+x = Split("abcdefghi","def")
+Call ok(x(0) = "abc", "Split returned " & x(0))
+Call ok(x(1) = "ghi", "Split returned " & x(1))
+x = Split("12345",3)
+Call ok(x(0) = "12", "Split returned " & x(0))
+Call ok(x(1) = "45", "Split returned " & x(1))
+x = Split("12345",5)
+Call ok(x(0) = "1234", "Split returned " & x(0))
+Call ok(UBound(x) = 0, "Split returned " & UBound(x))
+x = Split("12345",12)
+Call ok(x(0) = "345", "Split returned " & x(0))
+Call ok(UBound(x) = 0, "Split returned " & UBound(x))
+x = Split("abc-def-ghi","-")
+Call ok(UBound(x) = 2, "Split returned " & UBound(x))
+x = Split("abc-def-ghi","-",2)
+Call ok(UBound(x) = 1, "Split returned " & UBound(x))
+x = Split("abc-def-ghi","-",4)
+Call ok(UBound(x) = 2, "Split returned " & UBound(x))
+x = Split("abcZdefZghi","Z",3,0)
+Call ok(UBound(x) = 2, "Split returned " & UBound(x))
+x = Split("abcZdefZghi","z",3,0)
+Call ok(UBound(x) = 0, "Split returned " & UBound(x))
+x = Split("abcZdefZghi","z",3,1)
+Call ok(UBound(x) = 2, "Split returned " & UBound(x))
+
 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)
--
2.26.2





More information about the wine-devel mailing list