jscript: Added String.replace implementation.

oldstable
Jacek Caban 2008-09-25 00:53:29 +02:00 committed by Alexandre Julliard
parent b4796499e7
commit e0413ddfe5
5 changed files with 370 additions and 6 deletions

View File

@ -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)

View File

@ -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(&regexp->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)
{

View File

@ -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,

View File

@ -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");

View File

@ -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();