comctl32: Fix disabled thumb painting, for TBS_BOTH use edged rectangle.
[wine/multimedia.git] / dlls / jscript / jsregexp.c
blob0104f3ea5ff915d66fc1cf0262e608b3205788fc
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 const WCHAR emptyW[] = {0};
63 static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
65 return (RegExpInstance*)vdisp->u.jsdisp;
68 static void set_last_index(RegExpInstance *This, DWORD last_index)
70 This->last_index = last_index;
71 jsval_release(This->last_index_val);
72 This->last_index_val = jsval_number(last_index);
75 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
76 DWORD rem_flags, jsstr_t *jsstr, const WCHAR *str, match_state_t *ret)
78 HRESULT hres;
80 hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
81 str, jsstr_length(jsstr), ret);
82 if(FAILED(hres))
83 return hres;
84 if(hres == S_FALSE) {
85 if(rem_flags & REM_RESET_INDEX)
86 set_last_index(regexp, 0);
87 return S_FALSE;
90 if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != jsstr) {
91 jsstr_release(ctx->last_match);
92 ctx->last_match = jsstr_addref(jsstr);
95 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
96 DWORD i, n = min(sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]), ret->paren_count);
98 for(i=0; i < n; i++) {
99 if(ret->parens[i].index == -1) {
100 ctx->match_parens[i].index = 0;
101 ctx->match_parens[i].length = 0;
102 }else {
103 ctx->match_parens[i].index = ret->parens[i].index;
104 ctx->match_parens[i].length = ret->parens[i].length;
108 if(n < sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]))
109 memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
112 set_last_index(regexp, ret->cp-str);
114 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
115 ctx->last_match_index = ret->cp-str-ret->match_len;
116 ctx->last_match_length = ret->match_len;
119 return S_OK;
122 HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
123 DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret)
125 RegExpInstance *regexp = (RegExpInstance*)dispex;
126 match_state_t *match;
127 heap_pool_t *mark;
128 const WCHAR *str;
129 HRESULT hres;
131 if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
132 if(rem_flags & REM_ALLOC_RESULT)
133 *ret = NULL;
134 return S_FALSE;
137 str = jsstr_flatten(jsstr);
138 if(!str)
139 return E_OUTOFMEMORY;
141 if(rem_flags & REM_ALLOC_RESULT) {
142 match = alloc_match_state(regexp->jsregexp, NULL, str);
143 if(!match)
144 return E_OUTOFMEMORY;
145 *ret = match;
148 mark = heap_pool_mark(&ctx->tmp_heap);
150 if(rem_flags & REM_NO_PARENS) {
151 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
152 if(!match) {
153 heap_pool_clear(mark);
154 return E_OUTOFMEMORY;
156 match->cp = (*ret)->cp;
157 match->match_len = (*ret)->match_len;
158 }else {
159 match = *ret;
162 hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match);
164 if(rem_flags & REM_NO_PARENS) {
165 (*ret)->cp = match->cp;
166 (*ret)->match_len = match->match_len;
169 heap_pool_clear(mark);
171 if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
172 heap_free(match);
173 *ret = NULL;
176 return hres;
179 static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag,
180 match_result_t **match_result, DWORD *result_cnt)
182 RegExpInstance *This = (RegExpInstance*)dispex;
183 match_result_t *ret = NULL;
184 match_state_t *result;
185 DWORD i=0, ret_size = 0;
186 heap_pool_t *mark;
187 const WCHAR *str;
188 HRESULT hres;
190 mark = heap_pool_mark(&ctx->tmp_heap);
192 str = jsstr_flatten(jsstr);
193 if(!str)
194 return E_OUTOFMEMORY;
196 result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str);
197 if(!result) {
198 heap_pool_clear(mark);
199 return E_OUTOFMEMORY;
202 while(1) {
203 hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result);
204 if(hres == S_FALSE) {
205 hres = S_OK;
206 break;
209 if(FAILED(hres))
210 break;
212 if(ret_size == i) {
213 if(ret) {
214 match_result_t *old_ret = ret;
216 ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
217 if(!ret)
218 heap_free(old_ret);
219 }else {
220 ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
222 if(!ret) {
223 hres = E_OUTOFMEMORY;
224 break;
228 ret[i].index = result->cp - str - result->match_len;
229 ret[i++].length = result->match_len;
231 if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
232 hres = S_OK;
233 break;
237 heap_pool_clear(mark);
238 if(FAILED(hres)) {
239 heap_free(ret);
240 return hres;
243 *match_result = ret;
244 *result_cnt = i;
245 return S_OK;
248 static HRESULT RegExp_source(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
249 jsval_t *r)
251 TRACE("\n");
253 switch(flags) {
254 case DISPATCH_PROPERTYGET: {
255 RegExpInstance *This = regexp_from_vdisp(jsthis);
256 *r = jsval_string(jsstr_addref(This->str));
257 break;
259 default:
260 FIXME("Unimplemented flags %x\n", flags);
261 return E_NOTIMPL;
264 return S_OK;
267 static HRESULT RegExp_global(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
268 jsval_t *r)
270 FIXME("\n");
271 return E_NOTIMPL;
274 static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
275 jsval_t *r)
277 FIXME("\n");
278 return E_NOTIMPL;
281 static HRESULT RegExp_multiline(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
282 jsval_t *r)
284 FIXME("\n");
285 return E_NOTIMPL;
288 static INT index_from_val(script_ctx_t *ctx, jsval_t v)
290 double n;
291 HRESULT hres;
293 hres = to_number(ctx, v, &n);
294 if(FAILED(hres)) {
295 clear_ei(ctx); /* FIXME: Move ignoring exceptions to to_primitive */
296 return 0;
299 n = floor(n);
300 return is_int32(n) ? n : 0;
303 static HRESULT RegExp_lastIndex(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
304 jsval_t *r)
306 TRACE("\n");
308 switch(flags) {
309 case DISPATCH_PROPERTYGET: {
310 RegExpInstance *regexp = regexp_from_vdisp(jsthis);
312 return jsval_copy(regexp->last_index_val, r);
314 case DISPATCH_PROPERTYPUT: {
315 RegExpInstance *regexp = regexp_from_vdisp(jsthis);
316 HRESULT hres;
318 hres = jsval_copy(argv[0], &regexp->last_index_val);
319 if(FAILED(hres))
320 return hres;
322 regexp->last_index = index_from_val(ctx, argv[0]);
323 break;
325 default:
326 FIXME("unimplemented flags: %x\n", flags);
327 return E_NOTIMPL;
330 return S_OK;
333 static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
334 jsval_t *r)
336 FIXME("\n");
337 return E_NOTIMPL;
340 static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str,
341 const match_state_t *result, IDispatch **ret)
343 const WCHAR *input;
344 jsdisp_t *array;
345 jsstr_t *str;
346 DWORD i;
347 HRESULT hres = S_OK;
349 static const WCHAR indexW[] = {'i','n','d','e','x',0};
350 static const WCHAR inputW[] = {'i','n','p','u','t',0};
351 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
352 static const WCHAR zeroW[] = {'0',0};
354 input = jsstr_flatten(input_str);
355 if(!input)
356 return E_OUTOFMEMORY;
358 hres = create_array(ctx, result->paren_count+1, &array);
359 if(FAILED(hres))
360 return hres;
362 for(i=0; i < result->paren_count; i++) {
363 if(result->parens[i].index != -1)
364 str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length);
365 else
366 str = jsstr_empty();
367 if(!str) {
368 hres = E_OUTOFMEMORY;
369 break;
372 hres = jsdisp_propput_idx(array, i+1, jsval_string(str));
373 jsstr_release(str);
374 if(FAILED(hres))
375 break;
378 while(SUCCEEDED(hres)) {
379 hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input-result->match_len));
380 if(FAILED(hres))
381 break;
383 hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input));
384 if(FAILED(hres))
385 break;
387 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input_str)));
388 if(FAILED(hres))
389 break;
391 str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
392 if(!str) {
393 hres = E_OUTOFMEMORY;
394 break;
396 hres = jsdisp_propput_name(array, zeroW, jsval_string(str));
397 jsstr_release(str);
398 break;
401 if(FAILED(hres)) {
402 jsdisp_release(array);
403 return hres;
406 *ret = to_disp(array);
407 return S_OK;
410 static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg,
411 jsstr_t **input, match_state_t **result, BOOL *ret)
413 RegExpInstance *regexp;
414 match_state_t *match;
415 DWORD last_index = 0;
416 const WCHAR *string;
417 jsstr_t *jsstr;
418 HRESULT hres;
420 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
421 FIXME("Not a RegExp\n");
422 return E_NOTIMPL;
425 regexp = regexp_from_vdisp(jsthis);
427 hres = to_flat_string(ctx, arg, &jsstr, &string);
428 if(FAILED(hres))
429 return hres;
431 if(regexp->jsregexp->flags & REG_GLOB) {
432 if(regexp->last_index < 0) {
433 jsstr_release(jsstr);
434 set_last_index(regexp, 0);
435 *ret = FALSE;
436 if(input)
437 *input = jsstr_empty();
438 return S_OK;
441 last_index = regexp->last_index;
444 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string+last_index);
445 if(!match) {
446 jsstr_release(jsstr);
447 return E_OUTOFMEMORY;
450 hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, jsstr, &match);
451 if(FAILED(hres)) {
452 jsstr_release(jsstr);
453 return hres;
456 *result = match;
457 *ret = hres == S_OK;
458 if(input)
459 *input = jsstr;
460 else
461 jsstr_release(jsstr);
462 return S_OK;
465 static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
466 jsval_t *r)
468 match_state_t *match;
469 heap_pool_t *mark;
470 BOOL b;
471 jsstr_t *string;
472 HRESULT hres;
474 TRACE("\n");
476 mark = heap_pool_mark(&ctx->tmp_heap);
478 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
479 if(FAILED(hres)) {
480 heap_pool_clear(mark);
481 return hres;
484 if(r) {
485 if(b) {
486 IDispatch *ret;
488 hres = create_match_array(ctx, string, match, &ret);
489 if(SUCCEEDED(hres))
490 *r = jsval_disp(ret);
491 }else {
492 *r = jsval_null();
496 heap_pool_clear(mark);
497 jsstr_release(string);
498 return hres;
501 static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
502 jsval_t *r)
504 match_state_t *match;
505 jsstr_t *undef_str;
506 heap_pool_t *mark;
507 BOOL b;
508 HRESULT hres;
510 TRACE("\n");
512 mark = heap_pool_mark(&ctx->tmp_heap);
513 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
514 heap_pool_clear(mark);
515 if(!argc)
516 jsstr_release(undef_str);
517 if(FAILED(hres))
518 return hres;
520 if(r)
521 *r = jsval_bool(b);
522 return S_OK;
525 static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
526 jsval_t *r)
528 TRACE("\n");
530 switch(flags) {
531 case INVOKE_FUNC:
532 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
533 default:
534 FIXME("unimplemented flags %x\n", flags);
535 return E_NOTIMPL;
538 return S_OK;
541 static void RegExp_destructor(jsdisp_t *dispex)
543 RegExpInstance *This = (RegExpInstance*)dispex;
545 if(This->jsregexp)
546 regexp_destroy(This->jsregexp);
547 jsval_release(This->last_index_val);
548 jsstr_release(This->str);
549 heap_free(This);
552 static const builtin_prop_t RegExp_props[] = {
553 {execW, RegExp_exec, PROPF_METHOD|1},
554 {globalW, RegExp_global, 0},
555 {ignoreCaseW, RegExp_ignoreCase, 0},
556 {lastIndexW, RegExp_lastIndex, 0},
557 {multilineW, RegExp_multiline, 0},
558 {sourceW, RegExp_source, 0},
559 {testW, RegExp_test, PROPF_METHOD|1},
560 {toStringW, RegExp_toString, PROPF_METHOD}
563 static const builtin_info_t RegExp_info = {
564 JSCLASS_REGEXP,
565 {NULL, RegExp_value, 0},
566 sizeof(RegExp_props)/sizeof(*RegExp_props),
567 RegExp_props,
568 RegExp_destructor,
569 NULL
572 static const builtin_prop_t RegExpInst_props[] = {
573 {globalW, RegExp_global, 0},
574 {ignoreCaseW, RegExp_ignoreCase, 0},
575 {lastIndexW, RegExp_lastIndex, 0},
576 {multilineW, RegExp_multiline, 0},
577 {sourceW, RegExp_source, 0}
580 static const builtin_info_t RegExpInst_info = {
581 JSCLASS_REGEXP,
582 {NULL, RegExp_value, 0},
583 sizeof(RegExpInst_props)/sizeof(*RegExpInst_props),
584 RegExpInst_props,
585 RegExp_destructor,
586 NULL
589 static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret)
591 RegExpInstance *regexp;
592 HRESULT hres;
594 regexp = heap_alloc_zero(sizeof(RegExpInstance));
595 if(!regexp)
596 return E_OUTOFMEMORY;
598 if(object_prototype)
599 hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
600 else
601 hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
603 if(FAILED(hres)) {
604 heap_free(regexp);
605 return hres;
608 *ret = regexp;
609 return S_OK;
612 HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
614 RegExpInstance *regexp;
615 const WCHAR *str;
616 HRESULT hres;
618 TRACE("%s %x\n", debugstr_jsstr(src), flags);
620 str = jsstr_flatten(src);
621 if(!str)
622 return E_OUTOFMEMORY;
624 hres = alloc_regexp(ctx, NULL, &regexp);
625 if(FAILED(hres))
626 return hres;
628 regexp->str = jsstr_addref(src);
629 regexp->last_index_val = jsval_number(0);
631 regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE);
632 if(!regexp->jsregexp) {
633 WARN("regexp_new failed\n");
634 jsdisp_release(&regexp->dispex);
635 return E_FAIL;
638 *ret = &regexp->dispex;
639 return S_OK;
642 HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
644 unsigned flags, opt_len = 0;
645 const WCHAR *opt = NULL;
646 jsstr_t *src;
647 HRESULT hres;
649 if(is_object_instance(src_arg)) {
650 jsdisp_t *obj;
652 obj = iface_to_jsdisp((IUnknown*)get_object(src_arg));
653 if(obj) {
654 if(is_class(obj, JSCLASS_REGEXP)) {
655 RegExpInstance *regexp = (RegExpInstance*)obj;
657 hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
658 jsdisp_release(obj);
659 return hres;
662 jsdisp_release(obj);
666 if(!is_string(src_arg)) {
667 FIXME("src_arg = %s\n", debugstr_jsval(src_arg));
668 return E_NOTIMPL;
671 src = get_string(src_arg);
673 if(flags_arg) {
674 jsstr_t *opt_str;
676 if(!is_string(*flags_arg)) {
677 FIXME("unimplemented for %s\n", debugstr_jsval(*flags_arg));
678 return E_NOTIMPL;
681 opt_str = get_string(*flags_arg);
682 opt = jsstr_flatten(opt_str);
683 if(!opt)
684 return E_OUTOFMEMORY;
685 opt_len = jsstr_length(opt_str);
688 hres = parse_regexp_flags(opt, opt_len, &flags);
689 if(FAILED(hres))
690 return hres;
692 return create_regexp(ctx, src, flags, ret);
695 HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r)
697 static const WCHAR indexW[] = {'i','n','d','e','x',0};
698 static const WCHAR inputW[] = {'i','n','p','u','t',0};
699 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
701 RegExpInstance *regexp = (RegExpInstance*)re;
702 match_result_t *match_result;
703 unsigned match_cnt, i;
704 const WCHAR *str;
705 jsdisp_t *array;
706 HRESULT hres;
708 str = jsstr_flatten(jsstr);
709 if(!str)
710 return E_OUTOFMEMORY;
712 if(!(regexp->jsregexp->flags & REG_GLOB)) {
713 match_state_t *match;
714 heap_pool_t *mark;
716 mark = heap_pool_mark(&ctx->tmp_heap);
717 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str);
718 if(!match) {
719 heap_pool_clear(mark);
720 return E_OUTOFMEMORY;
723 hres = regexp_match_next(ctx, &regexp->dispex, 0, jsstr, &match);
724 if(FAILED(hres)) {
725 heap_pool_clear(mark);
726 return hres;
729 if(r) {
730 if(hres == S_OK) {
731 IDispatch *ret;
733 hres = create_match_array(ctx, jsstr, match, &ret);
734 if(SUCCEEDED(hres))
735 *r = jsval_disp(ret);
736 }else {
737 *r = jsval_null();
741 heap_pool_clear(mark);
742 return S_OK;
745 hres = regexp_match(ctx, &regexp->dispex, jsstr, FALSE, &match_result, &match_cnt);
746 if(FAILED(hres))
747 return hres;
749 if(!match_cnt) {
750 TRACE("no match\n");
752 if(r)
753 *r = jsval_null();
754 return S_OK;
757 hres = create_array(ctx, match_cnt, &array);
758 if(FAILED(hres))
759 return hres;
761 for(i=0; i < match_cnt; i++) {
762 jsstr_t *tmp_str;
764 tmp_str = jsstr_substr(jsstr, match_result[i].index, match_result[i].length);
765 if(!tmp_str) {
766 hres = E_OUTOFMEMORY;
767 break;
770 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
771 jsstr_release(tmp_str);
772 if(FAILED(hres))
773 break;
776 while(SUCCEEDED(hres)) {
777 hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index));
778 if(FAILED(hres))
779 break;
781 hres = jsdisp_propput_name(array, lastIndexW,
782 jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
783 if(FAILED(hres))
784 break;
786 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr));
787 break;
790 heap_free(match_result);
792 if(SUCCEEDED(hres) && r)
793 *r = jsval_obj(array);
794 else
795 jsdisp_release(array);
796 return hres;
799 static HRESULT global_idx(script_ctx_t *ctx, DWORD flags, DWORD idx, jsval_t *r)
801 switch(flags) {
802 case DISPATCH_PROPERTYGET: {
803 jsstr_t *ret;
805 ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
806 if(!ret)
807 return E_OUTOFMEMORY;
809 *r = jsval_string(ret);
810 break;
812 case DISPATCH_PROPERTYPUT:
813 break;
814 default:
815 FIXME("unsupported flags\n");
816 return E_NOTIMPL;
819 return S_OK;
822 static HRESULT RegExpConstr_idx1(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
823 unsigned argc, jsval_t *argv, jsval_t *r)
825 TRACE("\n");
826 return global_idx(ctx, flags, 0, r);
829 static HRESULT RegExpConstr_idx2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
830 unsigned argc, jsval_t *argv, jsval_t *r)
832 TRACE("\n");
833 return global_idx(ctx, flags, 1, r);
836 static HRESULT RegExpConstr_idx3(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
837 unsigned argc, jsval_t *argv, jsval_t *r)
839 TRACE("\n");
840 return global_idx(ctx, flags, 2, r);
843 static HRESULT RegExpConstr_idx4(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
844 unsigned argc, jsval_t *argv, jsval_t *r)
846 TRACE("\n");
847 return global_idx(ctx, flags, 3, r);
850 static HRESULT RegExpConstr_idx5(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
851 unsigned argc, jsval_t *argv, jsval_t *r)
853 TRACE("\n");
854 return global_idx(ctx, flags, 4, r);
857 static HRESULT RegExpConstr_idx6(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
858 unsigned argc, jsval_t *argv, jsval_t *r)
860 TRACE("\n");
861 return global_idx(ctx, flags, 5, r);
864 static HRESULT RegExpConstr_idx7(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
865 unsigned argc, jsval_t *argv, jsval_t *r)
867 TRACE("\n");
868 return global_idx(ctx, flags, 6, r);
871 static HRESULT RegExpConstr_idx8(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
872 unsigned argc, jsval_t *argv, jsval_t *r)
874 TRACE("\n");
875 return global_idx(ctx, flags, 7, r);
878 static HRESULT RegExpConstr_idx9(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
879 unsigned argc, jsval_t *argv, jsval_t *r)
881 TRACE("\n");
882 return global_idx(ctx, flags, 8, r);
885 static HRESULT RegExpConstr_leftContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
886 unsigned argc, jsval_t *argv, jsval_t *r)
888 TRACE("\n");
890 switch(flags) {
891 case DISPATCH_PROPERTYGET: {
892 jsstr_t *ret;
894 ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
895 if(!ret)
896 return E_OUTOFMEMORY;
898 *r = jsval_string(ret);
899 break;
901 case DISPATCH_PROPERTYPUT:
902 break;
903 default:
904 FIXME("unsupported flags\n");
905 return E_NOTIMPL;
908 return S_OK;
911 static HRESULT RegExpConstr_rightContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
912 unsigned argc, jsval_t *argv, jsval_t *r)
914 TRACE("\n");
916 switch(flags) {
917 case DISPATCH_PROPERTYGET: {
918 jsstr_t *ret;
920 ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
921 jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
922 if(!ret)
923 return E_OUTOFMEMORY;
925 *r = jsval_string(ret);
926 break;
928 case DISPATCH_PROPERTYPUT:
929 break;
930 default:
931 FIXME("unsupported flags\n");
932 return E_NOTIMPL;
935 return S_OK;
938 static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
939 jsval_t *r)
941 TRACE("\n");
943 switch(flags) {
944 case DISPATCH_METHOD:
945 if(argc) {
946 if(is_object_instance(argv[0])) {
947 jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
948 if(jsdisp) {
949 if(is_class(jsdisp, JSCLASS_REGEXP)) {
950 if(argc > 1 && !is_undefined(argv[1])) {
951 jsdisp_release(jsdisp);
952 return throw_regexp_error(ctx, JS_E_REGEXP_SYNTAX, NULL);
955 if(r)
956 *r = jsval_obj(jsdisp);
957 else
958 jsdisp_release(jsdisp);
959 return S_OK;
961 jsdisp_release(jsdisp);
965 /* fall through */
966 case DISPATCH_CONSTRUCT: {
967 jsdisp_t *ret;
968 HRESULT hres;
970 if(!argc) {
971 FIXME("no args\n");
972 return E_NOTIMPL;
975 hres = create_regexp_var(ctx, argv[0], argc > 1 ? argv+1 : NULL, &ret);
976 if(FAILED(hres))
977 return hres;
979 if(r)
980 *r = jsval_obj(ret);
981 else
982 jsdisp_release(ret);
983 return S_OK;
985 default:
986 FIXME("unimplemented flags: %x\n", flags);
987 return E_NOTIMPL;
990 return S_OK;
993 static const builtin_prop_t RegExpConstr_props[] = {
994 {idx1W, RegExpConstr_idx1, 0},
995 {idx2W, RegExpConstr_idx2, 0},
996 {idx3W, RegExpConstr_idx3, 0},
997 {idx4W, RegExpConstr_idx4, 0},
998 {idx5W, RegExpConstr_idx5, 0},
999 {idx6W, RegExpConstr_idx6, 0},
1000 {idx7W, RegExpConstr_idx7, 0},
1001 {idx8W, RegExpConstr_idx8, 0},
1002 {idx9W, RegExpConstr_idx9, 0},
1003 {leftContextW, RegExpConstr_leftContext, 0},
1004 {rightContextW, RegExpConstr_rightContext, 0}
1007 static const builtin_info_t RegExpConstr_info = {
1008 JSCLASS_FUNCTION,
1009 {NULL, Function_value, 0},
1010 sizeof(RegExpConstr_props)/sizeof(*RegExpConstr_props),
1011 RegExpConstr_props,
1012 NULL,
1013 NULL
1016 HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1018 RegExpInstance *regexp;
1019 HRESULT hres;
1021 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
1023 hres = alloc_regexp(ctx, object_prototype, &regexp);
1024 if(FAILED(hres))
1025 return hres;
1027 hres = create_builtin_constructor(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info,
1028 PROPF_CONSTR|2, &regexp->dispex, ret);
1030 jsdisp_release(&regexp->dispex);
1031 return hres;
1034 HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
1036 const WCHAR *p;
1037 DWORD flags = 0;
1039 for (p = str; p < str+str_len; p++) {
1040 switch (*p) {
1041 case 'g':
1042 flags |= REG_GLOB;
1043 break;
1044 case 'i':
1045 flags |= REG_FOLD;
1046 break;
1047 case 'm':
1048 flags |= REG_MULTILINE;
1049 break;
1050 case 'y':
1051 flags |= REG_STICKY;
1052 break;
1053 default:
1054 WARN("wrong flag %c\n", *p);
1055 return E_FAIL;
1059 *ret = flags;
1060 return S_OK;