Jacek Caban : vbscript: Add Replace function implementation.

Alexandre Julliard julliard at winehq.org
Tue Nov 5 16:11:44 CST 2019


Module: wine
Branch: master
Commit: e343fcaf7656eb0ca0b648d8aa159ab2f6007785
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e343fcaf7656eb0ca0b648d8aa159ab2f6007785

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Nov  5 14:07:58 2019 +0100

vbscript: Add Replace function implementation.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/vbscript/global.c      | 76 +++++++++++++++++++++++++++++++++++++++++++--
 dlls/vbscript/tests/api.vbs | 68 +++++++++++++++++++++++++++++++++++++---
 dlls/vbscript/vbregexp.c    | 42 +++++++++++++++++++++++++
 dlls/vbscript/vbscript.h    |  1 +
 4 files changed, 179 insertions(+), 8 deletions(-)

diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c
index e4ff572412..8d4150ad70 100644
--- a/dlls/vbscript/global.c
+++ b/dlls/vbscript/global.c
@@ -2278,10 +2278,80 @@ static HRESULT Global_Split(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt,
     return E_NOTIMPL;
 }
 
-static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
+static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    BSTR string, find = NULL, replace = NULL, ret;
+    int from = 1, cnt = -1;
+    HRESULT hres = S_OK;
+
+    TRACE("%s %s %s %u...\n", debugstr_variant(args), debugstr_variant(args+1), debugstr_variant(args+2), args_cnt);
+
+    assert(3 <= args_cnt && args_cnt <= 6);
+    if(V_VT(args) != VT_BSTR) {
+        hres = to_string(args, &string);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        string = V_BSTR(args);
+    }
+
+    if(V_VT(args+1) != VT_BSTR) {
+        hres = to_string(args+1, &find);
+        if(FAILED(hres))
+            goto error;
+    }else {
+        find = V_BSTR(args+1);
+    }
+
+    if(V_VT(args+2) != VT_BSTR) {
+        hres = to_string(args+2, &replace);
+        if(FAILED(hres))
+            goto error;
+    }else {
+        replace = V_BSTR(args+2);
+    }
+
+    if(args_cnt >= 4) {
+        hres = to_int(args+3, &from);
+        if(FAILED(hres))
+            goto error;
+        if(from < 1) {
+            hres = E_INVALIDARG;
+            goto error;
+        }
+    }
+
+    if(args_cnt >= 5) {
+        hres = to_int(args+4, &cnt);
+        if(FAILED(hres))
+            goto error;
+        if(cnt < -1) {
+            hres = E_INVALIDARG;
+            goto error;
+        }
+    }
+
+    if(args_cnt == 6)
+        FIXME("copare argument not supported\n");
+
+    ret = string_replace(string, find, replace, from - 1, cnt);
+    if(!ret) {
+        hres = E_OUTOFMEMORY;
+    }else if(res) {
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = ret;
+    }else {
+        SysFreeString(ret);
+    }
+
+error:
+    if(V_VT(args) != VT_BSTR)
+        SysFreeString(string);
+    if(V_VT(args+1) != VT_BSTR)
+        SysFreeString(find);
+    if(V_VT(args+2) != VT_BSTR)
+        SysFreeString(replace);
+    return hres;
 }
 
 static HRESULT Global_StrReverse(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs
index d4f3eeaa47..0a65984483 100644
--- a/dlls/vbscript/tests/api.vbs
+++ b/dlls/vbscript/tests/api.vbs
@@ -640,11 +640,6 @@ TestLTrim "", ""
 TestLTrim 123, "123"
 if isEnglishLang then TestLTrim true, "True"
 
-Sub TestRound(val, exval, vt)
-    Call ok(Round(val) = exval, "Round(" & val & ") = " & Round(val))
-    Call ok(getVT(Round(val)) = vt, "getVT(Round(" & val & ")) = " & getVT(Round(val)))
-End Sub
-
 Sub TestRTrim(str, exstr)
     Call ok(RTrim(str) = exstr, "RTrim(" & str & ") = " & RTrim(str))
 End Sub
@@ -657,6 +652,69 @@ TestRTrim "", ""
 TestRTrim 123, "123"
 if isEnglishLang then TestRTrim true, "True"
 
+sub test_replace(str, find, rep, exp)
+    dim r
+    r = Replace(str, find, rep)
+    ok r = exp, "Replace(""" & str & """, """ & find & """, """ & rep & """) = """ & _
+       r & """ expected """ & exp & """"
+end sub
+
+sub test_replace_from(str, find, rep, from, exp)
+    dim r
+    r = Replace(str, find, rep, from)
+    ok r = exp, "Replace(""" & str & """, """ & find & """, """ & rep & """, " & from & ") = """ & _
+       r & """ expected """ & exp & """"
+end sub
+
+sub test_replace_cnt(str, find, rep, from, cnt, exp)
+    dim r
+    r = Replace(str, find, rep, from, cnt)
+    ok r = exp, "Replace(""" & str & """, """ & find & """, """ & rep & """, " & from & ", " & cnt & ") = """ & _
+       r & """ expected """ & exp & """"
+end sub
+
+test_replace "xx testxx(xx)", "xx", "!", "! test!(!)"
+test_replace "xxx", "", "y", "xxx"
+test_replace "xxxxx", "xx", "y", "yyx"
+test_replace 123, 2, 6, "163"
+test_replace "xyz" & Chr(0) & "xyz", "y", "Y", "xYz" & Chr(0) & "xYz"
+test_replace "xyz" & Chr(0) & "xyz", Chr(0) & "x", "Y" & Chr(0) & Chr(0), "xyzY" & Chr(0) & Chr(0) & "yz"
+
+test_replace_from "xx testxx(xx)", "xx", "!", 1, "! test!(!)"
+test_replace_from "xx testxx(xx)", "xx", "!", 1, "! test!(!)"
+test_replace_from "xx testxx(xx)", "xx", "!", 2, "x test!(!)"
+test_replace_from "xx testxx(xx)", "xx", "!", 2000, ""
+test_replace_from "xxx", "", "y", 2, "xx"
+
+test_replace_cnt "xx testxx(xx)", "xx", "!", 1, 2, "! test!(xx)"
+test_replace_cnt "xx testxx(xx)", "xx", "!", 1, 1, "! testxx(xx)"
+test_replace_cnt "xx testxx(xx)", "xx", "!", 2, 1, "x test!(xx)"
+test_replace_cnt "xx testxx(xx)", "xx", "!", 1, -1, "! test!(!)"
+test_replace_cnt "xx testxx(xx)", "xx", "!", 1, 0, "xx testxx(xx)"
+
+on error resume next
+Replace "xx", "x", "y", -1
+x = err.number
+on error goto 0
+ok x = 5, "err = " & x
+
+on error resume next
+Replace "xx", "x", "y", 0
+x = err.number
+on error goto 0
+ok x = 5, "err = " & x
+
+on error resume next
+Replace "xx", "x", "y", 1, -2
+x = err.number
+on error goto 0
+ok x = 5, "err = " & x
+
+Sub TestRound(val, exval, vt)
+    Call ok(Round(val) = exval, "Round(" & val & ") = " & Round(val))
+    Call ok(getVT(Round(val)) = vt, "getVT(Round(" & val & ")) = " & getVT(Round(val)))
+End Sub
+
 TestRound 3, 3, "VT_I2"
 TestRound 3.3, 3, "VT_R8"
 TestRound 3.8, 4, "VT_R8"
diff --git a/dlls/vbscript/vbregexp.c b/dlls/vbscript/vbregexp.c
index 4edf9dcbfe..ac667da442 100644
--- a/dlls/vbscript/vbregexp.c
+++ b/dlls/vbscript/vbregexp.c
@@ -1629,6 +1629,48 @@ static const IRegExp2Vtbl RegExp2Vtbl = {
     RegExp2_Replace
 };
 
+BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt)
+{
+    const WCHAR *ptr, *string_end;
+    strbuf_t buf = { NULL, 0, 0 };
+    size_t replace_len, find_len;
+    BSTR ret = NULL;
+    HRESULT hres = S_OK;
+
+    string_end = string + SysStringLen(string);
+    ptr = from > SysStringLen(string) ? string_end : string + from;
+
+    find_len = SysStringLen(find);
+    replace_len = SysStringLen(replace);
+    if(!replace_len)
+        cnt = 0;
+
+    while(string_end - ptr >= find_len && cnt && find_len) {
+        if(memcmp(ptr, find, find_len * sizeof(WCHAR))) {
+            hres = strbuf_append(&buf, ptr, 1);
+            if(FAILED(hres))
+                break;
+            ptr++;
+        }else {
+            hres = strbuf_append(&buf, replace, replace_len);
+            if(FAILED(hres))
+                break;
+            ptr += find_len;
+            if(cnt != -1)
+                cnt--;
+        }
+    }
+
+    if(SUCCEEDED(hres)) {
+        hres = strbuf_append(&buf, ptr, string_end - ptr);
+        if(SUCCEEDED(hres))
+            ret = SysAllocStringLen(buf.buf, buf.len);
+    }
+
+    heap_free(buf.buf);
+    return ret;
+}
+
 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
 {
     return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 8543813c49..0bd1fce156 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -373,6 +373,7 @@ static inline BOOL is_int32(double d)
 }
 
 HRESULT create_regexp(IDispatch**) DECLSPEC_HIDDEN;
+BSTR string_replace(BSTR,BSTR,BSTR,int,int) DECLSPEC_HIDDEN;
 
 HRESULT map_hres(HRESULT) DECLSPEC_HIDDEN;
 




More information about the wine-cvs mailing list