d3d11: Report D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW in CheckFormatSupport().
[wine.git] / dlls / jscript / jsregexp.c
blob94abb6a3c9541f8fa192f160085267017a0b2b37
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <math.h>
21 #include "jscript.h"
22 #include "regexp.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28 typedef struct {
29 jsdisp_t dispex;
31 regexp_t *jsregexp;
32 jsstr_t *str;
33 INT last_index;
34 jsval_t last_index_val;
35 } RegExpInstance;
37 static const WCHAR sourceW[] = {'s','o','u','r','c','e',0};
38 static const WCHAR globalW[] = {'g','l','o','b','a','l',0};
39 static const WCHAR ignoreCaseW[] = {'i','g','n','o','r','e','C','a','s','e',0};
40 static const WCHAR multilineW[] = {'m','u','l','t','i','l','i','n','e',0};
41 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
42 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
43 static const WCHAR execW[] = {'e','x','e','c',0};
44 static const WCHAR testW[] = {'t','e','s','t',0};
46 static const WCHAR leftContextW[] =
47 {'l','e','f','t','C','o','n','t','e','x','t',0};
48 static const WCHAR rightContextW[] =
49 {'r','i','g','h','t','C','o','n','t','e','x','t',0};
51 static const WCHAR idx1W[] = {'$','1',0};
52 static const WCHAR idx2W[] = {'$','2',0};
53 static const WCHAR idx3W[] = {'$','3',0};
54 static const WCHAR idx4W[] = {'$','4',0};
55 static const WCHAR idx5W[] = {'$','5',0};
56 static const WCHAR idx6W[] = {'$','6',0};
57 static const WCHAR idx7W[] = {'$','7',0};
58 static const WCHAR idx8W[] = {'$','8',0};
59 static const WCHAR idx9W[] = {'$','9',0};
61 static inline RegExpInstance *regexp_from_jsdisp(jsdisp_t *jsdisp)
63 return CONTAINING_RECORD(jsdisp, RegExpInstance, dispex);
66 static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
68 return regexp_from_jsdisp(vdisp->u.jsdisp);
71 static void set_last_index(RegExpInstance *This, DWORD last_index)
73 This->last_index = last_index;
74 jsval_release(This->last_index_val);
75 This->last_index_val = jsval_number(last_index);
78 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
79 DWORD rem_flags, jsstr_t *jsstr, const WCHAR *str, match_state_t *ret)
81 HRESULT hres;
83 hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
84 str, jsstr_length(jsstr), ret);
85 if(FAILED(hres))
86 return hres;
87 if(hres == S_FALSE) {
88 if(rem_flags & REM_RESET_INDEX)
89 set_last_index(regexp, 0);
90 return S_FALSE;
93 if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != jsstr) {
94 jsstr_release(ctx->last_match);
95 ctx->last_match = jsstr_addref(jsstr);
98 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
99 DWORD i, n = min(ARRAY_SIZE(ctx->match_parens), ret->paren_count);
101 for(i=0; i < n; i++) {
102 if(ret->parens[i].index == -1) {
103 ctx->match_parens[i].index = 0;
104 ctx->match_parens[i].length = 0;
105 }else {
106 ctx->match_parens[i].index = ret->parens[i].index;
107 ctx->match_parens[i].length = ret->parens[i].length;
111 if(n < ARRAY_SIZE(ctx->match_parens))
112 memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
115 set_last_index(regexp, ret->cp-str);
117 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
118 ctx->last_match_index = ret->cp-str-ret->match_len;
119 ctx->last_match_length = ret->match_len;
122 return S_OK;
125 HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
126 DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret)
128 RegExpInstance *regexp = regexp_from_jsdisp(dispex);
129 match_state_t *match;
130 heap_pool_t *mark;
131 const WCHAR *str;
132 HRESULT hres;
134 if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
135 if(rem_flags & REM_ALLOC_RESULT)
136 *ret = NULL;
137 return S_FALSE;
140 str = jsstr_flatten(jsstr);
141 if(!str)
142 return E_OUTOFMEMORY;
144 if(rem_flags & REM_ALLOC_RESULT) {
145 match = alloc_match_state(regexp->jsregexp, NULL, str);
146 if(!match)
147 return E_OUTOFMEMORY;
148 *ret = match;
151 mark = heap_pool_mark(&ctx->tmp_heap);
153 if(rem_flags & REM_NO_PARENS) {
154 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
155 if(!match) {
156 heap_pool_clear(mark);
157 return E_OUTOFMEMORY;
159 match->cp = (*ret)->cp;
160 match->match_len = (*ret)->match_len;
161 }else {
162 match = *ret;
165 hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match);
167 if(rem_flags & REM_NO_PARENS) {
168 (*ret)->cp = match->cp;
169 (*ret)->match_len = match->match_len;
172 heap_pool_clear(mark);
174 if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
175 heap_free(match);
176 *ret = NULL;
179 return hres;
182 static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag,
183 match_result_t **match_result, DWORD *result_cnt)
185 RegExpInstance *This = regexp_from_jsdisp(dispex);
186 match_result_t *ret = NULL;
187 match_state_t *result;
188 DWORD i=0, ret_size = 0;
189 heap_pool_t *mark;
190 const WCHAR *str;
191 HRESULT hres;
193 mark = heap_pool_mark(&ctx->tmp_heap);
195 str = jsstr_flatten(jsstr);
196 if(!str)
197 return E_OUTOFMEMORY;
199 result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str);
200 if(!result) {
201 heap_pool_clear(mark);
202 return E_OUTOFMEMORY;
205 while(1) {
206 hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result);
207 if(hres == S_FALSE) {
208 hres = S_OK;
209 break;
212 if(FAILED(hres))
213 break;
215 if(ret_size == i) {
216 if(ret) {
217 match_result_t *old_ret = ret;
219 ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
220 if(!ret)
221 heap_free(old_ret);
222 }else {
223 ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
225 if(!ret) {
226 hres = E_OUTOFMEMORY;
227 break;
231 ret[i].index = result->cp - str - result->match_len;
232 ret[i++].length = result->match_len;
234 if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
235 hres = S_OK;
236 break;
240 heap_pool_clear(mark);
241 if(FAILED(hres)) {
242 heap_free(ret);
243 return hres;
246 *match_result = ret;
247 *result_cnt = i;
248 return S_OK;
251 static HRESULT RegExp_get_source(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
253 TRACE("\n");
255 *r = jsval_string(jsstr_addref(regexp_from_jsdisp(jsthis)->str));
256 return S_OK;
259 static HRESULT RegExp_get_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
261 TRACE("\n");
263 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_GLOB));
264 return S_OK;
267 static HRESULT RegExp_get_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
269 TRACE("\n");
271 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_FOLD));
272 return S_OK;
275 static HRESULT RegExp_get_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
277 TRACE("\n");
279 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_MULTILINE));
280 return S_OK;
283 static INT index_from_val(script_ctx_t *ctx, jsval_t v)
285 double n;
286 HRESULT hres;
288 hres = to_number(ctx, v, &n);
289 if(FAILED(hres))
290 return 0;
292 n = floor(n);
293 return is_int32(n) ? n : 0;
296 static HRESULT RegExp_get_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
298 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
300 TRACE("\n");
302 return jsval_copy(regexp->last_index_val, r);
305 static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
307 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
308 HRESULT hres;
310 TRACE("\n");
312 jsval_release(regexp->last_index_val);
313 hres = jsval_copy(value, &regexp->last_index_val);
314 if(FAILED(hres))
315 return hres;
317 regexp->last_index = index_from_val(ctx, value);
318 return S_OK;
321 static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
322 jsval_t *r)
324 RegExpInstance *regexp;
325 unsigned len, f;
326 jsstr_t *ret;
327 WCHAR *ptr;
329 TRACE("\n");
331 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
332 WARN("Not a RegExp\n");
333 return JS_E_REGEXP_EXPECTED;
336 regexp = regexp_from_vdisp(jsthis);
338 if(!r)
339 return S_OK;
341 len = jsstr_length(regexp->str) + 2;
343 f = regexp->jsregexp->flags;
344 if(f & REG_FOLD)
345 len++;
346 if(f & REG_GLOB)
347 len++;
348 if(f & REG_MULTILINE)
349 len++;
351 ret = jsstr_alloc_buf(len, &ptr);
352 if(!ret)
353 return E_OUTOFMEMORY;
355 *ptr++ = '/';
356 ptr += jsstr_flush(regexp->str, ptr);
357 *ptr++ = '/';
359 if(f & REG_FOLD)
360 *ptr++ = 'i';
361 if(f & REG_GLOB)
362 *ptr++ = 'g';
363 if(f & REG_MULTILINE)
364 *ptr++ = 'm';
366 *r = jsval_string(ret);
367 return S_OK;
370 static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str,
371 const match_state_t *result, IDispatch **ret)
373 const WCHAR *input;
374 jsdisp_t *array;
375 jsstr_t *str;
376 DWORD i;
377 HRESULT hres = S_OK;
379 static const WCHAR indexW[] = {'i','n','d','e','x',0};
380 static const WCHAR inputW[] = {'i','n','p','u','t',0};
381 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
382 static const WCHAR zeroW[] = {'0',0};
384 input = jsstr_flatten(input_str);
385 if(!input)
386 return E_OUTOFMEMORY;
388 hres = create_array(ctx, result->paren_count+1, &array);
389 if(FAILED(hres))
390 return hres;
392 for(i=0; i < result->paren_count; i++) {
393 if(result->parens[i].index != -1)
394 str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length);
395 else
396 str = jsstr_empty();
397 if(!str) {
398 hres = E_OUTOFMEMORY;
399 break;
402 hres = jsdisp_propput_idx(array, i+1, jsval_string(str));
403 jsstr_release(str);
404 if(FAILED(hres))
405 break;
408 while(SUCCEEDED(hres)) {
409 hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input-result->match_len));
410 if(FAILED(hres))
411 break;
413 hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input));
414 if(FAILED(hres))
415 break;
417 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input_str)));
418 if(FAILED(hres))
419 break;
421 str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
422 if(!str) {
423 hres = E_OUTOFMEMORY;
424 break;
426 hres = jsdisp_propput_name(array, zeroW, jsval_string(str));
427 jsstr_release(str);
428 break;
431 if(FAILED(hres)) {
432 jsdisp_release(array);
433 return hres;
436 *ret = to_disp(array);
437 return S_OK;
440 static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg,
441 jsstr_t **input, match_state_t **result, BOOL *ret)
443 RegExpInstance *regexp;
444 match_state_t *match;
445 DWORD last_index = 0;
446 const WCHAR *string;
447 jsstr_t *jsstr;
448 HRESULT hres;
450 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
451 FIXME("Not a RegExp\n");
452 return E_NOTIMPL;
455 regexp = regexp_from_vdisp(jsthis);
457 hres = to_flat_string(ctx, arg, &jsstr, &string);
458 if(FAILED(hres))
459 return hres;
461 if(regexp->jsregexp->flags & REG_GLOB) {
462 if(regexp->last_index < 0) {
463 jsstr_release(jsstr);
464 set_last_index(regexp, 0);
465 *ret = FALSE;
466 if(input)
467 *input = jsstr_empty();
468 return S_OK;
471 last_index = regexp->last_index;
474 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string+last_index);
475 if(!match) {
476 jsstr_release(jsstr);
477 return E_OUTOFMEMORY;
480 hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, jsstr, &match);
481 if(FAILED(hres)) {
482 jsstr_release(jsstr);
483 return hres;
486 *result = match;
487 *ret = hres == S_OK;
488 if(input)
489 *input = jsstr;
490 else
491 jsstr_release(jsstr);
492 return S_OK;
495 static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
496 jsval_t *r)
498 match_state_t *match;
499 heap_pool_t *mark;
500 BOOL b;
501 jsstr_t *string;
502 HRESULT hres;
504 TRACE("\n");
506 mark = heap_pool_mark(&ctx->tmp_heap);
508 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
509 if(FAILED(hres)) {
510 heap_pool_clear(mark);
511 return hres;
514 if(r) {
515 if(b) {
516 IDispatch *ret;
518 hres = create_match_array(ctx, string, match, &ret);
519 if(SUCCEEDED(hres))
520 *r = jsval_disp(ret);
521 }else {
522 *r = jsval_null();
526 heap_pool_clear(mark);
527 jsstr_release(string);
528 return hres;
531 static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
532 jsval_t *r)
534 match_state_t *match;
535 jsstr_t *undef_str;
536 heap_pool_t *mark;
537 BOOL b;
538 HRESULT hres;
540 TRACE("\n");
542 mark = heap_pool_mark(&ctx->tmp_heap);
543 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
544 heap_pool_clear(mark);
545 if(!argc)
546 jsstr_release(undef_str);
547 if(FAILED(hres))
548 return hres;
550 if(r)
551 *r = jsval_bool(b);
552 return S_OK;
555 static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
556 jsval_t *r)
558 TRACE("\n");
560 switch(flags) {
561 case INVOKE_FUNC:
562 return JS_E_FUNCTION_EXPECTED;
563 default:
564 FIXME("unimplemented flags %x\n", flags);
565 return E_NOTIMPL;
568 return S_OK;
571 static void RegExp_destructor(jsdisp_t *dispex)
573 RegExpInstance *This = regexp_from_jsdisp(dispex);
575 if(This->jsregexp)
576 regexp_destroy(This->jsregexp);
577 jsval_release(This->last_index_val);
578 jsstr_release(This->str);
579 heap_free(This);
582 static const builtin_prop_t RegExp_props[] = {
583 {execW, RegExp_exec, PROPF_METHOD|1},
584 {globalW, NULL,0, RegExp_get_global},
585 {ignoreCaseW, NULL,0, RegExp_get_ignoreCase},
586 {lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
587 {multilineW, NULL,0, RegExp_get_multiline},
588 {sourceW, NULL,0, RegExp_get_source},
589 {testW, RegExp_test, PROPF_METHOD|1},
590 {toStringW, RegExp_toString, PROPF_METHOD}
593 static const builtin_info_t RegExp_info = {
594 JSCLASS_REGEXP,
595 {NULL, RegExp_value, 0},
596 ARRAY_SIZE(RegExp_props),
597 RegExp_props,
598 RegExp_destructor,
599 NULL
602 static const builtin_prop_t RegExpInst_props[] = {
603 {globalW, NULL,0, RegExp_get_global},
604 {ignoreCaseW, NULL,0, RegExp_get_ignoreCase},
605 {lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
606 {multilineW, NULL,0, RegExp_get_multiline},
607 {sourceW, NULL,0, RegExp_get_source}
610 static const builtin_info_t RegExpInst_info = {
611 JSCLASS_REGEXP,
612 {NULL, RegExp_value, 0},
613 ARRAY_SIZE(RegExpInst_props),
614 RegExpInst_props,
615 RegExp_destructor,
616 NULL
619 static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret)
621 RegExpInstance *regexp;
622 HRESULT hres;
624 regexp = heap_alloc_zero(sizeof(RegExpInstance));
625 if(!regexp)
626 return E_OUTOFMEMORY;
628 if(object_prototype)
629 hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
630 else
631 hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
633 if(FAILED(hres)) {
634 heap_free(regexp);
635 return hres;
638 *ret = regexp;
639 return S_OK;
642 HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
644 RegExpInstance *regexp;
645 const WCHAR *str;
646 HRESULT hres;
648 str = jsstr_flatten(src);
649 if(!str)
650 return E_OUTOFMEMORY;
652 TRACE("%s %x\n", debugstr_wn(str, jsstr_length(src)), flags);
654 hres = alloc_regexp(ctx, NULL, &regexp);
655 if(FAILED(hres))
656 return hres;
658 regexp->str = jsstr_addref(src);
659 regexp->last_index_val = jsval_number(0);
661 regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE);
662 if(!regexp->jsregexp) {
663 WARN("regexp_new failed\n");
664 jsdisp_release(&regexp->dispex);
665 return E_FAIL;
668 *ret = &regexp->dispex;
669 return S_OK;
672 HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
674 unsigned flags = 0;
675 const WCHAR *opt = NULL;
676 jsstr_t *src;
677 HRESULT hres = S_OK;
679 if(is_object_instance(src_arg)) {
680 jsdisp_t *obj;
682 obj = iface_to_jsdisp(get_object(src_arg));
683 if(obj) {
684 if(is_class(obj, JSCLASS_REGEXP)) {
685 RegExpInstance *regexp = regexp_from_jsdisp(obj);
687 hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
688 jsdisp_release(obj);
689 return hres;
692 jsdisp_release(obj);
696 if(is_undefined(src_arg))
697 src = jsstr_empty();
698 else
699 hres = to_string(ctx, src_arg, &src);
700 if(FAILED(hres))
701 return hres;
703 if(flags_arg && !is_undefined(*flags_arg)) {
704 jsstr_t *opt_str;
706 hres = to_string(ctx, *flags_arg, &opt_str);
707 if(SUCCEEDED(hres)) {
708 opt = jsstr_flatten(opt_str);
709 if(opt)
710 hres = parse_regexp_flags(opt, jsstr_length(opt_str), &flags);
711 else
712 hres = E_OUTOFMEMORY;
713 jsstr_release(opt_str);
717 if(SUCCEEDED(hres))
718 hres = create_regexp(ctx, src, flags, ret);
719 jsstr_release(src);
720 return hres;
723 HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r)
725 static const WCHAR indexW[] = {'i','n','d','e','x',0};
726 static const WCHAR inputW[] = {'i','n','p','u','t',0};
727 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
729 RegExpInstance *regexp = regexp_from_jsdisp(re);
730 match_result_t *match_result;
731 unsigned match_cnt, i;
732 const WCHAR *str;
733 jsdisp_t *array;
734 HRESULT hres;
736 str = jsstr_flatten(jsstr);
737 if(!str)
738 return E_OUTOFMEMORY;
740 if(!(regexp->jsregexp->flags & REG_GLOB)) {
741 match_state_t *match;
742 heap_pool_t *mark;
744 mark = heap_pool_mark(&ctx->tmp_heap);
745 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str);
746 if(!match) {
747 heap_pool_clear(mark);
748 return E_OUTOFMEMORY;
751 hres = regexp_match_next(ctx, &regexp->dispex, 0, jsstr, &match);
752 if(FAILED(hres)) {
753 heap_pool_clear(mark);
754 return hres;
757 if(r) {
758 if(hres == S_OK) {
759 IDispatch *ret;
761 hres = create_match_array(ctx, jsstr, match, &ret);
762 if(SUCCEEDED(hres))
763 *r = jsval_disp(ret);
764 }else {
765 *r = jsval_null();
769 heap_pool_clear(mark);
770 return S_OK;
773 hres = regexp_match(ctx, &regexp->dispex, jsstr, FALSE, &match_result, &match_cnt);
774 if(FAILED(hres))
775 return hres;
777 if(!match_cnt) {
778 TRACE("no match\n");
780 if(r)
781 *r = jsval_null();
782 return S_OK;
785 hres = create_array(ctx, match_cnt, &array);
786 if(FAILED(hres))
787 return hres;
789 for(i=0; i < match_cnt; i++) {
790 jsstr_t *tmp_str;
792 tmp_str = jsstr_substr(jsstr, match_result[i].index, match_result[i].length);
793 if(!tmp_str) {
794 hres = E_OUTOFMEMORY;
795 break;
798 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
799 jsstr_release(tmp_str);
800 if(FAILED(hres))
801 break;
804 while(SUCCEEDED(hres)) {
805 hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index));
806 if(FAILED(hres))
807 break;
809 hres = jsdisp_propput_name(array, lastIndexW,
810 jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
811 if(FAILED(hres))
812 break;
814 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr));
815 break;
818 heap_free(match_result);
820 if(SUCCEEDED(hres) && r)
821 *r = jsval_obj(array);
822 else
823 jsdisp_release(array);
824 return hres;
827 static HRESULT global_idx(script_ctx_t *ctx, DWORD idx, jsval_t *r)
829 jsstr_t *ret;
831 ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
832 if(!ret)
833 return E_OUTOFMEMORY;
835 *r = jsval_string(ret);
836 return S_OK;
839 static HRESULT RegExpConstr_get_idx1(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
841 TRACE("\n");
842 return global_idx(ctx, 0, r);
845 static HRESULT RegExpConstr_get_idx2(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
847 TRACE("\n");
848 return global_idx(ctx, 1, r);
851 static HRESULT RegExpConstr_get_idx3(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
853 TRACE("\n");
854 return global_idx(ctx, 2, r);
857 static HRESULT RegExpConstr_get_idx4(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
859 TRACE("\n");
860 return global_idx(ctx, 3, r);
863 static HRESULT RegExpConstr_get_idx5(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
865 TRACE("\n");
866 return global_idx(ctx, 4, r);
869 static HRESULT RegExpConstr_get_idx6(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
871 TRACE("\n");
872 return global_idx(ctx, 5, r);
875 static HRESULT RegExpConstr_get_idx7(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
877 TRACE("\n");
878 return global_idx(ctx, 6, r);
881 static HRESULT RegExpConstr_get_idx8(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
883 TRACE("\n");
884 return global_idx(ctx, 7, r);
887 static HRESULT RegExpConstr_get_idx9(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
889 TRACE("\n");
890 return global_idx(ctx, 8, r);
893 static HRESULT RegExpConstr_get_leftContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
895 jsstr_t *ret;
897 TRACE("\n");
899 ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
900 if(!ret)
901 return E_OUTOFMEMORY;
903 *r = jsval_string(ret);
904 return S_OK;
907 static HRESULT RegExpConstr_get_rightContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
909 jsstr_t *ret;
911 TRACE("\n");
913 ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
914 jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
915 if(!ret)
916 return E_OUTOFMEMORY;
918 *r = jsval_string(ret);
919 return S_OK;
922 static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
923 jsval_t *r)
925 TRACE("\n");
927 switch(flags) {
928 case DISPATCH_METHOD:
929 if(argc) {
930 if(is_object_instance(argv[0])) {
931 jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0]));
932 if(jsdisp) {
933 if(is_class(jsdisp, JSCLASS_REGEXP)) {
934 if(argc > 1 && !is_undefined(argv[1])) {
935 jsdisp_release(jsdisp);
936 return JS_E_REGEXP_SYNTAX;
939 if(r)
940 *r = jsval_obj(jsdisp);
941 else
942 jsdisp_release(jsdisp);
943 return S_OK;
945 jsdisp_release(jsdisp);
949 /* fall through */
950 case DISPATCH_CONSTRUCT: {
951 jsdisp_t *ret;
952 HRESULT hres;
954 hres = create_regexp_var(ctx, argc ? argv[0] : jsval_undefined(), argc > 1 ? argv+1 : NULL, &ret);
955 if(FAILED(hres))
956 return hres;
958 if(r)
959 *r = jsval_obj(ret);
960 else
961 jsdisp_release(ret);
962 return S_OK;
964 default:
965 FIXME("unimplemented flags: %x\n", flags);
966 return E_NOTIMPL;
969 return S_OK;
972 static const builtin_prop_t RegExpConstr_props[] = {
973 {idx1W, NULL,0, RegExpConstr_get_idx1, builtin_set_const},
974 {idx2W, NULL,0, RegExpConstr_get_idx2, builtin_set_const},
975 {idx3W, NULL,0, RegExpConstr_get_idx3, builtin_set_const},
976 {idx4W, NULL,0, RegExpConstr_get_idx4, builtin_set_const},
977 {idx5W, NULL,0, RegExpConstr_get_idx5, builtin_set_const},
978 {idx6W, NULL,0, RegExpConstr_get_idx6, builtin_set_const},
979 {idx7W, NULL,0, RegExpConstr_get_idx7, builtin_set_const},
980 {idx8W, NULL,0, RegExpConstr_get_idx8, builtin_set_const},
981 {idx9W, NULL,0, RegExpConstr_get_idx9, builtin_set_const},
982 {leftContextW, NULL,0, RegExpConstr_get_leftContext, builtin_set_const},
983 {rightContextW, NULL,0, RegExpConstr_get_rightContext, builtin_set_const}
986 static const builtin_info_t RegExpConstr_info = {
987 JSCLASS_FUNCTION,
988 DEFAULT_FUNCTION_VALUE,
989 ARRAY_SIZE(RegExpConstr_props),
990 RegExpConstr_props,
991 NULL,
992 NULL
995 HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
997 RegExpInstance *regexp;
998 HRESULT hres;
1000 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
1002 hres = alloc_regexp(ctx, object_prototype, &regexp);
1003 if(FAILED(hres))
1004 return hres;
1006 hres = create_builtin_constructor(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info,
1007 PROPF_CONSTR|2, &regexp->dispex, ret);
1009 jsdisp_release(&regexp->dispex);
1010 return hres;
1013 HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
1015 const WCHAR *p;
1016 DWORD flags = 0;
1018 for (p = str; p < str+str_len; p++) {
1019 switch (*p) {
1020 case 'g':
1021 flags |= REG_GLOB;
1022 break;
1023 case 'i':
1024 flags |= REG_FOLD;
1025 break;
1026 case 'm':
1027 flags |= REG_MULTILINE;
1028 break;
1029 case 'y':
1030 flags |= REG_STICKY;
1031 break;
1032 default:
1033 WARN("wrong flag %c\n", *p);
1034 return E_FAIL;
1038 *ret = flags;
1039 return S_OK;