Jacek Caban : jscript: Added String.match implementation.

Alexandre Julliard julliard at winehq.org
Tue Sep 16 06:54:23 CDT 2008


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Sep 15 20:41:04 2008 +0200

jscript: Added String.match implementation.

RegExp part of patch is based on Mozilla regexp implementation.

---

 dlls/jscript/jscript.h |    7 ++
 dlls/jscript/regexp.c  |  151 ++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/jscript/string.c  |   73 ++++++++++++++++++++++-
 3 files changed, 229 insertions(+), 2 deletions(-)

diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index c4e61d6..a098b82 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -184,6 +184,13 @@ HRESULT create_object_constr(script_ctx_t*,DispatchEx**);
 HRESULT create_regexp_constr(script_ctx_t*,DispatchEx**);
 HRESULT create_string_constr(script_ctx_t*,DispatchEx**);
 
+typedef struct {
+    const WCHAR *str;
+    DWORD len;
+} match_result_t;
+
+HRESULT regexp_match(DispatchEx*,const WCHAR*,DWORD,BOOL,match_result_t**,DWORD*);
+
 static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i)
 {
     return dp->rgvarg + dp->cArgs-i-1;
diff --git a/dlls/jscript/regexp.c b/dlls/jscript/regexp.c
index f6fbec3..e8e9bea 100644
--- a/dlls/jscript/regexp.c
+++ b/dlls/jscript/regexp.c
@@ -3116,6 +3116,79 @@ good:
     return x;
 }
 
+static REMatchState *MatchRegExp(REGlobalData *gData, REMatchState *x)
+{
+    REMatchState *result;
+    const WCHAR *cp = x->cp;
+    const WCHAR *cp2;
+    UINT j;
+
+    /*
+     * Have to include the position beyond the last character
+     * in order to detect end-of-input/line condition.
+     */
+    for (cp2 = cp; cp2 <= gData->cpend; cp2++) {
+        gData->skipped = cp2 - cp;
+        x->cp = cp2;
+        for (j = 0; j < gData->regexp->parenCount; j++)
+            x->parens[j].index = -1;
+        result = ExecuteREBytecode(gData, x);
+        if (!gData->ok || result || (gData->regexp->flags & JSREG_STICKY))
+            return result;
+        gData->backTrackSP = gData->backTrackStack;
+        gData->cursz = 0;
+        gData->stateStackTop = 0;
+        cp2 = cp + gData->skipped;
+    }
+    return NULL;
+}
+
+#define MIN_BACKTRACK_LIMIT 400000
+
+static REMatchState *InitMatch(script_ctx_t *cx, REGlobalData *gData, JSRegExp *re, size_t length)
+{
+    REMatchState *result;
+    UINT i;
+
+    gData->backTrackStackSize = INITIAL_BACKTRACK;
+    gData->backTrackStack = jsheap_alloc(gData->pool, INITIAL_BACKTRACK);
+    if (!gData->backTrackStack)
+        goto bad;
+
+    gData->backTrackSP = gData->backTrackStack;
+    gData->cursz = 0;
+    gData->backTrackCount = 0;
+    gData->backTrackLimit = 0;
+
+    gData->stateStackLimit = INITIAL_STATESTACK;
+    gData->stateStack = jsheap_alloc(gData->pool, sizeof(REProgState) * INITIAL_STATESTACK);
+    if (!gData->stateStack)
+        goto bad;
+
+    gData->stateStackTop = 0;
+    gData->cx = cx;
+    gData->regexp = re;
+    gData->ok = TRUE;
+
+    result = jsheap_alloc(gData->pool, offsetof(REMatchState, parens) + re->parenCount * sizeof(RECapture));
+    if (!result)
+        goto bad;
+
+    for (i = 0; i < re->classCount; i++) {
+        if (!re->classList[i].converted &&
+            !ProcessCharSet(gData, &re->classList[i])) {
+            return NULL;
+        }
+    }
+
+    return result;
+
+bad:
+    js_ReportOutOfScriptQuota(cx);
+    gData->ok = FALSE;
+    return NULL;
+}
+
 static void
 js_DestroyRegExp(JSRegExp *re)
 {
@@ -3224,6 +3297,84 @@ out:
     return re;
 }
 
