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