wow32: Use spec file imports.
[wine.git] / dlls / jscript / jsregexp.c
blob7da365f4e6ccc722bf2264db2c04d472c5ad8cd9
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_this(jsval_t vthis)
44 jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL;
45 return (jsdisp && is_class(jsdisp, JSCLASS_REGEXP)) ? regexp_from_jsdisp(jsdisp) : NULL;
48 static void set_last_index(RegExpInstance *This, DWORD last_index)
50 This->last_index = last_index;
51 jsval_release(This->last_index_val);
52 This->last_index_val = jsval_number(last_index);
55 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
56 DWORD rem_flags, jsstr_t *jsstr, const WCHAR *str, match_state_t *ret)
58 HRESULT hres;
60 hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
61 str, jsstr_length(jsstr), ret);
62 if(FAILED(hres))
63 return hres;
64 if(hres == S_FALSE) {
65 if(rem_flags & REM_RESET_INDEX)
66 set_last_index(regexp, 0);
67 return S_FALSE;
70 if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != jsstr) {
71 jsstr_release(ctx->last_match);
72 ctx->last_match = jsstr_addref(jsstr);
75 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
76 DWORD i, n = min(ARRAY_SIZE(ctx->match_parens), ret->paren_count);
78 for(i=0; i < n; i++) {
79 if(ret->parens[i].index == -1) {
80 ctx->match_parens[i].index = 0;
81 ctx->match_parens[i].length = 0;
82 }else {
83 ctx->match_parens[i].index = ret->parens[i].index;
84 ctx->match_parens[i].length = ret->parens[i].length;
88 if(n < ARRAY_SIZE(ctx->match_parens))
89 memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
92 set_last_index(regexp, ret->cp-str);
94 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
95 ctx->last_match_index = ret->cp-str-ret->match_len;
96 ctx->last_match_length = ret->match_len;
99 return S_OK;
102 HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
103 DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret)
105 RegExpInstance *regexp = regexp_from_jsdisp(dispex);
106 match_state_t *match;
107 heap_pool_t *mark;
108 const WCHAR *str;
109 HRESULT hres;
111 if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
112 if(rem_flags & REM_ALLOC_RESULT)
113 *ret = NULL;
114 return S_FALSE;
117 str = jsstr_flatten(jsstr);
118 if(!str)
119 return E_OUTOFMEMORY;
121 if(rem_flags & REM_ALLOC_RESULT) {
122 match = alloc_match_state(regexp->jsregexp, NULL, str);
123 if(!match)
124 return E_OUTOFMEMORY;
125 *ret = match;
128 mark = heap_pool_mark(&ctx->tmp_heap);
130 if(rem_flags & REM_NO_PARENS) {
131 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
132 if(!match) {
133 heap_pool_clear(mark);
134 return E_OUTOFMEMORY;
136 match->cp = (*ret)->cp;
137 match->match_len = (*ret)->match_len;
138 }else {
139 match = *ret;
142 hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match);
144 if(rem_flags & REM_NO_PARENS) {
145 (*ret)->cp = match->cp;
146 (*ret)->match_len = match->match_len;
149 heap_pool_clear(mark);
151 if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
152 free(match);
153 *ret = NULL;
156 return hres;
159 static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag,
160 match_result_t **match_result, DWORD *result_cnt)
162 RegExpInstance *This = regexp_from_jsdisp(dispex);
163 match_result_t *ret = NULL;
164 match_state_t *result;
165 DWORD i=0, ret_size = 0;
166 heap_pool_t *mark;
167 const WCHAR *str;
168 HRESULT hres;
170 mark = heap_pool_mark(&ctx->tmp_heap);
172 str = jsstr_flatten(jsstr);
173 if(!str)
174 return E_OUTOFMEMORY;
176 result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str);
177 if(!result) {
178 heap_pool_clear(mark);
179 return E_OUTOFMEMORY;
182 while(1) {
183 hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result);
184 if(hres == S_FALSE) {
185 hres = S_OK;
186 break;
189 if(FAILED(hres))
190 break;
192 if(ret_size == i) {
193 if(ret) {
194 match_result_t *old_ret = ret;
196 ret = realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
197 if(!ret)
198 free(old_ret);
199 }else {
200 ret = malloc((ret_size=4) * sizeof(match_result_t));
202 if(!ret) {
203 hres = E_OUTOFMEMORY;
204 break;
208 ret[i].index = result->cp - str - result->match_len;
209 ret[i++].length = result->match_len;
211 if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
212 hres = S_OK;
213 break;
217 heap_pool_clear(mark);
218 if(FAILED(hres)) {
219 free(ret);
220 return hres;
223 *match_result = ret;
224 *result_cnt = i;
225 return S_OK;
228 static HRESULT RegExp_get_source(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
230 TRACE("\n");
232 *r = jsval_string(jsstr_addref(regexp_from_jsdisp(jsthis)->str));
233 return S_OK;
236 static HRESULT RegExp_get_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
238 TRACE("\n");
240 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_GLOB));
241 return S_OK;
244 static HRESULT RegExp_get_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
246 TRACE("\n");
248 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_FOLD));
249 return S_OK;
252 static HRESULT RegExp_get_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
254 TRACE("\n");
256 *r = jsval_bool(!!(regexp_from_jsdisp(jsthis)->jsregexp->flags & REG_MULTILINE));
257 return S_OK;
260 static INT index_from_val(script_ctx_t *ctx, jsval_t v)
262 double n;
263 HRESULT hres;
265 hres = to_number(ctx, v, &n);
266 if(FAILED(hres))
267 return 0;
269 n = floor(n);
270 return is_int32(n) ? n : 0;
273 static HRESULT RegExp_get_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
275 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
277 TRACE("\n");
279 return jsval_copy(regexp->last_index_val, r);
282 static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
284 RegExpInstance *regexp = regexp_from_jsdisp(jsthis);
285 HRESULT hres;
287 TRACE("\n");
289 jsval_release(regexp->last_index_val);
290 hres = jsval_copy(value, &regexp->last_index_val);
291 if(FAILED(hres))
292 return hres;
294 regexp->last_index = index_from_val(ctx, value);
295 return S_OK;
298 static HRESULT RegExp_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
299 jsval_t *r)
301 RegExpInstance *regexp;
302 unsigned len, f;
303 jsstr_t *ret;
304 WCHAR *ptr;
306 TRACE("\n");
308 if(!(regexp = regexp_this(vthis))) {
309 WARN("Not a RegExp\n");
310 return JS_E_REGEXP_EXPECTED;
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 jsval_t val;
366 if(result->parens[i].index != -1) {
367 if(!(str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length))) {
368 hres = E_OUTOFMEMORY;
369 break;
371 val = jsval_string(str);
372 }else if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) {
373 val = jsval_string(jsstr_empty());
374 }else {
375 val = jsval_undefined();
378 hres = jsdisp_propput_idx(array, i+1, val);
379 jsval_release(val);
380 if(FAILED(hres))
381 break;
384 while(SUCCEEDED(hres)) {
385 hres = jsdisp_propput_name(array, L"index", jsval_number(result->cp-input-result->match_len));
386 if(FAILED(hres))
387 break;
389 hres = jsdisp_propput_name(array, L"lastIndex", jsval_number(result->cp-input));
390 if(FAILED(hres))
391 break;
393 hres = jsdisp_propput_name(array, L"input", jsval_string(jsstr_addref(input_str)));
394 if(FAILED(hres))
395 break;
397 str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
398 if(!str) {
399 hres = E_OUTOFMEMORY;
400 break;
402 hres = jsdisp_propput_name(array, L"0", jsval_string(str));
403 jsstr_release(str);
404 break;
407 if(FAILED(hres)) {
408 jsdisp_release(array);
409 return hres;
412 *ret = to_disp(array);
413 return S_OK;
416 static HRESULT run_exec(script_ctx_t *ctx, jsval_t vthis, jsval_t arg,
417 jsstr_t **input, match_state_t **result, BOOL *ret)
419 RegExpInstance *regexp;
420 match_state_t *match;
421 DWORD last_index = 0;
422 const WCHAR *string;
423 jsstr_t *jsstr;
424 HRESULT hres;
426 if(!(regexp = regexp_this(vthis))) {
427 WARN("Not a RegExp\n");
428 return JS_E_REGEXP_EXPECTED;
431 hres = to_flat_string(ctx, arg, &jsstr, &string);
432 if(FAILED(hres))
433 return hres;
435 if(regexp->jsregexp->flags & REG_GLOB) {
436 if(regexp->last_index < 0) {
437 jsstr_release(jsstr);
438 set_last_index(regexp, 0);
439 *ret = FALSE;
440 if(input)
441 *input = jsstr_empty();
442 return S_OK;
445 last_index = regexp->last_index;
448 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string+last_index);
449 if(!match) {
450 jsstr_release(jsstr);
451 return E_OUTOFMEMORY;
454 hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, jsstr, &match);
455 if(FAILED(hres)) {
456 jsstr_release(jsstr);
457 return hres;
460 *result = match;
461 *ret = hres == S_OK;
462 if(input)
463 *input = jsstr;
464 else
465 jsstr_release(jsstr);
466 return S_OK;
469 static HRESULT RegExp_exec(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
470 jsval_t *r)
472 match_state_t *match;
473 heap_pool_t *mark;
474 BOOL b;
475 jsstr_t *string;
476 HRESULT hres;
478 TRACE("\n");
480 mark = heap_pool_mark(&ctx->tmp_heap);
482 hres = run_exec(ctx, vthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
483 if(FAILED(hres)) {
484 heap_pool_clear(mark);
485 return hres;
488 if(r) {
489 if(b) {
490 IDispatch *ret;
492 hres = create_match_array(ctx, string, match, &ret);
493 if(SUCCEEDED(hres))
494 *r = jsval_disp(ret);
495 }else {
496 *r = jsval_null();
500 heap_pool_clear(mark);
501 jsstr_release(string);
502 return hres;
505 static HRESULT RegExp_test(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
506 jsval_t *r)
508 match_state_t *match;
509 jsstr_t *undef_str;
510 heap_pool_t *mark;
511 BOOL b;
512 HRESULT hres;
514 TRACE("\n");
516 mark = heap_pool_mark(&ctx->tmp_heap);
517 hres = run_exec(ctx, vthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
518 heap_pool_clear(mark);
519 if(!argc)
520 jsstr_release(undef_str);
521 if(FAILED(hres))
522 return hres;
524 if(r)
525 *r = jsval_bool(b);
526 return S_OK;
529 static HRESULT RegExp_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
530 jsval_t *r)
532 TRACE("\n");
534 switch(flags) {
535 case INVOKE_FUNC:
536 return JS_E_FUNCTION_EXPECTED;
537 default:
538 FIXME("unimplemented flags %x\n", flags);
539 return E_NOTIMPL;
542 return S_OK;
545 static void RegExp_destructor(jsdisp_t *dispex)
547 RegExpInstance *This = regexp_from_jsdisp(dispex);
549 if(This->jsregexp)
550 regexp_destroy(This->jsregexp);
551 jsval_release(This->last_index_val);
552 jsstr_release(This->str);
553 free(This);
556 static HRESULT RegExp_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex)
558 return gc_process_linked_val(gc_ctx, op, dispex, &regexp_from_jsdisp(dispex)->last_index_val);
561 static const builtin_prop_t RegExp_props[] = {
562 {L"exec", RegExp_exec, PROPF_METHOD|1},
563 {L"global", NULL,0, RegExp_get_global},
564 {L"ignoreCase", NULL,0, RegExp_get_ignoreCase},
565 {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
566 {L"multiline", NULL,0, RegExp_get_multiline},
567 {L"source", NULL,0, RegExp_get_source},
568 {L"test", RegExp_test, PROPF_METHOD|1},
569 {L"toString", RegExp_toString, PROPF_METHOD}
572 static const builtin_info_t RegExp_info = {
573 JSCLASS_REGEXP,
574 RegExp_value,
575 ARRAY_SIZE(RegExp_props),
576 RegExp_props,
577 RegExp_destructor,
578 NULL,
579 NULL,
580 NULL,
581 NULL,
582 RegExp_gc_traverse
585 static const builtin_prop_t RegExpInst_props[] = {
586 {L"global", NULL,0, RegExp_get_global},
587 {L"ignoreCase", NULL,0, RegExp_get_ignoreCase},
588 {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
589 {L"multiline", NULL,0, RegExp_get_multiline},
590 {L"source", NULL,0, RegExp_get_source}
593 static const builtin_info_t RegExpInst_info = {
594 JSCLASS_REGEXP,
595 RegExp_value,
596 ARRAY_SIZE(RegExpInst_props),
597 RegExpInst_props,
598 RegExp_destructor,
599 NULL,
600 NULL,
601 NULL,
602 NULL,
603 RegExp_gc_traverse
606 static HRESULT alloc_regexp(script_ctx_t *ctx, jsstr_t *str, jsdisp_t *object_prototype, RegExpInstance **ret)
608 RegExpInstance *regexp;
609 HRESULT hres;
611 regexp = calloc(1, sizeof(RegExpInstance));
612 if(!regexp)
613 return E_OUTOFMEMORY;
615 if(object_prototype)
616 hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
617 else
618 hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
620 if(FAILED(hres)) {
621 free(regexp);
622 return hres;
625 regexp->str = jsstr_addref(str);
626 regexp->last_index_val = jsval_number(0);
628 *ret = regexp;
629 return S_OK;
632 HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
634 RegExpInstance *regexp;
635 const WCHAR *str;
636 HRESULT hres;
638 str = jsstr_flatten(src);
639 if(!str)
640 return E_OUTOFMEMORY;
642 TRACE("%s %lx\n", debugstr_wn(str, jsstr_length(src)), flags);
644 hres = alloc_regexp(ctx, src, NULL, &regexp);
645 if(FAILED(hres))
646 return hres;
648 regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE);
649 if(!regexp->jsregexp) {
650 WARN("regexp_new failed\n");
651 jsdisp_release(&regexp->dispex);
652 return DISP_E_EXCEPTION;
655 *ret = &regexp->dispex;
656 return S_OK;
659 HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
661 DWORD flags = 0;
662 const WCHAR *opt = NULL;
663 jsstr_t *src;
664 HRESULT hres = S_OK;
666 if(is_object_instance(src_arg)) {
667 jsdisp_t *obj;
669 obj = iface_to_jsdisp(get_object(src_arg));
670 if(obj) {
671 if(is_class(obj, JSCLASS_REGEXP)) {
672 RegExpInstance *regexp = regexp_from_jsdisp(obj);
674 hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
675 jsdisp_release(obj);
676 return hres;
679 jsdisp_release(obj);
683 if(is_undefined(src_arg))
684 src = jsstr_empty();
685 else
686 hres = to_string(ctx, src_arg, &src);
687 if(FAILED(hres))
688 return hres;
690 if(flags_arg && !is_undefined(*flags_arg)) {
691 jsstr_t *opt_str;
693 hres = to_string(ctx, *flags_arg, &opt_str);
694 if(SUCCEEDED(hres)) {
695 opt = jsstr_flatten(opt_str);
696 if(opt)
697 hres = parse_regexp_flags(opt, jsstr_length(opt_str), &flags);
698 else
699 hres = E_OUTOFMEMORY;
700 jsstr_release(opt_str);
704 if(SUCCEEDED(hres))
705 hres = create_regexp(ctx, src, flags, ret);
706 jsstr_release(src);
707 return hres;
710 HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r)
712 RegExpInstance *regexp = regexp_from_jsdisp(re);
713 match_result_t *match_result;
714 DWORD match_cnt, i;
715 const WCHAR *str;
716 jsdisp_t *array;
717 HRESULT hres;
719 str = jsstr_flatten(jsstr);
720 if(!str)
721 return E_OUTOFMEMORY;
723 if(!(regexp->jsregexp->flags & REG_GLOB)) {
724 match_state_t *match;
725 heap_pool_t *mark;
727 mark = heap_pool_mark(&ctx->tmp_heap);
728 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str);
729 if(!match) {
730 heap_pool_clear(mark);
731 return E_OUTOFMEMORY;
734 hres = regexp_match_next(ctx, &regexp->dispex, 0, jsstr, &match);
735 if(FAILED(hres)) {
736 heap_pool_clear(mark);
737 return hres;
740 if(r) {
741 if(hres == S_OK) {
742 IDispatch *ret;
744 hres = create_match_array(ctx, jsstr, match, &ret);
745 if(SUCCEEDED(hres))
746 *r = jsval_disp(ret);
747 }else {
748 *r = jsval_null();
752 heap_pool_clear(mark);
753 return S_OK;
756 hres = regexp_match(ctx, &regexp->dispex, jsstr, FALSE, &match_result, &match_cnt);
757 if(FAILED(hres))
758 return hres;
760 if(!match_cnt) {
761 TRACE("no match\n");
763 if(r)
764 *r = jsval_null();
765 return S_OK;
768 hres = create_array(ctx, match_cnt, &array);
769 if(FAILED(hres))
770 return hres;
772 for(i=0; i < match_cnt; i++) {
773 jsstr_t *tmp_str;
775 tmp_str = jsstr_substr(jsstr, match_result[i].index, match_result[i].length);
776 if(!tmp_str) {
777 hres = E_OUTOFMEMORY;
778 break;
781 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
782 jsstr_release(tmp_str);
783 if(FAILED(hres))
784 break;
787 while(SUCCEEDED(hres)) {
788 hres = jsdisp_propput_name(array, L"index", jsval_number(match_result[match_cnt-1].index));
789 if(FAILED(hres))
790 break;
792 hres = jsdisp_propput_name(array, L"lastIndex",
793 jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
794 if(FAILED(hres))
795 break;
797 hres = jsdisp_propput_name(array, L"input", jsval_string(jsstr));
798 break;
801 free(match_result);
803 if(SUCCEEDED(hres) && r)
804 *r = jsval_obj(array);
805 else
806 jsdisp_release(array);
807 return hres;
810 static HRESULT global_idx(script_ctx_t *ctx, DWORD idx, jsval_t *r)
812 jsstr_t *ret;
814 ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
815 if(!ret)
816 return E_OUTOFMEMORY;
818 *r = jsval_string(ret);
819 return S_OK;
822 static HRESULT RegExpConstr_get_idx1(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
824 TRACE("\n");
825 return global_idx(ctx, 0, r);
828 static HRESULT RegExpConstr_get_idx2(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
830 TRACE("\n");
831 return global_idx(ctx, 1, r);
834 static HRESULT RegExpConstr_get_idx3(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
836 TRACE("\n");
837 return global_idx(ctx, 2, r);
840 static HRESULT RegExpConstr_get_idx4(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
842 TRACE("\n");
843 return global_idx(ctx, 3, r);
846 static HRESULT RegExpConstr_get_idx5(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
848 TRACE("\n");
849 return global_idx(ctx, 4, r);
852 static HRESULT RegExpConstr_get_idx6(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
854 TRACE("\n");
855 return global_idx(ctx, 5, r);
858 static HRESULT RegExpConstr_get_idx7(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
860 TRACE("\n");
861 return global_idx(ctx, 6, r);
864 static HRESULT RegExpConstr_get_idx8(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
866 TRACE("\n");
867 return global_idx(ctx, 7, r);
870 static HRESULT RegExpConstr_get_idx9(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
872 TRACE("\n");
873 return global_idx(ctx, 8, r);
876 static HRESULT RegExpConstr_get_leftContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
878 jsstr_t *ret;
880 TRACE("\n");
882 ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
883 if(!ret)
884 return E_OUTOFMEMORY;
886 *r = jsval_string(ret);
887 return S_OK;
890 static HRESULT RegExpConstr_get_rightContext(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
892 jsstr_t *ret;
894 TRACE("\n");
896 ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
897 jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
898 if(!ret)
899 return E_OUTOFMEMORY;
901 *r = jsval_string(ret);
902 return S_OK;
905 static HRESULT RegExpConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
906 jsval_t *r)
908 TRACE("\n");
910 switch(flags) {
911 case DISPATCH_METHOD:
912 if(argc) {
913 if(is_object_instance(argv[0])) {
914 jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0]));
915 if(jsdisp) {
916 if(is_class(jsdisp, JSCLASS_REGEXP)) {
917 if(argc > 1 && !is_undefined(argv[1])) {
918 jsdisp_release(jsdisp);
919 return JS_E_REGEXP_SYNTAX;
922 if(r)
923 *r = jsval_obj(jsdisp);
924 else
925 jsdisp_release(jsdisp);
926 return S_OK;
928 jsdisp_release(jsdisp);
932 /* fall through */
933 case DISPATCH_CONSTRUCT: {
934 jsdisp_t *ret;
935 HRESULT hres;
937 hres = create_regexp_var(ctx, argc ? argv[0] : jsval_undefined(), argc > 1 ? argv+1 : NULL, &ret);
938 if(FAILED(hres))
939 return hres;
941 if(r)
942 *r = jsval_obj(ret);
943 else
944 jsdisp_release(ret);
945 return S_OK;
947 default:
948 FIXME("unimplemented flags: %x\n", flags);
949 return E_NOTIMPL;
952 return S_OK;
955 static const builtin_prop_t RegExpConstr_props[] = {
956 {L"$1", NULL,0, RegExpConstr_get_idx1, builtin_set_const},
957 {L"$2", NULL,0, RegExpConstr_get_idx2, builtin_set_const},
958 {L"$3", NULL,0, RegExpConstr_get_idx3, builtin_set_const},
959 {L"$4", NULL,0, RegExpConstr_get_idx4, builtin_set_const},
960 {L"$5", NULL,0, RegExpConstr_get_idx5, builtin_set_const},
961 {L"$6", NULL,0, RegExpConstr_get_idx6, builtin_set_const},
962 {L"$7", NULL,0, RegExpConstr_get_idx7, builtin_set_const},
963 {L"$8", NULL,0, RegExpConstr_get_idx8, builtin_set_const},
964 {L"$9", NULL,0, RegExpConstr_get_idx9, builtin_set_const},
965 {L"leftContext", NULL,0, RegExpConstr_get_leftContext, builtin_set_const},
966 {L"rightContext", NULL,0, RegExpConstr_get_rightContext, builtin_set_const}
969 static const builtin_info_t RegExpConstr_info = {
970 JSCLASS_FUNCTION,
971 Function_value,
972 ARRAY_SIZE(RegExpConstr_props),
973 RegExpConstr_props,
974 NULL,
975 NULL
978 HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
980 jsstr_t *str = jsstr_empty();
981 RegExpInstance *regexp;
982 HRESULT hres;
984 hres = alloc_regexp(ctx, str, object_prototype, &regexp);
985 jsstr_release(str);
986 if(FAILED(hres))
987 return hres;
989 hres = create_builtin_constructor(ctx, RegExpConstr_value, L"RegExp", &RegExpConstr_info,
990 PROPF_CONSTR|2, &regexp->dispex, ret);
992 jsdisp_release(&regexp->dispex);
993 return hres;
996 HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
998 const WCHAR *p;
999 DWORD flags = 0;
1001 for (p = str; p < str+str_len; p++) {
1002 switch (*p) {
1003 case 'g':
1004 flags |= REG_GLOB;
1005 break;
1006 case 'i':
1007 flags |= REG_FOLD;
1008 break;
1009 case 'm':
1010 flags |= REG_MULTILINE;
1011 break;
1012 case 'y':
1013 flags |= REG_STICKY;
1014 break;
1015 default:
1016 WARN("wrong flag %c\n", *p);
1017 return E_FAIL;
1021 *ret = flags;
1022 return S_OK;