[TASKMGR] Process page: Allow using "Open File Location" functionality without runnin...
[reactos.git] / dll / win32 / vbscript / interp.c
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 static DISPID propput_dispid = DISPID_PROPERTYPUT;
28
29 typedef struct {
30 vbscode_t *code;
31 instr_t *instr;
32 script_ctx_t *script;
33 function_t *func;
34 IDispatch *this_obj;
35 vbdisp_t *vbthis;
36
37 VARIANT *args;
38 VARIANT *vars;
39 SAFEARRAY **arrays;
40
41 dynamic_var_t *dynamic_vars;
42 heap_pool_t heap;
43
44 BOOL resume_next;
45
46 unsigned stack_size;
47 unsigned top;
48 VARIANT *stack;
49
50 VARIANT ret_val;
51 } exec_ctx_t;
52
53 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
54
55 typedef enum {
56 REF_NONE,
57 REF_DISP,
58 REF_VAR,
59 REF_OBJ,
60 REF_CONST,
61 REF_FUNC
62 } ref_type_t;
63
64 typedef struct {
65 ref_type_t type;
66 union {
67 struct {
68 IDispatch *disp;
69 DISPID id;
70 } d;
71 VARIANT *v;
72 function_t *f;
73 IDispatch *obj;
74 } u;
75 } ref_t;
76
77 typedef struct {
78 VARIANT *v;
79 VARIANT store;
80 BOOL owned;
81 } variant_val_t;
82
83 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
84 {
85 while(var) {
86 if(!wcsicmp(var->name, name)) {
87 ref->type = var->is_const ? REF_CONST : REF_VAR;
88 ref->u.v = &var->v;
89 return TRUE;
90 }
91
92 var = var->next;
93 }
94
95 return FALSE;
96 }
97
98 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
99 {
100 named_item_t *item;
101 function_t *func;
102 IDispatch *disp;
103 unsigned i;
104 DISPID id;
105 HRESULT hres;
106
107 if(invoke_type == VBDISP_LET
108 && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
109 && !wcsicmp(name, ctx->func->name)) {
110 ref->type = REF_VAR;
111 ref->u.v = &ctx->ret_val;
112 return S_OK;
113 }
114
115 for(i=0; i < ctx->func->var_cnt; i++) {
116 if(!wcsicmp(ctx->func->vars[i].name, name)) {
117 ref->type = REF_VAR;
118 ref->u.v = ctx->vars+i;
119 return TRUE;
120 }
121 }
122
123 for(i=0; i < ctx->func->arg_cnt; i++) {
124 if(!wcsicmp(ctx->func->args[i].name, name)) {
125 ref->type = REF_VAR;
126 ref->u.v = ctx->args+i;
127 return S_OK;
128 }
129 }
130
131 if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
132 return S_OK;
133
134 if(ctx->func->type != FUNC_GLOBAL) {
135 if(ctx->vbthis) {
136 /* FIXME: Bind such identifier while generating bytecode. */
137 for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) {
138 if(!wcsicmp(ctx->vbthis->desc->props[i].name, name)) {
139 ref->type = REF_VAR;
140 ref->u.v = ctx->vbthis->props+i;
141 return S_OK;
142 }
143 }
144 }
145
146 hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
147 if(SUCCEEDED(hres)) {
148 ref->type = REF_DISP;
149 ref->u.d.disp = ctx->this_obj;
150 ref->u.d.id = id;
151 return S_OK;
152 }
153 }
154
155 if(ctx->func->code_ctx->context) {
156 hres = disp_get_id(ctx->func->code_ctx->context, name, invoke_type, TRUE, &id);
157 if(SUCCEEDED(hres)) {
158 ref->type = REF_DISP;
159 ref->u.d.disp = ctx->func->code_ctx->context;
160 ref->u.d.id = id;
161 return S_OK;
162 }
163 }
164
165 if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
166 return S_OK;
167
168 for(func = ctx->script->global_funcs; func; func = func->next) {
169 if(!wcsicmp(func->name, name)) {
170 ref->type = REF_FUNC;
171 ref->u.f = func;
172 return S_OK;
173 }
174 }
175
176 hres = get_builtin_id(ctx->script->global_obj, name, &id);
177 if(SUCCEEDED(hres)) {
178 ref->type = REF_DISP;
179 ref->u.d.disp = &ctx->script->global_obj->IDispatch_iface;
180 ref->u.d.id = id;
181 return S_OK;
182 }
183
184 disp = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE);
185 if(disp) {
186 ref->type = REF_OBJ;
187 ref->u.obj = disp;
188 return S_OK;
189 }
190
191 LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
192 if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
193 hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
194 if(SUCCEEDED(hres)) {
195 ref->type = REF_DISP;
196 ref->u.d.disp = item->disp;
197 ref->u.d.id = id;
198 return S_OK;
199 }
200 }
201 }
202
203 ref->type = REF_NONE;
204 return S_OK;
205 }
206
207 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name,
208 BOOL is_const, VARIANT **out_var)
209 {
210 dynamic_var_t *new_var;
211 heap_pool_t *heap;
212 WCHAR *str;
213 unsigned size;
214
215 heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
216
217 new_var = heap_pool_alloc(heap, sizeof(*new_var));
218 if(!new_var)
219 return E_OUTOFMEMORY;
220
221 size = (lstrlenW(name)+1)*sizeof(WCHAR);
222 str = heap_pool_alloc(heap, size);
223 if(!str)
224 return E_OUTOFMEMORY;
225 memcpy(str, name, size);
226 new_var->name = str;
227 new_var->is_const = is_const;
228 V_VT(&new_var->v) = VT_EMPTY;
229
230 if(ctx->func->type == FUNC_GLOBAL) {
231 new_var->next = ctx->script->global_vars;
232 ctx->script->global_vars = new_var;
233 }else {
234 new_var->next = ctx->dynamic_vars;
235 ctx->dynamic_vars = new_var;
236 }
237
238 *out_var = &new_var->v;
239 return S_OK;
240 }
241
242 void clear_ei(EXCEPINFO *ei)
243 {
244 SysFreeString(ei->bstrSource);
245 SysFreeString(ei->bstrDescription);
246 SysFreeString(ei->bstrHelpFile);
247 memset(ei, 0, sizeof(*ei));
248 }
249
250 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
251 {
252 assert(ctx->top);
253 return ctx->stack + --ctx->top;
254 }
255
256 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n)
257 {
258 assert(ctx->top >= n);
259 return ctx->stack + (ctx->top-n-1);
260 }
261
262 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
263 {
264 if(ctx->stack_size == ctx->top) {
265 VARIANT *new_stack;
266
267 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack));
268 if(!new_stack) {
269 VariantClear(v);
270 return E_OUTOFMEMORY;
271 }
272
273 ctx->stack = new_stack;
274 ctx->stack_size *= 2;
275 }
276
277 ctx->stack[ctx->top++] = *v;
278 return S_OK;
279 }
280
281 static inline HRESULT stack_push_null(exec_ctx_t *ctx)
282 {
283 VARIANT v;
284 V_VT(&v) = VT_NULL;
285 return stack_push(ctx, &v);
286 }
287
288 static void stack_popn(exec_ctx_t *ctx, unsigned n)
289 {
290 while(n--)
291 VariantClear(stack_pop(ctx));
292 }
293
294 static void stack_pop_deref(exec_ctx_t *ctx, variant_val_t *r)
295 {
296 VARIANT *v;
297
298 v = stack_pop(ctx);
299 if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
300 r->owned = FALSE;
301 r->v = V_VARIANTREF(v);
302 }else {
303 r->owned = TRUE;
304 r->v = v;
305 }
306 }
307
308 static inline void release_val(variant_val_t *v)
309 {
310 if(v->owned)
311 VariantClear(v->v);
312 }
313
314 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *r)
315 {
316 stack_pop_deref(ctx, r);
317
318 if(V_VT(r->v) == VT_DISPATCH) {
319 HRESULT hres;
320
321 hres = get_disp_value(ctx->script, V_DISPATCH(r->v), &r->store);
322 if(r->owned && V_DISPATCH(r->v))
323 IDispatch_Release(V_DISPATCH(r->v));
324 if(FAILED(hres))
325 return hres;
326
327 r->owned = TRUE;
328 r->v = &r->store;
329 }
330
331 return S_OK;
332 }
333
334 static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n)
335 {
336 VARIANT *v = stack_top(ctx, n);
337 HRESULT hres;
338
339 if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
340 VARIANT *ref = V_VARIANTREF(v);
341
342 V_VT(v) = VT_EMPTY;
343 hres = VariantCopy(v, ref);
344 if(FAILED(hres))
345 return hres;
346 }
347
348 if(V_VT(v) == VT_DISPATCH) {
349 IDispatch *disp;
350
351 disp = V_DISPATCH(v);
352 hres = get_disp_value(ctx->script, disp, v);
353 if(disp)
354 IDispatch_Release(disp);
355 if(FAILED(hres))
356 return hres;
357 }
358
359 return S_OK;
360 }
361
362 static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b)
363 {
364 variant_val_t val;
365 HRESULT hres;
366
367 hres = stack_pop_val(ctx, &val);
368 if(FAILED(hres))
369 return hres;
370
371 switch (V_VT(val.v))
372 {
373 case VT_BOOL:
374 *b = V_BOOL(val.v);
375 break;
376 case VT_NULL:
377 *b = FALSE;
378 break;
379 case VT_I2:
380 *b = V_I2(val.v);
381 break;
382 case VT_I4:
383 *b = V_I4(val.v);
384 break;
385 default:
386 FIXME("unsupported for %s\n", debugstr_variant(val.v));
387 release_val(&val);
388 return E_NOTIMPL;
389 }
390 return S_OK;
391 }
392
393 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
394 {
395 VARIANT *v = stack_pop(ctx);
396
397 if(V_VT(v) == VT_DISPATCH) {
398 *ret = V_DISPATCH(v);
399 return S_OK;
400 }
401
402 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
403 FIXME("not supported type: %s\n", debugstr_variant(v));
404 VariantClear(v);
405 return E_FAIL;
406 }
407
408 v = V_BYREF(v);
409 if(V_VT(v) != VT_DISPATCH) {
410 FIXME("not disp %s\n", debugstr_variant(v));
411 return E_FAIL;
412 }
413
414 if(V_DISPATCH(v))
415 IDispatch_AddRef(V_DISPATCH(v));
416 *ret = V_DISPATCH(v);
417 return S_OK;
418 }
419
420 static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp)
421 {
422 VARIANT *v = stack_top(ctx, n), *ref;
423
424 if(V_VT(v) != VT_DISPATCH) {
425 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
426 FIXME("not supported type: %s\n", debugstr_variant(v));
427 return E_FAIL;
428 }
429
430 ref = V_VARIANTREF(v);
431 if(V_VT(ref) != VT_DISPATCH) {
432 FIXME("not disp %s\n", debugstr_variant(ref));
433 return E_FAIL;
434 }
435
436 V_VT(v) = VT_DISPATCH;
437 V_DISPATCH(v) = V_DISPATCH(ref);
438 if(V_DISPATCH(v))
439 IDispatch_AddRef(V_DISPATCH(v));
440 }
441
442 if(disp)
443 *disp = V_DISPATCH(v);
444 return S_OK;
445 }
446
447 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
448 {
449 ctx->instr = ctx->code->instrs + addr;
450 }
451
452 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp)
453 {
454 dp->cNamedArgs = is_propput ? 1 : 0;
455 dp->cArgs = arg_cnt + dp->cNamedArgs;
456 dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
457
458 if(arg_cnt) {
459 VARIANT tmp;
460 unsigned i;
461
462 assert(ctx->top >= arg_cnt);
463
464 for(i=1; i*2 <= arg_cnt; i++) {
465 tmp = ctx->stack[ctx->top-i];
466 ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
467 ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
468 }
469
470 dp->rgvarg = ctx->stack + ctx->top-dp->cArgs;
471 }else {
472 dp->rgvarg = is_propput ? ctx->stack+ctx->top-1 : NULL;
473 }
474 }
475
476 static HRESULT array_access(exec_ctx_t *ctx, SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret)
477 {
478 unsigned i, argc = arg_cnt(dp);
479 LONG *indices;
480 HRESULT hres;
481
482 if(!array) {
483 FIXME("NULL array\n");
484 return E_FAIL;
485 }
486
487 hres = SafeArrayLock(array);
488 if(FAILED(hres))
489 return hres;
490
491 if(array->cDims != argc) {
492 FIXME("argc %d does not match cDims %d\n", dp->cArgs, array->cDims);
493 SafeArrayUnlock(array);
494 return E_FAIL;
495 }
496
497 indices = heap_alloc(sizeof(*indices) * argc);
498 if(!indices) {
499 SafeArrayUnlock(array);
500 return E_OUTOFMEMORY;
501 }
502
503 for(i=0; i<argc; i++) {
504 hres = to_int(get_arg(dp, i), indices+i);
505 if(FAILED(hres)) {
506 heap_free(indices);
507 SafeArrayUnlock(array);
508 return hres;
509 }
510 }
511
512 hres = SafeArrayPtrOfIndex(array, indices, (void**)ret);
513 SafeArrayUnlock(array);
514 heap_free(indices);
515 return hres;
516 }
517
518 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
519 {
520 BSTR identifier = ctx->instr->arg1.bstr;
521 const unsigned arg_cnt = ctx->instr->arg2.uint;
522 DISPPARAMS dp;
523 ref_t ref;
524 HRESULT hres;
525
526 hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
527 if(FAILED(hres))
528 return hres;
529
530 switch(ref.type) {
531 case REF_VAR:
532 case REF_CONST: {
533 VARIANT *v;
534
535 if(!res) {
536 FIXME("REF_VAR no res\n");
537 return E_NOTIMPL;
538 }
539
540 v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
541
542 if(arg_cnt) {
543 SAFEARRAY *array = NULL;
544
545 switch(V_VT(v)) {
546 case VT_ARRAY|VT_BYREF|VT_VARIANT:
547 array = *V_ARRAYREF(ref.u.v);
548 break;
549 case VT_ARRAY|VT_VARIANT:
550 array = V_ARRAY(ref.u.v);
551 break;
552 case VT_DISPATCH:
553 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
554 hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res);
555 if(FAILED(hres))
556 return hres;
557 break;
558 default:
559 FIXME("arguments not implemented\n");
560 return E_NOTIMPL;
561 }
562
563 if(!array)
564 break;
565
566 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
567 hres = array_access(ctx, array, &dp, &v);
568 if(FAILED(hres))
569 return hres;
570 }
571
572 V_VT(res) = VT_BYREF|VT_VARIANT;
573 V_BYREF(res) = v;
574 break;
575 }
576 case REF_DISP:
577 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
578 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
579 if(FAILED(hres))
580 return hres;
581 break;
582 case REF_FUNC:
583 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
584 hres = exec_script(ctx->script, FALSE, ref.u.f, NULL, &dp, res);
585 if(FAILED(hres))
586 return hres;
587 break;
588 case REF_OBJ:
589 if(arg_cnt) {
590 FIXME("arguments on object\n");
591 return E_NOTIMPL;
592 }
593
594 if(res) {
595 IDispatch_AddRef(ref.u.obj);
596 V_VT(res) = VT_DISPATCH;
597 V_DISPATCH(res) = ref.u.obj;
598 }
599 break;
600 case REF_NONE:
601 if(res && !ctx->func->code_ctx->option_explicit && arg_cnt == 0) {
602 VARIANT *new;
603 hres = add_dynamic_var(ctx, identifier, FALSE, &new);
604 if(FAILED(hres))
605 return hres;
606 V_VT(res) = VT_BYREF|VT_VARIANT;
607 V_BYREF(res) = new;
608 break;
609 }
610 FIXME("%s not found\n", debugstr_w(identifier));
611 return DISP_E_UNKNOWNNAME;
612 }
613
614 stack_popn(ctx, arg_cnt);
615 return S_OK;
616 }
617
618 static HRESULT interp_icall(exec_ctx_t *ctx)
619 {
620 VARIANT v;
621 HRESULT hres;
622
623 TRACE("\n");
624
625 hres = do_icall(ctx, &v);
626 if(FAILED(hres))
627 return hres;
628
629 return stack_push(ctx, &v);
630 }
631
632 static HRESULT interp_icallv(exec_ctx_t *ctx)
633 {
634 TRACE("\n");
635 return do_icall(ctx, NULL);
636 }
637
638 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
639 {
640 const BSTR identifier = ctx->instr->arg1.bstr;
641 const unsigned arg_cnt = ctx->instr->arg2.uint;
642 IDispatch *obj;
643 DISPPARAMS dp;
644 DISPID id;
645 HRESULT hres;
646
647 hres = stack_pop_disp(ctx, &obj);
648 if(FAILED(hres))
649 return hres;
650
651 if(!obj) {
652 FIXME("NULL obj\n");
653 return E_FAIL;
654 }
655
656 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
657
658 hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
659 if(SUCCEEDED(hres))
660 hres = disp_call(ctx->script, obj, id, &dp, res);
661 IDispatch_Release(obj);
662 if(FAILED(hres))
663 return hres;
664
665 stack_popn(ctx, arg_cnt);
666 return S_OK;
667 }
668
669 static HRESULT interp_mcall(exec_ctx_t *ctx)
670 {
671 VARIANT res;
672 HRESULT hres;
673
674 TRACE("\n");
675
676 hres = do_mcall(ctx, &res);
677 if(FAILED(hres))
678 return hres;
679
680 return stack_push(ctx, &res);
681 }
682
683 static HRESULT interp_mcallv(exec_ctx_t *ctx)
684 {
685 TRACE("\n");
686
687 return do_mcall(ctx, NULL);
688 }
689
690 static HRESULT assign_value(exec_ctx_t *ctx, VARIANT *dst, VARIANT *src, WORD flags)
691 {
692 VARIANT value;
693 HRESULT hres;
694
695 V_VT(&value) = VT_EMPTY;
696 hres = VariantCopyInd(&value, src);
697 if(FAILED(hres))
698 return hres;
699
700 if(V_VT(&value) == VT_DISPATCH && !(flags & DISPATCH_PROPERTYPUTREF)) {
701 IDispatch *disp = V_DISPATCH(&value);
702
703 V_VT(&value) = VT_EMPTY;
704 hres = get_disp_value(ctx->script, disp, &value);
705 if(disp)
706 IDispatch_Release(disp);
707 if(FAILED(hres))
708 return hres;
709 }
710
711 VariantClear(dst);
712 *dst = value;
713 return S_OK;
714 }
715
716 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS *dp)
717 {
718 ref_t ref;
719 HRESULT hres;
720
721 hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
722 if(FAILED(hres))
723 return hres;
724
725 switch(ref.type) {
726 case REF_VAR: {
727 VARIANT *v = ref.u.v;
728
729 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
730 v = V_VARIANTREF(v);
731
732 if(arg_cnt(dp)) {
733 SAFEARRAY *array;
734
735 if(!(V_VT(v) & VT_ARRAY)) {
736 FIXME("array assign on type %d\n", V_VT(v));
737 return E_FAIL;
738 }
739
740 switch(V_VT(v)) {
741 case VT_ARRAY|VT_BYREF|VT_VARIANT:
742 array = *V_ARRAYREF(v);
743 break;
744 case VT_ARRAY|VT_VARIANT:
745 array = V_ARRAY(v);
746 break;
747 default:
748 FIXME("Unsupported array type %x\n", V_VT(v));
749 return E_NOTIMPL;
750 }
751
752 if(!array) {
753 FIXME("null array\n");
754 return E_FAIL;
755 }
756
757 hres = array_access(ctx, array, dp, &v);
758 if(FAILED(hres))
759 return hres;
760 }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) {
761 FIXME("non-array assign\n");
762 return E_NOTIMPL;
763 }
764
765 hres = assign_value(ctx, v, dp->rgvarg, flags);
766 break;
767 }
768 case REF_DISP:
769 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, flags, dp);
770 break;
771 case REF_FUNC:
772 FIXME("functions not implemented\n");
773 return E_NOTIMPL;
774 case REF_OBJ:
775 FIXME("REF_OBJ\n");
776 return E_NOTIMPL;
777 case REF_CONST:
778 FIXME("REF_CONST\n");
779 return E_NOTIMPL;
780 case REF_NONE:
781 if(ctx->func->code_ctx->option_explicit) {
782 FIXME("throw exception\n");
783 hres = E_FAIL;
784 }else {
785 VARIANT *new_var;
786
787 if(arg_cnt(dp)) {
788 FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
789 return E_NOTIMPL;
790 }
791
792 TRACE("creating variable %s\n", debugstr_w(name));
793 hres = add_dynamic_var(ctx, name, FALSE, &new_var);
794 if(SUCCEEDED(hres))
795 hres = assign_value(ctx, new_var, dp->rgvarg, flags);
796 }
797 }
798
799 return hres;
800 }
801
802 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
803 {
804 const BSTR arg = ctx->instr->arg1.bstr;
805 const unsigned arg_cnt = ctx->instr->arg2.uint;
806 DISPPARAMS dp;
807 HRESULT hres;
808
809 TRACE("%s\n", debugstr_w(arg));
810
811 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
812 hres = assign_ident(ctx, arg, DISPATCH_PROPERTYPUT, &dp);
813 if(FAILED(hres))
814 return hres;
815
816 stack_popn(ctx, arg_cnt+1);
817 return S_OK;
818 }
819
820 static HRESULT interp_set_ident(exec_ctx_t *ctx)
821 {
822 const BSTR arg = ctx->instr->arg1.bstr;
823 const unsigned arg_cnt = ctx->instr->arg2.uint;
824 DISPPARAMS dp;
825 HRESULT hres;
826
827 TRACE("%s\n", debugstr_w(arg));
828
829 if(arg_cnt) {
830 FIXME("arguments not supported\n");
831 return E_NOTIMPL;
832 }
833
834 hres = stack_assume_disp(ctx, 0, NULL);
835 if(FAILED(hres))
836 return hres;
837
838 vbstack_to_dp(ctx, 0, TRUE, &dp);
839 hres = assign_ident(ctx, ctx->instr->arg1.bstr, DISPATCH_PROPERTYPUTREF, &dp);
840 if(FAILED(hres))
841 return hres;
842
843 stack_popn(ctx, 1);
844 return S_OK;
845 }
846
847 static HRESULT interp_assign_member(exec_ctx_t *ctx)
848 {
849 BSTR identifier = ctx->instr->arg1.bstr;
850 const unsigned arg_cnt = ctx->instr->arg2.uint;
851 IDispatch *obj;
852 DISPPARAMS dp;
853 DISPID id;
854 HRESULT hres;
855
856 TRACE("%s\n", debugstr_w(identifier));
857
858 hres = stack_assume_disp(ctx, arg_cnt+1, &obj);
859 if(FAILED(hres))
860 return hres;
861
862 if(!obj) {
863 FIXME("NULL obj\n");
864 return E_FAIL;
865 }
866
867 hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
868 if(SUCCEEDED(hres)) {
869 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
870 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUT, &dp);
871 }
872 if(FAILED(hres))
873 return hres;
874
875 stack_popn(ctx, arg_cnt+2);
876 return S_OK;
877 }
878
879 static HRESULT interp_set_member(exec_ctx_t *ctx)
880 {
881 BSTR identifier = ctx->instr->arg1.bstr;
882 const unsigned arg_cnt = ctx->instr->arg2.uint;
883 IDispatch *obj;
884 DISPPARAMS dp;
885 DISPID id;
886 HRESULT hres;
887
888 TRACE("%s\n", debugstr_w(identifier));
889
890 if(arg_cnt) {
891 FIXME("arguments not supported\n");
892 return E_NOTIMPL;
893 }
894
895 hres = stack_assume_disp(ctx, 1, &obj);
896 if(FAILED(hres))
897 return hres;
898
899 if(!obj) {
900 FIXME("NULL obj\n");
901 return E_FAIL;
902 }
903
904 hres = stack_assume_disp(ctx, 0, NULL);
905 if(FAILED(hres))
906 return hres;
907
908 hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
909 if(SUCCEEDED(hres)) {
910 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
911 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUTREF, &dp);
912 }
913 if(FAILED(hres))
914 return hres;
915
916 stack_popn(ctx, 2);
917 return S_OK;
918 }
919
920 static HRESULT interp_const(exec_ctx_t *ctx)
921 {
922 BSTR arg = ctx->instr->arg1.bstr;
923 VARIANT *v;
924 ref_t ref;
925 HRESULT hres;
926
927 TRACE("%s\n", debugstr_w(arg));
928
929 assert(ctx->func->type == FUNC_GLOBAL);
930
931 hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
932 if(FAILED(hres))
933 return hres;
934
935 if(ref.type != REF_NONE) {
936 FIXME("%s already defined\n", debugstr_w(arg));
937 return E_FAIL;
938 }
939
940 hres = stack_assume_val(ctx, 0);
941 if(FAILED(hres))
942 return hres;
943
944 hres = add_dynamic_var(ctx, arg, TRUE, &v);
945 if(FAILED(hres))
946 return hres;
947
948 *v = *stack_pop(ctx);
949 return S_OK;
950 }
951
952 static HRESULT interp_val(exec_ctx_t *ctx)
953 {
954 variant_val_t val;
955 VARIANT v;
956 HRESULT hres;
957
958 TRACE("\n");
959
960 hres = stack_pop_val(ctx, &val);
961 if(FAILED(hres))
962 return hres;
963
964 if(!val.owned) {
965 V_VT(&v) = VT_EMPTY;
966 hres = VariantCopy(&v, val.v);
967 if(FAILED(hres))
968 return hres;
969 }
970
971 return stack_push(ctx, val.owned ? val.v : &v);
972 }
973
974 static HRESULT interp_pop(exec_ctx_t *ctx)
975 {
976 const unsigned n = ctx->instr->arg1.uint;
977
978 TRACE("%u\n", n);
979
980 stack_popn(ctx, n);
981 return S_OK;
982 }
983
984 static HRESULT interp_new(exec_ctx_t *ctx)
985 {
986 const WCHAR *arg = ctx->instr->arg1.bstr;
987 class_desc_t *class_desc;
988 vbdisp_t *obj;
989 VARIANT v;
990 HRESULT hres;
991
992 static const WCHAR regexpW[] = {'r','e','g','e','x','p',0};
993
994 TRACE("%s\n", debugstr_w(arg));
995
996 if(!wcsicmp(arg, regexpW)) {
997 V_VT(&v) = VT_DISPATCH;
998 hres = create_regexp(&V_DISPATCH(&v));
999 if(FAILED(hres))
1000 return hres;
1001
1002 return stack_push(ctx, &v);
1003 }
1004
1005 for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
1006 if(!wcsicmp(class_desc->name, arg))
1007 break;
1008 }
1009 if(!class_desc) {
1010 FIXME("Class %s not found\n", debugstr_w(arg));
1011 return E_FAIL;
1012 }
1013
1014 hres = create_vbdisp(class_desc, &obj);
1015 if(FAILED(hres))
1016 return hres;
1017
1018 V_VT(&v) = VT_DISPATCH;
1019 V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
1020 return stack_push(ctx, &v);
1021 }
1022
1023 static HRESULT interp_dim(exec_ctx_t *ctx)
1024 {
1025 const BSTR ident = ctx->instr->arg1.bstr;
1026 const unsigned array_id = ctx->instr->arg2.uint;
1027 const array_desc_t *array_desc;
1028 ref_t ref;
1029 HRESULT hres;
1030
1031 TRACE("%s\n", debugstr_w(ident));
1032
1033 assert(array_id < ctx->func->array_cnt);
1034 if(!ctx->arrays) {
1035 ctx->arrays = heap_alloc_zero(ctx->func->array_cnt * sizeof(SAFEARRAY*));
1036 if(!ctx->arrays)
1037 return E_OUTOFMEMORY;
1038 }
1039
1040 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1041 if(FAILED(hres)) {
1042 FIXME("lookup %s failed: %08x\n", debugstr_w(ident), hres);
1043 return hres;
1044 }
1045
1046 if(ref.type != REF_VAR) {
1047 FIXME("got ref.type = %d\n", ref.type);
1048 return E_FAIL;
1049 }
1050
1051 if(ctx->arrays[array_id]) {
1052 FIXME("Array already initialized\n");
1053 return E_FAIL;
1054 }
1055
1056 array_desc = ctx->func->array_descs + array_id;
1057 if(array_desc->dim_cnt) {
1058 ctx->arrays[array_id] = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds);
1059 if(!ctx->arrays[array_id])
1060 return E_OUTOFMEMORY;
1061 }
1062
1063 V_VT(ref.u.v) = VT_ARRAY|VT_BYREF|VT_VARIANT;
1064 V_ARRAYREF(ref.u.v) = ctx->arrays+array_id;
1065 return S_OK;
1066 }
1067
1068 static HRESULT interp_step(exec_ctx_t *ctx)
1069 {
1070 const BSTR ident = ctx->instr->arg2.bstr;
1071 BOOL gteq_zero;
1072 VARIANT zero;
1073 ref_t ref;
1074 HRESULT hres;
1075
1076 TRACE("%s\n", debugstr_w(ident));
1077
1078 V_VT(&zero) = VT_I2;
1079 V_I2(&zero) = 0;
1080 hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
1081 if(FAILED(hres))
1082 return hres;
1083
1084 gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
1085
1086 hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
1087 if(FAILED(hres))
1088 return hres;
1089
1090 if(ref.type != REF_VAR) {
1091 FIXME("%s is not REF_VAR\n", debugstr_w(ident));
1092 return E_FAIL;
1093 }
1094
1095 hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
1096 if(FAILED(hres))
1097 return hres;
1098
1099 if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) {
1100 ctx->instr++;
1101 }else {
1102 stack_popn(ctx, 2);
1103 instr_jmp(ctx, ctx->instr->arg1.uint);
1104 }
1105 return S_OK;
1106 }
1107
1108 static HRESULT interp_newenum(exec_ctx_t *ctx)
1109 {
1110 variant_val_t v;
1111 VARIANT *r;
1112 HRESULT hres;
1113
1114 TRACE("\n");
1115
1116 stack_pop_deref(ctx, &v);
1117 assert(V_VT(stack_top(ctx, 0)) == VT_EMPTY);
1118 r = stack_top(ctx, 0);
1119
1120 switch(V_VT(v.v)) {
1121 case VT_DISPATCH|VT_BYREF:
1122 case VT_DISPATCH: {
1123 IEnumVARIANT *iter;
1124 DISPPARAMS dp = {0};
1125 VARIANT iterv;
1126
1127 hres = disp_call(ctx->script, V_ISBYREF(v.v) ? *V_DISPATCHREF(v.v) : V_DISPATCH(v.v), DISPID_NEWENUM, &dp, &iterv);
1128 release_val(&v);
1129 if(FAILED(hres))
1130 return hres;
1131
1132 if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) {
1133 FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv));
1134 VariantClear(&iterv);
1135 return hres;
1136 }
1137
1138 hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter);
1139 IUnknown_Release(V_UNKNOWN(&iterv));
1140 if(FAILED(hres)) {
1141 FIXME("Could not get IEnumVARIANT iface: %08x\n", hres);
1142 return hres;
1143 }
1144
1145 V_VT(r) = VT_UNKNOWN;
1146 V_UNKNOWN(r) = (IUnknown*)iter;
1147 break;
1148 }
1149 case VT_VARIANT|VT_ARRAY:
1150 case VT_VARIANT|VT_ARRAY|VT_BYREF: {
1151 IEnumVARIANT *iter;
1152
1153 hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), &iter);
1154 if(FAILED(hres))
1155 return hres;
1156
1157 V_VT(r) = VT_UNKNOWN;
1158 V_UNKNOWN(r) = (IUnknown*)iter;
1159 break;
1160 }
1161 default:
1162 FIXME("Unsupported for %s\n", debugstr_variant(v.v));
1163 release_val(&v);
1164 return E_NOTIMPL;
1165 }
1166
1167 return S_OK;
1168 }
1169
1170 static HRESULT interp_enumnext(exec_ctx_t *ctx)
1171 {
1172 const unsigned loop_end = ctx->instr->arg1.uint;
1173 const BSTR ident = ctx->instr->arg2.bstr;
1174 VARIANT v;
1175 DISPPARAMS dp = {&v, &propput_dispid, 1, 1};
1176 IEnumVARIANT *iter;
1177 BOOL do_continue;
1178 HRESULT hres;
1179
1180 TRACE("\n");
1181
1182 if(V_VT(stack_top(ctx, 0)) == VT_EMPTY) {
1183 FIXME("uninitialized\n");
1184 return E_FAIL;
1185 }
1186
1187 assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN);
1188 iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0));
1189
1190 V_VT(&v) = VT_EMPTY;
1191 hres = IEnumVARIANT_Next(iter, 1, &v, NULL);
1192 if(FAILED(hres))
1193 return hres;
1194
1195 do_continue = hres == S_OK;
1196 hres = assign_ident(ctx, ident, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &dp);
1197 VariantClear(&v);
1198 if(FAILED(hres))
1199 return hres;
1200
1201 if(do_continue) {
1202 ctx->instr++;
1203 }else {
1204 stack_popn(ctx, 1);
1205 instr_jmp(ctx, loop_end);
1206 }
1207 return S_OK;
1208 }
1209
1210 static HRESULT interp_jmp(exec_ctx_t *ctx)
1211 {
1212 const unsigned arg = ctx->instr->arg1.uint;
1213
1214 TRACE("%u\n", arg);
1215
1216 instr_jmp(ctx, arg);
1217 return S_OK;
1218 }
1219
1220 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
1221 {
1222 const unsigned arg = ctx->instr->arg1.uint;
1223 HRESULT hres;
1224 BOOL b;
1225
1226 TRACE("%u\n", arg);
1227
1228 hres = stack_pop_bool(ctx, &b);
1229 if(FAILED(hres))
1230 return hres;
1231
1232 if(b)
1233 ctx->instr++;
1234 else
1235 instr_jmp(ctx, ctx->instr->arg1.uint);
1236 return S_OK;
1237 }
1238
1239 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
1240 {
1241 const unsigned arg = ctx->instr->arg1.uint;
1242 HRESULT hres;
1243 BOOL b;
1244
1245 TRACE("%u\n", arg);
1246
1247 hres = stack_pop_bool(ctx, &b);
1248 if(FAILED(hres))
1249 return hres;
1250
1251 if(b)
1252 instr_jmp(ctx, ctx->instr->arg1.uint);
1253 else
1254 ctx->instr++;
1255 return S_OK;
1256 }
1257
1258 static HRESULT interp_ret(exec_ctx_t *ctx)
1259 {
1260 TRACE("\n");
1261
1262 ctx->instr = NULL;
1263 return S_OK;
1264 }
1265
1266 static HRESULT interp_retval(exec_ctx_t *ctx)
1267 {
1268 variant_val_t val;
1269 HRESULT hres;
1270
1271 TRACE("\n");
1272
1273 hres = stack_pop_val(ctx, &val);
1274 if(FAILED(hres))
1275 return hres;
1276
1277 if(val.owned) {
1278 VariantClear(&ctx->ret_val);
1279 ctx->ret_val = *val.v;
1280 }
1281 else {
1282 hres = VariantCopy(&ctx->ret_val, val.v);
1283 if(FAILED(hres))
1284 return hres;
1285 }
1286
1287 return S_OK;
1288 }
1289
1290 static HRESULT interp_stop(exec_ctx_t *ctx)
1291 {
1292 WARN("\n");
1293
1294 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1295 return S_OK;
1296 }
1297
1298 static HRESULT interp_me(exec_ctx_t *ctx)
1299 {
1300 VARIANT v;
1301
1302 TRACE("\n");
1303
1304 IDispatch_AddRef(ctx->this_obj);
1305 V_VT(&v) = VT_DISPATCH;
1306 V_DISPATCH(&v) = ctx->this_obj;
1307 return stack_push(ctx, &v);
1308 }
1309
1310 static HRESULT interp_bool(exec_ctx_t *ctx)
1311 {
1312 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
1313 VARIANT v;
1314
1315 TRACE("%s\n", arg ? "true" : "false");
1316
1317 V_VT(&v) = VT_BOOL;
1318 V_BOOL(&v) = arg;
1319 return stack_push(ctx, &v);
1320 }
1321
1322 static HRESULT interp_errmode(exec_ctx_t *ctx)
1323 {
1324 const int err_mode = ctx->instr->arg1.uint;
1325
1326 TRACE("%d\n", err_mode);
1327
1328 ctx->resume_next = err_mode;
1329 clear_ei(&ctx->script->ei);
1330 return S_OK;
1331 }
1332
1333 static HRESULT interp_string(exec_ctx_t *ctx)
1334 {
1335 VARIANT v;
1336
1337 TRACE("\n");
1338
1339 V_VT(&v) = VT_BSTR;
1340 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
1341 if(!V_BSTR(&v))
1342 return E_OUTOFMEMORY;
1343
1344 return stack_push(ctx, &v);
1345 }
1346
1347 static HRESULT interp_int(exec_ctx_t *ctx)
1348 {
1349 const LONG arg = ctx->instr->arg1.lng;
1350 VARIANT v;
1351
1352 TRACE("%d\n", arg);
1353
1354 if(arg == (INT16)arg) {
1355 V_VT(&v) = VT_I2;
1356 V_I2(&v) = arg;
1357 }else {
1358 V_VT(&v) = VT_I4;
1359 V_I4(&v) = arg;
1360 }
1361 return stack_push(ctx, &v);
1362 }
1363
1364 static HRESULT interp_double(exec_ctx_t *ctx)
1365 {
1366 const DOUBLE *arg = ctx->instr->arg1.dbl;
1367 VARIANT v;
1368
1369 TRACE("%lf\n", *arg);
1370
1371 V_VT(&v) = VT_R8;
1372 V_R8(&v) = *arg;
1373 return stack_push(ctx, &v);
1374 }
1375
1376 static HRESULT interp_empty(exec_ctx_t *ctx)
1377 {
1378 VARIANT v;
1379
1380 TRACE("\n");
1381
1382 V_VT(&v) = VT_EMPTY;
1383 return stack_push(ctx, &v);
1384 }
1385
1386 static HRESULT interp_null(exec_ctx_t *ctx)
1387 {
1388 TRACE("\n");
1389 return stack_push_null(ctx);
1390 }
1391
1392 static HRESULT interp_nothing(exec_ctx_t *ctx)
1393 {
1394 VARIANT v;
1395
1396 TRACE("\n");
1397
1398 V_VT(&v) = VT_DISPATCH;
1399 V_DISPATCH(&v) = NULL;
1400 return stack_push(ctx, &v);
1401 }
1402
1403 static HRESULT interp_hres(exec_ctx_t *ctx)
1404 {
1405 const unsigned arg = ctx->instr->arg1.uint;
1406 VARIANT v;
1407
1408 TRACE("%d\n", arg);
1409
1410 V_VT(&v) = VT_ERROR;
1411 V_ERROR(&v) = arg;
1412 return stack_push(ctx, &v);
1413 }
1414
1415 static HRESULT interp_not(exec_ctx_t *ctx)
1416 {
1417 variant_val_t val;
1418 VARIANT v;
1419 HRESULT hres;
1420
1421 TRACE("\n");
1422
1423 hres = stack_pop_val(ctx, &val);
1424 if(FAILED(hres))
1425 return hres;
1426
1427 hres = VarNot(val.v, &v);
1428 release_val(&val);
1429 if(FAILED(hres))
1430 return hres;
1431
1432 return stack_push(ctx, &v);
1433 }
1434
1435 static HRESULT interp_and(exec_ctx_t *ctx)
1436 {
1437 variant_val_t r, l;
1438 VARIANT v;
1439 HRESULT hres;
1440
1441 TRACE("\n");
1442
1443 hres = stack_pop_val(ctx, &r);
1444 if(FAILED(hres))
1445 return hres;
1446
1447 hres = stack_pop_val(ctx, &l);
1448 if(SUCCEEDED(hres)) {
1449 hres = VarAnd(l.v, r.v, &v);
1450 release_val(&l);
1451 }
1452 release_val(&r);
1453 if(FAILED(hres))
1454 return hres;
1455
1456 return stack_push(ctx, &v);
1457 }
1458
1459 static HRESULT interp_or(exec_ctx_t *ctx)
1460 {
1461 variant_val_t r, l;
1462 VARIANT v;
1463 HRESULT hres;
1464
1465 TRACE("\n");
1466
1467 hres = stack_pop_val(ctx, &r);
1468 if(FAILED(hres))
1469 return hres;
1470
1471 hres = stack_pop_val(ctx, &l);
1472 if(SUCCEEDED(hres)) {
1473 hres = VarOr(l.v, r.v, &v);
1474 release_val(&l);
1475 }
1476 release_val(&r);
1477 if(FAILED(hres))
1478 return hres;
1479
1480 return stack_push(ctx, &v);
1481 }
1482
1483 static HRESULT interp_xor(exec_ctx_t *ctx)
1484 {
1485 variant_val_t r, l;
1486 VARIANT v;
1487 HRESULT hres;
1488
1489 TRACE("\n");
1490
1491 hres = stack_pop_val(ctx, &r);
1492 if(FAILED(hres))
1493 return hres;
1494
1495 hres = stack_pop_val(ctx, &l);
1496 if(SUCCEEDED(hres)) {
1497 hres = VarXor(l.v, r.v, &v);
1498 release_val(&l);
1499 }
1500 release_val(&r);
1501 if(FAILED(hres))
1502 return hres;
1503
1504 return stack_push(ctx, &v);
1505 }
1506
1507 static HRESULT interp_eqv(exec_ctx_t *ctx)
1508 {
1509 variant_val_t r, l;
1510 VARIANT v;
1511 HRESULT hres;
1512
1513 TRACE("\n");
1514
1515 hres = stack_pop_val(ctx, &r);
1516 if(FAILED(hres))
1517 return hres;
1518
1519 hres = stack_pop_val(ctx, &l);
1520 if(SUCCEEDED(hres)) {
1521 hres = VarEqv(l.v, r.v, &v);
1522 release_val(&l);
1523 }
1524 release_val(&r);
1525 if(FAILED(hres))
1526 return hres;
1527
1528 return stack_push(ctx, &v);
1529 }
1530
1531 static HRESULT interp_imp(exec_ctx_t *ctx)
1532 {
1533 variant_val_t r, l;
1534 VARIANT v;
1535 HRESULT hres;
1536
1537 TRACE("\n");
1538
1539 hres = stack_pop_val(ctx, &r);
1540 if(FAILED(hres))
1541 return hres;
1542
1543 hres = stack_pop_val(ctx, &l);
1544 if(SUCCEEDED(hres)) {
1545 hres = VarImp(l.v, r.v, &v);
1546 release_val(&l);
1547 }
1548 release_val(&r);
1549 if(FAILED(hres))
1550 return hres;
1551
1552 return stack_push(ctx, &v);
1553 }
1554
1555 static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r)
1556 {
1557 TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r));
1558
1559 /* FIXME: Fix comparing string to number */
1560
1561 return VarCmp(l, r, ctx->script->lcid, 0);
1562 }
1563
1564 static HRESULT cmp_oper(exec_ctx_t *ctx)
1565 {
1566 variant_val_t l, r;
1567 HRESULT hres;
1568
1569 hres = stack_pop_val(ctx, &r);
1570 if(FAILED(hres))
1571 return hres;
1572
1573 hres = stack_pop_val(ctx, &l);
1574 if(SUCCEEDED(hres)) {
1575 hres = var_cmp(ctx, l.v, r.v);
1576 release_val(&l);
1577 }
1578
1579 release_val(&r);
1580 return hres;
1581 }
1582
1583 static HRESULT interp_equal(exec_ctx_t *ctx)
1584 {
1585 VARIANT v;
1586 HRESULT hres;
1587
1588 TRACE("\n");
1589
1590 hres = cmp_oper(ctx);
1591 if(FAILED(hres))
1592 return hres;
1593 if(hres == VARCMP_NULL)
1594 return stack_push_null(ctx);
1595
1596 V_VT(&v) = VT_BOOL;
1597 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1598 return stack_push(ctx, &v);
1599 }
1600
1601 static HRESULT interp_nequal(exec_ctx_t *ctx)
1602 {
1603 VARIANT v;
1604 HRESULT hres;
1605
1606 TRACE("\n");
1607
1608 hres = cmp_oper(ctx);
1609 if(FAILED(hres))
1610 return hres;
1611 if(hres == VARCMP_NULL)
1612 return stack_push_null(ctx);
1613
1614 V_VT(&v) = VT_BOOL;
1615 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1616 return stack_push(ctx, &v);
1617 }
1618
1619 static HRESULT interp_gt(exec_ctx_t *ctx)
1620 {
1621 VARIANT v;
1622 HRESULT hres;
1623
1624 TRACE("\n");
1625
1626 hres = cmp_oper(ctx);
1627 if(FAILED(hres))
1628 return hres;
1629 if(hres == VARCMP_NULL)
1630 return stack_push_null(ctx);
1631
1632 V_VT(&v) = VT_BOOL;
1633 V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1634 return stack_push(ctx, &v);
1635 }
1636
1637 static HRESULT interp_gteq(exec_ctx_t *ctx)
1638 {
1639 VARIANT v;
1640 HRESULT hres;
1641
1642 TRACE("\n");
1643
1644 hres = cmp_oper(ctx);
1645 if(FAILED(hres))
1646 return hres;
1647 if(hres == VARCMP_NULL)
1648 return stack_push_null(ctx);
1649
1650 V_VT(&v) = VT_BOOL;
1651 V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1652 return stack_push(ctx, &v);
1653 }
1654
1655 static HRESULT interp_lt(exec_ctx_t *ctx)
1656 {
1657 VARIANT v;
1658 HRESULT hres;
1659
1660 TRACE("\n");
1661
1662 hres = cmp_oper(ctx);
1663 if(FAILED(hres))
1664 return hres;
1665 if(hres == VARCMP_NULL)
1666 return stack_push_null(ctx);
1667
1668 V_VT(&v) = VT_BOOL;
1669 V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1670 return stack_push(ctx, &v);
1671 }
1672
1673 static HRESULT interp_lteq(exec_ctx_t *ctx)
1674 {
1675 VARIANT v;
1676 HRESULT hres;
1677
1678 TRACE("\n");
1679
1680 hres = cmp_oper(ctx);
1681 if(FAILED(hres))
1682 return hres;
1683 if(hres == VARCMP_NULL)
1684 return stack_push_null(ctx);
1685
1686 V_VT(&v) = VT_BOOL;
1687 V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1688 return stack_push(ctx, &v);
1689 }
1690
1691 static HRESULT interp_case(exec_ctx_t *ctx)
1692 {
1693 const unsigned arg = ctx->instr->arg1.uint;
1694 variant_val_t v;
1695 HRESULT hres;
1696
1697 TRACE("%d\n", arg);
1698
1699 hres = stack_pop_val(ctx, &v);
1700 if(FAILED(hres))
1701 return hres;
1702
1703 hres = var_cmp(ctx, stack_top(ctx, 0), v.v);
1704 release_val(&v);
1705 if(FAILED(hres))
1706 return hres;
1707
1708 if(hres == VARCMP_EQ) {
1709 stack_popn(ctx, 1);
1710 instr_jmp(ctx, arg);
1711 }else {
1712 ctx->instr++;
1713 }
1714
1715 return S_OK;
1716 }
1717
1718 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1719 {
1720 IObjectIdentity *identity;
1721 IUnknown *unk1, *unk2;
1722 HRESULT hres;
1723
1724 if(disp1 == disp2) {
1725 *ret = VARIANT_TRUE;
1726 return S_OK;
1727 }
1728
1729 if(!disp1 || !disp2) {
1730 *ret = VARIANT_FALSE;
1731 return S_OK;
1732 }
1733
1734 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1735 if(FAILED(hres))
1736 return hres;
1737
1738 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1739 if(FAILED(hres)) {
1740 IUnknown_Release(unk1);
1741 return hres;
1742 }
1743
1744 if(unk1 == unk2) {
1745 *ret = VARIANT_TRUE;
1746 }else {
1747 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1748 if(SUCCEEDED(hres)) {
1749 hres = IObjectIdentity_IsEqualObject(identity, unk2);
1750 IObjectIdentity_Release(identity);
1751 *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1752 }else {
1753 *ret = VARIANT_FALSE;
1754 }
1755 }
1756
1757 IUnknown_Release(unk1);
1758 IUnknown_Release(unk2);
1759 return S_OK;
1760 }
1761
1762 static HRESULT interp_is(exec_ctx_t *ctx)
1763 {
1764 IDispatch *l, *r;
1765 VARIANT v;
1766 HRESULT hres;
1767
1768 TRACE("\n");
1769
1770 hres = stack_pop_disp(ctx, &r);
1771 if(FAILED(hres))
1772 return hres;
1773
1774 hres = stack_pop_disp(ctx, &l);
1775 if(SUCCEEDED(hres)) {
1776 V_VT(&v) = VT_BOOL;
1777 hres = disp_cmp(l, r, &V_BOOL(&v));
1778 if(l)
1779 IDispatch_Release(l);
1780 }
1781 if(r)
1782 IDispatch_Release(r);
1783 if(FAILED(hres))
1784 return hres;
1785
1786 return stack_push(ctx, &v);
1787 }
1788
1789 static HRESULT interp_concat(exec_ctx_t *ctx)
1790 {
1791 variant_val_t r, l;
1792 VARIANT v;
1793 HRESULT hres;
1794
1795 TRACE("\n");
1796
1797 hres = stack_pop_val(ctx, &r);
1798 if(FAILED(hres))
1799 return hres;
1800
1801 hres = stack_pop_val(ctx, &l);
1802 if(SUCCEEDED(hres)) {
1803 hres = VarCat(l.v, r.v, &v);
1804 release_val(&l);
1805 }
1806 release_val(&r);
1807 if(FAILED(hres))
1808 return hres;
1809
1810 return stack_push(ctx, &v);
1811 }
1812
1813 static HRESULT interp_add(exec_ctx_t *ctx)
1814 {
1815 variant_val_t r, l;
1816 VARIANT v;
1817 HRESULT hres;
1818
1819 TRACE("\n");
1820
1821 hres = stack_pop_val(ctx, &r);
1822 if(FAILED(hres))
1823 return hres;
1824
1825 hres = stack_pop_val(ctx, &l);
1826 if(SUCCEEDED(hres)) {
1827 hres = VarAdd(l.v, r.v, &v);
1828 release_val(&l);
1829 }
1830 release_val(&r);
1831 if(FAILED(hres))
1832 return hres;
1833
1834 return stack_push(ctx, &v);
1835 }
1836
1837 static HRESULT interp_sub(exec_ctx_t *ctx)
1838 {
1839 variant_val_t r, l;
1840 VARIANT v;
1841 HRESULT hres;
1842
1843 TRACE("\n");
1844
1845 hres = stack_pop_val(ctx, &r);
1846 if(FAILED(hres))
1847 return hres;
1848
1849 hres = stack_pop_val(ctx, &l);
1850 if(SUCCEEDED(hres)) {
1851 hres = VarSub(l.v, r.v, &v);
1852 release_val(&l);
1853 }
1854 release_val(&r);
1855 if(FAILED(hres))
1856 return hres;
1857
1858 return stack_push(ctx, &v);
1859 }
1860
1861 static HRESULT interp_mod(exec_ctx_t *ctx)
1862 {
1863 variant_val_t r, l;
1864 VARIANT v;
1865 HRESULT hres;
1866
1867 TRACE("\n");
1868
1869 hres = stack_pop_val(ctx, &r);
1870 if(FAILED(hres))
1871 return hres;
1872
1873 hres = stack_pop_val(ctx, &l);
1874 if(SUCCEEDED(hres)) {
1875 hres = VarMod(l.v, r.v, &v);
1876 release_val(&l);
1877 }
1878 release_val(&r);
1879 if(FAILED(hres))
1880 return hres;
1881
1882 return stack_push(ctx, &v);
1883 }
1884
1885 static HRESULT interp_idiv(exec_ctx_t *ctx)
1886 {
1887 variant_val_t r, l;
1888 VARIANT v;
1889 HRESULT hres;
1890
1891 TRACE("\n");
1892
1893 hres = stack_pop_val(ctx, &r);
1894 if(FAILED(hres))
1895 return hres;
1896
1897 hres = stack_pop_val(ctx, &l);
1898 if(SUCCEEDED(hres)) {
1899 hres = VarIdiv(l.v, r.v, &v);
1900 release_val(&l);
1901 }
1902 release_val(&r);
1903 if(FAILED(hres))
1904 return hres;
1905
1906 return stack_push(ctx, &v);
1907 }
1908
1909 static HRESULT interp_div(exec_ctx_t *ctx)
1910 {
1911 variant_val_t r, l;
1912 VARIANT v;
1913 HRESULT hres;
1914
1915 TRACE("\n");
1916
1917 hres = stack_pop_val(ctx, &r);
1918 if(FAILED(hres))
1919 return hres;
1920
1921 hres = stack_pop_val(ctx, &l);
1922 if(SUCCEEDED(hres)) {
1923 hres = VarDiv(l.v, r.v, &v);
1924 release_val(&l);
1925 }
1926 release_val(&r);
1927 if(FAILED(hres))
1928 return hres;
1929
1930 return stack_push(ctx, &v);
1931 }
1932
1933 static HRESULT interp_mul(exec_ctx_t *ctx)
1934 {
1935 variant_val_t r, l;
1936 VARIANT v;
1937 HRESULT hres;
1938
1939 TRACE("\n");
1940
1941 hres = stack_pop_val(ctx, &r);
1942 if(FAILED(hres))
1943 return hres;
1944
1945 hres = stack_pop_val(ctx, &l);
1946 if(SUCCEEDED(hres)) {
1947 hres = VarMul(l.v, r.v, &v);
1948 release_val(&l);
1949 }
1950 release_val(&r);
1951 if(FAILED(hres))
1952 return hres;
1953
1954 return stack_push(ctx, &v);
1955 }
1956
1957 static HRESULT interp_exp(exec_ctx_t *ctx)
1958 {
1959 variant_val_t r, l;
1960 VARIANT v;
1961 HRESULT hres;
1962
1963 TRACE("\n");
1964
1965 hres = stack_pop_val(ctx, &r);
1966 if(FAILED(hres))
1967 return hres;
1968
1969 hres = stack_pop_val(ctx, &l);
1970 if(SUCCEEDED(hres)) {
1971 hres = VarPow(l.v, r.v, &v);
1972 release_val(&l);
1973 }
1974 release_val(&r);
1975 if(FAILED(hres))
1976 return hres;
1977
1978 return stack_push(ctx, &v);
1979 }
1980
1981 static HRESULT interp_neg(exec_ctx_t *ctx)
1982 {
1983 variant_val_t val;
1984 VARIANT v;
1985 HRESULT hres;
1986
1987 hres = stack_pop_val(ctx, &val);
1988 if(FAILED(hres))
1989 return hres;
1990
1991 hres = VarNeg(val.v, &v);
1992 release_val(&val);
1993 if(FAILED(hres))
1994 return hres;
1995
1996 return stack_push(ctx, &v);
1997 }
1998
1999 static HRESULT interp_incc(exec_ctx_t *ctx)
2000 {
2001 const BSTR ident = ctx->instr->arg1.bstr;
2002 VARIANT v;
2003 ref_t ref;
2004 HRESULT hres;
2005
2006 TRACE("\n");
2007
2008 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
2009 if(FAILED(hres))
2010 return hres;
2011
2012 if(ref.type != REF_VAR) {
2013 FIXME("ref.type is not REF_VAR\n");
2014 return E_FAIL;
2015 }
2016
2017 hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
2018 if(FAILED(hres))
2019 return hres;
2020
2021 VariantClear(ref.u.v);
2022 *ref.u.v = v;
2023 return S_OK;
2024 }
2025
2026 static HRESULT interp_catch(exec_ctx_t *ctx)
2027 {
2028 /* Nothing to do here, the OP is for unwinding only. */
2029 return S_OK;
2030 }
2031
2032 static const instr_func_t op_funcs[] = {
2033 #define X(x,n,a,b) interp_ ## x,
2034 OP_LIST
2035 #undef X
2036 };
2037
2038 static const unsigned op_move[] = {
2039 #define X(x,n,a,b) n,
2040 OP_LIST
2041 #undef X
2042 };
2043
2044 void release_dynamic_vars(dynamic_var_t *var)
2045 {
2046 while(var) {
2047 VariantClear(&var->v);
2048 var = var->next;
2049 }
2050 }
2051
2052 static void release_exec(exec_ctx_t *ctx)
2053 {
2054 unsigned i;
2055
2056 VariantClear(&ctx->ret_val);
2057 release_dynamic_vars(ctx->dynamic_vars);
2058
2059 if(ctx->this_obj)
2060 IDispatch_Release(ctx->this_obj);
2061
2062 if(ctx->args) {
2063 for(i=0; i < ctx->func->arg_cnt; i++)
2064 VariantClear(ctx->args+i);
2065 }
2066
2067 if(ctx->vars) {
2068 for(i=0; i < ctx->func->var_cnt; i++)
2069 VariantClear(ctx->vars+i);
2070 }
2071
2072 if(ctx->arrays) {
2073 for(i=0; i < ctx->func->var_cnt; i++) {
2074 if(ctx->arrays[i])
2075 SafeArrayDestroy(ctx->arrays[i]);
2076 }
2077 heap_free(ctx->arrays);
2078 }
2079
2080 heap_pool_free(&ctx->heap);
2081 heap_free(ctx->args);
2082 heap_free(ctx->vars);
2083 heap_free(ctx->stack);
2084 }
2085
2086 HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res)
2087 {
2088 exec_ctx_t exec = {func->code_ctx};
2089 vbsop_t op;
2090 HRESULT hres = S_OK;
2091
2092 exec.code = func->code_ctx;
2093
2094 if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
2095 FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
2096 return E_FAIL;
2097 }
2098
2099 heap_pool_init(&exec.heap);
2100
2101 if(func->arg_cnt) {
2102 VARIANT *v;
2103 unsigned i;
2104
2105 exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
2106 if(!exec.args) {
2107 release_exec(&exec);
2108 return E_OUTOFMEMORY;
2109 }
2110
2111 for(i=0; i < func->arg_cnt; i++) {
2112 v = get_arg(dp, i);
2113 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
2114 if(func->args[i].by_ref)
2115 exec.args[i] = *v;
2116 else
2117 hres = VariantCopyInd(exec.args+i, V_VARIANTREF(v));
2118 }else {
2119 hres = VariantCopyInd(exec.args+i, v);
2120 }
2121 if(FAILED(hres)) {
2122 release_exec(&exec);
2123 return hres;
2124 }
2125 }
2126 }else {
2127 exec.args = NULL;
2128 }
2129
2130 if(func->var_cnt) {
2131 exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
2132 if(!exec.vars) {
2133 release_exec(&exec);
2134 return E_OUTOFMEMORY;
2135 }
2136 }else {
2137 exec.vars = NULL;
2138 }
2139
2140 exec.stack_size = 16;
2141 exec.top = 0;
2142 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
2143 if(!exec.stack) {
2144 release_exec(&exec);
2145 return E_OUTOFMEMORY;
2146 }
2147
2148 if(extern_caller)
2149 IActiveScriptSite_OnEnterScript(ctx->site);
2150
2151 if(vbthis) {
2152 exec.this_obj = (IDispatch*)&vbthis->IDispatchEx_iface;
2153 exec.vbthis = vbthis;
2154 }else if (ctx->host_global) {
2155 exec.this_obj = ctx->host_global;
2156 }else {
2157 exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
2158 }
2159 IDispatch_AddRef(exec.this_obj);
2160
2161 exec.instr = exec.code->instrs + func->code_off;
2162 exec.script = ctx;
2163 exec.func = func;
2164
2165 while(exec.instr) {
2166 op = exec.instr->op;
2167 hres = op_funcs[op](&exec);
2168 if(FAILED(hres)) {
2169 if(hres != SCRIPT_E_RECORDED) {
2170 clear_ei(&ctx->ei);
2171
2172 ctx->ei.scode = hres = map_hres(hres);
2173 ctx->ei.bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR);
2174 ctx->ei.bstrDescription = get_vbscript_error_string(hres);
2175 }else {
2176 hres = ctx->ei.scode;
2177 }
2178
2179 if(exec.resume_next) {
2180 unsigned stack_off;
2181
2182 WARN("Failed %08x in resume next mode\n", hres);
2183
2184 /*
2185 * Unwinding here is simple. We need to find the next OP_catch, which contains
2186 * information about expected stack size and jump offset on error. Generated
2187 * bytecode needs to guarantee, that simple jump and stack adjustment will
2188 * guarantee proper execution continuation.
2189 */
2190 while((++exec.instr)->op != OP_catch);
2191
2192 TRACE("unwind jmp %d stack_off %d\n", exec.instr->arg1.uint, exec.instr->arg2.uint);
2193
2194 stack_off = exec.instr->arg2.uint;
2195 instr_jmp(&exec, exec.instr->arg1.uint);
2196
2197 if(exec.top > stack_off) {
2198 stack_popn(&exec, exec.top-stack_off);
2199 }else if(exec.top < stack_off) {
2200 VARIANT v;
2201
2202 V_VT(&v) = VT_EMPTY;
2203 while(exec.top < stack_off) {
2204 hres = stack_push(&exec, &v);
2205 if(FAILED(hres))
2206 break;
2207 }
2208 }
2209
2210 continue;
2211 }else {
2212 WARN("Failed %08x\n", hres);
2213 stack_popn(&exec, exec.top);
2214 break;
2215 }
2216 }
2217
2218 exec.instr += op_move[op];
2219 }
2220
2221 assert(!exec.top);
2222
2223 if(extern_caller) {
2224 IActiveScriptSite_OnLeaveScript(ctx->site);
2225 if(FAILED(hres)) {
2226 if(!ctx->ei.scode)
2227 ctx->ei.scode = hres;
2228 hres = report_script_error(ctx);
2229 }
2230 }
2231
2232 if(SUCCEEDED(hres) && res) {
2233 *res = exec.ret_val;
2234 V_VT(&exec.ret_val) = VT_EMPTY;
2235 }
2236
2237 release_exec(&exec);
2238 return hres;
2239 }