mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / jscript / jsregexp.c
blobf80452d0c0bbec2d7dcfec219c7c9b5c86f67ddc
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 inline RegExpInstance *regexp_from_jsdisp(jsdisp_t *jsdisp)
39 return CONTAINING_RECORD(jsdisp, RegExpInstance, dispex);
42 static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
44 return regexp_from_jsdisp(vdisp->u.jsdisp);
47 static void set_last_index(RegExpInstance *This, DWORD last_index)
49 This->last_index = last_index;
50 jsval_release(This->last_index_val);
51 This->last_index_val = jsval_number(last_index);
54 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
55 DWORD rem_flags, jsstr_t *jsstr, const WCHAR *str, match_state_t *ret)
57 HRESULT hres;
59 hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
60 str, jsstr_length(jsstr), ret);
61 if(FAILED(hres))
62 return hres;
63 if(hres == S_FALSE) {
64 if(rem_flags & REM_RESET_INDEX)
65 set_last_index(regexp, 0);
66 return S_FALSE;
69 if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != jsstr) {
70 jsstr_release(ctx->last_match);
71 ctx->last_match = jsstr_addref(jsstr);
74 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
75 DWORD i, n = min(ARRAY_SIZE(ctx->match_parens), ret->paren_count);
77 for(i=0; i < n; i++) {
78 if(ret->parens[i].index == -1) {
79 ctx->match_parens[i].index = 0;
80 ctx->match_parens[i].length = 0;
81 }else {
82 ctx->match_parens[i].index = ret->parens[i].index;
83 ctx->match_parens[i].length = ret->parens[i].length;
87 if(n < ARRAY_SIZE(ctx->match_parens))
88 memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
91 set_last_index(regexp, ret->cp-str);
93 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
94 ctx->last_match_index = ret->cp-str-ret->match_len;
95 ctx->last_match_length = ret->match_len;
98 return S_OK;
101 HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
102 DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret)
104 RegExpInstance *regexp = regexp_from_jsdisp(dispex);
105 match_state_t *match;
106 heap_pool_t *mark;
107 const WCHAR *str;
108 HRESULT hres;
110 if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
111 if(rem_flags & REM_ALLOC_RESULT)
112 *ret = NULL;
113 return S_FALSE;
116 str = jsstr_flatten(jsstr);
117 if(!str)
118 return E_OUTOFMEMORY;
120 if(rem_flags & REM_ALLOC_RESULT) {
121 match = alloc_match_state(regexp->jsregexp, NULL, str);
122 if(!match)
123 return E_OUTOFMEMORY;
124 *ret = match;
127 mark = heap_pool_mark(&ctx->tmp_heap);
129 if(rem_flags & REM_NO_PARENS) {
130 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
131 if(!match) {
132 heap_pool_clear(mark);
133 return E_OUTOFMEMORY;
135 match->cp = (*ret)->cp;
136 match->match_len = (*ret)->match_len;
137 }else {
138 match = *ret;
141 hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match);
143 if(rem_flags & REM_NO_PARENS) {
144 (*ret)->cp = match->cp;
145 (*ret)->match_len = match->match_len;
148 heap_pool_clear(mark);
150 if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
151 heap_free(match);
152 *ret = NULL;
155 return hres;
158 static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag,
159 match_result_t **match_result, DWORD *result_cnt)
161 RegExpInstance *This = regexp_from_jsdisp(dispex);
162 match_result_t *ret = NULL;
163 match_state_t *result;
164 DWORD i=0, ret_size = 0;
165 heap_pool_t *mark;
166 const WCHAR *str;
167 HRESULT hres;
169 mark = heap_pool_mark(&ctx->tmp_heap);
171 str = jsstr_flatten(jsstr);
172 if(!str)
173 return E_OUTOFMEMORY;
175 result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str);
176 if(!result) {
177 heap_pool_clear(mark);
178 return E_OUTOFMEMORY;
181 while(1) {
182 hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result);
183 if(hres == S_FALSE) {
184 hres = S_OK;
185 break;
188 if(FAILED(hres))
189 break;
191 if(ret_size == i) {
192 if(ret) {
193 match_result_t *old_ret = ret;
195 ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
196 if(!ret)
197 heap_free(old_ret);
198 }else {
199 ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
201 if(!ret) {
202 hres = E_OUTOFMEMORY;
203 break;
207 ret[i].index = result->cp - str - result->match_len;
208 ret[i++].length = result->match_len;
210 if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
211 hres = S_OK;
212 break;
216 heap_pool_clear(mark);
217 if(FAILED(hres)) {
218 heap_free(ret);
219 return hres;
222 *match_result = ret;
223 *result_cnt = i;
224 return S_OK;
227 static HRESULT RegExp_get_source(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
229 TRACE("\n");
231 *r = jsval_string(jsstr_addref(regexp_from_jsdisp(jsthis)->str));
232 return S_OK;
235 static HRESULT RegExp_get_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
237 TRACE("\n");
239 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_GLOB));
240 return S_OK;
243 static HRESULT RegExp_get_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
245 TRACE("\n");
247 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_FOLD));
248 return S_OK;
251 static HRESULT RegExp_get_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
253 TRACE("\n");
255 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_MULTILINE));
256 return S_OK;
259 static INT index_from_val(script_ctx_t *ctx, jsval_t v)
261 double n;
262 HRESULT hres;
264 hres = to_number(ctx, v, &n);
265 if(FAILED(hres))
266 return 0;
268 n = floor(n);
269 return is_int32(n) ? n : 0;
272 static HRESULT RegExp_get_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
274 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
276 TRACE("\n");
278 return jsval_copy(regexp->last_index_val, r);
281 static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
283 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
284 HRESULT hres;
286 TRACE("\n");
288 jsval_release(regexp->last_index_val);
289 hres = jsval_copy(value, &regexp->last_index_val);
290 if(FAILED(hres))
291 return hres;
293 regexp->last_index = index_from_val(ctx, value);
294 return S_OK;
297 static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
298 jsval_t *r)
300 RegExpInstance *regexp;
301 unsigned len, f;
302 jsstr_t *ret;
303 WCHAR *ptr;
305 TRACE("\n");
307 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
308 WARN("Not a RegExp\n");
309 return JS_E_REGEXP_EXPECTED;
312 regexp = regexp_from_vdisp(jsthis);
314 if(!r)
315 return S_OK;
317 len = jsstr_length(regexp->str) + 2;
319 f = regexp->jsregexp->flags;
320 if(f & REG_FOLD)
321 len++;
322 if(f & REG_GLOB)
323 len++;
324 if(f & REG_MULTILINE)
325 len++;
327 ret = jsstr_alloc_buf(len, &ptr);
328 if(!ret)
329 return E_OUTOFMEMORY;
331 *ptr++ = '/';
332 ptr += jsstr_flush(regexp->str, ptr);
333 *ptr++ = '/';
335 if(f & REG_FOLD)
336 *ptr++ = 'i';
337 if(f & REG_GLOB)
338 *ptr++ = 'g';
339 if(f & REG_MULTILINE)
340 *ptr++ = 'm';
342 *r = jsval_string(ret);
343 return S_OK;
346 static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str,
347 const match_state_t *result, IDispatch **ret)
349 const WCHAR *input;
350 jsdisp_t *array;
351 jsstr_t *str;
352 DWORD i;
353 HRESULT hres = S_OK;
355 input = jsstr_flatten(input_str);
356 if(!input)
357 return E_OUTOFMEMORY;
359 hres = create_array(ctx, result->paren_count+1, &array);
360 if(FAILED(hres))
361 return hres;
363 for(i=0; i < result->paren_count; i++) {
364 if(result->parens[i].index != -1)
365 str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length);
366 else
367 str = jsstr_empty();
368 if(!str) {
369 hres = E_OUTOFMEMORY;
370 break;
373 hres = jsdisp_propput_idx(array, i+1, jsval_string(str));
374 jsstr_release(str);
375 if(FAILED(hres))
376 break;
379 while(SUCCEEDED(hres)) {
380 hres = jsdisp_propput_name(array, L"index", jsval_number(result->cp-input-result->match_len));
381 if(FAILED(hres))
382 break;
384 hres = jsdisp_propput_name(array, L"lastIndex", jsval_number(result->cp-input));
385 if(FAILED(hres))
386 break;
388 hres = jsdisp_propput_name(array, L"input", jsval_string(jsstr_addref(input_str)));
389 if(FAILED(hres))
390 break;
392 str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
393 if(!str) {
394 hres = E_OUTOFMEMORY;
395 break;
397 hres = jsdisp_propput_name(array, L"0", jsval_string(str));
398 jsstr_release(str);
399 break;
402 if(FAILED(hres)) {
403 jsdisp_release(array);
404 return hres;
407 *ret = to_disp(array);
408 return S_OK;
411 static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg,
412 jsstr_t **input, match_state_t **result, BOOL *ret)
414 RegExpInstance *regexp;
415 match_state_t *match;
416 DWORD last_index = 0;
417 const WCHAR *string;
418 jsstr_t *jsstr;
419 HRESULT hres;
421 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
422 FIXME("Not a RegExp\n");
423 return E_NOTIMPL;
426 regexp = regexp_from_vdisp(jsthis);
428 hres = to_flat_string(ctx, arg, &jsstr, &string);
429 if(FAILED(hres))
430 return hres;
432 if(regexp->jsregexp->flags & REG_GLOB) {
433 if(regexp->last_index < 0) {
434 jsstr_release(jsstr);
435 set_last_index(regexp, 0);
436 *ret = FALSE;
437 if(input)
438 *input = jsstr_empty();
439 return S_OK;
442 last_index = regexp->last_index;
445 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string+last_index);
446 if(!match) {
447 jsstr_release(jsstr);
448 return E_OUTOFMEMORY;
451 hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, jsstr, &match);
452 if(FAILED(hres)) {
453 jsstr_release(jsstr);
454 return hres;
457 *result = match;
458 *ret = hres == S_OK;
459 if(input)
460 *input = jsstr;
461 else
462 jsstr_release(jsstr);
463 return S_OK;
466 static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
467 jsval_t *r)
469 match_state_t *match;
470 heap_pool_t *mark;
471 BOOL b;
472 jsstr_t *string;
473 HRESULT hres;
475 TRACE("\n");
477 mark = heap_pool_mark(&ctx->tmp_heap);
479 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
480 if(FAILED(hres)) {
481 heap_pool_clear(mark);
482 return hres;
485 if(r) {
486 if(b) {
487 IDispatch *ret;
489 hres = create_match_array(ctx, string, match, &ret);
490 if(SUCCEEDED(hres))
491 *r = jsval_disp(ret);
492 }else {
493 *r = jsval_null();
497 heap_pool_clear(mark);
498 jsstr_release(string);
499 return hres;
502 static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
503 jsval_t *r)
505 match_state_t *match;
506 jsstr_t *undef_str;
507 heap_pool_t *mark;
508 BOOL b;
509 HRESULT hres;
511 TRACE("\n");
513 mark = heap_pool_mark(&ctx->tmp_heap);
514 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
515 heap_pool_clear(mark);
516 if(!argc)
517 jsstr_release(undef_str);
518 if(FAILED(hres))
519 return hres;
521 if(r)
522 *r = jsval_bool(b);
523 return S_OK;
526 static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
527 jsval_t *r)
529 TRACE("\n");
531 switch(flags) {
532 case INVOKE_FUNC:
533 return JS_E_FUNCTION_EXPECTED;
534 default:
535 FIXME("unimplemented flags %x\n", flags);
536 return E_NOTIMPL;
539 return S_OK;
542 static void RegExp_destructor(jsdisp_t *dispex)
544 RegExpInstance *This = regexp_from_jsdisp(dispex);
546 if(This->jsregexp)
547 regexp_destroy(This->jsregexp);
548 jsval_release(This->last_index_val);
549 jsstr_release(This->str);
550 heap_free(This);
553 static const builtin_prop_t RegExp_props[] = {
554 {L"exec", RegExp_exec, PROPF_METHOD|1},
555 {L"global", NULL,0, RegExp_get_global},
556 {L"ignoreCase", NULL,0, RegExp_get_ignoreCase},
557 {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
558 {L"multiline", NULL,0, RegExp_get_multiline},
559 {L"source", NULL,0, RegExp_get_source},
560 {L"test", RegExp_test, PROPF_METHOD|1},
561 {L"toString", RegExp_toString, PROPF_METHOD}
564 static const builtin_info_t RegExp_info = {
565 JSCLASS_REGEXP,
566 {NULL, RegExp_value, 0},
567 ARRAY_SIZE(RegExp_props),
568 RegExp_props,
569 RegExp_destructor,
570 NULL
573 static const builtin_prop_t RegExpInst_props[] = {
574 {L"global", NULL,0, RegExp_get_global},
575 {L"ignoreCase", NULL,0, RegExp_get_ignoreCase},
576 {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
577 {L"multiline", NULL,0, RegExp_get_multiline},
578 {L"source", NULL,0, RegExp_get_source}
581 static const builtin_info_t RegExpInst_info = {
582 JSCLASS_REGEXP,
583 {NULL, RegExp_value, 0},
584 ARRAY_SIZE(RegExpInst_props),
585 RegExpInst_props,
586 RegExp_destructor,
587 NULL
590 static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret)
592 RegExpInstance *regexp;
593 HRESULT hres;
595 regexp = heap_alloc_zero(sizeof(RegExpInstance));
596 if(!regexp)
597 return E_OUTOFMEMORY;
599 if(object_prototype)
600 hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
601 else
602 hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
604 if(FAILED(hres)) {
605 heap_free(regexp);
606 return hres;
609 *ret = regexp;
610 return S_OK;
613 HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
615 RegExpInstance *regexp;
616 const WCHAR *str;
617 HRESULT hres;
619 str = jsstr_flatten(src);
620 if(!str)
621 return E_OUTOFMEMORY;
623 TRACE("%s %x\n", debugstr_wn(str, jsstr_length(src)), flags);
625 hres = alloc_regexp(ctx, NULL, &regexp);
626 if(FAILED(hres))
627 return hres;
629 regexp->str = jsstr_addref(src);
630 regexp->last_index_val = jsval_number(0);
632 regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE);
633 if(!regexp->jsregexp) {
634 WARN("regexp_new failed\n");
635 jsdisp_release(&regexp->dispex);
636 return E_FAIL;
639 *ret = &regexp->dispex;
640 return S_OK;
643 HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
645 unsigned flags = 0;
646 const WCHAR *opt = NULL;
647 jsstr_t *src;
648 HRESULT hres = S_OK;
650 if(is_object_instance(src_arg)) {
651 jsdisp_t *obj;
653 obj = iface_to_jsdisp(get_object(src_arg));
654 if(obj) {
655 if(is_class(obj, JSCLASS_REGEXP)) {
656 RegExpInstance *regexp = regexp_from_jsdisp(obj);
658 hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
659 jsdisp_release(obj);
660 return hres;
663 jsdisp_release(obj);
667 if(is_undefined(src_arg))
668 src = jsstr_empty();
669 else
670 hres = to_string(ctx, src_arg, &src);
671 if(FAILED(hres))
672 return hres;
674 if(flags_arg && !is_undefined(*flags_arg)) {
675 jsstr_t *opt_str;
677 hres = to_string(ctx, *flags_arg, &opt_str);
678 if(SUCCEEDED(hres)) {
679 opt = jsstr_flatten(opt_str);
680 if(opt)
681 hres = parse_regexp_flags(opt, jsstr_length(opt_str), &flags);
682 else
683 hres = E_OUTOFMEMORY;
684 jsstr_release(opt_str);
688 if(SUCCEEDED(hres))
689 hres = create_regexp(ctx, src, flags, ret);
690 jsstr_release(src);
691 return hres;
694 HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r)
696 RegExpInstance *regexp = regexp_from_jsdisp(re);
697 match_result_t *match_result;
698 unsigned match_cnt, i;
699 const WCHAR *str;
700 jsdisp_t *array;
701 HRESULT hres;
703 str = jsstr_flatten(jsstr);
704 if(!str)
705 return E_OUTOFMEMORY;
707 if(!(regexp->jsregexp->flags & REG_GLOB)) {
708 match_state_t *match;
709 heap_pool_t *mark;
711 mark = heap_pool_mark(&ctx->tmp_heap);
712 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str);
713 if(!match) {
714 heap_pool_clear(mark);
715 return E_OUTOFMEMORY;
718 hres = regexp_match_next(ctx, &regexp->dispex, 0, jsstr, &match);
719 if(FAILED(hres)) {
720 heap_pool_clear(mark);
721 return hres;
724 if(r) {
725 if(hres == S_OK) {
726 IDispatch *ret;
728 hres = create_match_array(ctx, jsstr, match, &ret);
729 if(SUCCEEDED(hres))
730 *r = jsval_disp(ret);
731 }else {
732 *r = jsval_null();
736 heap_pool_clear(mark);
737 return S_OK;
740 hres = regexp_match(ctx, &regexp->dispex, jsstr, FALSE, &match_result, &match_cnt);
741 if(FAILED(hres))
742 return hres;
744 if(!match_cnt) {
745 TRACE("no match\n");
747 if(r)
748 *r = jsval_null();
749 return S_OK;
752 hres = create_array(ctx, match_cnt, &array);
753 if(FAILED(hres))
754 return hres;
756 for(i=0; i < match_cnt; i++) {
757 jsstr_t *tmp_str;
759 tmp_str = jsstr_substr(jsstr, match_result[i].index, match_result[i].length);
760 if(!tmp_str) {
761 hres = E_OUTOFMEMORY;
762 break;
765 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
766 jsstr_release(tmp_str);
767 if(FAILED(hres))
768 break;
771 while(SUCCEEDED(hres)) {
772 hres = jsdisp_propput_name(array, L"index", jsval_number(match_result[match_cnt-1].index));
773 if(FAILED(hres))
774 break;
776 hres = jsdisp_propput_name(array, L"lastIndex",
777 jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
778 if(FAILED(hres))
779 break;
781 hres = jsdisp_propput_name(array, L"input", jsval_string(jsstr));
782 break;
785 heap_free(match_result);
787 if(SUCCEEDED(hres) && r)
788 *r = jsval_obj(array);
789 else
790 jsdisp_release(array);
791 return hres;
794 static HRESULT global_idx(script_ctx_t *ctx, DWORD idx, jsval_t *r)
796 jsstr_t *ret;
798 ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
799 if(!ret)
800 return E_OUTOFMEMORY;
802 *r = jsval_string(ret);
803 return S_OK;
806 static HRESULT RegExpConstr_get_idx1(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
808 TRACE("\n");
809 return global_idx(ctx, 0, r);
812 static HRESULT RegExpConstr_get_idx2(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
814 TRACE("\n");
815 return global_idx(ctx, 1, r);
818 static HRESULT RegExpConstr_get_idx3(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
820 TRACE("\n");
821 return global_idx(ctx, 2, r);
824 static HRESULT RegExpConstr_get_idx4(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
826 TRACE("\n");
827 return global_idx(ctx, 3, r);
830 static HRESULT RegExpConstr_get_idx5(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
832 TRACE("\n");
833 return global_idx(ctx, 4, r);
836 static HRESULT RegExpConstr_get_idx6(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
838 TRACE("\n");
839 return global_idx(ctx, 5, r);
842 static HRESULT RegExpConstr_get_idx7(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
844 TRACE("\n");
845 return global_idx(ctx, 6, r);
848 static HRESULT RegExpConstr_get_idx8(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
850 TRACE("\n");
851 return global_idx(ctx, 7, r);
854 static HRESULT RegExpConstr_get_idx9(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
856 TRACE("\n");
857 return global_idx(ctx, 8, r);
860 static HRESULT RegExpConstr_get_leftContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
862 jsstr_t *ret;
864 TRACE("\n");
866 ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
867 if(!ret)
868 return E_OUTOFMEMORY;
870 *r = jsval_string(ret);
871 return S_OK;
874 static HRESULT RegExpConstr_get_rightContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
876 jsstr_t *ret;
878 TRACE("\n");
880 ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
881 jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
882 if(!ret)
883 return E_OUTOFMEMORY;
885 *r = jsval_string(ret);
886 return S_OK;
889 static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
890 jsval_t *r)
892 TRACE("\n");
894 switch(flags) {
895 case DISPATCH_METHOD:
896 if(argc) {
897 if(is_object_instance(argv[0])) {
898 jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0]));
899 if(jsdisp) {
900 if(is_class(jsdisp, JSCLASS_REGEXP)) {
901 if(argc > 1 && !is_undefined(argv[1])) {
902 jsdisp_release(jsdisp);
903 return JS_E_REGEXP_SYNTAX;
906 if(r)
907 *r = jsval_obj(jsdisp);
908 else
909 jsdisp_release(jsdisp);
910 return S_OK;
912 jsdisp_release(jsdisp);
916 /* fall through */
917 case DISPATCH_CONSTRUCT: {
918 jsdisp_t *ret;
919 HRESULT hres;
921 hres = create_regexp_var(ctx, argc ? argv[0] : jsval_undefined(), argc > 1 ? argv+1 : NULL, &ret);
922 if(FAILED(hres))
923 return hres;
925 if(r)
926 *r = jsval_obj(ret);
927 else
928 jsdisp_release(ret);
929 return S_OK;
931 default:
932 FIXME("unimplemented flags: %x\n", flags);
933 return E_NOTIMPL;
936 return S_OK;
939 static const builtin_prop_t RegExpConstr_props[] = {
940 {L"$1", NULL,0, RegExpConstr_get_idx1, builtin_set_const},
941 {L"$2", NULL,0, RegExpConstr_get_idx2, builtin_set_const},
942 {L"$3", NULL,0, RegExpConstr_get_idx3, builtin_set_const},
943 {L"$4", NULL,0, RegExpConstr_get_idx4, builtin_set_const},
944 {L"$5", NULL,0, RegExpConstr_get_idx5, builtin_set_const},
945 {L"$6", NULL,0, RegExpConstr_get_idx6, builtin_set_const},
946 {L"$7", NULL,0, RegExpConstr_get_idx7, builtin_set_const},
947 {L"$8", NULL,0, RegExpConstr_get_idx8, builtin_set_const},
948 {L"$9", NULL,0, RegExpConstr_get_idx9, builtin_set_const},
949 {L"leftContext", NULL,0, RegExpConstr_get_leftContext, builtin_set_const},
950 {L"rightContext", NULL,0, RegExpConstr_get_rightContext, builtin_set_const}
953 static const builtin_info_t RegExpConstr_info = {
954 JSCLASS_FUNCTION,
955 DEFAULT_FUNCTION_VALUE,
956 ARRAY_SIZE(RegExpConstr_props),
957 RegExpConstr_props,
958 NULL,
959 NULL
962 HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
964 RegExpInstance *regexp;
965 HRESULT hres;
967 hres = alloc_regexp(ctx, object_prototype, &regexp);
968 if(FAILED(hres))
969 return hres;
971 hres = create_builtin_constructor(ctx, RegExpConstr_value, L"RegExp", &RegExpConstr_info,
972 PROPF_CONSTR|2, &regexp->dispex, ret);
974 jsdisp_release(&regexp->dispex);
975 return hres;
978 HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
980 const WCHAR *p;
981 DWORD flags = 0;
983 for (p = str; p < str+str_len; p++) {
984 switch (*p) {
985 case 'g':
986 flags |= REG_GLOB;
987 break;
988 case 'i':
989 flags |= REG_FOLD;
990 break;
991 case 'm':
992 flags |= REG_MULTILINE;
993 break;
994 case 'y':
995 flags |= REG_STICKY;
996 break;
997 default:
998 WARN("wrong flag %c\n", *p);
999 return E_FAIL;
1003 *ret = flags;
1004 return S_OK;