jscript: Remove unused code (Clang).
[wine/multimedia.git] / dlls / jscript / jsregexp.c
blobc39e3a139551d71864af6b770a5041bd31a0a2ba
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_vdisp(vdisp_t *vdisp)
63 return (RegExpInstance*)vdisp->u.jsdisp;
66 static void set_last_index(RegExpInstance *This, DWORD last_index)
68 This->last_index = last_index;
69 jsval_release(This->last_index_val);
70 This->last_index_val = jsval_number(last_index);
73 static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
74 DWORD rem_flags, jsstr_t *jsstr, const WCHAR *str, match_state_t *ret)
76 HRESULT hres;
78 hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
79 str, jsstr_length(jsstr), ret);
80 if(FAILED(hres))
81 return hres;
82 if(hres == S_FALSE) {
83 if(rem_flags & REM_RESET_INDEX)
84 set_last_index(regexp, 0);
85 return S_FALSE;
88 if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != jsstr) {
89 jsstr_release(ctx->last_match);
90 ctx->last_match = jsstr_addref(jsstr);
93 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
94 DWORD i, n = min(sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]), ret->paren_count);
96 for(i=0; i < n; i++) {
97 if(ret->parens[i].index == -1) {
98 ctx->match_parens[i].index = 0;
99 ctx->match_parens[i].length = 0;
100 }else {
101 ctx->match_parens[i].index = ret->parens[i].index;
102 ctx->match_parens[i].length = ret->parens[i].length;
106 if(n < sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]))
107 memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
110 set_last_index(regexp, ret->cp-str);
112 if(!(rem_flags & REM_NO_CTX_UPDATE)) {
113 ctx->last_match_index = ret->cp-str-ret->match_len;
114 ctx->last_match_length = ret->match_len;
117 return S_OK;
120 HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
121 DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret)
123 RegExpInstance *regexp = (RegExpInstance*)dispex;
124 match_state_t *match;
125 heap_pool_t *mark;
126 const WCHAR *str;
127 HRESULT hres;
129 if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
130 if(rem_flags & REM_ALLOC_RESULT)
131 *ret = NULL;
132 return S_FALSE;
135 str = jsstr_flatten(jsstr);
136 if(!str)
137 return E_OUTOFMEMORY;
139 if(rem_flags & REM_ALLOC_RESULT) {
140 match = alloc_match_state(regexp->jsregexp, NULL, str);
141 if(!match)
142 return E_OUTOFMEMORY;
143 *ret = match;
146 mark = heap_pool_mark(&ctx->tmp_heap);
148 if(rem_flags & REM_NO_PARENS) {
149 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
150 if(!match) {
151 heap_pool_clear(mark);
152 return E_OUTOFMEMORY;
154 match->cp = (*ret)->cp;
155 match->match_len = (*ret)->match_len;
156 }else {
157 match = *ret;
160 hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match);
162 if(rem_flags & REM_NO_PARENS) {
163 (*ret)->cp = match->cp;
164 (*ret)->match_len = match->match_len;
167 heap_pool_clear(mark);
169 if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
170 heap_free(match);
171 *ret = NULL;
174 return hres;
177 static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag,
178 match_result_t **match_result, DWORD *result_cnt)
180 RegExpInstance *This = (RegExpInstance*)dispex;
181 match_result_t *ret = NULL;
182 match_state_t *result;
183 DWORD i=0, ret_size = 0;
184 heap_pool_t *mark;
185 const WCHAR *str;
186 HRESULT hres;
188 mark = heap_pool_mark(&ctx->tmp_heap);
190 str = jsstr_flatten(jsstr);
191 if(!str)
192 return E_OUTOFMEMORY;
194 result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str);
195 if(!result) {
196 heap_pool_clear(mark);
197 return E_OUTOFMEMORY;
200 while(1) {
201 hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result);
202 if(hres == S_FALSE) {
203 hres = S_OK;
204 break;
207 if(FAILED(hres))
208 break;
210 if(ret_size == i) {
211 if(ret) {
212 match_result_t *old_ret = ret;
214 ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
215 if(!ret)
216 heap_free(old_ret);
217 }else {
218 ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
220 if(!ret) {
221 hres = E_OUTOFMEMORY;
222 break;
226 ret[i].index = result->cp - str - result->match_len;
227 ret[i++].length = result->match_len;
229 if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
230 hres = S_OK;
231 break;
235 heap_pool_clear(mark);
236 if(FAILED(hres)) {
237 heap_free(ret);
238 return hres;
241 *match_result = ret;
242 *result_cnt = i;
243 return S_OK;
246 static HRESULT RegExp_source(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
247 jsval_t *r)
249 TRACE("\n");
251 switch(flags) {
252 case DISPATCH_PROPERTYGET: {
253 RegExpInstance *This = regexp_from_vdisp(jsthis);
254 *r = jsval_string(jsstr_addref(This->str));
255 break;
257 default:
258 FIXME("Unimplemented flags %x\n", flags);
259 return E_NOTIMPL;
262 return S_OK;
265 static HRESULT RegExp_global(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
266 jsval_t *r)
268 FIXME("\n");
269 return E_NOTIMPL;
272 static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
273 jsval_t *r)
275 FIXME("\n");
276 return E_NOTIMPL;
279 static HRESULT RegExp_multiline(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
280 jsval_t *r)
282 FIXME("\n");
283 return E_NOTIMPL;
286 static INT index_from_val(script_ctx_t *ctx, jsval_t v)
288 double n;
289 HRESULT hres;
291 hres = to_number(ctx, v, &n);
292 if(FAILED(hres)) {
293 clear_ei(ctx); /* FIXME: Move ignoring exceptions to to_primitive */
294 return 0;
297 n = floor(n);
298 return is_int32(n) ? n : 0;
301 static HRESULT RegExp_lastIndex(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
302 jsval_t *r)
304 TRACE("\n");
306 switch(flags) {
307 case DISPATCH_PROPERTYGET: {
308 RegExpInstance *regexp = regexp_from_vdisp(jsthis);
310 return jsval_copy(regexp->last_index_val, r);
312 case DISPATCH_PROPERTYPUT: {
313 RegExpInstance *regexp = regexp_from_vdisp(jsthis);
314 HRESULT hres;
316 hres = jsval_copy(argv[0], &regexp->last_index_val);
317 if(FAILED(hres))
318 return hres;
320 regexp->last_index = index_from_val(ctx, argv[0]);
321 break;
323 default:
324 FIXME("unimplemented flags: %x\n", flags);
325 return E_NOTIMPL;
328 return S_OK;
331 static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
332 jsval_t *r)
334 RegExpInstance *regexp;
335 unsigned len, f;
336 jsstr_t *ret;
337 WCHAR *ptr;
339 TRACE("\n");
341 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
342 FIXME("Not a RegExp\n");
343 return E_NOTIMPL;
346 regexp = regexp_from_vdisp(jsthis);
348 if(!r)
349 return S_OK;
351 len = jsstr_length(regexp->str) + 2;
353 f = regexp->jsregexp->flags;
354 if(f & REG_FOLD)
355 len++;
356 if(f & REG_GLOB)
357 len++;
358 if(f & REG_MULTILINE)
359 len++;
361 ptr = jsstr_alloc_buf(len, &ret);
362 if(!ptr)
363 return E_OUTOFMEMORY;
365 *ptr++ = '/';
366 ptr += jsstr_flush(regexp->str, ptr);
367 *ptr++ = '/';
369 if(f & REG_FOLD)
370 *ptr++ = 'i';
371 if(f & REG_GLOB)
372 *ptr++ = 'g';
373 if(f & REG_MULTILINE)
374 *ptr++ = 'm';
376 *r = jsval_string(ret);
377 return S_OK;
380 static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str,
381 const match_state_t *result, IDispatch **ret)
383 const WCHAR *input;
384 jsdisp_t *array;
385 jsstr_t *str;
386 DWORD i;
387 HRESULT hres = S_OK;
389 static const WCHAR indexW[] = {'i','n','d','e','x',0};
390 static const WCHAR inputW[] = {'i','n','p','u','t',0};
391 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
392 static const WCHAR zeroW[] = {'0',0};
394 input = jsstr_flatten(input_str);
395 if(!input)
396 return E_OUTOFMEMORY;
398 hres = create_array(ctx, result->paren_count+1, &array);
399 if(FAILED(hres))
400 return hres;
402 for(i=0; i < result->paren_count; i++) {
403 if(result->parens[i].index != -1)
404 str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length);
405 else
406 str = jsstr_empty();
407 if(!str) {
408 hres = E_OUTOFMEMORY;
409 break;
412 hres = jsdisp_propput_idx(array, i+1, jsval_string(str));
413 jsstr_release(str);
414 if(FAILED(hres))
415 break;
418 while(SUCCEEDED(hres)) {
419 hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input-result->match_len));
420 if(FAILED(hres))
421 break;
423 hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input));
424 if(FAILED(hres))
425 break;
427 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input_str)));
428 if(FAILED(hres))
429 break;
431 str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
432 if(!str) {
433 hres = E_OUTOFMEMORY;
434 break;
436 hres = jsdisp_propput_name(array, zeroW, jsval_string(str));
437 jsstr_release(str);
438 break;
441 if(FAILED(hres)) {
442 jsdisp_release(array);
443 return hres;
446 *ret = to_disp(array);
447 return S_OK;
450 static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg,
451 jsstr_t **input, match_state_t **result, BOOL *ret)
453 RegExpInstance *regexp;
454 match_state_t *match;
455 DWORD last_index = 0;
456 const WCHAR *string;
457 jsstr_t *jsstr;
458 HRESULT hres;
460 if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
461 FIXME("Not a RegExp\n");
462 return E_NOTIMPL;
465 regexp = regexp_from_vdisp(jsthis);
467 hres = to_flat_string(ctx, arg, &jsstr, &string);
468 if(FAILED(hres))
469 return hres;
471 if(regexp->jsregexp->flags & REG_GLOB) {
472 if(regexp->last_index < 0) {
473 jsstr_release(jsstr);
474 set_last_index(regexp, 0);
475 *ret = FALSE;
476 if(input)
477 *input = jsstr_empty();
478 return S_OK;
481 last_index = regexp->last_index;
484 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string+last_index);
485 if(!match) {
486 jsstr_release(jsstr);
487 return E_OUTOFMEMORY;
490 hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, jsstr, &match);
491 if(FAILED(hres)) {
492 jsstr_release(jsstr);
493 return hres;
496 *result = match;
497 *ret = hres == S_OK;
498 if(input)
499 *input = jsstr;
500 else
501 jsstr_release(jsstr);
502 return S_OK;
505 static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
506 jsval_t *r)
508 match_state_t *match;
509 heap_pool_t *mark;
510 BOOL b;
511 jsstr_t *string;
512 HRESULT hres;
514 TRACE("\n");
516 mark = heap_pool_mark(&ctx->tmp_heap);
518 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
519 if(FAILED(hres)) {
520 heap_pool_clear(mark);
521 return hres;
524 if(r) {
525 if(b) {
526 IDispatch *ret;
528 hres = create_match_array(ctx, string, match, &ret);
529 if(SUCCEEDED(hres))
530 *r = jsval_disp(ret);
531 }else {
532 *r = jsval_null();
536 heap_pool_clear(mark);
537 jsstr_release(string);
538 return hres;
541 static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
542 jsval_t *r)
544 match_state_t *match;
545 jsstr_t *undef_str;
546 heap_pool_t *mark;
547 BOOL b;
548 HRESULT hres;
550 TRACE("\n");
552 mark = heap_pool_mark(&ctx->tmp_heap);
553 hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
554 heap_pool_clear(mark);
555 if(!argc)
556 jsstr_release(undef_str);
557 if(FAILED(hres))
558 return hres;
560 if(r)
561 *r = jsval_bool(b);
562 return S_OK;
565 static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
566 jsval_t *r)
568 TRACE("\n");
570 switch(flags) {
571 case INVOKE_FUNC:
572 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
573 default:
574 FIXME("unimplemented flags %x\n", flags);
575 return E_NOTIMPL;
578 return S_OK;
581 static void RegExp_destructor(jsdisp_t *dispex)
583 RegExpInstance *This = (RegExpInstance*)dispex;
585 if(This->jsregexp)
586 regexp_destroy(This->jsregexp);
587 jsval_release(This->last_index_val);
588 jsstr_release(This->str);
589 heap_free(This);
592 static const builtin_prop_t RegExp_props[] = {
593 {execW, RegExp_exec, PROPF_METHOD|1},
594 {globalW, RegExp_global, 0},
595 {ignoreCaseW, RegExp_ignoreCase, 0},
596 {lastIndexW, RegExp_lastIndex, 0},
597 {multilineW, RegExp_multiline, 0},
598 {sourceW, RegExp_source, 0},
599 {testW, RegExp_test, PROPF_METHOD|1},
600 {toStringW, RegExp_toString, PROPF_METHOD}
603 static const builtin_info_t RegExp_info = {
604 JSCLASS_REGEXP,
605 {NULL, RegExp_value, 0},
606 sizeof(RegExp_props)/sizeof(*RegExp_props),
607 RegExp_props,
608 RegExp_destructor,
609 NULL
612 static const builtin_prop_t RegExpInst_props[] = {
613 {globalW, RegExp_global, 0},
614 {ignoreCaseW, RegExp_ignoreCase, 0},
615 {lastIndexW, RegExp_lastIndex, 0},
616 {multilineW, RegExp_multiline, 0},
617 {sourceW, RegExp_source, 0}
620 static const builtin_info_t RegExpInst_info = {
621 JSCLASS_REGEXP,
622 {NULL, RegExp_value, 0},
623 sizeof(RegExpInst_props)/sizeof(*RegExpInst_props),
624 RegExpInst_props,
625 RegExp_destructor,
626 NULL
629 static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret)
631 RegExpInstance *regexp;
632 HRESULT hres;
634 regexp = heap_alloc_zero(sizeof(RegExpInstance));
635 if(!regexp)
636 return E_OUTOFMEMORY;
638 if(object_prototype)
639 hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
640 else
641 hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
643 if(FAILED(hres)) {
644 heap_free(regexp);
645 return hres;
648 *ret = regexp;
649 return S_OK;
652 HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
654 RegExpInstance *regexp;
655 const WCHAR *str;
656 HRESULT hres;
658 TRACE("%s %x\n", debugstr_jsstr(src), flags);
660 str = jsstr_flatten(src);
661 if(!str)
662 return E_OUTOFMEMORY;
664 hres = alloc_regexp(ctx, NULL, &regexp);
665 if(FAILED(hres))
666 return hres;
668 regexp->str = jsstr_addref(src);
669 regexp->last_index_val = jsval_number(0);
671 regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE);
672 if(!regexp->jsregexp) {
673 WARN("regexp_new failed\n");
674 jsdisp_release(&regexp->dispex);
675 return E_FAIL;
678 *ret = &regexp->dispex;
679 return S_OK;
682 HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
684 unsigned flags, opt_len = 0;
685 const WCHAR *opt = NULL;
686 jsstr_t *src;
687 HRESULT hres;
689 if(is_object_instance(src_arg)) {
690 jsdisp_t *obj;
692 obj = iface_to_jsdisp((IUnknown*)get_object(src_arg));
693 if(obj) {
694 if(is_class(obj, JSCLASS_REGEXP)) {
695 RegExpInstance *regexp = (RegExpInstance*)obj;
697 hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
698 jsdisp_release(obj);
699 return hres;
702 jsdisp_release(obj);
706 if(!is_string(src_arg)) {
707 FIXME("src_arg = %s\n", debugstr_jsval(src_arg));
708 return E_NOTIMPL;
711 src = get_string(src_arg);
713 if(flags_arg) {
714 jsstr_t *opt_str;
716 if(!is_string(*flags_arg)) {
717 FIXME("unimplemented for %s\n", debugstr_jsval(*flags_arg));
718 return E_NOTIMPL;
721 opt_str = get_string(*flags_arg);
722 opt = jsstr_flatten(opt_str);
723 if(!opt)
724 return E_OUTOFMEMORY;
725 opt_len = jsstr_length(opt_str);
728 hres = parse_regexp_flags(opt, opt_len, &flags);
729 if(FAILED(hres))
730 return hres;
732 return create_regexp(ctx, src, flags, ret);
735 HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r)
737 static const WCHAR indexW[] = {'i','n','d','e','x',0};
738 static const WCHAR inputW[] = {'i','n','p','u','t',0};
739 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
741 RegExpInstance *regexp = (RegExpInstance*)re;
742 match_result_t *match_result;
743 unsigned match_cnt, i;
744 const WCHAR *str;
745 jsdisp_t *array;
746 HRESULT hres;
748 str = jsstr_flatten(jsstr);
749 if(!str)
750 return E_OUTOFMEMORY;
752 if(!(regexp->jsregexp->flags & REG_GLOB)) {
753 match_state_t *match;
754 heap_pool_t *mark;
756 mark = heap_pool_mark(&ctx->tmp_heap);
757 match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str);
758 if(!match) {
759 heap_pool_clear(mark);
760 return E_OUTOFMEMORY;
763 hres = regexp_match_next(ctx, &regexp->dispex, 0, jsstr, &match);
764 if(FAILED(hres)) {
765 heap_pool_clear(mark);
766 return hres;
769 if(r) {
770 if(hres == S_OK) {
771 IDispatch *ret;
773 hres = create_match_array(ctx, jsstr, match, &ret);
774 if(SUCCEEDED(hres))
775 *r = jsval_disp(ret);
776 }else {
777 *r = jsval_null();
781 heap_pool_clear(mark);
782 return S_OK;
785 hres = regexp_match(ctx, &regexp->dispex, jsstr, FALSE, &match_result, &match_cnt);
786 if(FAILED(hres))
787 return hres;
789 if(!match_cnt) {
790 TRACE("no match\n");
792 if(r)
793 *r = jsval_null();
794 return S_OK;
797 hres = create_array(ctx, match_cnt, &array);
798 if(FAILED(hres))
799 return hres;
801 for(i=0; i < match_cnt; i++) {
802 jsstr_t *tmp_str;
804 tmp_str = jsstr_substr(jsstr, match_result[i].index, match_result[i].length);
805 if(!tmp_str) {
806 hres = E_OUTOFMEMORY;
807 break;
810 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
811 jsstr_release(tmp_str);
812 if(FAILED(hres))
813 break;
816 while(SUCCEEDED(hres)) {
817 hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index));
818 if(FAILED(hres))
819 break;
821 hres = jsdisp_propput_name(array, lastIndexW,
822 jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
823 if(FAILED(hres))
824 break;
826 hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr));
827 break;
830 heap_free(match_result);
832 if(SUCCEEDED(hres) && r)
833 *r = jsval_obj(array);
834 else
835 jsdisp_release(array);
836 return hres;
839 static HRESULT global_idx(script_ctx_t *ctx, DWORD flags, DWORD idx, jsval_t *r)
841 switch(flags) {
842 case DISPATCH_PROPERTYGET: {
843 jsstr_t *ret;
845 ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
846 if(!ret)
847 return E_OUTOFMEMORY;
849 *r = jsval_string(ret);
850 break;
852 case DISPATCH_PROPERTYPUT:
853 break;
854 default:
855 FIXME("unsupported flags\n");
856 return E_NOTIMPL;
859 return S_OK;
862 static HRESULT RegExpConstr_idx1(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
863 unsigned argc, jsval_t *argv, jsval_t *r)
865 TRACE("\n");
866 return global_idx(ctx, flags, 0, r);
869 static HRESULT RegExpConstr_idx2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
870 unsigned argc, jsval_t *argv, jsval_t *r)
872 TRACE("\n");
873 return global_idx(ctx, flags, 1, r);
876 static HRESULT RegExpConstr_idx3(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
877 unsigned argc, jsval_t *argv, jsval_t *r)
879 TRACE("\n");
880 return global_idx(ctx, flags, 2, r);
883 static HRESULT RegExpConstr_idx4(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
884 unsigned argc, jsval_t *argv, jsval_t *r)
886 TRACE("\n");
887 return global_idx(ctx, flags, 3, r);
890 static HRESULT RegExpConstr_idx5(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
891 unsigned argc, jsval_t *argv, jsval_t *r)
893 TRACE("\n");
894 return global_idx(ctx, flags, 4, r);
897 static HRESULT RegExpConstr_idx6(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
898 unsigned argc, jsval_t *argv, jsval_t *r)
900 TRACE("\n");
901 return global_idx(ctx, flags, 5, r);
904 static HRESULT RegExpConstr_idx7(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
905 unsigned argc, jsval_t *argv, jsval_t *r)
907 TRACE("\n");
908 return global_idx(ctx, flags, 6, r);
911 static HRESULT RegExpConstr_idx8(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
912 unsigned argc, jsval_t *argv, jsval_t *r)
914 TRACE("\n");
915 return global_idx(ctx, flags, 7, r);
918 static HRESULT RegExpConstr_idx9(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
919 unsigned argc, jsval_t *argv, jsval_t *r)
921 TRACE("\n");
922 return global_idx(ctx, flags, 8, r);
925 static HRESULT RegExpConstr_leftContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
926 unsigned argc, jsval_t *argv, jsval_t *r)
928 TRACE("\n");
930 switch(flags) {
931 case DISPATCH_PROPERTYGET: {
932 jsstr_t *ret;
934 ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
935 if(!ret)
936 return E_OUTOFMEMORY;
938 *r = jsval_string(ret);
939 break;
941 case DISPATCH_PROPERTYPUT:
942 break;
943 default:
944 FIXME("unsupported flags\n");
945 return E_NOTIMPL;
948 return S_OK;
951 static HRESULT RegExpConstr_rightContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
952 unsigned argc, jsval_t *argv, jsval_t *r)
954 TRACE("\n");
956 switch(flags) {
957 case DISPATCH_PROPERTYGET: {
958 jsstr_t *ret;
960 ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
961 jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
962 if(!ret)
963 return E_OUTOFMEMORY;
965 *r = jsval_string(ret);
966 break;
968 case DISPATCH_PROPERTYPUT:
969 break;
970 default:
971 FIXME("unsupported flags\n");
972 return E_NOTIMPL;
975 return S_OK;
978 static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
979 jsval_t *r)
981 TRACE("\n");
983 switch(flags) {
984 case DISPATCH_METHOD:
985 if(argc) {
986 if(is_object_instance(argv[0])) {
987 jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
988 if(jsdisp) {
989 if(is_class(jsdisp, JSCLASS_REGEXP)) {
990 if(argc > 1 && !is_undefined(argv[1])) {
991 jsdisp_release(jsdisp);
992 return throw_regexp_error(ctx, JS_E_REGEXP_SYNTAX, NULL);
995 if(r)
996 *r = jsval_obj(jsdisp);
997 else
998 jsdisp_release(jsdisp);
999 return S_OK;
1001 jsdisp_release(jsdisp);
1005 /* fall through */
1006 case DISPATCH_CONSTRUCT: {
1007 jsdisp_t *ret;
1008 HRESULT hres;
1010 if(!argc) {
1011 FIXME("no args\n");
1012 return E_NOTIMPL;
1015 hres = create_regexp_var(ctx, argv[0], argc > 1 ? argv+1 : NULL, &ret);
1016 if(FAILED(hres))
1017 return hres;
1019 if(r)
1020 *r = jsval_obj(ret);
1021 else
1022 jsdisp_release(ret);
1023 return S_OK;
1025 default:
1026 FIXME("unimplemented flags: %x\n", flags);
1027 return E_NOTIMPL;
1030 return S_OK;
1033 static const builtin_prop_t RegExpConstr_props[] = {
1034 {idx1W, RegExpConstr_idx1, 0},
1035 {idx2W, RegExpConstr_idx2, 0},
1036 {idx3W, RegExpConstr_idx3, 0},
1037 {idx4W, RegExpConstr_idx4, 0},
1038 {idx5W, RegExpConstr_idx5, 0},
1039 {idx6W, RegExpConstr_idx6, 0},
1040 {idx7W, RegExpConstr_idx7, 0},
1041 {idx8W, RegExpConstr_idx8, 0},
1042 {idx9W, RegExpConstr_idx9, 0},
1043 {leftContextW, RegExpConstr_leftContext, 0},
1044 {rightContextW, RegExpConstr_rightContext, 0}
1047 static const builtin_info_t RegExpConstr_info = {
1048 JSCLASS_FUNCTION,
1049 {NULL, Function_value, 0},
1050 sizeof(RegExpConstr_props)/sizeof(*RegExpConstr_props),
1051 RegExpConstr_props,
1052 NULL,
1053 NULL
1056 HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1058 RegExpInstance *regexp;
1059 HRESULT hres;
1061 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
1063 hres = alloc_regexp(ctx, object_prototype, &regexp);
1064 if(FAILED(hres))
1065 return hres;
1067 hres = create_builtin_constructor(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info,
1068 PROPF_CONSTR|2, &regexp->dispex, ret);
1070 jsdisp_release(&regexp->dispex);
1071 return hres;
1074 HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
1076 const WCHAR *p;
1077 DWORD flags = 0;
1079 for (p = str; p < str+str_len; p++) {
1080 switch (*p) {
1081 case 'g':
1082 flags |= REG_GLOB;
1083 break;
1084 case 'i':
1085 flags |= REG_FOLD;
1086 break;
1087 case 'm':
1088 flags |= REG_MULTILINE;
1089 break;
1090 case 'y':
1091 flags |= REG_STICKY;
1092 break;
1093 default:
1094 WARN("wrong flag %c\n", *p);
1095 return E_FAIL;
1099 *ret = flags;
1100 return S_OK;