Module: wine Branch: master Commit: e343fcaf7656eb0ca0b648d8aa159ab2f6007785 URL: https://source.winehq.org/git/wine.git/?a=commit;h=e343fcaf7656eb0ca0b648d8a...
Author: Jacek Caban jacek@codeweavers.com Date: Tue Nov 5 14:07:58 2019 +0100
vbscript: Add Replace function implementation.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@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;