>From b686aa26552a0ba073ced0a474fcad1d7910285b Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Wed, 16 Oct 2019 15:03:23 +0800
Subject: [PATCH 04/10] vbscript: Implement IRegExp2::Replace().
Content-Type: text/plain; charset=UTF-8
To: wine-devel@winehq.org

Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru>
---
 dlls/vbscript/tests/vbscript.c |  2 -
 dlls/vbscript/vbregexp.c       | 89 +++++++++++++++++++++++++++++++++-
 2 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c
index d0763d416f..fdbfc4465b 100644
--- a/dlls/vbscript/tests/vbscript.c
+++ b/dlls/vbscript/tests/vbscript.c
@@ -1178,10 +1178,8 @@ static void test_RegExp_Replace(void)
         V_VT(&var) = VT_BSTR;
         V_BSTR(&var) = a2bstr(test[i].replace);
         hr = IRegExp2_Replace(regexp, str, var, &ret);
-todo_wine
         ok(hr == S_OK, "got %#x\n", hr);
         result = a2bstr(test[i].result);
-if (hr == S_OK)
         ok(!wcscmp(ret, result), "got %s, expected %s\n", wine_dbgstr_w(ret), wine_dbgstr_w(result));
         SysFreeString(result);
         SysFreeString(ret);
diff --git a/dlls/vbscript/vbregexp.c b/dlls/vbscript/vbregexp.c
index 3400e81066..74a54bc710 100644
--- a/dlls/vbscript/vbregexp.c
+++ b/dlls/vbscript/vbregexp.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2013 Piotr Caban for CodeWeavers
+ * Copyright 2019 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -1432,13 +1433,97 @@ static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_B
     return hres;
 }
 
+static HRESULT bstrcat(BSTR *str, const WCHAR *append, unsigned int len)
+{
+    unsigned int old_len = SysStringLen(*str);
+
+    if (!SysReAllocStringLen(str, NULL, old_len + len))
+        return E_OUTOFMEMORY;
+
+    memcpy(*str + old_len, append, len * sizeof(WCHAR));
+    return S_OK;
+}
+
 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR sourceString,
         VARIANT replaceVar, BSTR *pDestString)
 {
     RegExp2 *This = impl_from_IRegExp2(iface);
-    FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(sourceString),
+    match_state_t *result;
+    const WCHAR *pos;
+    BSTR ret;
+    HRESULT hres;
+
+    TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(sourceString),
             debugstr_variant(&replaceVar), pDestString);
-    return E_NOTIMPL;
+
+    if(!This->pattern) {
+        FIXME("NULL pattern\n");
+        return E_NOTIMPL;
+    }
+
+    if(!This->regexp) {
+        This->regexp = regexp_new(NULL, &This->pool, This->pattern,
+                lstrlenW(This->pattern), This->flags, FALSE);
+        if(!This->regexp)
+            return E_FAIL;
+    }else {
+        hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    ret = SysAllocString(L"");
+    if(!ret)
+        return E_OUTOFMEMORY;
+
+    pos = sourceString;
+    while(1) {
+        result = alloc_match_state(This->regexp, NULL, pos);
+        if(!result) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+
+        hres = regexp_execute(This->regexp, NULL, &This->pool,
+                sourceString, SysStringLen(sourceString), result);
+        if(hres != S_OK) {
+            heap_free(result);
+            break;
+        }
+
+        /* add part of original string */
+        hres = bstrcat(&ret, pos, result->cp - result->match_len - pos);
+        if(hres != S_OK) {
+            heap_free(result);
+            break;
+        }
+
+        pos = result->cp;
+
+        /* add replacement */
+        hres = bstrcat(&ret, V_BSTR(&replaceVar), SysStringLen(V_BSTR(&replaceVar)));
+        heap_free(result);
+        if(hres != S_OK)
+            break;
+
+        if(!(This->flags & REG_GLOB))
+            break;
+    }
+
+    if(FAILED(hres)) {
+        SysFreeString(ret);
+        return hres;
+    }
+
+    /* add remainder */
+    hres = bstrcat(&ret, pos, SysStringLen(sourceString) - (pos - sourceString));
+    if(FAILED(hres)) {
+        SysFreeString(ret);
+        return hres;
+    }
+
+    *pDestString = ret;
+    return S_OK;
 }
 
 static const IRegExp2Vtbl RegExp2Vtbl = {
-- 
2.20.1