+HRESULT regexp_match(DispatchEx *dispex, const WCHAR *str, DWORD len, BOOL gflag, match_result_t **match_result,
+        DWORD *result_cnt)
+{
+    RegExpInstance *This = (RegExpInstance*)dispex;
+    match_result_t *ret = NULL;
+    const WCHAR *cp = str;
+    REGlobalData gData;
+    REMatchState *x, *result;
+    DWORD matchlen;
+    DWORD i=0, ret_size = 0;
+    jsheap_t *mark;
+    size_t length;
+    HRESULT hres = E_FAIL;
+
+    length = len;
+
+    mark = jsheap_mark(&This->dispex.ctx->tmp_heap);
+    gData.pool = &This->dispex.ctx->tmp_heap;
+
+    while(1) {
+        gData.cpbegin = cp;
+        gData.cpend = str + len;
+        gData.start = cp-str;
+        gData.skipped = 0;
+
+        x = InitMatch(NULL, &gData, This->jsregexp, length);
+        if(!x) {
+            WARN("InitMatch failed\n");
+            break;
+        }
+
+        x->cp = cp;
+        result = MatchRegExp(&gData, x);
+        if(!gData.ok) {
+            WARN("MatchRegExp failed\n");
+            break;
+        }
+
+        if(!result) {
+            hres = S_OK;
+            break;
+        }
+
+        matchlen = (result->cp-cp) - gData.skipped;
+
+        if(ret)
+            ret = heap_realloc(ret, (ret_size <<= 1) * sizeof(match_result_t));
+        else if(ret_size == i)
+            ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
+        if(!ret) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+
+        ret[i].str = result->cp-matchlen;
+        ret[i].len = matchlen;
+
+        length -= result->cp-cp;
+        cp = result->cp;
+        i++;
+
+        if(!gflag && !(This->jsregexp->flags & JSREG_GLOB)) {
+            hres = S_OK;
+            break;
+        }
+    }
+
+    jsheap_clear(mark);
+    if(FAILED(hres)) {
+        heap_free(ret);
+        return hres;
+    }
+
+    *match_result = ret;
+    *result_cnt = i;
+    return S_OK;
+}
+
 static HRESULT RegExp_source(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c
index 033e906..b310cab 100644
--- a/dlls/jscript/string.c
+++ b/dlls/jscript/string.c
@@ -189,8 +189,77 @@ static HRESULT String_link(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS
 static HRESULT String_match(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    StringInstance *This = (StringInstance*)dispex;
+    match_result_t *match_result;
+    DispatchEx *array;
+    VARIANT var, *arg_var;
+    DWORD match_cnt, i;
+    HRESULT hres = S_OK;
+
+    TRACE("\n");
+
+    if(dp->cArgs - dp->cNamedArgs != 1) {
+        FIXME("unsupported args\n");
+        return E_NOTIMPL;
+    }
+
+    arg_var = get_arg(dp, 0);
+    switch(V_VT(arg_var)) {
+    case VT_DISPATCH: {
+        DispatchEx *regexp;
+
+        regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
+        if(regexp) {
+            if(regexp->builtin_info->class == JSCLASS_REGEXP) {
+                hres = regexp_match(regexp, This->str, This->length, FALSE, &match_result, &match_cnt);
+                jsdisp_release(regexp);
+                if(FAILED(hres))
+                    return hres;
+                break;
+            }
+            jsdisp_release(regexp);
+        }
+    }
+    default:
+        FIXME("implemented only for regexp args\n");
+        return E_NOTIMPL;
+    }
+
+    if(!match_cnt) {
+        TRACE("no match\n");
+
+        if(retv)
+            V_VT(retv) = VT_NULL;
+        return S_OK;
+    }
+
+    hres = create_array(dispex->ctx, match_cnt, &array);
+    if(FAILED(hres))
+        return hres;
+
+    V_VT(&var) = VT_BSTR;
+
+    for(i=0; i < match_cnt; i++) {
+        V_BSTR(&var) = SysAllocStringLen(match_result[i].str, match_result[i].len);
+        if(!V_BSTR(&var)) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+
+        hres = jsdisp_propput_idx(array, i, lcid, &var, ei, NULL/*FIXME*/);
+        SysFreeString(V_BSTR(&var));
+        if(FAILED(hres))
+            break;
+    }
+
+    if(FAILED(hres)) {
+        jsdisp_release(array);
+        return hres;
+    }
+
+    V_VT(retv) = VT_DISPATCH;
+    V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
+    return S_OK;
 }
 
 static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,




More information about the wine-cvs mailing list