From 3be18bb757de4fbd7515c47b71df70395f01a44a Mon Sep 17 00:00:00 2001 From: Dmitry Kislyuk Date: Tue, 25 Aug 2020 12:47:17 -0500 Subject: [PATCH] vbscript: Implement case-insensitive search in Replace function. Signed-off-by: Dmitry Kislyuk Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/vbscript/global.c | 22 ++++++++++++++++++---- dlls/vbscript/tests/api.vbs | 34 ++++++++++++++++++++++++++++++++++ dlls/vbscript/vbregexp.c | 19 +++++++++++-------- dlls/vbscript/vbscript.h | 2 +- 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index cdfbdf22154..80323fe1366 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -2449,12 +2449,19 @@ error: static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { BSTR string, find = NULL, replace = NULL, ret; - int from = 1, cnt = -1; + int from = 1, cnt = -1, mode = 0; 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_NULL || V_VT(args+1) == VT_NULL || (V_VT(args+2) == VT_NULL) + || (args_cnt >= 4 && V_VT(args+3) == VT_NULL) || (args_cnt >= 5 && V_VT(args+4) == VT_NULL) + || (args_cnt == 6 && V_VT(args+5) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if(V_VT(args) != VT_BSTR) { hres = to_string(args, &string); if(FAILED(hres)) @@ -2499,10 +2506,17 @@ static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cn } } - if(args_cnt == 6) - FIXME("copare argument not supported\n"); + if(args_cnt == 6) { + hres = to_int(args+5, &mode); + if(FAILED(hres)) + goto error; + if (mode != 0 && mode != 1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + } - ret = string_replace(string, find, replace, from - 1, cnt); + ret = string_replace(string, find, replace, from - 1, cnt, mode); if(!ret) { hres = E_OUTOFMEMORY; }else if(res) { diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index 4834029183e..be95aae4b91 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -844,6 +844,7 @@ TestRTrim "", "" TestRTrim 123, "123" if isEnglishLang then TestRTrim true, "True" + sub test_replace(str, find, rep, exp) dim r r = Replace(str, find, rep) @@ -865,8 +866,17 @@ sub test_replace_cnt(str, find, rep, from, cnt, exp) r & """ expected """ & exp & """" end sub +sub test_replace_mode(str, find, rep, from, cnt, mode, exp) + dim r + r = Replace(str, find, rep, from, cnt, mode) + ok r = exp, "Replace(""" & str & """, """ & find & """, """ & rep & """, " & from & ", " & cnt & ", " & mode _ + & ") = """ & r & """ expected """ & exp & """" +end sub + test_replace "xx testxx(xx)", "xx", "!", "! test!(!)" +test_replace "", "x", "y", "" test_replace "xxx", "", "y", "xxx" +test_replace "yxxy", "x", "", "yy" test_replace "xxxxx", "xx", "y", "yyx" test_replace 123, 2, 6, "163" test_replace "xyz" & Chr(0) & "xyz", "y", "Y", "xYz" & Chr(0) & "xYz" @@ -884,6 +894,12 @@ 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)" +test_replace_mode "Aa testAAa(aa)", "aa", "!", 1, 2, 1, "! test!a(aa)" +test_replace_mode "aA testaa(aa)", "AA", "!", 1, 1, 1, "! testaa(aa)" +test_replace_mode "aa testAa(aa)", "aa", "!", 2, 2, 0, "a testAa(!)" +test_replace_mode "aa testAA(aA)", "Aa", "!", 1, -1, 1, "! test!(!)" +test_replace_mode "aa testaa(aa)", "A", "!", 1, -1, 1, "!! test!!(!!)" + on error resume next Replace "xx", "x", "y", -1 x = err.number @@ -902,6 +918,24 @@ x = err.number on error goto 0 ok x = 5, "err = " & x +Sub testReplaceError(arg1, arg2, arg3, arg4, arg5, arg6, error_num) + on error resume next + Dim x + + Call Err.clear() + x = Replace(arg1, arg2, arg3, arg4, arg5, arg6) + Call ok(Err.number = error_num, "Err.number = " & Err.number) +End Sub + +Call testReplaceError(Null, "x", "y", 1, 1, 0, 94) +Call testReplaceError("xx", null, "y", 1, 1, 0, 94) +Call testReplaceError("xx", "x", null, 1, 1, 0, 94) +Call testReplaceError("xx", "x", "y", null, 1, 0, 94) +Call testReplaceError("xx", "x", "y", 1, null, 0, 94) +Call testReplaceError("xx", "x", "y", 1, 1, null, 94) +Call testReplaceError("xx", "x", "y", 1, 1, 8, 5) + + 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))) diff --git a/dlls/vbscript/vbregexp.c b/dlls/vbscript/vbregexp.c index 60c99772d3d..49046bc7810 100644 --- a/dlls/vbscript/vbregexp.c +++ b/dlls/vbscript/vbregexp.c @@ -1629,33 +1629,36 @@ static const IRegExp2Vtbl RegExp2Vtbl = { RegExp2_Replace }; -BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt) +BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt, int mode) { const WCHAR *ptr, *string_end; strbuf_t buf = { NULL, 0, 0 }; size_t replace_len, find_len; BSTR ret = NULL; HRESULT hres = S_OK; + int pos; 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); + pos = FindStringOrdinal(FIND_FROMSTART, ptr, string_end - ptr, + find, find_len, mode); + + if(pos == -1) + break; + else { + hres = strbuf_append(&buf, ptr, pos); if(FAILED(hres)) break; - ptr++; - }else { hres = strbuf_append(&buf, replace, replace_len); if(FAILED(hres)) break; - ptr += find_len; + + ptr = ptr + pos + find_len; if(cnt != -1) cnt--; } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index aa75b1c0dd0..1edf7906af9 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -393,7 +393,7 @@ static inline BOOL is_digit(WCHAR c) } HRESULT create_regexp(IDispatch**) DECLSPEC_HIDDEN; -BSTR string_replace(BSTR,BSTR,BSTR,int,int) DECLSPEC_HIDDEN; +BSTR string_replace(BSTR,BSTR,BSTR,int,int,int) DECLSPEC_HIDDEN; HRESULT map_hres(HRESULT) DECLSPEC_HIDDEN;