mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
jscript: Added String.replace implementation.
This commit is contained in:
parent
b4796499e7
commit
e0413ddfe5
@ -197,6 +197,8 @@ typedef struct {
|
||||
DWORD len;
|
||||
} match_result_t;
|
||||
|
||||
HRESULT regexp_match_next(DispatchEx*,BOOL,const WCHAR*,DWORD,const WCHAR**,match_result_t**,
|
||||
DWORD*,DWORD*,match_result_t*);
|
||||
HRESULT regexp_match(DispatchEx*,const WCHAR*,DWORD,BOOL,match_result_t**,DWORD*);
|
||||
|
||||
static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i)
|
||||
|
@ -3358,6 +3358,24 @@ static HRESULT do_regexp_match_next(RegExpInstance *regexp, const WCHAR *str, DW
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT regexp_match_next(DispatchEx *dispex, BOOL gcheck, const WCHAR *str, DWORD len,
|
||||
const WCHAR **cp, match_result_t **parens, DWORD *parens_size, DWORD *parens_cnt, match_result_t *ret)
|
||||
{
|
||||
RegExpInstance *regexp = (RegExpInstance*)dispex;
|
||||
jsheap_t *mark;
|
||||
HRESULT hres;
|
||||
|
||||
if(gcheck && !(regexp->jsregexp->flags & JSREG_GLOB))
|
||||
return S_FALSE;
|
||||
|
||||
mark = jsheap_mark(®exp->dispex.ctx->tmp_heap);
|
||||
|
||||
hres = do_regexp_match_next(regexp, str, len, cp, parens, parens_size, parens_cnt, ret);
|
||||
|
||||
jsheap_clear(mark);
|
||||
return hres;
|
||||
}
|
||||
|
||||
HRESULT regexp_match(DispatchEx *dispex, const WCHAR *str, DWORD len, BOOL gflag, match_result_t **match_result,
|
||||
DWORD *result_cnt)
|
||||
{
|
||||
|
@ -425,11 +425,263 @@ static HRESULT String_match(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAM
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
||||
VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
|
||||
typedef struct {
|
||||
WCHAR *buf;
|
||||
DWORD size;
|
||||
DWORD len;
|
||||
} strbuf_t;
|
||||
|
||||
static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
|
||||
{
|
||||
FIXME("\n");
|
||||
return E_NOTIMPL;
|
||||
if(!len)
|
||||
return S_OK;
|
||||
|
||||
if(len + buf->len > buf->size) {
|
||||
WCHAR *new_buf;
|
||||
DWORD new_size;
|
||||
|
||||
new_size = buf->size ? buf->size<<1 : 16;
|
||||
if(new_size < buf->len+len)
|
||||
new_size = buf->len+len;
|
||||
if(buf->buf)
|
||||
new_buf = heap_realloc(buf->buf, new_size*sizeof(WCHAR));
|
||||
else
|
||||
new_buf = heap_alloc(new_size*sizeof(WCHAR));
|
||||
if(!new_buf)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
buf->buf = new_buf;
|
||||
buf->size = new_size;
|
||||
}
|
||||
|
||||
memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
|
||||
buf->len += len;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT rep_call(DispatchEx *func, const WCHAR *str, match_result_t *match, match_result_t *parens,
|
||||
DWORD parens_cnt, LCID lcid, BSTR *ret, jsexcept_t *ei, IServiceProvider *caller)
|
||||
{
|
||||
DISPPARAMS dp = {NULL, NULL, 0, 0};
|
||||
VARIANTARG *args, *arg;
|
||||
VARIANT var;
|
||||
DWORD i;
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
dp.cArgs = parens_cnt+3;
|
||||
dp.rgvarg = args = heap_alloc_zero(sizeof(VARIANT)*dp.cArgs);
|
||||
if(!args)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
arg = get_arg(&dp,0);
|
||||
V_VT(arg) = VT_BSTR;
|
||||
V_BSTR(arg) = SysAllocStringLen(match->str, match->len);
|
||||
if(!V_BSTR(arg))
|
||||
hres = E_OUTOFMEMORY;
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
for(i=0; i < parens_cnt; i++) {
|
||||
arg = get_arg(&dp,i+1);
|
||||
V_VT(arg) = VT_BSTR;
|
||||
V_BSTR(arg) = SysAllocStringLen(parens[i].str, parens[i].len);
|
||||
if(!V_BSTR(arg)) {
|
||||
hres = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
arg = get_arg(&dp,parens_cnt+1);
|
||||
V_VT(arg) = VT_I4;
|
||||
V_I4(arg) = match->str - str;
|
||||
|
||||
arg = get_arg(&dp,parens_cnt+2);
|
||||
V_VT(arg) = VT_BSTR;
|
||||
V_BSTR(arg) = SysAllocString(str);
|
||||
if(!V_BSTR(arg))
|
||||
hres = E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres))
|
||||
hres = jsdisp_call_value(func, lcid, DISPATCH_METHOD, &dp, &var, ei, caller);
|
||||
|
||||
for(i=0; i < parens_cnt+1; i++) {
|
||||
if(i != parens_cnt+1)
|
||||
SysFreeString(V_BSTR(get_arg(&dp,i)));
|
||||
}
|
||||
heap_free(args);
|
||||
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = to_string(func->ctx, &var, ei, ret);
|
||||
VariantClear(&var);
|
||||
return hres;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 15.5.4.11 */
|
||||
static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
||||
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
|
||||
{
|
||||
DWORD parens_cnt, parens_size=0, rep_len=0, length;
|
||||
BSTR rep_str = NULL, match_str = NULL, ret_str;
|
||||
DispatchEx *rep_func = NULL, *regexp = NULL;
|
||||
match_result_t *parens = NULL, match;
|
||||
const WCHAR *str;
|
||||
strbuf_t ret = {NULL,0,0};
|
||||
BOOL gcheck = FALSE;
|
||||
VARIANT *arg_var;
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
if(is_class(dispex, JSCLASS_STRING)) {
|
||||
StringInstance *string = (StringInstance*)dispex;
|
||||
str = string->str;
|
||||
length = string->length;
|
||||
}else {
|
||||
FIXME("not String this\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if(!arg_cnt(dp)) {
|
||||
if(retv) {
|
||||
ret_str = SysAllocString(str);
|
||||
if(!ret_str)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
V_VT(retv) = VT_BSTR;
|
||||
V_BSTR(retv) = ret_str;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
arg_var = get_arg(dp, 0);
|
||||
switch(V_VT(arg_var)) {
|
||||
case VT_DISPATCH:
|
||||
regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
|
||||
if(regexp) {
|
||||
if(is_class(regexp, JSCLASS_REGEXP)) {
|
||||
break;
|
||||
}else {
|
||||
jsdisp_release(regexp);
|
||||
regexp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
hres = to_string(dispex->ctx, arg_var, ei, &match_str);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
if(arg_cnt(dp) >= 2) {
|
||||
arg_var = get_arg(dp,1);
|
||||
switch(V_VT(arg_var)) {
|
||||
case VT_DISPATCH:
|
||||
rep_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
|
||||
if(rep_func) {
|
||||
if(is_class(rep_func, JSCLASS_FUNCTION)) {
|
||||
break;
|
||||
}else {
|
||||
jsdisp_release(rep_func);
|
||||
rep_func = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
hres = to_string(dispex->ctx, arg_var, ei, &rep_str);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
if(strchrW(rep_str, '$')) {
|
||||
FIXME("unsupported $ in replace string\n");
|
||||
hres = E_NOTIMPL;
|
||||
}
|
||||
|
||||
rep_len = SysStringLen(rep_str);
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
const WCHAR *cp, *ecp;
|
||||
|
||||
cp = ecp = str;
|
||||
|
||||
while(1) {
|
||||
if(regexp) {
|
||||
hres = regexp_match_next(regexp, gcheck, str, length, &cp, rep_func ? &parens : NULL,
|
||||
&parens_size, &parens_cnt, &match);
|
||||
gcheck = TRUE;
|
||||
|
||||
if(hres == S_FALSE) {
|
||||
hres = S_OK;
|
||||
break;
|
||||
}
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}else {
|
||||
match.str = strstrW(cp, match_str);
|
||||
if(!match.str)
|
||||
break;
|
||||
match.len = SysStringLen(match_str);
|
||||
cp = match.str+match.len;
|
||||
}
|
||||
|
||||
hres = strbuf_append(&ret, ecp, match.str-ecp);
|
||||
ecp = match.str+match.len;
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
if(rep_func) {
|
||||
BSTR cstr;
|
||||
|
||||
hres = rep_call(rep_func, str, &match, parens, parens_cnt, lcid, &cstr, ei, caller);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
|
||||
hres = strbuf_append(&ret, cstr, SysStringLen(cstr));
|
||||
SysFreeString(cstr);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}else if(rep_str) {
|
||||
hres = strbuf_append(&ret, rep_str, rep_len);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}else {
|
||||
static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d'};
|
||||
|
||||
hres = strbuf_append(&ret, undefinedW, sizeof(undefinedW)/sizeof(WCHAR));
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres))
|
||||
hres = strbuf_append(&ret, ecp, (str+length)-ecp);
|
||||
}
|
||||
|
||||
if(rep_func)
|
||||
jsdisp_release(rep_func);
|
||||
if(regexp)
|
||||
jsdisp_release(regexp);
|
||||
SysFreeString(rep_str);
|
||||
SysFreeString(match_str);
|
||||
heap_free(parens);
|
||||
|
||||
if(SUCCEEDED(hres) && retv) {
|
||||
ret_str = SysAllocStringLen(ret.buf, ret.len);
|
||||
if(!ret_str)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
V_VT(retv) = VT_BSTR;
|
||||
V_BSTR(retv) = ret_str;
|
||||
TRACE("= %s\n", debugstr_w(ret_str));
|
||||
}
|
||||
|
||||
heap_free(ret.buf);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT String_search(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
||||
|
@ -151,6 +151,29 @@ arr.concat = String.prototype.concat;
|
||||
tmp = arr.concat("d");
|
||||
ok(tmp === "2,ad", "arr.concat = " + tmp);
|
||||
|
||||
r = "- [test] -".replace("[test]", "success");
|
||||
ok(r === "- success -", "r = " + r + " expected '- success -'");
|
||||
|
||||
r = "- [test] -".replace("[test]", "success", "test");
|
||||
ok(r === "- success -", "r = " + r + " expected '- success -'");
|
||||
|
||||
r = "test".replace();
|
||||
ok(r === "test", "r = " + r + " expected 'test'");
|
||||
|
||||
function replaceFunc3(m, off, str) {
|
||||
ok(arguments.length === 3, "arguments.length = " + arguments.length);
|
||||
ok(m === "[test]", "m = " + m + " expected [test1]");
|
||||
ok(off === 1, "off = " + off + " expected 0");
|
||||
ok(str === "-[test]-", "str = " + arguments[3]);
|
||||
return "ret";
|
||||
}
|
||||
|
||||
r = "-[test]-".replace("[test]", replaceFunc3);
|
||||
ok(r === "-ret-", "r = " + r + " expected '-ret-'");
|
||||
|
||||
r = "-[test]-".replace("[test]", replaceFunc3, "test");
|
||||
ok(r === "-ret-", "r = " + r + " expected '-ret-'");
|
||||
|
||||
var arr = new Array();
|
||||
ok(typeof(arr) === "object", "arr () is not object");
|
||||
ok((arr.length === 0), "arr.length is not 0");
|
||||
|
@ -56,7 +56,6 @@ ok(typeof(m) === "object", "typeof m is not object");
|
||||
ok(m.length === 1, "m.length is not 1");
|
||||
ok(m["0"] === "ab", "m[0] is not \"ab\"");
|
||||
|
||||
/*
|
||||
m = "abcabc".match(new RegExp("ab","g"));
|
||||
ok(typeof(m) === "object", "typeof m is not object");
|
||||
ok(m.length === 2, "m.length is not 1");
|
||||
@ -74,5 +73,75 @@ ok(typeof(m) === "object", "typeof m is not object");
|
||||
ok(m.length === 2, "m.length is not 1");
|
||||
ok(m["0"] === "ab", "m[0] is not \"ab\"");
|
||||
ok(m["1"] === "ab", "m[1] is not \"ab\"");
|
||||
*/
|
||||
|
||||
r = "- [test] -".replace(/\[([^\[]+)\]/g, "success");
|
||||
ok(r === "- success -", "r = " + r + " expected '- success -'");
|
||||
|
||||
r = "[test] [test]".replace(/\[([^\[]+)\]/g, "aa");
|
||||
ok(r === "aa aa", "r = " + r + "aa aa");
|
||||
|
||||
r = "[test] [test]".replace(/\[([^\[]+)\]/, "aa");
|
||||
ok(r === "aa [test]", "r = " + r + " expected 'aa [test]'");
|
||||
|
||||
r = "- [test] -".replace(/\[([^\[]+)\]/g);
|
||||
ok(r === "- undefined -", "r = " + r + " expected '- undefined -'");
|
||||
|
||||
r = "- [test] -".replace(/\[([^\[]+)\]/g, true);
|
||||
ok(r === "- true -", "r = " + r + " expected '- true -'");
|
||||
|
||||
r = "- [test] -".replace(/\[([^\[]+)\]/g, true, "test");
|
||||
ok(r === "- true -", "r = " + r + " expected '- true -'");
|
||||
|
||||
var tmp = 0;
|
||||
|
||||
function replaceFunc1(m, off, str) {
|
||||
ok(arguments.length === 3, "arguments.length = " + arguments.length);
|
||||
|
||||
switch(tmp) {
|
||||
case 0:
|
||||
ok(m === "[test1]", "m = " + m + " expected [test1]");
|
||||
ok(off === 0, "off = " + off + " expected 0");
|
||||
break;
|
||||
case 1:
|
||||
ok(m === "[test2]", "m = " + m + " expected [test2]");
|
||||
ok(off === 8, "off = " + off + " expected 8");
|
||||
break;
|
||||
default:
|
||||
ok(false, "unexpected call");
|
||||
}
|
||||
|
||||
ok(str === "[test1] [test2]", "str = " + arguments[3]);
|
||||
return "r" + tmp++;
|
||||
}
|
||||
|
||||
r = "[test1] [test2]".replace(/\[[^\[]+\]/g, replaceFunc1);
|
||||
ok(r === "r0 r1", "r = " + r + " expected 'r0 r1'");
|
||||
|
||||
tmp = 0;
|
||||
|
||||
function replaceFunc2(m, subm, off, str) {
|
||||
ok(arguments.length === 4, "arguments.length = " + arguments.length);
|
||||
|
||||
switch(tmp) {
|
||||
case 0:
|
||||
ok(subm === "test1", "subm = " + subm);
|
||||
ok(m === "[test1]", "m = " + m + " expected [test1]");
|
||||
ok(off === 0, "off = " + off + " expected 0");
|
||||
break;
|
||||
case 1:
|
||||
ok(subm === "test2", "subm = " + subm);
|
||||
ok(m === "[test2]", "m = " + m + " expected [test2]");
|
||||
ok(off === 8, "off = " + off + " expected 8");
|
||||
break;
|
||||
default:
|
||||
ok(false, "unexpected call");
|
||||
}
|
||||
|
||||
ok(str === "[test1] [test2]", "str = " + arguments[3]);
|
||||
return "r" + tmp++;
|
||||
}
|
||||
|
||||
r = "[test1] [test2]".replace(/\[([^\[]+)\]/g, replaceFunc2);
|
||||
ok(r === "r0 r1", "r = '" + r + "' expected 'r0 r1'");
|
||||
|
||||
reportSuccess();
|
||||
|
Loading…
Reference in New Issue
Block a user