From c51c28447492a2c3010134d77e90fc8576d6b6ba Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Wed, 10 Jun 2026 18:06:05 +0100 Subject: [PATCH] [VBSCRIPT] Sync with Wine 10.0. CORE-20606 --- dll/win32/vbscript/CMakeLists.txt | 19 +- dll/win32/vbscript/compile.c | 589 +++++++---- dll/win32/vbscript/global.c | 1241 ++++++++++++++++++----- dll/win32/vbscript/guid.c | 16 + dll/win32/vbscript/interp.c | 903 ++++++++++++----- dll/win32/vbscript/lex.c | 305 +++--- dll/win32/vbscript/parse.h | 54 +- dll/win32/vbscript/parser.y | 522 ++++++---- dll/win32/vbscript/precomp.h | 1 + dll/win32/vbscript/regexp.c | 36 +- dll/win32/vbscript/regexp.h | 10 +- dll/win32/vbscript/utils.c | 21 +- dll/win32/vbscript/vbdisp.c | 1134 +++++++++++++++++---- dll/win32/vbscript/vbregexp.c | 333 ++++-- dll/win32/vbscript/vbscript.c | 517 +++++++--- dll/win32/vbscript/vbscript.h | 203 ++-- dll/win32/vbscript/vbscript.rc | 12 +- dll/win32/vbscript/vbscript.rgs | 8 +- dll/win32/vbscript/vbscript_classes.rgs | 46 - dll/win32/vbscript/vbscript_defs.h | 1 + dll/win32/vbscript/vbscript_main.c | 81 +- dll/win32/vbscript/vbsglobal.rgs | 32 - dll/win32/vbscript/vbsregexp10.idl | 1 + dll/win32/vbscript/vbsregexp10.rgs | 38 - dll/win32/vbscript/vbsregexp55.idl | 1 + dll/win32/vbscript/vbsregexp55.rgs | 62 -- media/doc/WINESYNC.txt | 2 +- 27 files changed, 4370 insertions(+), 1818 deletions(-) create mode 100644 dll/win32/vbscript/guid.c delete mode 100644 dll/win32/vbscript/vbscript_classes.rgs delete mode 100644 dll/win32/vbscript/vbsglobal.rgs delete mode 100644 dll/win32/vbscript/vbsregexp10.rgs delete mode 100644 dll/win32/vbscript/vbsregexp55.rgs diff --git a/dll/win32/vbscript/CMakeLists.txt b/dll/win32/vbscript/CMakeLists.txt index 0fa203090fc..054a619483e 100644 --- a/dll/win32/vbscript/CMakeLists.txt +++ b/dll/win32/vbscript/CMakeLists.txt @@ -1,5 +1,4 @@ -add_definitions(-D__ROS_LONG64__) spec2def(vbscript.dll vbscript.spec) list(APPEND SOURCE @@ -14,23 +13,17 @@ list(APPEND SOURCE vbscript.c vbscript_main.c) -BISON_TARGET(parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.c COMPILE_FLAGS "-p parser_") +BISON_TARGET(parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.c) list(APPEND PCH_SKIP_SOURCE + guid.c ${BISON_parser_OUTPUTS}) list(APPEND vbscript_rc_deps - ${CMAKE_CURRENT_SOURCE_DIR}/vbscript_classes.rgs - ${CMAKE_CURRENT_SOURCE_DIR}/vbsglobal.rgs - ${CMAKE_CURRENT_SOURCE_DIR}/vbsregexp10.rgs - ${CMAKE_CURRENT_SOURCE_DIR}/vbsregexp55.rgs - ${CMAKE_CURRENT_BINARY_DIR}/vbsglobal.tlb - ${CMAKE_CURRENT_BINARY_DIR}/vbsregexp10.tlb - ${CMAKE_CURRENT_BINARY_DIR}/vbsregexp55.tlb) + ${CMAKE_CURRENT_SOURCE_DIR}/vbscript.rgs) set_source_files_properties(vbscript.rc PROPERTIES OBJECT_DEPENDS "${vbscript_rc_deps}") add_idl_headers(vbscript_idlheader vbscript_classes.idl vbsglobal.idl vbsregexp55.idl) -add_typelib(vbsglobal.idl vbsregexp10.idl vbsregexp55.idl) add_library(vbscript MODULE ${SOURCE} @@ -43,9 +36,11 @@ if(MSVC) target_compile_options(vbscript PRIVATE /wd4267) endif() +add_idl_reg_scripts(vbscript registry vbscript_classes.idl) +add_idl_reg_scripts(vbscript regtypelib vbsglobal.idl vbsregexp10.idl vbsregexp55.idl) set_module_type(vbscript win32dll) -target_link_libraries(vbscript uuid wine oldnames) -add_importlibs(vbscript oleaut32 ole32 user32 msvcrt kernel32 ntdll) +target_link_libraries(vbscript uuid wine oldnames wine_dll_register wine_dll_canunload) +add_importlibs(vbscript oleaut32 ole32 user32 msvcrt kernelbase kernel32_vista kernel32 ntdll) add_dependencies(vbscript vbscript_idlheader stdole2) add_pch(vbscript precomp.h "${PCH_SKIP_SOURCE}") add_cd_file(TARGET vbscript DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/vbscript/compile.c b/dll/win32/vbscript/compile.c index c129f3670da..baddc51d7e4 100644 --- a/dll/win32/vbscript/compile.c +++ b/dll/win32/vbscript/compile.c @@ -32,6 +32,7 @@ typedef struct _statement_ctx_t { unsigned while_end_label; unsigned for_end_label; + unsigned with_stack_offset; struct _statement_ctx_t *next; } statement_ctx_t; @@ -43,6 +44,7 @@ typedef struct { unsigned instr_size; vbscode_t *code; + unsigned loc; statement_ctx_t *stat_ctx; unsigned *labels; @@ -55,16 +57,12 @@ typedef struct { dim_decl_t *dim_decls; dim_decl_t *dim_decls_tail; - dynamic_var_t *global_vars; const_decl_t *const_decls; const_decl_t *global_consts; function_t *func; - function_t *funcs; function_decl_t *func_decls; - - class_desc_t *classes; } compile_ctx_t; static HRESULT compile_expression(compile_ctx_t*,expression_t*); @@ -94,6 +92,7 @@ static void dump_instr_arg(instr_arg_type_t type, instr_arg_t *arg) case ARG_ADDR: TRACE_(vbscript_disas)("\t%u", arg->uint); break; + case ARG_DATE: case ARG_DOUBLE: TRACE_(vbscript_disas)("\t%lf", *arg->dbl); break; @@ -156,7 +155,7 @@ static unsigned push_instr(compile_ctx_t *ctx, vbsop_t op) if(ctx->instr_size == ctx->instr_cnt) { instr_t *new_instr; - new_instr = heap_realloc(ctx->code->instrs, ctx->instr_size*2*sizeof(instr_t)); + new_instr = realloc(ctx->code->instrs, ctx->instr_size*2*sizeof(instr_t)); if(!new_instr) return 0; @@ -165,6 +164,7 @@ static unsigned push_instr(compile_ctx_t *ctx, vbsop_t op) } ctx->code->instrs[ctx->instr_cnt].op = op; + ctx->code->instrs[ctx->instr_cnt].loc = ctx->loc; return ctx->instr_cnt++; } @@ -239,17 +239,35 @@ static HRESULT push_instr_double(compile_ctx_t *ctx, vbsop_t op, double arg) return S_OK; } +static HRESULT push_instr_date(compile_ctx_t *ctx, vbsop_t op, DATE arg) +{ + unsigned instr; + DATE *d; + + d = compiler_alloc(ctx->code, sizeof(DATE)); + if(!d) + return E_OUTOFMEMORY; + + instr = push_instr(ctx, op); + if(!instr) + return E_OUTOFMEMORY; + + *d = arg; + instr_ptr(ctx, instr)->arg1.date = d; + return S_OK; +} + static BSTR alloc_bstr_arg(compile_ctx_t *ctx, const WCHAR *str) { if(!ctx->code->bstr_pool_size) { - ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR)); + ctx->code->bstr_pool = malloc(8 * sizeof(BSTR)); if(!ctx->code->bstr_pool) return NULL; ctx->code->bstr_pool_size = 8; }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) { BSTR *new_pool; - new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR)); + new_pool = realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR)); if(!new_pool) return NULL; @@ -322,14 +340,14 @@ static HRESULT push_instr_uint_bstr(compile_ctx_t *ctx, vbsop_t op, unsigned arg static unsigned alloc_label(compile_ctx_t *ctx) { if(!ctx->labels_size) { - ctx->labels = heap_alloc(8 * sizeof(*ctx->labels)); + ctx->labels = malloc(8 * sizeof(*ctx->labels)); if(!ctx->labels) return 0; ctx->labels_size = 8; }else if(ctx->labels_size == ctx->labels_cnt) { unsigned *new_labels; - new_labels = heap_realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels)); + new_labels = realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels)); if(!new_labels) return 0; @@ -375,16 +393,16 @@ static inline BOOL emit_catch(compile_ctx_t *ctx, unsigned off) return emit_catch_jmp(ctx, off, ctx->instr_cnt); } -static HRESULT compile_error(script_ctx_t *ctx, HRESULT error) +static HRESULT compile_error(script_ctx_t *ctx, compile_ctx_t *compiler, HRESULT error) { if(error == SCRIPT_E_REPORTED) return error; clear_ei(&ctx->ei); - ctx->ei.scode = error = map_hres(error); + ctx->ei.scode = error; ctx->ei.bstrSource = get_vbscript_string(VBS_COMPILE_ERROR); - ctx->ei.bstrDescription = get_vbscript_error_string(error); - return report_script_error(ctx); + map_vbs_exception(&ctx->ei); + return report_script_error(ctx, compiler->code, compiler->loc); } static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, BOOL lookup_global) @@ -407,6 +425,30 @@ static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, B return NULL; } +static BOOL lookup_args_name(compile_ctx_t *ctx, const WCHAR *name) +{ + unsigned i; + + for(i = 0; i < ctx->func->arg_cnt; i++) { + if(!wcsicmp(ctx->func->args[i].name, name)) + return TRUE; + } + + return FALSE; +} + +static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name) +{ + dim_decl_t *dim_decl; + + for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) { + if(!wcsicmp(dim_decl->name, name)) + return TRUE; + } + + return FALSE; +} + static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *ret) { unsigned arg_cnt = 0; @@ -417,6 +459,9 @@ static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *re if(FAILED(hres)) return hres; + if(args->type == EXPR_BRACKETS && !push_instr(ctx, OP_deref)) + return E_OUTOFMEMORY; + arg_cnt++; args = args->next; } @@ -425,12 +470,12 @@ static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *re return S_OK; } -static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr, BOOL ret_val) +static HRESULT compile_member_call_expression(compile_ctx_t *ctx, member_expression_t *expr, + unsigned arg_cnt, BOOL ret_val) { - unsigned arg_cnt = 0; HRESULT hres; - if(ret_val && !expr->args) { + if(ret_val && !arg_cnt) { expression_t *const_expr; const_expr = lookup_const_decls(ctx, expr->identifier, TRUE); @@ -438,10 +483,6 @@ static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t return compile_expression(ctx, const_expr); } - hres = compile_args(ctx, expr->args, &arg_cnt); - if(FAILED(hres)) - return hres; - if(expr->obj_expr) { hres = compile_expression(ctx, expr->obj_expr); if(FAILED(hres)) @@ -455,6 +496,58 @@ static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t return hres; } +static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr) +{ + expression_t *const_expr; + + if (expr->obj_expr) /* FIXME: we should probably have a dedicated opcode as well */ + return compile_member_call_expression(ctx, expr, 0, TRUE); + + if (!lookup_dim_decls(ctx, expr->identifier) && !lookup_args_name(ctx, expr->identifier)) { + const_expr = lookup_const_decls(ctx, expr->identifier, TRUE); + if(const_expr) + return compile_expression(ctx, const_expr); + } + return push_instr_bstr(ctx, OP_ident, expr->identifier); +} + +static HRESULT compile_call_expression(compile_ctx_t *ctx, call_expression_t *expr, BOOL ret_val) +{ + unsigned arg_cnt = 0; + expression_t *call; + HRESULT hres; + + hres = compile_args(ctx, expr->args, &arg_cnt); + if(FAILED(hres)) + return hres; + + for(call = expr->call_expr; call->type == EXPR_BRACKETS; call = ((unary_expression_t*)call)->subexpr); + + if(call->type == EXPR_MEMBER) + return compile_member_call_expression(ctx, (member_expression_t*)call, arg_cnt, ret_val); + + hres = compile_expression(ctx, call); + if(FAILED(hres)) + return hres; + + return push_instr_uint(ctx, ret_val ? OP_vcall : OP_vcallv, arg_cnt); +} + +static HRESULT compile_dot_expression(compile_ctx_t *ctx) +{ + statement_ctx_t *stat_ctx; + + for(stat_ctx = ctx->stat_ctx; stat_ctx; stat_ctx = stat_ctx->next) { + if(!stat_ctx->with_stack_offset) + continue; + + return push_instr_uint(ctx, OP_stack, stat_ctx->with_stack_offset - 1); + } + + WARN("dot expression outside with statement\n"); + return push_instr_uint(ctx, OP_stack, ~0); +} + static HRESULT compile_unary_expression(compile_ctx_t *ctx, unary_expression_t *expr, vbsop_t op) { HRESULT hres; @@ -492,10 +585,16 @@ static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr) return push_instr_int(ctx, OP_bool, ((bool_expression_t*)expr)->value); case EXPR_BRACKETS: return compile_expression(ctx, ((unary_expression_t*)expr)->subexpr); + case EXPR_CALL: + return compile_call_expression(ctx, (call_expression_t*)expr, TRUE); case EXPR_CONCAT: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_concat); + case EXPR_DATE: + return push_instr_date(ctx, OP_date, ((date_expression_t*)expr)->value); case EXPR_DIV: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div); + case EXPR_DOT: + return compile_dot_expression(ctx); case EXPR_DOUBLE: return push_instr_double(ctx, OP_double, ((double_expression_t*)expr)->value); case EXPR_EMPTY: @@ -523,7 +622,7 @@ static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr) case EXPR_ME: return push_instr(ctx, OP_me) ? S_OK : E_OUTOFMEMORY; case EXPR_MEMBER: - return compile_member_expression(ctx, (member_expression_t*)expr, TRUE); + return compile_member_expression(ctx, (member_expression_t*)expr); case EXPR_MOD: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mod); case EXPR_MUL: @@ -594,6 +693,8 @@ static HRESULT compile_if_statement(compile_ctx_t *ctx, if_statement_t *stat) for(elseif_decl = stat->elseifs; elseif_decl; elseif_decl = elseif_decl->next) { instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt; + ctx->loc = elseif_decl->loc; + hres = compile_expression(ctx, elseif_decl->expr); if(FAILED(hres)) return hres; @@ -687,6 +788,7 @@ static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t * if(FAILED(hres)) return hres; + ctx->loc = stat->stat.loc; if(stat->expr) { hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) @@ -742,6 +844,7 @@ static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t return hres; /* We need a separated enumnext here, because we need to jump out of the loop on exception. */ + ctx->loc = stat->stat.loc; hres = push_instr_uint_bstr(ctx, OP_enumnext, loop_ctx.for_end_label, stat->identifier); if(FAILED(hres)) return hres; @@ -751,6 +854,10 @@ static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t return hres; label_set_addr(ctx, loop_ctx.for_end_label); + + if(!emit_catch(ctx, 0)) + return E_OUTOFMEMORY; + return S_OK; } @@ -768,6 +875,8 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st hres = compile_expression(ctx, stat->from_expr); if(FAILED(hres)) return hres; + if(!push_instr(ctx, OP_numval)) + return E_OUTOFMEMORY; /* FIXME: Assign should happen after both expressions evaluation. */ instr = push_instr(ctx, OP_assign_ident); @@ -780,7 +889,7 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st if(FAILED(hres)) return hres; - if(!push_instr(ctx, OP_val)) + if(!push_instr(ctx, OP_numval)) return E_OUTOFMEMORY; if(stat->step_expr) { @@ -788,7 +897,7 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st if(FAILED(hres)) return hres; - if(!push_instr(ctx, OP_val)) + if(!push_instr(ctx, OP_numval)) return E_OUTOFMEMORY; }else { hres = push_instr_int(ctx, OP_int, 1); @@ -836,6 +945,26 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st return S_OK; } +static HRESULT compile_with_statement(compile_ctx_t *ctx, with_statement_t *stat) +{ + statement_ctx_t with_ctx = { 1 }; + HRESULT hres; + + hres = compile_expression(ctx, stat->expr); + if(FAILED(hres)) + return hres; + + if(!emit_catch(ctx, 1)) + return E_OUTOFMEMORY; + + with_ctx.with_stack_offset = stack_offset(ctx) + 1; + hres = compile_statement(ctx, &with_ctx, stat->body); + if(FAILED(hres)) + return hres; + + return push_instr_uint(ctx, OP_pop, 1); +} + static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t *stat) { unsigned end_label, case_cnt = 0, *case_labels = NULL, i; @@ -861,7 +990,7 @@ static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t * case_cnt++; if(case_cnt) { - case_labels = heap_alloc(case_cnt*sizeof(*case_labels)); + case_labels = malloc(case_cnt*sizeof(*case_labels)); if(!case_labels) return E_OUTOFMEMORY; } @@ -893,19 +1022,19 @@ static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t * } if(FAILED(hres)) { - heap_free(case_labels); + free(case_labels); return hres; } hres = push_instr_uint(ctx, OP_pop, 1); if(FAILED(hres)) { - heap_free(case_labels); + free(case_labels); return hres; } hres = push_instr_addr(ctx, OP_jmp, case_iter ? case_labels[i] : end_label); if(FAILED(hres)) { - heap_free(case_labels); + free(case_labels); return hres; } @@ -923,7 +1052,7 @@ static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t * break; } - heap_free(case_labels); + free(case_labels); if(FAILED(hres)) return hres; @@ -931,12 +1060,28 @@ static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t * return S_OK; } -static HRESULT compile_assignment(compile_ctx_t *ctx, member_expression_t *member_expr, expression_t *value_expr, BOOL is_set) +static HRESULT compile_assignment(compile_ctx_t *ctx, expression_t *left, expression_t *value_expr, BOOL is_set) { - unsigned args_cnt; + call_expression_t *call_expr = NULL; + member_expression_t *member_expr; + unsigned args_cnt = 0; vbsop_t op; HRESULT hres; + switch(left->type) { + case EXPR_MEMBER: + member_expr = (member_expression_t*)left; + break; + case EXPR_CALL: + call_expr = (call_expression_t*)left; + assert(call_expr->call_expr->type == EXPR_MEMBER); + member_expr = (member_expression_t*)call_expr->call_expr; + break; + default: + assert(0); + return E_FAIL; + } + if(member_expr->obj_expr) { hres = compile_expression(ctx, member_expr->obj_expr); if(FAILED(hres)) @@ -951,9 +1096,11 @@ static HRESULT compile_assignment(compile_ctx_t *ctx, member_expression_t *membe if(FAILED(hres)) return hres; - hres = compile_args(ctx, member_expr->args, &args_cnt); - if(FAILED(hres)) - return hres; + if(call_expr) { + hres = compile_args(ctx, call_expr->args, &args_cnt); + if(FAILED(hres)) + return hres; + } hres = push_instr_bstr_uint(ctx, op, member_expr->identifier, args_cnt); if(FAILED(hres)) @@ -967,29 +1114,14 @@ static HRESULT compile_assignment(compile_ctx_t *ctx, member_expression_t *membe static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat, BOOL is_set) { - return compile_assignment(ctx, stat->member_expr, stat->value_expr, is_set); + return compile_assignment(ctx, stat->left_expr, stat->value_expr, is_set); } static HRESULT compile_call_statement(compile_ctx_t *ctx, call_statement_t *stat) { HRESULT hres; - /* It's challenging for parser to distinguish parameterized assignment with one argument from call - * with equality expression argument, so we do it in compiler. */ - if(!stat->is_strict && stat->expr->args && !stat->expr->args->next && stat->expr->args->type == EXPR_EQUAL) { - binary_expression_t *eqexpr = (binary_expression_t*)stat->expr->args; - - if(eqexpr->left->type == EXPR_BRACKETS) { - member_expression_t new_member = *stat->expr; - - WARN("converting call expr to assign expr\n"); - - new_member.args = ((unary_expression_t*)eqexpr->left)->subexpr; - return compile_assignment(ctx, &new_member, eqexpr->right, FALSE); - } - } - - hres = compile_member_expression(ctx, stat->expr, FALSE); + hres = compile_call_expression(ctx, stat->expr, FALSE); if(FAILED(hres)) return hres; @@ -999,30 +1131,6 @@ static HRESULT compile_call_statement(compile_ctx_t *ctx, call_statement_t *stat return S_OK; } -static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name) -{ - dim_decl_t *dim_decl; - - for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) { - if(!wcsicmp(dim_decl->name, name)) - return TRUE; - } - - return FALSE; -} - -static BOOL lookup_args_name(compile_ctx_t *ctx, const WCHAR *name) -{ - unsigned i; - - for(i = 0; i < ctx->func->arg_cnt; i++) { - if(!wcsicmp(ctx->func->args[i].name, name)) - return TRUE; - } - - return FALSE; -} - static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat) { dim_decl_t *dim_decl = stat->dim_decls; @@ -1058,6 +1166,32 @@ static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat) return S_OK; } +static HRESULT compile_redim_statement(compile_ctx_t *ctx, redim_statement_t *stat) +{ + redim_decl_t *decl = stat->redim_decls; + unsigned arg_cnt; + HRESULT hres; + + while(1) { + hres = compile_args(ctx, decl->dims, &arg_cnt); + if(FAILED(hres)) + return hres; + + hres = push_instr_bstr_uint(ctx, stat->preserve ? OP_redim_preserve : OP_redim, decl->identifier, arg_cnt); + if(FAILED(hres)) + return hres; + + if(!emit_catch(ctx, 0)) + return E_OUTOFMEMORY; + + if(!decl->next) + break; + decl = decl->next; + } + + return S_OK; +} + static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *stat) { const_decl_t *decl, *next_decl = stat->decls; @@ -1233,6 +1367,8 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, } while(stat) { + ctx->loc = stat->loc; + switch(stat->type) { case STAT_ASSIGN: hres = compile_assign_statement(ctx, (assign_statement_t*)stat, FALSE); @@ -1280,6 +1416,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, case STAT_ONERROR: hres = compile_onerror_statement(ctx, (onerror_statement_t*)stat); break; + case STAT_REDIM: + hres = compile_redim_statement(ctx, (redim_statement_t*)stat); + break; case STAT_SELECT: hres = compile_select_statement(ctx, (select_statement_t*)stat); break; @@ -1294,6 +1433,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, case STAT_WHILELOOP: hres = compile_while_statement(ctx, (while_statement_t*)stat); break; + case STAT_WITH: + hres = compile_with_statement(ctx, (with_statement_t*)stat); + break; case STAT_RETVAL: hres = compile_retval_statement(ctx, (retval_statement_t*)stat); break; @@ -1376,7 +1518,6 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f case FUNC_PROPGET: case FUNC_PROPLET: case FUNC_PROPSET: - case FUNC_DEFGET: ctx->prop_end_label = alloc_label(ctx); if(!ctx->prop_end_label) return E_OUTOFMEMORY; @@ -1407,42 +1548,19 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f if(func->var_cnt) { dim_decl_t *dim_decl; + unsigned i; - if(func->type == FUNC_GLOBAL) { - dynamic_var_t *new_var; + func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t)); + if(!func->vars) + return E_OUTOFMEMORY; - func->var_cnt = 0; - - for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) { - new_var = compiler_alloc(ctx->code, sizeof(*new_var)); - if(!new_var) - return E_OUTOFMEMORY; - - new_var->name = compiler_alloc_string(ctx->code, dim_decl->name); - if(!new_var->name) - return E_OUTOFMEMORY; - - V_VT(&new_var->v) = VT_EMPTY; - new_var->is_const = FALSE; - - new_var->next = ctx->global_vars; - ctx->global_vars = new_var; - } - }else { - unsigned i; - - func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t)); - if(!func->vars) + for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) { + func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name); + if(!func->vars[i].name) return E_OUTOFMEMORY; - - for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) { - func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name); - if(!func->vars[i].name) - return E_OUTOFMEMORY; - } - - assert(i == func->var_cnt); } + + assert(i == func->var_cnt); } if(func->array_cnt) { @@ -1471,7 +1589,7 @@ static BOOL lookup_funcs_name(compile_ctx_t *ctx, const WCHAR *name) { function_t *iter; - for(iter = ctx->funcs; iter; iter = iter->next) { + for(iter = ctx->code->funcs; iter; iter = iter->next) { if(!wcsicmp(iter->name, name)) return TRUE; } @@ -1484,7 +1602,7 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi function_t *func; HRESULT hres; - if(lookup_dim_decls(ctx, decl->name) || lookup_funcs_name(ctx, decl->name) || lookup_const_decls(ctx, decl->name, FALSE)) { + if(lookup_dim_decls(ctx, decl->name) || lookup_const_decls(ctx, decl->name, FALSE)) { FIXME("%s: redefinition\n", debugstr_w(decl->name)); return E_FAIL; } @@ -1538,7 +1656,7 @@ static BOOL lookup_class_name(compile_ctx_t *ctx, const WCHAR *name) { class_desc_t *iter; - for(iter = ctx->classes; iter; iter = iter->next) { + for(iter = ctx->code->classes; iter; iter = iter->next) { if(!wcsicmp(iter->name, name)) return TRUE; } @@ -1561,7 +1679,6 @@ static HRESULT create_class_funcprop(compile_ctx_t *ctx, function_decl_t *func_d case FUNC_FUNCTION: case FUNC_SUB: case FUNC_PROPGET: - case FUNC_DEFGET: invoke_type = VBDISP_CALLGET; break; case FUNC_PROPLET: @@ -1601,14 +1718,12 @@ static BOOL lookup_class_funcs(class_desc_t *class_desc, const WCHAR *name) static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) { function_decl_t *func_decl, *func_prop_decl; + BOOL is_default, have_default = FALSE; class_desc_t *class_desc; dim_decl_t *prop_decl; unsigned i; HRESULT hres; - static const WCHAR class_initializeW[] = {'c','l','a','s','s','_','i','n','i','t','i','a','l','i','z','e',0}; - static const WCHAR class_terminateW[] = {'c','l','a','s','s','_','t','e','r','m','i','n','a','t','e',0}; - if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name) || lookup_const_decls(ctx, class_decl->name, FALSE) || lookup_class_name(ctx, class_decl->name)) { FIXME("%s: redefinition\n", debugstr_w(class_decl->name)); @@ -1623,14 +1738,21 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) if(!class_desc->name) return E_OUTOFMEMORY; - class_desc->func_cnt = 1; /* always allocate slot for default getter */ + class_desc->func_cnt = 1; /* always allocate slot for default getter or method */ for(func_decl = class_decl->funcs; func_decl; func_decl = func_decl->next) { + is_default = FALSE; for(func_prop_decl = func_decl; func_prop_decl; func_prop_decl = func_prop_decl->next_prop_func) { - if(func_prop_decl->type == FUNC_DEFGET) + if(func_prop_decl->is_default) { + if(have_default) { + FIXME("multiple default getters or methods\n"); + return E_FAIL; + } + is_default = have_default = TRUE; break; + } } - if(!func_prop_decl) + if(!is_default) class_desc->func_cnt++; } @@ -1641,20 +1763,20 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) for(func_decl = class_decl->funcs, i=1; func_decl; func_decl = func_decl->next, i++) { for(func_prop_decl = func_decl; func_prop_decl; func_prop_decl = func_prop_decl->next_prop_func) { - if(func_prop_decl->type == FUNC_DEFGET) { + if(func_prop_decl->is_default) { i--; break; } } - if(!wcsicmp(class_initializeW, func_decl->name)) { + if(!wcsicmp(L"class_initialize", func_decl->name)) { if(func_decl->type != FUNC_SUB) { FIXME("class initializer is not sub\n"); return E_FAIL; } class_desc->class_initialize_id = i; - }else if(!wcsicmp(class_terminateW, func_decl->name)) { + }else if(!wcsicmp(L"class_terminate", func_decl->name)) { if(func_decl->type != FUNC_SUB) { FIXME("class terminator is not sub\n"); return E_FAIL; @@ -1706,30 +1828,62 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) } } - class_desc->next = ctx->classes; - ctx->classes = class_desc; + class_desc->next = ctx->code->classes; + ctx->code->classes = class_desc; return S_OK; } -static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier) +static BOOL lookup_script_identifier(compile_ctx_t *ctx, script_ctx_t *script, const WCHAR *identifier) { + ScriptDisp *contexts[] = { + ctx->code->named_item ? ctx->code->named_item->script_obj : NULL, + script->script_obj + }; class_desc_t *class; - dynamic_var_t *var; - function_t *func; + vbscode_t *code; + unsigned c, i; - for(var = script->global_vars; var; var = var->next) { - if(!wcsicmp(var->name, identifier)) - return TRUE; + for(c = 0; c < ARRAY_SIZE(contexts); c++) { + if(!contexts[c]) continue; + + for(i = 0; i < contexts[c]->global_vars_cnt; i++) { + if(!wcsicmp(contexts[c]->global_vars[i]->name, identifier)) + return TRUE; + } + + for(i = 0; i < contexts[c]->global_funcs_cnt; i++) { + if(!wcsicmp(contexts[c]->global_funcs[i]->name, identifier)) + return TRUE; + } + + for(class = contexts[c]->classes; class; class = class->next) { + if(!wcsicmp(class->name, identifier)) + return TRUE; + } } - for(func = script->global_funcs; func; func = func->next) { - if(!wcsicmp(func->name, identifier)) - return TRUE; - } + LIST_FOR_EACH_ENTRY(code, &script->code_list, vbscode_t, entry) { + unsigned var_cnt = code->main_code.var_cnt; + var_desc_t *vars = code->main_code.vars; + function_t *func; - for(class = script->classes; class; class = class->next) { - if(!wcsicmp(class->name, identifier)) - return TRUE; + if(!code->pending_exec || (code->named_item && code->named_item != ctx->code->named_item)) + continue; + + for(i = 0; i < var_cnt; i++) { + if(!wcsicmp(vars[i].name, identifier)) + return TRUE; + } + + for(func = code->funcs; func; func = func->next) { + if(!wcsicmp(func->name, identifier)) + return TRUE; + } + + for(class = code->classes; class; class = class->next) { + if(!wcsicmp(class->name, identifier)) + return TRUE; + } } return FALSE; @@ -1737,26 +1891,19 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script) { + unsigned i, var_cnt = ctx->code->main_code.var_cnt; + var_desc_t *vars = ctx->code->main_code.vars; class_desc_t *class; - dynamic_var_t *var; - function_t *func; - for(var = ctx->global_vars; var; var = var->next) { - if(lookup_script_identifier(script, var->name)) { - FIXME("%s: redefined\n", debugstr_w(var->name)); + for(i = 0; i < var_cnt; i++) { + if(lookup_script_identifier(ctx, script, vars[i].name)) { + FIXME("%s: redefined\n", debugstr_w(vars[i].name)); return E_FAIL; } } - for(func = ctx->funcs; func; func = func->next) { - if(lookup_script_identifier(script, func->name)) { - FIXME("%s: redefined\n", debugstr_w(func->name)); - return E_FAIL; - } - } - - for(class = ctx->classes; class; class = class->next) { - if(lookup_script_identifier(script, class->name)) { + for(class = ctx->code->classes; class; class = class->next) { + if(lookup_script_identifier(ctx, script, class->name)) { FIXME("%s: redefined\n", debugstr_w(class->name)); return E_FAIL; } @@ -1769,36 +1916,49 @@ void release_vbscode(vbscode_t *code) { unsigned i; - list_remove(&code->entry); + if(--code->ref) + return; for(i=0; i < code->bstr_cnt; i++) SysFreeString(code->bstr_pool[i]); - if(code->context) - IDispatch_Release(code->context); + if(code->named_item) + release_named_item(code->named_item); heap_pool_free(&code->heap); - heap_free(code->bstr_pool); - heap_free(code->source); - heap_free(code->instrs); - heap_free(code); + free(code->bstr_pool); + free(code->source); + free(code->instrs); + free(code); } -static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source) +static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source, DWORD_PTR cookie, unsigned start_line) { vbscode_t *ret; + size_t len; - ret = heap_alloc_zero(sizeof(*ret)); + len = source ? lstrlenW(source) : 0; + if(len > INT32_MAX) + return NULL; + + ret = calloc(1, sizeof(*ret)); if(!ret) return NULL; - ret->source = heap_strdupW(source); + ret->source = malloc((len + 1) * sizeof(WCHAR)); if(!ret->source) { - heap_free(ret); + free(ret); return NULL; } + if(len) + memcpy(ret->source, source, len * sizeof(WCHAR)); + ret->source[len] = 0; - ret->instrs = heap_alloc(32*sizeof(instr_t)); + ret->ref = 1; + ret->cookie = cookie; + ret->start_line = start_line; + + ret->instrs = malloc(32*sizeof(instr_t)); if(!ret->instrs) { release_vbscode(ret); return NULL; @@ -1808,8 +1968,6 @@ static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source) ctx->instr_size = 32; heap_pool_init(&ret->heap); - ret->option_explicit = ctx->parser.option_explicit; - ret->main_code.type = FUNC_GLOBAL; ret->main_code.code_ctx = ret; @@ -1820,101 +1978,91 @@ static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source) static void release_compiler(compile_ctx_t *ctx) { parser_release(&ctx->parser); - heap_free(ctx->labels); + free(ctx->labels); if(ctx->code) release_vbscode(ctx->code); } -HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, DWORD flags, vbscode_t **ret) +HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item_name, const WCHAR *delimiter, + DWORD_PTR cookie, unsigned start_line, DWORD flags, vbscode_t **ret) { - function_t *new_func; function_decl_t *func_decl; + named_item_t *item = NULL; class_decl_t *class_decl; + function_t *new_func; compile_ctx_t ctx; vbscode_t *code; HRESULT hres; - if (!src) src = L""; + if(item_name) { + item = lookup_named_item(script, item_name, 0); + if(!item) { + WARN("Unknown context %s\n", debugstr_w(item_name)); + return E_INVALIDARG; + } + if(!item->script_obj) item = NULL; + } - hres = parse_script(&ctx.parser, src, delimiter, flags); - if(FAILED(hres)) - return compile_error(script, hres); - - code = ctx.code = alloc_vbscode(&ctx, src); + memset(&ctx, 0, sizeof(ctx)); + code = ctx.code = alloc_vbscode(&ctx, src, cookie, start_line); if(!ctx.code) - return compile_error(script, E_OUTOFMEMORY); + return E_OUTOFMEMORY; + if(item) { + code->named_item = item; + item->ref++; + } - ctx.funcs = NULL; - ctx.func_decls = NULL; - ctx.global_vars = NULL; - ctx.classes = NULL; - ctx.labels = NULL; - ctx.global_consts = NULL; - ctx.stat_ctx = NULL; - ctx.labels_cnt = ctx.labels_size = 0; + ctx.parser.lcid = script->lcid; + hres = parse_script(&ctx.parser, code->source, delimiter, flags); + if(FAILED(hres)) { + if(ctx.parser.error_loc != -1) + ctx.loc = ctx.parser.error_loc; + hres = compile_error(script, &ctx, hres); + release_vbscode(code); + return hres; + } hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->main_code); if(FAILED(hres)) { + hres = compile_error(script, &ctx, hres); release_compiler(&ctx); - return compile_error(script, hres); + return hres; } + code->option_explicit = ctx.parser.option_explicit; ctx.global_consts = ctx.const_decls; + code->option_explicit = ctx.parser.option_explicit; + for(func_decl = ctx.func_decls; func_decl; func_decl = func_decl->next) { hres = create_function(&ctx, func_decl, &new_func); if(FAILED(hres)) { + hres = compile_error(script, &ctx, hres); release_compiler(&ctx); - return compile_error(script, hres); + return hres; } - new_func->next = ctx.funcs; - ctx.funcs = new_func; + new_func->next = ctx.code->funcs; + ctx.code->funcs = new_func; } for(class_decl = ctx.parser.class_decls; class_decl; class_decl = class_decl->next) { hres = compile_class(&ctx, class_decl); if(FAILED(hres)) { + hres = compile_error(script, &ctx, hres); release_compiler(&ctx); - return compile_error(script, hres); + return hres; } } hres = check_script_collisions(&ctx, script); if(FAILED(hres)) { + hres = compile_error(script, &ctx, hres); release_compiler(&ctx); - return compile_error(script, hres); + return hres; } - if(ctx.global_vars) { - dynamic_var_t *var; - - for(var = ctx.global_vars; var->next; var = var->next); - - var->next = script->global_vars; - script->global_vars = ctx.global_vars; - } - - if(ctx.funcs) { - for(new_func = ctx.funcs; new_func->next; new_func = new_func->next); - - new_func->next = script->global_funcs; - script->global_funcs = ctx.funcs; - } - - if(ctx.classes) { - class_desc_t *class = ctx.classes; - - while(1) { - class->ctx = script; - if(!class->next) - break; - class = class->next; - } - - class->next = script->classes; - script->classes = ctx.classes; - } + code->is_persistent = (flags & SCRIPTTEXT_ISPERSISTENT) != 0; if(TRACE_ON(vbscript_disas)) dump_code(&ctx); @@ -1927,13 +2075,15 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli return S_OK; } -HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, DWORD flags, class_desc_t **ret) +HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *item_name, const WCHAR *delimiter, + DWORD_PTR cookie, unsigned start_line, DWORD flags, class_desc_t **ret) { class_desc_t *desc; vbscode_t *code; HRESULT hres; - hres = compile_script(script, src, delimiter, flags, &code); + hres = compile_script(script, src, item_name, delimiter, cookie, start_line, + flags & ~SCRIPTTEXT_ISPERSISTENT, &code); if(FAILED(hres)) return hres; @@ -1946,9 +2096,6 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *d desc->func_cnt = 1; desc->funcs->entries[VBDISP_CALLGET] = &code->main_code; - desc->next = script->procs; - script->procs = desc; - *ret = desc; return S_OK; } diff --git a/dll/win32/vbscript/global.c b/dll/win32/vbscript/global.c index db1f4c74405..ba8f4f23490 100644 --- a/dll/win32/vbscript/global.c +++ b/dll/win32/vbscript/global.c @@ -24,6 +24,7 @@ #include "mshtmhst.h" #include "objsafe.h" +#include "wchar.h" #include "wine/debug.h" @@ -41,9 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}}; -static const WCHAR emptyW[] = {0}; -static const WCHAR vbscriptW[] = {'V','B','S','c','r','i','p','t',0}; - #define BP_GET 1 #define BP_GETPUT 2 @@ -76,7 +74,8 @@ static HRESULT WINAPI Builtin_QueryInterface(IDispatch *iface, REFIID riid, void TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv); *ppv = &This->IDispatch_iface; }else { - WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + if(!IsEqualGUID(riid, &IID_IDispatchEx)) + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); *ppv = NULL; return E_NOINTERFACE; } @@ -90,7 +89,7 @@ static ULONG WINAPI Builtin_AddRef(IDispatch *iface) BuiltinDisp *This = impl_from_IDispatch(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -100,11 +99,11 @@ static ULONG WINAPI Builtin_Release(IDispatch *iface) BuiltinDisp *This = impl_from_IDispatch(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { assert(!This->ctx); - heap_free(This); + free(This); } return ref; @@ -121,7 +120,7 @@ static HRESULT WINAPI Builtin_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) static HRESULT WINAPI Builtin_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { BuiltinDisp *This = impl_from_IDispatch(iface); - TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); return DISP_E_BADINDEX; } @@ -154,7 +153,7 @@ static HRESULT WINAPI Builtin_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLE unsigned i; HRESULT hres; - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), names, name_cnt, lcid, ids); + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), names, name_cnt, lcid, ids); if(!This->ctx) { FIXME("NULL context\n"); @@ -175,10 +174,11 @@ static HRESULT WINAPI Builtin_Invoke(IDispatch *iface, DISPID id, REFIID riid, L { BuiltinDisp *This = impl_from_IDispatch(iface); const builtin_prop_t *prop; - VARIANT args[8]; + VARIANT args_buf[8], *args; unsigned argn, i; + HRESULT hres; - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, id, debugstr_guid(riid), lcid, flags, dp, res, ei, err); + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, id, debugstr_guid(riid), lcid, flags, dp, res, ei, err); if(!This->ctx) { FIXME("NULL context\n"); @@ -251,7 +251,13 @@ static HRESULT WINAPI Builtin_Invoke(IDispatch *iface, DISPID id, REFIID riid, L return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH); } - assert(argn < ARRAY_SIZE(args)); + if(argn <= ARRAY_SIZE(args_buf)) { + args = args_buf; + }else { + args = malloc(argn * sizeof(*args)); + if(!args) + return E_OUTOFMEMORY; + } for(i=0; i < argn; i++) { if(V_VT(dp->rgvarg+dp->cArgs-i-1) == (VT_BYREF|VT_VARIANT)) @@ -260,7 +266,10 @@ static HRESULT WINAPI Builtin_Invoke(IDispatch *iface, DISPID id, REFIID riid, L args[i] = dp->rgvarg[dp->cArgs-i-1]; } - return prop->proc(This, args, dp->cArgs, res); + hres = prop->proc(This, args, dp->cArgs, res); + if(args != args_buf) + free(args); + return hres; } static const IDispatchVtbl BuiltinDispVtbl = { @@ -277,7 +286,7 @@ static HRESULT create_builtin_dispatch(script_ctx_t *ctx, const builtin_prop_t * { BuiltinDisp *disp; - if(!(disp = heap_alloc(sizeof(*disp)))) + if(!(disp = malloc(sizeof(*disp)))) return E_OUTOFMEMORY; disp->IDispatch_iface.lpVtbl = &BuiltinDispVtbl; @@ -435,6 +444,20 @@ static HRESULT to_double(VARIANT *v, double *ret) return S_OK; } +static HRESULT to_float(VARIANT *v, float *ret) +{ + VARIANT dst; + HRESULT hres; + + V_VT(&dst) = VT_EMPTY; + hres = VariantChangeType(&dst, v, 0, VT_R4); + if(FAILED(hres)) + return hres; + + *ret = V_R4(&dst); + return S_OK; +} + static HRESULT to_string(VARIANT *v, BSTR *ret) { VARIANT dst; @@ -593,21 +616,21 @@ static HRESULT show_msgbox(script_ctx_t *ctx, BSTR prompt, unsigned type, BSTR o if(orig_title && *orig_title) { WCHAR *ptr; - title = title_buf = heap_alloc(sizeof(vbscriptW) + (lstrlenW(orig_title)+2)*sizeof(WCHAR)); + title = title_buf = malloc(sizeof(L"VBScript") + (lstrlenW(orig_title)+2)*sizeof(WCHAR)); if(!title) return E_OUTOFMEMORY; - memcpy(title_buf, vbscriptW, sizeof(vbscriptW)); - ptr = title_buf + ARRAY_SIZE(vbscriptW)-1; + memcpy(title_buf, L"VBScript", sizeof(L"VBScript")); + ptr = title_buf + ARRAY_SIZE(L"VBScript")-1; *ptr++ = ':'; *ptr++ = ' '; lstrcpyW(ptr, orig_title); }else { - title = vbscriptW; + title = L"VBScript"; } }else { - title = orig_title ? orig_title : emptyW; + title = orig_title ? orig_title : L""; } hres = IActiveScriptSiteWindow_GetWindow(acts_window, &hwnd); @@ -619,10 +642,10 @@ static HRESULT show_msgbox(script_ctx_t *ctx, BSTR prompt, unsigned type, BSTR o } } - heap_free(title_buf); + free(title_buf); IActiveScriptSiteWindow_Release(acts_window); if(FAILED(hres)) { - FIXME("failed: %08x\n", hres); + FIXME("failed: %08lx\n", hres); return hres; } @@ -738,8 +761,31 @@ static HRESULT Global_CByte(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, static HRESULT Global_CDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + VARIANT v; + HRESULT hres; + + TRACE("%s\n", debugstr_variant(arg)); + + assert(args_cnt == 1); + + if(V_VT(arg) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + V_VT(&v) = VT_EMPTY; + hres = VariantChangeType(&v, arg, 0, VT_DATE); + if(FAILED(hres)) { + hres = VariantChangeType(&v, arg, 0, VT_R8); + if(FAILED(hres)) + return hres; + hres = VariantChangeType(&v, &v, 0, VT_DATE); + if(FAILED(hres)) + return hres; + } + + if(!res) + return DISP_E_BADVARTYPE; + *res = v; + return S_OK; } static HRESULT Global_CDbl(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -821,9 +867,7 @@ static HRESULT Global_Hex(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA n = (WORD)V_I2(arg); break; case VT_NULL: - if(res) - V_VT(res) = VT_NULL; - return S_OK; + return return_null(res); default: hres = to_int(arg, &ret); if(FAILED(hres)) @@ -862,9 +906,7 @@ static HRESULT Global_Oct(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA n = (WORD)V_I2(arg); break; case VT_NULL: - if(res) - V_VT(res) = VT_NULL; - return S_OK; + return return_null(res); default: hres = to_int(arg, &ret); if(FAILED(hres)) @@ -908,8 +950,9 @@ static HRESULT Global_VarType(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt static HRESULT Global_IsDate(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + TRACE("%s\n", debugstr_variant(arg)); + + return return_bool(res, V_VT(arg) == VT_DATE); } static HRESULT Global_IsEmpty(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -917,12 +960,7 @@ static HRESULT Global_IsEmpty(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt TRACE("(%s)\n", debugstr_variant(arg)); assert(args_cnt == 1); - - if(res) { - V_VT(res) = VT_BOOL; - V_BOOL(res) = V_VT(arg) == VT_EMPTY ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; + return return_bool(res, V_VT(arg) == VT_EMPTY); } static HRESULT Global_IsNull(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -931,11 +969,7 @@ static HRESULT Global_IsNull(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, assert(args_cnt == 1); - if(res) { - V_VT(res) = VT_BOOL; - V_BOOL(res) = V_VT(arg) == VT_NULL ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; + return return_bool(res, V_VT(arg) == VT_NULL); } static HRESULT Global_IsNumeric(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -954,8 +988,11 @@ static HRESULT Global_IsNumeric(BuiltinDisp *This, VARIANT *arg, unsigned args_c static HRESULT Global_IsArray(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + TRACE("(%s)\n", debugstr_variant(arg)); + + assert(args_cnt == 1); + + return return_bool(res, V_ISARRAY(arg)); } static HRESULT Global_IsObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -964,11 +1001,7 @@ static HRESULT Global_IsObject(BuiltinDisp *This, VARIANT *arg, unsigned args_cn assert(args_cnt == 1); - if(res) { - V_VT(res) = VT_BOOL; - V_BOOL(res) = V_VT(arg) == VT_DISPATCH ? VARIANT_TRUE : VARIANT_FALSE; - } - return S_OK; + return return_bool(res, V_VT(arg) == VT_DISPATCH); } static HRESULT Global_Atn(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1061,16 +1094,70 @@ static HRESULT Global_Sqr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA return return_double(res, sqrt(d)); } +static unsigned int get_next_rnd(int value) +{ + return (value * 0x43fd43fd + 0xc39ec3) & 0xffffff; +} + static HRESULT Global_Randomize(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + union + { + double d; + unsigned int i[2]; + } dtoi; + unsigned int seed; + HRESULT hres; + + assert(args_cnt == 0 || args_cnt == 1); + if (args_cnt == 1) { + hres = to_double(arg, &dtoi.d); + if (FAILED(hres)) + return hres; + } + else + dtoi.d = GetTickCount() * 0.001; + + seed = dtoi.i[1]; + seed ^= (seed >> 16); + seed = ((seed & 0xffff) << 8) | (This->ctx->script_obj->rnd & 0xff); + This->ctx->script_obj->rnd = seed; + + return res ? DISP_E_TYPEMISMATCH : S_OK; } static HRESULT Global_Rnd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + static const float modulus = 16777216.0f; + unsigned int value; + HRESULT hres; + float f; + + assert(args_cnt == 0 || args_cnt == 1); + + value = This->ctx->script_obj->rnd; + if (args_cnt == 1) + { + hres = to_float(arg, &f); + if (FAILED(hres)) + return hres; + + if (f < 0.0f) + { + value = *(unsigned int *)&f; + This->ctx->script_obj->rnd = value = get_next_rnd(value + (value >> 24)); + } + else if (f == 0.0f) + value = This->ctx->script_obj->rnd; + else + This->ctx->script_obj->rnd = value = get_next_rnd(value); + } + else + { + This->ctx->script_obj->rnd = value = get_next_rnd(value); + } + + return return_float(res, (float)value / modulus); } static HRESULT Global_Timer(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1086,8 +1173,43 @@ static HRESULT Global_Timer(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, static HRESULT Global_LBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + SAFEARRAY *sa; + HRESULT hres; + LONG lbound; + int dim; + + assert(args_cnt == 1 || args_cnt == 2); + + TRACE("%s %s\n", debugstr_variant(arg), args_cnt == 2 ? debugstr_variant(arg + 1) : "1"); + + switch(V_VT(arg)) { + case VT_VARIANT|VT_ARRAY: + sa = V_ARRAY(arg); + break; + case VT_VARIANT|VT_ARRAY|VT_BYREF: + sa = *V_ARRAYREF(arg); + break; + case VT_EMPTY: + case VT_NULL: + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + default: + FIXME("arg %s not supported\n", debugstr_variant(arg)); + return E_NOTIMPL; + } + + if(args_cnt == 2) { + hres = to_int(arg + 1, &dim); + if(FAILED(hres)) + return hres; + }else { + dim = 1; + } + + hres = SafeArrayGetLBound(sa, dim, &lbound); + if(FAILED(hres)) + return hres; + + return return_int(res, lbound); } static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1108,6 +1230,9 @@ static HRESULT Global_UBound(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, case VT_VARIANT|VT_ARRAY|VT_BYREF: sa = *V_ARRAYREF(arg); break; + case VT_EMPTY: + case VT_NULL: + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); default: FIXME("arg %s not supported\n", debugstr_variant(arg)); return E_NOTIMPL; @@ -1234,7 +1359,20 @@ static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, TRACE("(%s %s)\n", debugstr_variant(args), debugstr_variant(args+1)); - if(V_VT(args+1) == VT_BSTR) { + if(V_VT(args+1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args+1, &len); + if(FAILED(hres)) + return hres; + + if(len < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + if(V_VT(args) == VT_NULL) + return return_null(res); + + if(V_VT(args) == VT_BSTR) { str = V_BSTR(args); }else { hres = to_string(args, &conv_str); @@ -1243,15 +1381,6 @@ static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, str = conv_str; } - hres = to_int(args+1, &len); - if(FAILED(hres)) - return hres; - - if(len < 0) { - FIXME("len = %d\n", len); - return E_FAIL; - } - str_len = SysStringLen(str); if(len > str_len) len = str_len; @@ -1273,35 +1402,52 @@ static HRESULT Global_RightB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { int len = -1, start, str_len; - BSTR str; + BSTR str, conv_str = NULL; HRESULT hres; TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1)); assert(args_cnt == 2 || args_cnt == 3); - if(V_VT(args) != VT_BSTR) { - FIXME("args[0] = %s\n", debugstr_variant(args)); - return E_NOTIMPL; - } + if(V_VT(args+1) == VT_NULL || (args_cnt == 3 && V_VT(args+2) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); - str = V_BSTR(args); + if(V_VT(args+1) == VT_EMPTY) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); hres = to_int(args+1, &start); if(FAILED(hres)) return hres; + if(start <= 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + if(args_cnt == 3) { + if(V_VT(args+2) == VT_EMPTY) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + hres = to_int(args+2, &len); if(FAILED(hres)) return hres; - if(len < 0) { - FIXME("len = %d\n", len); - return E_FAIL; - } + if(len < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); } + if(V_VT(args) == VT_EMPTY) + return return_string(res, L""); + + if(V_VT(args) == VT_NULL) + return return_null(res); + + if(V_VT(args) == VT_BSTR) { + str = V_BSTR(args); + }else { + hres = to_string(args, &conv_str); + if(FAILED(hres)) + return hres; + str = conv_str; + } str_len = SysStringLen(str); start--; @@ -1317,10 +1463,12 @@ static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, V V_VT(res) = VT_BSTR; V_BSTR(res) = SysAllocStringLen(str+start, len); if(!V_BSTR(res)) - return E_OUTOFMEMORY; + hres = E_OUTOFMEMORY; } - return S_OK; + SysFreeString(conv_str); + + return hres; } static HRESULT Global_MidB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1380,9 +1528,7 @@ static HRESULT Global_LCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, TRACE("%s\n", debugstr_variant(arg)); if(V_VT(arg) == VT_NULL) { - if(res) - V_VT(res) = VT_NULL; - return S_OK; + return return_null(res); } hres = to_string(arg, &str); @@ -1411,9 +1557,7 @@ static HRESULT Global_UCase(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, TRACE("%s\n", debugstr_variant(arg)); if(V_VT(arg) == VT_NULL) { - if(res) - V_VT(res) = VT_NULL; - return S_OK; + return return_null(res); } hres = to_string(arg, &str); @@ -1524,14 +1668,17 @@ static HRESULT Global_Space(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, TRACE("%s\n", debugstr_variant(arg)); + assert(args_cnt == 1); + + if(V_VT(arg) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + hres = to_int(arg, &n); if(FAILED(hres)) return hres; - if(n < 0) { - FIXME("n = %d\n", n); - return E_NOTIMPL; - } + if(n < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); if(!res) return S_OK; @@ -1548,20 +1695,47 @@ static HRESULT Global_Space(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, return S_OK; } -static HRESULT Global_String(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_String(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + WCHAR ch; + int cnt; + HRESULT hres; + + TRACE("%s %s\n", debugstr_variant(args), debugstr_variant(args + 1)); + + hres = to_int(args, &cnt); + if(FAILED(hres)) + return hres; + if(cnt < 0) + return E_INVALIDARG; + + if(V_VT(args + 1) != VT_BSTR) { + FIXME("Unsupported argument %s\n", debugstr_variant(args+1)); + return E_NOTIMPL; + } + if(!SysStringLen(V_BSTR(args + 1))) + return E_INVALIDARG; + ch = V_BSTR(args + 1)[0]; + + if(res) { + BSTR str = SysAllocStringLen(NULL, cnt); + if(!str) + return E_OUTOFMEMORY; + wmemset(str, ch, cnt); + V_VT(res) = VT_BSTR; + V_BSTR(res) = str; + } + return S_OK; } static HRESULT Global_InStr(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { VARIANT *startv, *str1v, *str2v; BSTR str1, str2; - int start, ret; + int ret = -1, start = 0, mode = 0; HRESULT hres; - TRACE("\n"); + TRACE("args_cnt=%u\n", args_cnt); assert(2 <= args_cnt && args_cnt <= 4); @@ -1577,48 +1751,67 @@ static HRESULT Global_InStr(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, str2v = args+2; break; case 4: - FIXME("unsupported compare argument %s\n", debugstr_variant(args)); - return E_NOTIMPL; + startv = args; + str1v = args+1; + str2v = args+2; + + if(V_VT(args+3) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args+3, &mode); + if(FAILED(hres)) + return hres; + + if (mode != 0 && mode != 1) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + break; DEFAULT_UNREACHABLE; } if(startv) { + if(V_VT(startv) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + hres = to_int(startv, &start); if(FAILED(hres)) return hres; - if(--start < 0) { - FIXME("start %d\n", start); - return E_FAIL; - } - }else { - start = 0; + if(--start < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); } if(V_VT(str1v) == VT_NULL || V_VT(str2v) == VT_NULL) return return_null(res); if(V_VT(str1v) != VT_BSTR) { - FIXME("Unsupported str1 type %s\n", debugstr_variant(str1v)); - return E_NOTIMPL; + hres = to_string(str1v, &str1); + if(FAILED(hres)) + return hres; } - str1 = V_BSTR(str1v); + else + str1 = V_BSTR(str1v); if(V_VT(str2v) != VT_BSTR) { - FIXME("Unsupported str2 type %s\n", debugstr_variant(str2v)); - return E_NOTIMPL; + hres = to_string(str2v, &str2); + if(FAILED(hres)){ + if(V_VT(str1v) != VT_BSTR) + SysFreeString(str1); + return hres; + } } - str2 = V_BSTR(str2v); + else + str2 = V_BSTR(str2v); if(start < SysStringLen(str1)) { - WCHAR *ptr; - - ptr = wcsstr(str1+start, str2); - ret = ptr ? ptr-str1+1 : 0; - }else { - ret = 0; + ret = FindStringOrdinal(FIND_FROMSTART, str1 + start, SysStringLen(str1)-start, + str2, SysStringLen(str2), mode); } - return return_int(res, ret); + if(V_VT(str1v) != VT_BSTR) + SysFreeString(str1); + if(V_VT(str2v) != VT_BSTR) + SysFreeString(str2); + return return_int(res, ++ret ? ret+start : 0); } static HRESULT Global_InStrB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1661,17 +1854,33 @@ static HRESULT Global_Asc(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA str = conv_str; } - if(!SysStringLen(str) || *str >= 0x100) + if(!SysStringLen(str)) hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); - else if(res) + else if (This->ctx->codepage == CP_UTF8) hres = return_short(res, *str); + else { + unsigned char buf[2]; + short val = 0; + int n = WideCharToMultiByte(This->ctx->codepage, 0, str, 1, (char*)buf, sizeof(buf), NULL, NULL); + switch(n) { + case 1: + val = buf[0]; + break; + case 2: + val = (buf[0] << 8) | buf[1]; + break; + default: + WARN("Failed to convert %x\n", *str); + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + if(SUCCEEDED(hres)) + hres = return_short(res, val); + } + SysFreeString(conv_str); return hres; } -/* The function supports only single-byte and double-byte character sets. It - * ignores language specified by IActiveScriptSite::GetLCID. The argument needs - * to be in range of short or unsigned short. */ static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { int cp, c, len = 0; @@ -1686,7 +1895,7 @@ static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA if(FAILED(hres)) return hres; - cp = GetACP(); + cp = This->ctx->codepage; if(!GetCPInfo(cp, &cpi)) cpi.MaxCharSize = 1; @@ -1696,13 +1905,20 @@ static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); } - if(c>>8) - buf[len++] = c>>8; - if(!len || IsDBCSLeadByteEx(cp, buf[0])) - buf[len++] = c; - if(!MultiByteToWideChar(CP_ACP, 0, buf, len, &ch, 1)) { - WARN("invalid arg %d, cp %d\n", c, cp); - return E_FAIL; + if (cp == CP_UTF8) + { + ch = c; + } + else + { + if(c>>8) + buf[len++] = c>>8; + if(!len || IsDBCSLeadByteEx(cp, buf[0])) + buf[len++] = c; + if(!MultiByteToWideChar(cp, 0, buf, len, &ch, 1)) { + WARN("invalid arg %d, cp %d\n", c, cp); + return E_FAIL; + } } if(res) { @@ -1880,10 +2096,50 @@ static HRESULT Global_Month(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, return FAILED(hres) ? hres : return_short(res, st.wMonth); } -static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Weekday(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + HRESULT hres = S_OK; + int first_day = 0; + SYSTEMTIME st; + + TRACE("(%s)\n", debugstr_variant(args)); + + assert(args_cnt == 1 || args_cnt == 2); + + /* [vbSunday = 1, vbSaturday = 7] -> wDayOfWeek [0, 6] */ + if (args_cnt == 2) + { + if (V_VT(args + 1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args + 1, &first_day); + if (SUCCEEDED(hres)) + { + if (!first_day) + { + /* vbUseSystemDayOfWeek */ + GetLocaleInfoW(This->ctx->lcid, LOCALE_RETURN_NUMBER | LOCALE_IFIRSTDAYOFWEEK, (LPWSTR)&first_day, + sizeof(first_day) / sizeof(WCHAR)); + first_day = (first_day + 1) % 7; + } + else if (first_day >= 1 && first_day <= 7) + { + first_day--; + } + else + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + } + + if (FAILED(hres)) + return hres; + + if (V_VT(args) == VT_NULL) + return return_null(res); + + if (FAILED(hres = to_system_time(args, &st))) return hres; + + return return_short(res, 1 + (7 - first_day + st.wDayOfWeek) % 7); } static HRESULT Global_Year(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -1930,6 +2186,12 @@ static HRESULT Global_Second(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, return FAILED(hres) ? hres : return_short(res, st.wSecond); } +static HRESULT Global_SetLocale(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) +{ + FIXME("\n"); + return E_NOTIMPL; +} + static HRESULT Global_DateValue(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { FIXME("\n"); @@ -1942,16 +2204,75 @@ static HRESULT Global_TimeValue(BuiltinDisp *This, VARIANT *arg, unsigned args_c return E_NOTIMPL; } -static HRESULT Global_DateSerial(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_DateSerial(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + int year, month, day; + UDATE ud = {{ 0 }}; + HRESULT hres; + double date; + + TRACE("\n"); + + assert(args_cnt == 3); + + if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL || V_VT(args + 2) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args, &year); + if (SUCCEEDED(hres)) + hres = to_int(args + 1, &month); + if (SUCCEEDED(hres)) + hres = to_int(args + 2, &day); + + if (SUCCEEDED(hres)) + { + ud.st.wYear = year; + ud.st.wMonth = month; + ud.st.wDay = day; + hres = VarDateFromUdateEx(&ud, 0, 0, &date); + } + + if (SUCCEEDED(hres)) + hres = return_date(res, date); + + return hres; } -static HRESULT Global_TimeSerial(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_TimeSerial(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + int hour, minute, second; + UDATE ud = {{ 0 }}; + HRESULT hres; + double date; + + TRACE("\n"); + + assert(args_cnt == 3); + + if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL || V_VT(args + 2) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args, &hour); + if (SUCCEEDED(hres)) + hres = to_int(args + 1, &minute); + if (SUCCEEDED(hres)) + hres = to_int(args + 2, &second); + + if (SUCCEEDED(hres)) + { + ud.st.wYear = 1899; + ud.st.wMonth = 12; + ud.st.wDay = 30; + ud.st.wHour = hour; + ud.st.wMinute = minute; + ud.st.wSecond = second; + hres = VarDateFromUdateEx(&ud, 0, 0, &date); + } + + if (SUCCEEDED(hres)) + hres = return_date(res, date); + + return hres; } static HRESULT Global_InputBox(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -2078,10 +2399,67 @@ static HRESULT Global_GetObject(BuiltinDisp *This, VARIANT *args, unsigned args_ return hres; } -static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR interval = NULL; + UDATE ud = {{ 0 }}; + HRESULT hres; + double date; + int count; + + TRACE("\n"); + + assert(args_cnt == 3); + + if (V_VT(args) == VT_NULL || V_VT(args + 1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if (V_VT(args + 2) == VT_NULL) + return return_null(res); + + hres = to_string(args, &interval); + if (SUCCEEDED(hres)) + hres = to_int(args + 1, &count); + if (SUCCEEDED(hres)) + hres = to_system_time(args + 2, &ud.st); + if (SUCCEEDED(hres)) + { + if (!wcsicmp(interval, L"yyyy")) + ud.st.wYear += count; + else if (!wcsicmp(interval, L"q")) + ud.st.wMonth += 3 * count; + else if (!wcsicmp(interval, L"m")) + ud.st.wMonth += count; + else if (!wcsicmp(interval, L"y") + || !wcsicmp(interval, L"d") + || !wcsicmp(interval, L"w")) + { + ud.st.wDay += count; + } + else if (!wcsicmp(interval, L"ww")) + ud.st.wDay += 7 * count; + else if (!wcsicmp(interval, L"h")) + ud.st.wHour += count; + else if (!wcsicmp(interval, L"n")) + ud.st.wMinute += count; + else if (!wcsicmp(interval, L"s")) + ud.st.wSecond += count; + else + { + WARN("Unrecognized interval %s.\n", debugstr_w(interval)); + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + } + + SysFreeString(interval); + + if (SUCCEEDED(hres)) + hres = VarDateFromUdateEx(&ud, 0, 0, &date); + + if (SUCCEEDED(hres)) + hres = return_date(res, date); + + return hres; } static HRESULT Global_DateDiff(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -2098,48 +2476,56 @@ static HRESULT Global_DatePart(BuiltinDisp *This, VARIANT *arg, unsigned args_cn static HRESULT Global_TypeName(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - static const WCHAR ByteW[] = {'B', 'y', 't', 'e', 0}; - static const WCHAR IntegerW[] = {'I', 'n', 't', 'e', 'g', 'e', 'r', 0}; - static const WCHAR LongW[] = {'L', 'o', 'n', 'g', 0}; - static const WCHAR SingleW[] = {'S', 'i', 'n', 'g', 'l', 'e', 0}; - static const WCHAR DoubleW[] = {'D', 'o', 'u', 'b', 'l', 'e', 0}; - static const WCHAR CurrencyW[] = {'C', 'u', 'r', 'r', 'e', 'n', 'c', 'y', 0}; - static const WCHAR DecimalW[] = {'D', 'e', 'c', 'i', 'm', 'a', 'l', 0}; - static const WCHAR DateW[] = {'D', 'a', 't', 'e', 0}; - static const WCHAR StringW[] = {'S', 't', 'r', 'i', 'n', 'g', 0}; - static const WCHAR BooleanW[] = {'B', 'o', 'o', 'l', 'e', 'a', 'n', 0}; - static const WCHAR EmptyW[] = {'E', 'm', 'p', 't', 'y', 0}; - static const WCHAR NullW[] = {'N', 'u', 'l', 'l', 0}; + ITypeInfo *typeinfo; + BSTR name = NULL; + HRESULT hres; TRACE("(%s)\n", debugstr_variant(arg)); assert(args_cnt == 1); + if (V_ISARRAY(arg)) + return return_string(res, L"Variant()"); + switch(V_VT(arg)) { case VT_UI1: - return return_string(res, ByteW); + return return_string(res, L"Byte"); case VT_I2: - return return_string(res, IntegerW); + return return_string(res, L"Integer"); case VT_I4: - return return_string(res, LongW); + return return_string(res, L"Long"); case VT_R4: - return return_string(res, SingleW); + return return_string(res, L"Single"); case VT_R8: - return return_string(res, DoubleW); + return return_string(res, L"Double"); case VT_CY: - return return_string(res, CurrencyW); + return return_string(res, L"Currency"); case VT_DECIMAL: - return return_string(res, DecimalW); + return return_string(res, L"Decimal"); case VT_DATE: - return return_string(res, DateW); + return return_string(res, L"Date"); case VT_BSTR: - return return_string(res, StringW); + return return_string(res, L"String"); case VT_BOOL: - return return_string(res, BooleanW); + return return_string(res, L"Boolean"); case VT_EMPTY: - return return_string(res, EmptyW); + return return_string(res, L"Empty"); case VT_NULL: - return return_string(res, NullW); + return return_string(res, L"Null"); + case VT_DISPATCH: + if (!V_DISPATCH(arg)) + return return_string(res, L"Nothing"); + if (SUCCEEDED(IDispatch_GetTypeInfo(V_DISPATCH(arg), 0, GetUserDefaultLCID(), &typeinfo))) + { + hres = ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &name, NULL, NULL, NULL); + ITypeInfo_Release(typeinfo); + + if (SUCCEEDED(hres) && name && *name) + return return_bstr(res, name); + + SysFreeString(name); + } + return return_string(res, L"Object"); default: FIXME("arg %s not supported\n", debugstr_variant(arg)); return E_NOTIMPL; @@ -2206,16 +2592,236 @@ static HRESULT Global_Join(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, V return E_NOTIMPL; } -static HRESULT Global_Split(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Split(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR string, delimiter = NULL; + int count, max, mode, len, start, end, ret, delimiterlen = 1; + int i, *indices = NULL, *new_indices, indices_max = 8; + SAFEARRAYBOUND bounds; + SAFEARRAY *sa = NULL; + VARIANT *data; + HRESULT hres = S_OK; + + TRACE("%s %u...\n", debugstr_variant(args), args_cnt); + + assert(1 <= args_cnt && args_cnt <= 4); + + if(V_VT(args) == VT_NULL || (args_cnt > 1 && V_VT(args+1) == VT_NULL) || (args_cnt > 2 && V_VT(args+2) == VT_NULL) + || (args_cnt == 4 && V_VT(args+3) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if(V_VT(args) != VT_BSTR) { + hres = to_string(args, &string); + if(FAILED(hres)) + return hres; + }else { + string = V_BSTR(args); + } + + if(args_cnt > 1) { + if(V_VT(args+1) != VT_BSTR) { + hres = to_string(args+1, &delimiter); + if(FAILED(hres)) + goto error; + }else { + delimiter = V_BSTR(args+1); + } + delimiterlen = SysStringLen(delimiter); + } + + if(args_cnt > 2) { + hres = to_int(args+2, &max); + if(FAILED(hres)) + goto error; + if (max < -1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + }else { + max = -1; + } + + if(args_cnt == 4) { + hres = to_int(args+3, &mode); + if(FAILED(hres)) + goto error; + if (mode != 0 && mode != 1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + }else { + mode = 0; + } + + start = 0; + + len = SysStringLen(string); + count = 0; + + indices = malloc( indices_max * sizeof(int)); + if(!indices) { + hres = E_OUTOFMEMORY; + goto error; + } + + while(1) { + ret = -1; + if (delimiterlen) { + ret = FindStringOrdinal(FIND_FROMSTART, string + start, len - start, + delimiter ? delimiter : L" ", delimiterlen, mode); + } + + if (ret == -1) { + end = len; + }else { + end = start + ret; + } + + if (count == indices_max) { + new_indices = realloc(indices, indices_max * 2 * sizeof(int)); + if(!new_indices) { + hres = E_OUTOFMEMORY; + goto error; + } + indices = new_indices; + indices_max *= 2; + } + indices[count++] = end; + + if (ret == -1 || count == max) break; + start = start + ret + delimiterlen; + if (start > len) break; + } + + bounds.lLbound = 0; + bounds.cElements = count; + sa = SafeArrayCreate( VT_VARIANT, 1, &bounds); + if (!sa) { + hres = E_OUTOFMEMORY; + goto error; + } + hres = SafeArrayAccessData(sa, (void**)&data); + if(FAILED(hres)) { + goto error; + } + + start = 0; + for (i = 0; i < count; i++) { + V_VT(&data[i]) = VT_BSTR; + V_BSTR(&data[i]) = SysAllocStringLen(string + start, indices[i] - start); + + if (!V_BSTR(&data[i])) { + hres = E_OUTOFMEMORY; + break; + } + start = indices[i]+delimiterlen; + } + SafeArrayUnaccessData(sa); + +error: + if(SUCCEEDED(hres) && res) { + V_VT(res) = VT_ARRAY|VT_VARIANT; + V_ARRAY(res) = sa; + }else { + SafeArrayDestroy(sa); + } + + free(indices); + if(V_VT(args) != VT_BSTR) + SysFreeString(string); + if(args_cnt > 1 && V_VT(args+1) != VT_BSTR) + SysFreeString(delimiter); + return hres; } -static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Replace(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR string, find = NULL, replace = NULL, ret; + int from = 1, cnt = -1, mode = 0; + HRESULT hres = S_OK; + + TRACE("%s %s %s %u...\n", debugstr_variant(args), debugstr_variant(args+1), debugstr_variant(args+2), args_cnt); + + assert(3 <= args_cnt && args_cnt <= 6); + + if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (V_VT(args+2) == VT_NULL) + || (args_cnt >= 4 && V_VT(args+3) == VT_NULL) || (args_cnt >= 5 && V_VT(args+4) == VT_NULL) + || (args_cnt == 6 && V_VT(args+5) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + + if(V_VT(args) != VT_BSTR) { + hres = to_string(args, &string); + if(FAILED(hres)) + return hres; + }else { + string = V_BSTR(args); + } + + if(V_VT(args+1) != VT_BSTR) { + hres = to_string(args+1, &find); + if(FAILED(hres)) + goto error; + }else { + find = V_BSTR(args+1); + } + + if(V_VT(args+2) != VT_BSTR) { + hres = to_string(args+2, &replace); + if(FAILED(hres)) + goto error; + }else { + replace = V_BSTR(args+2); + } + + if(args_cnt >= 4) { + hres = to_int(args+3, &from); + if(FAILED(hres)) + goto error; + if(from < 1) { + hres = E_INVALIDARG; + goto error; + } + } + + if(args_cnt >= 5) { + hres = to_int(args+4, &cnt); + if(FAILED(hres)) + goto error; + if(cnt < -1) { + hres = E_INVALIDARG; + goto error; + } + } + + if(args_cnt == 6) { + hres = to_int(args+5, &mode); + if(FAILED(hres)) + goto error; + if (mode != 0 && mode != 1) { + hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + goto error; + } + } + + ret = string_replace(string, find, replace, from - 1, cnt, mode); + if(!ret) { + hres = E_OUTOFMEMORY; + }else if(res) { + V_VT(res) = VT_BSTR; + V_BSTR(res) = ret; + }else { + SysFreeString(ret); + } + +error: + if(V_VT(args) != VT_BSTR) + SysFreeString(string); + if(V_VT(args+1) != VT_BSTR) + SysFreeString(find); + if(V_VT(args+2) != VT_BSTR) + SysFreeString(replace); + return hres; } static HRESULT Global_StrReverse(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -2243,61 +2849,80 @@ static HRESULT Global_StrReverse(BuiltinDisp *This, VARIANT *arg, unsigned args_ static HRESULT Global_InStrRev(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - int start, ret = 0; + int start = -1, ret = -1, mode = 0; BSTR str1, str2; + size_t len1, len2; HRESULT hres; TRACE("%s %s arg_cnt=%u\n", debugstr_variant(args), debugstr_variant(args+1), args_cnt); - if(args_cnt > 3) { - FIXME("Unsupported args\n"); - return E_NOTIMPL; - } - assert(2 <= args_cnt && args_cnt <= 4); - if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (args_cnt > 2 && V_VT(args+2) == VT_NULL)) + if(V_VT(args) == VT_NULL || V_VT(args+1) == VT_NULL || (args_cnt > 2 && V_VT(args+2) == VT_NULL) + || (args_cnt == 4 && V_VT(args+3) == VT_NULL)) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); - hres = to_string(args, &str1); - if(FAILED(hres)) - return hres; - - hres = to_string(args+1, &str2); - if(SUCCEEDED(hres)) { - if(args_cnt > 2) { - hres = to_int(args+2, &start); - if(SUCCEEDED(hres) && start <= 0) { - FIXME("Unsupported start %d\n", start); - hres = E_NOTIMPL; - } - }else { - start = SysStringLen(str1); - } - } else { - str2 = NULL; + if(args_cnt == 4) { + hres = to_int(args+3, &mode); + if(FAILED(hres)) + return hres; + if (mode != 0 && mode != 1) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); } - if(SUCCEEDED(hres)) { - const WCHAR *ptr; - size_t len; - - len = SysStringLen(str2); - if(start >= len && start <= SysStringLen(str1)) { - for(ptr = str1+start-SysStringLen(str2); ptr >= str1; ptr--) { - if(!memcmp(ptr, str2, len*sizeof(WCHAR))) { - ret = ptr-str1+1; - break; - } - } - } + if(args_cnt >= 3) { + hres = to_int(args+2, &start); + if(FAILED(hres)) + return hres; + if(!start || start < -1) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); } - SysFreeString(str1); - SysFreeString(str2); - if(FAILED(hres)) - return hres; + if(V_VT(args) != VT_BSTR) { + hres = to_string(args, &str1); + if(FAILED(hres)) + return hres; + } + else + str1 = V_BSTR(args); + if(V_VT(args+1) != VT_BSTR) { + hres = to_string(args+1, &str2); + if(FAILED(hres)) { + if(V_VT(args) != VT_BSTR) + SysFreeString(str1); + return hres; + } + } + else + str2 = V_BSTR(args+1); + + len1 = SysStringLen(str1); + if(!len1) { + ret = 0; + goto end; + } + + if(start == -1) + start = len1; + + len2 = SysStringLen(str2); + if(!len2) { + ret = start; + goto end; + } + + if(start >= len2 && start <= len1) { + ret = FindStringOrdinal(FIND_FROMEND, str1, start, + str2, len2, mode); + } + ret++; + +end: + if(V_VT(args) != VT_BSTR) + SysFreeString(str1); + if(V_VT(args+1) != VT_BSTR) + SysFreeString(str2); return return_int(res, ret); } @@ -2313,7 +2938,7 @@ static HRESULT Global_ScriptEngine(BuiltinDisp *This, VARIANT *arg, unsigned arg assert(args_cnt == 0); - return return_string(res, vbscriptW); + return return_string(res, L"VBScript"); } static HRESULT Global_ScriptEngineMajorVersion(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -2343,28 +2968,134 @@ static HRESULT Global_ScriptEngineBuildVersion(BuiltinDisp *This, VARIANT *arg, return return_int(res, VBSCRIPT_BUILD_VERSION); } -static HRESULT Global_FormatNumber(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_FormatNumber(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) +{ + union + { + struct + { + int num_dig, inc_lead, use_parens, group; + } s; + int val[4]; + } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 }; + HRESULT hres; + BSTR str; + int i; + + TRACE("\n"); + + assert(1 <= args_cnt && args_cnt <= 5); + + for (i = 1; i < args_cnt; ++i) + { + if (V_VT(args+i) == VT_ERROR) continue; + if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres; + } + + hres = VarFormatNumber(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens, + int_args.s.group, 0, &str); + if (FAILED(hres)) return hres; + + return return_bstr(res, str); +} + +static HRESULT Global_FormatCurrency(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) +{ + union + { + struct + { + int num_dig, inc_lead, use_parens, group; + } s; + int val[4]; + } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 }; + HRESULT hres; + BSTR str; + int i; + + TRACE("\n"); + + assert(1 <= args_cnt && args_cnt <= 5); + + for (i = 1; i < args_cnt; ++i) + { + if (V_VT(args+i) == VT_ERROR) continue; + if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres; + } + + hres = VarFormatCurrency(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens, + int_args.s.group, 0, &str); + if (FAILED(hres)) return hres; + + return return_bstr(res, str); +} + +static HRESULT Global_FormatPercent(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) +{ + union + { + struct + { + int num_dig, inc_lead, use_parens, group; + } s; + int val[4]; + } int_args = { .s.num_dig = -1, .s.inc_lead = -2, .s.use_parens = -2, .s.group = -2 }; + HRESULT hres; + BSTR str; + int i; + + TRACE("\n"); + + assert(1 <= args_cnt && args_cnt <= 5); + + for (i = 1; i < args_cnt; ++i) + { + if (V_VT(args+i) == VT_ERROR) continue; + if (V_VT(args+i) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + if (FAILED(hres = to_int(args+i, &int_args.val[i-1]))) return hres; + } + + hres = VarFormatPercent(args, int_args.s.num_dig, int_args.s.inc_lead, int_args.s.use_parens, + int_args.s.group, 0, &str); + if (FAILED(hres)) return hres; + + return return_bstr(res, str); +} + +static HRESULT Global_GetLocale(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { FIXME("\n"); return E_NOTIMPL; } -static HRESULT Global_FormatCurrency(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_FormatDateTime(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; -} + int format = 0; + HRESULT hres; + BSTR str; -static HRESULT Global_FormatPercent(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) -{ - FIXME("\n"); - return E_NOTIMPL; -} + TRACE("\n"); -static HRESULT Global_FormatDateTime(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) -{ - FIXME("\n"); - return E_NOTIMPL; + assert(1 <= args_cnt && args_cnt <= 2); + + if (V_VT(args) == VT_NULL) + return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); + + if (args_cnt == 2) + { + if (V_VT(args+1) == VT_NULL) return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + if (V_VT(args+1) != VT_ERROR) + { + if (FAILED(hres = to_int(args+1, &format))) return hres; + } + } + + hres = VarFormatDateTime(args, format, 0, &str); + if (FAILED(hres)) return hres; + + return return_bstr(res, str); } static HRESULT Global_WeekdayName(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) @@ -2410,6 +3141,9 @@ static HRESULT Global_MonthName(BuiltinDisp *This, VARIANT *args, unsigned args_ assert(args_cnt == 1 || args_cnt == 2); + if(V_VT(args) == VT_NULL || (args_cnt == 2 && V_VT(args+1) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + hres = to_int(args, &month); if(FAILED(hres)) return hres; @@ -2427,32 +3161,47 @@ static HRESULT Global_MonthName(BuiltinDisp *This, VARIANT *args, unsigned args_ return return_bstr(res, ret); } -static HRESULT Global_Round(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_Round(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - double n; + int decimal_places = 0; + double d; HRESULT hres; - TRACE("%s\n", debugstr_variant(arg)); + TRACE("%s %s\n", debugstr_variant(args), args_cnt == 2 ? debugstr_variant(args + 1) : "0"); + + assert(args_cnt == 1 || args_cnt == 2); if(!res) return S_OK; - switch(V_VT(arg)) { + if(args_cnt == 2) { + if (V_VT(args + 1) != VT_ERROR) { + hres = to_int(args + 1, &decimal_places); + if (FAILED(hres)) + return hres; + } + } + + switch(V_VT(args)) { case VT_I2: case VT_I4: case VT_BOOL: - *res = *arg; + *res = *args; return S_OK; case VT_R8: - n = V_R8(arg); + d = V_R8(args); break; default: - hres = to_double(arg, &n); + hres = to_double(args, &d); if(FAILED(hres)) return hres; } - return return_double(res, round(n)); + hres = VarR8Round(d, decimal_places, &d); + if(FAILED(hres)) + return hres; + + return return_double(res, d); } static HRESULT Global_Escape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) @@ -2558,6 +3307,7 @@ static const builtin_prop_t global_props[] = { {L"FormatDateTime", Global_FormatDateTime, 0, 1, 2}, {L"FormatNumber", Global_FormatNumber, 0, 1, 5}, {L"FormatPercent", Global_FormatPercent, 0, 1, 5}, + {L"GetLocale", Global_GetLocale, 0, 0}, {L"GetObject", Global_GetObject, 0, 0, 2}, {L"GetRef", Global_GetRef, 0, 1}, {L"Hex", Global_Hex, 0, 1}, @@ -2574,7 +3324,7 @@ static const builtin_prop_t global_props[] = { {L"IsNumeric", Global_IsNumeric, 0, 1}, {L"IsObject", Global_IsObject, 0, 1}, {L"Join", Global_Join, 0, 1, 2}, - {L"LBound", Global_LBound, 0, 1}, + {L"LBound", Global_LBound, 0, 1, 2}, {L"LCase", Global_LCase, 0, 1}, {L"Left", Global_Left, 0, 2}, {L"LeftB", Global_LeftB, 0, 2}, @@ -2591,12 +3341,12 @@ static const builtin_prop_t global_props[] = { {L"MsgBox", Global_MsgBox, 0, 1, 5}, {L"Now", Global_Now, 0, 0}, {L"Oct", Global_Oct, 0, 1}, - {L"Randomize", Global_Randomize, 0, 1}, + {L"Randomize", Global_Randomize, 0, 0, 1}, {L"Replace", Global_Replace, 0, 3, 6}, {L"RGB", Global_RGB, 0, 3}, {L"Right", Global_Right, 0, 2}, {L"RightB", Global_RightB, 0, 2}, - {L"Rnd", Global_Rnd, 0, 1}, + {L"Rnd", Global_Rnd, 0, 0, 1}, {L"Round", Global_Round, 0, 1, 2}, {L"RTrim", Global_RTrim, 0, 1}, {L"ScriptEngine", Global_ScriptEngine, 0, 0}, @@ -2604,6 +3354,7 @@ static const builtin_prop_t global_props[] = { {L"ScriptEngineMajorVersion", Global_ScriptEngineMajorVersion, 0, 0}, {L"ScriptEngineMinorVersion", Global_ScriptEngineMinorVersion, 0, 0}, {L"Second", Global_Second, 0, 1}, + {L"SetLocale", Global_SetLocale, 0, 0, 1}, {L"Sgn", Global_Sgn, 0, 1}, {L"Sin", Global_Sin, 0, 1}, {L"Space", Global_Space, 0, 1}, @@ -2787,14 +3538,14 @@ static HRESULT Err_Raise(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VA { BSTR source = NULL, description = NULL, helpfile = NULL; int code, helpcontext = 0; - HRESULT hres, error; + HRESULT hres; TRACE("%s %u...\n", debugstr_variant(args), args_cnt); hres = to_int(args, &code); if(FAILED(hres)) return hres; - if(code > 0 && code > 0xffff) + if(code == 0 || code > 0xffff) return E_INVALIDARG; if(args_cnt >= 2) @@ -2809,28 +3560,24 @@ static HRESULT Err_Raise(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VA if(SUCCEEDED(hres)) { script_ctx_t *ctx = This->ctx; - error = (code & ~0xffff) ? map_hres(code) : MAKE_VBSERROR(code); - if(source) { - if(ctx->ei.bstrSource) SysFreeString(ctx->ei.bstrSource); + SysFreeString(ctx->ei.bstrSource); ctx->ei.bstrSource = source; } - if(!ctx->ei.bstrSource) - ctx->ei.bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR); if(description) { - if(ctx->ei.bstrDescription) SysFreeString(ctx->ei.bstrDescription); + SysFreeString(ctx->ei.bstrDescription); ctx->ei.bstrDescription = description; } - if(!ctx->ei.bstrDescription) - ctx->ei.bstrDescription = get_vbscript_error_string(error); if(helpfile) { - if(ctx->ei.bstrHelpFile) SysFreeString(ctx->ei.bstrHelpFile); + SysFreeString(ctx->ei.bstrHelpFile); ctx->ei.bstrHelpFile = helpfile; } if(args_cnt >= 5) ctx->ei.dwHelpContext = helpcontext; - ctx->ei.scode = error; + ctx->ei.scode = (code & ~0xffff) ? code : MAKE_VBSERROR(code); + map_vbs_exception(&ctx->ei); + hres = SCRIPT_E_RECORDED; }else { SysFreeString(source); diff --git a/dll/win32/vbscript/guid.c b/dll/win32/vbscript/guid.c new file mode 100644 index 00000000000..63a8fd4f040 --- /dev/null +++ b/dll/win32/vbscript/guid.c @@ -0,0 +1,16 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS + +#include +#include +#include +#include +#include +#include +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/dll/win32/vbscript/interp.c b/dll/win32/vbscript/interp.c index 80ecc416998..937cdaf1c8c 100644 --- a/dll/win32/vbscript/interp.c +++ b/dll/win32/vbscript/interp.c @@ -31,7 +31,6 @@ typedef struct { instr_t *instr; script_ctx_t *script; function_t *func; - IDispatch *this_obj; vbdisp_t *vbthis; VARIANT *args; @@ -95,43 +94,74 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re return FALSE; } +static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref) +{ + dynamic_var_t **vars = script->global_vars; + size_t i, cnt = script->global_vars_cnt; + + for(i = 0; i < cnt; i++) { + if(!wcsicmp(vars[i]->name, name)) { + ref->type = vars[i]->is_const ? REF_CONST : REF_VAR; + ref->u.v = &vars[i]->v; + return TRUE; + } + } + + return FALSE; +} + +static BOOL lookup_global_funcs(ScriptDisp *script, const WCHAR *name, ref_t *ref) +{ + function_t **funcs = script->global_funcs; + size_t i, cnt = script->global_funcs_cnt; + + for(i = 0; i < cnt; i++) { + if(!wcsicmp(funcs[i]->name, name)) { + ref->type = REF_FUNC; + ref->u.f = funcs[i]; + return TRUE; + } + } + + return FALSE; +} + static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref) { + ScriptDisp *script_obj = ctx->script->script_obj; named_item_t *item; - function_t *func; - IDispatch *disp; unsigned i; DISPID id; HRESULT hres; - if(invoke_type == VBDISP_LET - && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET) - && !wcsicmp(name, ctx->func->name)) { + if(invoke_type != VBDISP_CALLGET + && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET) + && !wcsicmp(name, ctx->func->name)) { ref->type = REF_VAR; ref->u.v = &ctx->ret_val; return S_OK; } - for(i=0; i < ctx->func->var_cnt; i++) { - if(!wcsicmp(ctx->func->vars[i].name, name)) { - ref->type = REF_VAR; - ref->u.v = ctx->vars+i; - return TRUE; - } - } - - for(i=0; i < ctx->func->arg_cnt; i++) { - if(!wcsicmp(ctx->func->args[i].name, name)) { - ref->type = REF_VAR; - ref->u.v = ctx->args+i; - return S_OK; - } - } - - if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref)) - return S_OK; - if(ctx->func->type != FUNC_GLOBAL) { + for(i=0; i < ctx->func->var_cnt; i++) { + if(!wcsicmp(ctx->func->vars[i].name, name)) { + ref->type = REF_VAR; + ref->u.v = ctx->vars+i; + return S_OK; + } + } + + for(i=0; i < ctx->func->arg_cnt; i++) { + if(!wcsicmp(ctx->func->args[i].name, name)) { + ref->type = REF_VAR; + ref->u.v = ctx->args+i; + return S_OK; + } + } + + if(lookup_dynamic_vars(ctx->dynamic_vars, name, ref)) + return S_OK; + if(ctx->vbthis) { /* FIXME: Bind such identifier while generating bytecode. */ for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) { @@ -141,37 +171,40 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ return S_OK; } } - } - hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id); + hres = vbdisp_get_id(ctx->vbthis, name, invoke_type, TRUE, &id); + if(SUCCEEDED(hres)) { + ref->type = REF_DISP; + ref->u.d.disp = (IDispatch*)&ctx->vbthis->IDispatchEx_iface; + ref->u.d.id = id; + return S_OK; + } + } + } + + if(ctx->code->named_item) { + if(lookup_global_vars(ctx->code->named_item->script_obj, name, ref)) + return S_OK; + if(lookup_global_funcs(ctx->code->named_item->script_obj, name, ref)) + return S_OK; + } + + if(ctx->func->code_ctx->named_item && ctx->func->code_ctx->named_item->disp && + !(ctx->func->code_ctx->named_item->flags & SCRIPTITEM_CODEONLY)) + { + hres = disp_get_id(ctx->func->code_ctx->named_item->disp, name, invoke_type, TRUE, &id); if(SUCCEEDED(hres)) { ref->type = REF_DISP; - ref->u.d.disp = ctx->this_obj; + ref->u.d.disp = ctx->func->code_ctx->named_item->disp; ref->u.d.id = id; return S_OK; } } - if(ctx->func->code_ctx->context) { - hres = disp_get_id(ctx->func->code_ctx->context, name, invoke_type, TRUE, &id); - if(SUCCEEDED(hres)) { - ref->type = REF_DISP; - ref->u.d.disp = ctx->func->code_ctx->context; - ref->u.d.id = id; - return S_OK; - } - } - - if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref)) + if(lookup_global_vars(script_obj, name, ref)) + return S_OK; + if(lookup_global_funcs(script_obj, name, ref)) return S_OK; - - for(func = ctx->script->global_funcs; func; func = func->next) { - if(!wcsicmp(func->name, name)) { - ref->type = REF_FUNC; - ref->u.f = func; - return S_OK; - } - } hres = get_builtin_id(ctx->script->global_obj, name, &id); if(SUCCEEDED(hres)) { @@ -181,10 +214,10 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ return S_OK; } - disp = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE); - if(disp) { + item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE); + if(item && item->disp) { ref->type = REF_OBJ; - ref->u.obj = disp; + ref->u.obj = item->disp; return S_OK; } @@ -207,12 +240,13 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT **out_var) { + ScriptDisp *script_obj = ctx->code->named_item ? ctx->code->named_item->script_obj : ctx->script->script_obj; dynamic_var_t *new_var; heap_pool_t *heap; WCHAR *str; unsigned size; - heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap; + heap = ctx->func->type == FUNC_GLOBAL ? &script_obj->heap : &ctx->heap; new_var = heap_pool_alloc(heap, sizeof(*new_var)); if(!new_var) @@ -225,11 +259,23 @@ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, memcpy(str, name, size); new_var->name = str; new_var->is_const = is_const; + new_var->array = NULL; V_VT(&new_var->v) = VT_EMPTY; if(ctx->func->type == FUNC_GLOBAL) { - new_var->next = ctx->script->global_vars; - ctx->script->global_vars = new_var; + size_t cnt = script_obj->global_vars_cnt + 1; + if(cnt > script_obj->global_vars_size) { + dynamic_var_t **new_vars; + if(script_obj->global_vars) + new_vars = realloc(script_obj->global_vars, cnt * 2 * sizeof(*new_vars)); + else + new_vars = malloc(cnt * 2 * sizeof(*new_vars)); + if(!new_vars) + return E_OUTOFMEMORY; + script_obj->global_vars = new_vars; + script_obj->global_vars_size = cnt * 2; + } + script_obj->global_vars[script_obj->global_vars_cnt++] = new_var; }else { new_var->next = ctx->dynamic_vars; ctx->dynamic_vars = new_var; @@ -247,6 +293,14 @@ void clear_ei(EXCEPINFO *ei) memset(ei, 0, sizeof(*ei)); } +static void clear_error_loc(script_ctx_t *ctx) +{ + if(ctx->error_loc_code) { + release_vbscode(ctx->error_loc_code); + ctx->error_loc_code = NULL; + } +} + static inline VARIANT *stack_pop(exec_ctx_t *ctx) { assert(ctx->top); @@ -264,7 +318,7 @@ static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v) if(ctx->stack_size == ctx->top) { VARIANT *new_stack; - new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack)); + new_stack = realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack)); if(!new_stack) { VariantClear(v); return E_OUTOFMEMORY; @@ -359,35 +413,30 @@ static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n) return S_OK; } -static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b) +static HRESULT stack_pop_bool(exec_ctx_t *ctx, BOOL *b) { variant_val_t val; HRESULT hres; + VARIANT v; hres = stack_pop_val(ctx, &val); if(FAILED(hres)) return hres; - switch (V_VT(val.v)) + if (V_VT(val.v) == VT_NULL) { - case VT_BOOL: - *b = V_BOOL(val.v); - break; - case VT_NULL: *b = FALSE; - break; - case VT_I2: - *b = V_I2(val.v); - break; - case VT_I4: - *b = V_I4(val.v); - break; - default: - FIXME("unsupported for %s\n", debugstr_variant(val.v)); - release_val(&val); - return E_NOTIMPL; } - return S_OK; + else + { + V_VT(&v) = VT_EMPTY; + if (SUCCEEDED(hres = VariantChangeType(&v, val.v, VARIANT_LOCALBOOL, VT_BOOL))) + *b = !!V_BOOL(&v); + } + + release_val(&val); + + return hres; } static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret) @@ -421,22 +470,22 @@ static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp) { VARIANT *v = stack_top(ctx, n), *ref; - if(V_VT(v) != VT_DISPATCH) { + if(V_VT(v) != VT_DISPATCH && (disp || V_VT(v) != VT_UNKNOWN)) { if(V_VT(v) != (VT_VARIANT|VT_BYREF)) { FIXME("not supported type: %s\n", debugstr_variant(v)); return E_FAIL; } ref = V_VARIANTREF(v); - if(V_VT(ref) != VT_DISPATCH) { + if(V_VT(ref) != VT_DISPATCH && (disp || V_VT(ref) != VT_UNKNOWN)) { FIXME("not disp %s\n", debugstr_variant(ref)); return E_FAIL; } - V_VT(v) = VT_DISPATCH; - V_DISPATCH(v) = V_DISPATCH(ref); - if(V_DISPATCH(v)) - IDispatch_AddRef(V_DISPATCH(v)); + V_VT(v) = V_VT(ref); + V_UNKNOWN(v) = V_UNKNOWN(ref); + if(V_UNKNOWN(v)) + IUnknown_AddRef(V_UNKNOWN(v)); } if(disp) @@ -473,7 +522,7 @@ static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DI } } -static HRESULT array_access(exec_ctx_t *ctx, SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret) +HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret) { unsigned i, argc = arg_cnt(dp); LONG *indices; @@ -494,16 +543,16 @@ static HRESULT array_access(exec_ctx_t *ctx, SAFEARRAY *array, DISPPARAMS *dp, V return E_FAIL; } - indices = heap_alloc(sizeof(*indices) * argc); + indices = malloc(sizeof(*indices) * argc); if(!indices) { SafeArrayUnlock(array); return E_OUTOFMEMORY; } for(i=0; iscript, V_DISPATCH(v), DISPID_VALUE, &dp, res); + break; + default: + FIXME("unsupported on %s\n", debugstr_variant(v)); + return E_NOTIMPL; + } + + if(array) { + if(!res) { + FIXME("no res\n"); + return E_NOTIMPL; + } + + vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); + hres = array_access(array, &dp, &v); + if(FAILED(hres)) + return hres; + + V_VT(res) = VT_BYREF|VT_VARIANT; + V_BYREF(res) = v; + } + + stack_popn(ctx, arg_cnt); + return S_OK; +} + +static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res, BSTR identifier, unsigned arg_cnt) { - BSTR identifier = ctx->instr->arg1.bstr; - const unsigned arg_cnt = ctx->instr->arg2.uint; DISPPARAMS dp; ref_t ref; HRESULT hres; + TRACE("%s %u\n", debugstr_w(identifier), arg_cnt); + hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref); if(FAILED(hres)) return hres; switch(ref.type) { case REF_VAR: - case REF_CONST: { - VARIANT *v; + case REF_CONST: + if(arg_cnt) + return variant_call(ctx, ref.u.v, arg_cnt, res); if(!res) { FIXME("REF_VAR no res\n"); return E_NOTIMPL; } - v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v; - - if(arg_cnt) { - SAFEARRAY *array = NULL; - - switch(V_VT(v)) { - case VT_ARRAY|VT_BYREF|VT_VARIANT: - array = *V_ARRAYREF(ref.u.v); - break; - case VT_ARRAY|VT_VARIANT: - array = V_ARRAY(ref.u.v); - break; - case VT_DISPATCH: - vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); - hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res); - if(FAILED(hres)) - return hres; - break; - default: - FIXME("arguments not implemented\n"); - return E_NOTIMPL; - } - - if(!array) - break; - - vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); - hres = array_access(ctx, array, &dp, &v); - if(FAILED(hres)) - return hres; - } - V_VT(res) = VT_BYREF|VT_VARIANT; - V_BYREF(res) = v; + V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v; break; - } case REF_DISP: vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res); @@ -617,12 +680,14 @@ static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res) static HRESULT interp_icall(exec_ctx_t *ctx) { + BSTR identifier = ctx->instr->arg1.bstr; + const unsigned arg_cnt = ctx->instr->arg2.uint; VARIANT v; HRESULT hres; TRACE("\n"); - hres = do_icall(ctx, &v); + hres = do_icall(ctx, &v, identifier, arg_cnt); if(FAILED(hres)) return hres; @@ -631,8 +696,43 @@ static HRESULT interp_icall(exec_ctx_t *ctx) static HRESULT interp_icallv(exec_ctx_t *ctx) { + BSTR identifier = ctx->instr->arg1.bstr; + const unsigned arg_cnt = ctx->instr->arg2.uint; + TRACE("\n"); - return do_icall(ctx, NULL); + + return do_icall(ctx, NULL, identifier, arg_cnt); +} + +static HRESULT interp_vcall(exec_ctx_t *ctx) +{ + const unsigned arg_cnt = ctx->instr->arg1.uint; + VARIANT res, *v; + HRESULT hres; + + TRACE("\n"); + + v = stack_pop(ctx); + hres = variant_call(ctx, v, arg_cnt, &res); + VariantClear(v); + if(FAILED(hres)) + return hres; + + return stack_push(ctx, &res); +} + +static HRESULT interp_vcallv(exec_ctx_t *ctx) +{ + const unsigned arg_cnt = ctx->instr->arg1.uint; + VARIANT *v; + HRESULT hres; + + TRACE("\n"); + + v = stack_pop(ctx); + hres = variant_call(ctx, v, arg_cnt, NULL); + VariantClear(v); + return hres; } static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res) @@ -687,6 +787,28 @@ static HRESULT interp_mcallv(exec_ctx_t *ctx) return do_mcall(ctx, NULL); } +static HRESULT interp_ident(exec_ctx_t *ctx) +{ + BSTR identifier = ctx->instr->arg1.bstr; + VARIANT v; + HRESULT hres; + + TRACE("%s\n", debugstr_w(identifier)); + + if((ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET) + && !wcsicmp(identifier, ctx->func->name)) { + V_VT(&v) = VT_BYREF|VT_VARIANT; + V_BYREF(&v) = &ctx->ret_val; + return stack_push(ctx, &v); + } + + hres = do_icall(ctx, &v, identifier, 0); + if(FAILED(hres)) + return hres; + + return stack_push(ctx, &v); +} + static HRESULT assign_value(exec_ctx_t *ctx, VARIANT *dst, VARIANT *src, WORD flags) { VARIANT value; @@ -732,6 +854,11 @@ static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS * if(arg_cnt(dp)) { SAFEARRAY *array; + if(V_VT(v) == VT_DISPATCH) { + hres = disp_propput(ctx->script, V_DISPATCH(v), DISPID_VALUE, flags, dp); + break; + } + if(!(V_VT(v) & VT_ARRAY)) { FIXME("array assign on type %d\n", V_VT(v)); return E_FAIL; @@ -754,7 +881,7 @@ static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS * return E_FAIL; } - hres = array_access(ctx, array, dp, &v); + hres = array_access(array, dp, &v); if(FAILED(hres)) return hres; }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) { @@ -824,23 +951,18 @@ static HRESULT interp_set_ident(exec_ctx_t *ctx) DISPPARAMS dp; HRESULT hres; - TRACE("%s\n", debugstr_w(arg)); + TRACE("%s %u\n", debugstr_w(arg), arg_cnt); - if(arg_cnt) { - FIXME("arguments not supported\n"); - return E_NOTIMPL; - } - - hres = stack_assume_disp(ctx, 0, NULL); + hres = stack_assume_disp(ctx, arg_cnt, NULL); if(FAILED(hres)) return hres; - vbstack_to_dp(ctx, 0, TRUE, &dp); - hres = assign_ident(ctx, ctx->instr->arg1.bstr, DISPATCH_PROPERTYPUTREF, &dp); + vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); + hres = assign_ident(ctx, arg, DISPATCH_PROPERTYPUTREF, &dp); if(FAILED(hres)) return hres; - stack_popn(ctx, 1); + stack_popn(ctx, arg_cnt + 1); return S_OK; } @@ -887,12 +1009,7 @@ static HRESULT interp_set_member(exec_ctx_t *ctx) TRACE("%s\n", debugstr_w(identifier)); - if(arg_cnt) { - FIXME("arguments not supported\n"); - return E_NOTIMPL; - } - - hres = stack_assume_disp(ctx, 1, &obj); + hres = stack_assume_disp(ctx, arg_cnt+1, &obj); if(FAILED(hres)) return hres; @@ -901,7 +1018,7 @@ static HRESULT interp_set_member(exec_ctx_t *ctx) return E_FAIL; } - hres = stack_assume_disp(ctx, 0, NULL); + hres = stack_assume_disp(ctx, arg_cnt, NULL); if(FAILED(hres)) return hres; @@ -913,7 +1030,7 @@ static HRESULT interp_set_member(exec_ctx_t *ctx) if(FAILED(hres)) return hres; - stack_popn(ctx, 2); + stack_popn(ctx, arg_cnt+2); return S_OK; } @@ -971,6 +1088,37 @@ static HRESULT interp_val(exec_ctx_t *ctx) return stack_push(ctx, val.owned ? val.v : &v); } +static HRESULT interp_numval(exec_ctx_t *ctx) +{ + variant_val_t val; + VARIANT v; + HRESULT hres; + + TRACE("\n"); + + hres = stack_pop_val(ctx, &val); + if(FAILED(hres)) + return hres; + + if (V_VT(val.v) == VT_BSTR) { + V_VT(&v) = VT_EMPTY; + hres = VariantChangeType(&v, val.v, 0, VT_R8); + if(FAILED(hres)) + return hres; + release_val(&val); + return stack_push(ctx, &v); + } + + if(!val.owned) { + V_VT(&v) = VT_EMPTY; + hres = VariantCopy(&v, val.v); + if(FAILED(hres)) + return hres; + } + + return stack_push(ctx, val.owned ? val.v : &v); +} + static HRESULT interp_pop(exec_ctx_t *ctx) { const unsigned n = ctx->instr->arg1.uint; @@ -981,19 +1129,54 @@ static HRESULT interp_pop(exec_ctx_t *ctx) return S_OK; } +static HRESULT interp_stack(exec_ctx_t *ctx) +{ + const unsigned n = ctx->instr->arg1.uint; + VARIANT v; + HRESULT hres; + + TRACE("%#x\n", n); + + if(n == ~0) + return MAKE_VBSERROR(505); + assert(n < ctx->top); + + V_VT(&v) = VT_EMPTY; + hres = VariantCopy(&v, ctx->stack + n); + if(FAILED(hres)) + return hres; + + return stack_push(ctx, &v); +} + +static HRESULT interp_deref(exec_ctx_t *ctx) +{ + VARIANT copy, *v = stack_top(ctx, 0); + HRESULT hres; + + TRACE("%s\n", debugstr_variant(v)); + + if(V_VT(v) != (VT_BYREF|VT_VARIANT)) + return S_OK; + + V_VT(©) = VT_EMPTY; + hres = VariantCopy(©, V_VARIANTREF(v)); + if(SUCCEEDED(hres)) + *v = copy; + return hres; +} + static HRESULT interp_new(exec_ctx_t *ctx) { const WCHAR *arg = ctx->instr->arg1.bstr; - class_desc_t *class_desc; + class_desc_t *class_desc = NULL; vbdisp_t *obj; VARIANT v; HRESULT hres; - static const WCHAR regexpW[] = {'r','e','g','e','x','p',0}; - TRACE("%s\n", debugstr_w(arg)); - if(!wcsicmp(arg, regexpW)) { + if(!wcsicmp(arg, L"regexp")) { V_VT(&v) = VT_DISPATCH; hres = create_regexp(&V_DISPATCH(&v)); if(FAILED(hres)) @@ -1002,10 +1185,14 @@ static HRESULT interp_new(exec_ctx_t *ctx) return stack_push(ctx, &v); } - for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) { - if(!wcsicmp(class_desc->name, arg)) - break; - } + if(ctx->code->named_item) + for(class_desc = ctx->code->named_item->script_obj->classes; class_desc; class_desc = class_desc->next) + if(!wcsicmp(class_desc->name, arg)) + break; + if(!class_desc) + for(class_desc = ctx->script->script_obj->classes; class_desc; class_desc = class_desc->next) + if(!wcsicmp(class_desc->name, arg)) + break; if(!class_desc) { FIXME("Class %s not found\n", debugstr_w(arg)); return E_FAIL; @@ -1022,24 +1209,110 @@ static HRESULT interp_new(exec_ctx_t *ctx) static HRESULT interp_dim(exec_ctx_t *ctx) { + ScriptDisp *script_obj = ctx->code->named_item ? ctx->code->named_item->script_obj : ctx->script->script_obj; const BSTR ident = ctx->instr->arg1.bstr; const unsigned array_id = ctx->instr->arg2.uint; const array_desc_t *array_desc; - ref_t ref; + SAFEARRAY **array_ref; + VARIANT *v; HRESULT hres; TRACE("%s\n", debugstr_w(ident)); assert(array_id < ctx->func->array_cnt); - if(!ctx->arrays) { - ctx->arrays = heap_alloc_zero(ctx->func->array_cnt * sizeof(SAFEARRAY*)); - if(!ctx->arrays) - return E_OUTOFMEMORY; + + if(ctx->func->type == FUNC_GLOBAL) { + unsigned i; + for(i = 0; i < script_obj->global_vars_cnt; i++) { + if(!wcsicmp(script_obj->global_vars[i]->name, ident)) + break; + } + assert(i < script_obj->global_vars_cnt); + v = &script_obj->global_vars[i]->v; + array_ref = &script_obj->global_vars[i]->array; + }else { + ref_t ref; + + if(!ctx->arrays) { + ctx->arrays = calloc(ctx->func->array_cnt, sizeof(SAFEARRAY*)); + if(!ctx->arrays) + return E_OUTOFMEMORY; + } + + hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref); + if(FAILED(hres)) { + FIXME("lookup %s failed: %08lx\n", debugstr_w(ident), hres); + return hres; + } + + if(ref.type != REF_VAR) { + FIXME("got ref.type = %d\n", ref.type); + return E_FAIL; + } + + v = ref.u.v; + array_ref = ctx->arrays + array_id; } - hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref); + if(*array_ref) { + FIXME("Array already initialized\n"); + return E_FAIL; + } + + array_desc = ctx->func->array_descs + array_id; + if(array_desc->dim_cnt) { + *array_ref = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds); + if(!*array_ref) + return E_OUTOFMEMORY; + (*array_ref)->fFeatures |= (FADF_FIXEDSIZE | FADF_STATIC); + } + + V_VT(v) = VT_ARRAY|VT_BYREF|VT_VARIANT; + V_ARRAYREF(v) = array_ref; + return S_OK; +} + +static HRESULT array_bounds_from_stack(exec_ctx_t *ctx, unsigned dim_cnt, SAFEARRAYBOUND **ret) +{ + SAFEARRAYBOUND *bounds; + unsigned i; + int dim; + HRESULT hres; + + if(!(bounds = malloc(dim_cnt * sizeof(*bounds)))) + return E_OUTOFMEMORY; + + for(i = 0; i < dim_cnt; i++) { + hres = to_int(stack_top(ctx, dim_cnt - i - 1), &dim); + if(FAILED(hres)) { + free(bounds); + return hres; + } + + bounds[i].cElements = dim + 1; + bounds[i].lLbound = 0; + } + + stack_popn(ctx, dim_cnt); + *ret = bounds; + return S_OK; +} + +static HRESULT interp_redim(exec_ctx_t *ctx) +{ + BSTR identifier = ctx->instr->arg1.bstr; + const unsigned dim_cnt = ctx->instr->arg2.uint; + VARIANT *v; + SAFEARRAYBOUND *bounds; + SAFEARRAY *array; + ref_t ref; + HRESULT hres; + + TRACE("%s %u\n", debugstr_w(identifier), dim_cnt); + + hres = lookup_identifier(ctx, identifier, VBDISP_LET, &ref); if(FAILED(hres)) { - FIXME("lookup %s failed: %08x\n", debugstr_w(ident), hres); + FIXME("lookup %s failed: %08lx\n", debugstr_w(identifier), hres); return hres; } @@ -1048,21 +1321,103 @@ static HRESULT interp_dim(exec_ctx_t *ctx) return E_FAIL; } - if(ctx->arrays[array_id]) { - FIXME("Array already initialized\n"); + v = ref.u.v; + + if(V_VT(v) == (VT_VARIANT|VT_BYREF)) { + v = V_VARIANTREF(v); + } + + if(V_ISARRAY(v)) { + SAFEARRAY *sa = V_ISBYREF(v) ? *V_ARRAYREF(v) : V_ARRAY(v); + if(sa->fFeatures & FADF_FIXEDSIZE) + return MAKE_VBSERROR(VBSE_ARRAY_LOCKED); + } + + hres = array_bounds_from_stack(ctx, dim_cnt, &bounds); + if(FAILED(hres)) + return hres; + + array = SafeArrayCreate(VT_VARIANT, dim_cnt, bounds); + free(bounds); + if(!array) + return E_OUTOFMEMORY; + + VariantClear(v); + V_VT(v) = VT_ARRAY|VT_VARIANT; + V_ARRAY(v) = array; + + return S_OK; +} + +static HRESULT interp_redim_preserve(exec_ctx_t *ctx) +{ + BSTR identifier = ctx->instr->arg1.bstr; + const unsigned dim_cnt = ctx->instr->arg2.uint; + unsigned i; + VARIANT *v; + SAFEARRAYBOUND *bounds; + SAFEARRAY *array; + ref_t ref; + HRESULT hres; + + TRACE("%s %u\n", debugstr_w(identifier), dim_cnt); + + hres = lookup_identifier(ctx, identifier, VBDISP_LET, &ref); + if(FAILED(hres)) { + FIXME("lookup %s failed: %08lx\n", debugstr_w(identifier), hres); + return hres; + } + + if(ref.type != REF_VAR) { + FIXME("got ref.type = %d\n", ref.type); return E_FAIL; } - array_desc = ctx->func->array_descs + array_id; - if(array_desc->dim_cnt) { - ctx->arrays[array_id] = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds); - if(!ctx->arrays[array_id]) - return E_OUTOFMEMORY; + v = ref.u.v; + + if(V_VT(v) == (VT_VARIANT|VT_BYREF)) { + v = V_VARIANTREF(v); } - V_VT(ref.u.v) = VT_ARRAY|VT_BYREF|VT_VARIANT; - V_ARRAYREF(ref.u.v) = ctx->arrays+array_id; - return S_OK; + if(!(V_VT(v) & VT_ARRAY)) { + FIXME("ReDim Preserve not valid on type %d\n", V_VT(v)); + return E_FAIL; + } + + array = V_ISBYREF(v) ? *V_ARRAYREF(v) : V_ARRAY(v); + + hres = array_bounds_from_stack(ctx, dim_cnt, &bounds); + if(FAILED(hres)) + return hres; + + if(array == NULL || array->cDims == 0) { + /* can initially allocate the array */ + array = SafeArrayCreate(VT_VARIANT, dim_cnt, bounds); + if(!array) + hres = E_OUTOFMEMORY; + else { + VariantClear(v); + V_VT(v) = VT_ARRAY|VT_VARIANT; + V_ARRAY(v) = array; + } + } else if(array->cDims != dim_cnt) { + /* can't otherwise change the number of dimensions */ + TRACE("Can't resize %s, cDims %d != %d\n", debugstr_w(identifier), array->cDims, dim_cnt); + hres = MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + } else { + /* can resize the last dimensions (if others match */ + for(i = 0; i+1 < dim_cnt; ++i) { + if(array->rgsabound[array->cDims - 1 - i].cElements != bounds[i].cElements) { + TRACE("Can't resize %s, bound[%d] %ld != %ld\n", debugstr_w(identifier), i, array->rgsabound[i].cElements, bounds[i].cElements); + hres = MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); + break; + } + } + if(SUCCEEDED(hres)) + hres = SafeArrayRedim(array, &bounds[dim_cnt-1]); + } + free(bounds); + return hres; } static HRESULT interp_step(exec_ctx_t *ctx) @@ -1138,7 +1493,7 @@ static HRESULT interp_newenum(exec_ctx_t *ctx) hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter); IUnknown_Release(V_UNKNOWN(&iterv)); if(FAILED(hres)) { - FIXME("Could not get IEnumVARIANT iface: %08x\n", hres); + FIXME("Could not get IEnumVARIANT iface: %08lx\n", hres); return hres; } @@ -1150,7 +1505,7 @@ static HRESULT interp_newenum(exec_ctx_t *ctx) case VT_VARIANT|VT_ARRAY|VT_BYREF: { IEnumVARIANT *iter; - hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), &iter); + hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), v.owned && !V_ISBYREF(v.v), &iter); if(FAILED(hres)) return hres; @@ -1270,9 +1625,7 @@ static HRESULT interp_retval(exec_ctx_t *ctx) TRACE("\n"); - hres = stack_pop_val(ctx, &val); - if(FAILED(hres)) - return hres; + stack_pop_deref(ctx, &val); if(val.owned) { VariantClear(&ctx->ret_val); @@ -1297,13 +1650,32 @@ static HRESULT interp_stop(exec_ctx_t *ctx) static HRESULT interp_me(exec_ctx_t *ctx) { + IDispatch *disp; VARIANT v; TRACE("\n"); - IDispatch_AddRef(ctx->this_obj); + if(ctx->vbthis) { + disp = (IDispatch*)&ctx->vbthis->IDispatchEx_iface; + }else if(ctx->code->named_item) { + disp = (ctx->code->named_item->flags & SCRIPTITEM_CODEONLY) + ? (IDispatch*)&ctx->code->named_item->script_obj->IDispatchEx_iface + : ctx->code->named_item->disp; + }else { + named_item_t *item; + disp = NULL; + LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) { + if(!(item->flags & SCRIPTITEM_GLOBALMEMBERS)) continue; + disp = item->disp; + break; + } + if(!disp) + disp = (IDispatch*)&ctx->script->script_obj->IDispatchEx_iface; + } + + IDispatch_AddRef(disp); V_VT(&v) = VT_DISPATCH; - V_DISPATCH(&v) = ctx->this_obj; + V_DISPATCH(&v) = disp; return stack_push(ctx, &v); } @@ -1344,12 +1716,25 @@ static HRESULT interp_string(exec_ctx_t *ctx) return stack_push(ctx, &v); } +static HRESULT interp_date(exec_ctx_t *ctx) +{ + const DATE *d = ctx->instr->arg1.date; + VARIANT v; + + TRACE("%lf\n",*d); + + V_VT(&v) = VT_DATE; + V_DATE(&v) = *d; + + return stack_push(ctx, &v); +} + static HRESULT interp_int(exec_ctx_t *ctx) { const LONG arg = ctx->instr->arg1.lng; VARIANT v; - TRACE("%d\n", arg); + TRACE("%ld\n", arg); if(arg == (INT16)arg) { V_VT(&v) = VT_I2; @@ -1715,75 +2100,57 @@ static HRESULT interp_case(exec_ctx_t *ctx) return S_OK; } -static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret) -{ - IObjectIdentity *identity; - IUnknown *unk1, *unk2; - HRESULT hres; - - if(disp1 == disp2) { - *ret = VARIANT_TRUE; - return S_OK; - } - - if(!disp1 || !disp2) { - *ret = VARIANT_FALSE; - return S_OK; - } - - hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1); - if(FAILED(hres)) - return hres; - - hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2); - if(FAILED(hres)) { - IUnknown_Release(unk1); - return hres; - } - - if(unk1 == unk2) { - *ret = VARIANT_TRUE; - }else { - hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity); - if(SUCCEEDED(hres)) { - hres = IObjectIdentity_IsEqualObject(identity, unk2); - IObjectIdentity_Release(identity); - *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE; - }else { - *ret = VARIANT_FALSE; - } - } - - IUnknown_Release(unk1); - IUnknown_Release(unk2); - return S_OK; -} - static HRESULT interp_is(exec_ctx_t *ctx) { - IDispatch *l, *r; - VARIANT v; - HRESULT hres; + IUnknown *l = NULL, *r = NULL; + variant_val_t v; + HRESULT hres = S_OK; TRACE("\n"); - hres = stack_pop_disp(ctx, &r); + stack_pop_deref(ctx, &v); + if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) { + FIXME("Unhandled type %s\n", debugstr_variant(v.v)); + hres = E_NOTIMPL; + }else if(V_UNKNOWN(v.v)) { + hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&r); + } + if(v.owned) VariantClear(v.v); if(FAILED(hres)) return hres; - hres = stack_pop_disp(ctx, &l); + stack_pop_deref(ctx, &v); + if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) { + FIXME("Unhandled type %s\n", debugstr_variant(v.v)); + hres = E_NOTIMPL; + }else if(V_UNKNOWN(v.v)) { + hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&l); + } + if(v.owned) VariantClear(v.v); + if(SUCCEEDED(hres)) { - V_VT(&v) = VT_BOOL; - hres = disp_cmp(l, r, &V_BOOL(&v)); - if(l) - IDispatch_Release(l); + VARIANT res; + V_VT(&res) = VT_BOOL; + if(r == l) + V_BOOL(&res) = VARIANT_TRUE; + else if(!r || !l) + V_BOOL(&res) = VARIANT_FALSE; + else { + IObjectIdentity *identity; + hres = IUnknown_QueryInterface(l, &IID_IObjectIdentity, (void**)&identity); + if(SUCCEEDED(hres)) { + hres = IObjectIdentity_IsEqualObject(identity, r); + IObjectIdentity_Release(identity); + } + V_BOOL(&res) = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE; + } + hres = stack_push(ctx, &res); } if(r) - IDispatch_Release(r); - if(FAILED(hres)) - return hres; - - return stack_push(ctx, &v); + IUnknown_Release(r); + if(l) + IUnknown_Release(l); + return hres; } static HRESULT interp_concat(exec_ctx_t *ctx) @@ -2041,23 +2408,25 @@ OP_LIST #undef X }; -void release_dynamic_vars(dynamic_var_t *var) +void release_dynamic_var(dynamic_var_t *var) { - while(var) { - VariantClear(&var->v); - var = var->next; - } + VariantClear(&var->v); + if(var->array) + SafeArrayDestroy(var->array); } static void release_exec(exec_ctx_t *ctx) { + dynamic_var_t *var; unsigned i; VariantClear(&ctx->ret_val); - release_dynamic_vars(ctx->dynamic_vars); - if(ctx->this_obj) - IDispatch_Release(ctx->this_obj); + for(var = ctx->dynamic_vars; var; var = var->next) + release_dynamic_var(var); + + if(ctx->vbthis) + IDispatchEx_Release(&ctx->vbthis->IDispatchEx_iface); if(ctx->args) { for(i=0; i < ctx->func->arg_cnt; i++) @@ -2070,17 +2439,17 @@ static void release_exec(exec_ctx_t *ctx) } if(ctx->arrays) { - for(i=0; i < ctx->func->var_cnt; i++) { + for(i=0; i < ctx->func->array_cnt; i++) { if(ctx->arrays[i]) SafeArrayDestroy(ctx->arrays[i]); } - heap_free(ctx->arrays); + free(ctx->arrays); } heap_pool_free(&ctx->heap); - heap_free(ctx->args); - heap_free(ctx->vars); - heap_free(ctx->stack); + free(ctx->args); + free(ctx->vars); + free(ctx->stack); } HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res) @@ -2098,11 +2467,12 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd heap_pool_init(&exec.heap); + TRACE("%s args=%u\n", debugstr_w(func->name),func->arg_cnt); if(func->arg_cnt) { VARIANT *v; unsigned i; - exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT)); + exec.args = calloc(func->arg_cnt, sizeof(VARIANT)); if(!exec.args) { release_exec(&exec); return E_OUTOFMEMORY; @@ -2110,6 +2480,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd for(i=0; i < func->arg_cnt; i++) { v = get_arg(dp, i); + TRACE(" [%d] %s\n", i, debugstr_variant(v)); if(V_VT(v) == (VT_VARIANT|VT_BYREF)) { if(func->args[i].by_ref) exec.args[i] = *v; @@ -2128,7 +2499,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd } if(func->var_cnt) { - exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT)); + exec.vars = calloc(func->var_cnt, sizeof(VARIANT)); if(!exec.vars) { release_exec(&exec); return E_OUTOFMEMORY; @@ -2139,7 +2510,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd exec.stack_size = 16; exec.top = 0; - exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT)); + exec.stack = malloc(exec.stack_size * sizeof(VARIANT)); if(!exec.stack) { release_exec(&exec); return E_OUTOFMEMORY; @@ -2149,14 +2520,9 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd IActiveScriptSite_OnEnterScript(ctx->site); if(vbthis) { - exec.this_obj = (IDispatch*)&vbthis->IDispatchEx_iface; + IDispatchEx_AddRef(&vbthis->IDispatchEx_iface); exec.vbthis = vbthis; - }else if (ctx->host_global) { - exec.this_obj = ctx->host_global; - }else { - exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface; } - IDispatch_AddRef(exec.this_obj); exec.instr = exec.code->instrs + func->code_off; exec.script = ctx; @@ -2167,19 +2533,18 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd hres = op_funcs[op](&exec); if(FAILED(hres)) { if(hres != SCRIPT_E_RECORDED) { + /* SCRIPT_E_RECORDED means ctx->ei is already populated */ clear_ei(&ctx->ei); - - ctx->ei.scode = hres = map_hres(hres); - ctx->ei.bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR); - ctx->ei.bstrDescription = get_vbscript_error_string(hres); - }else { - hres = ctx->ei.scode; + ctx->ei.scode = hres; } + if(!ctx->ei.bstrDescription) + map_vbs_exception(&ctx->ei); + if(exec.resume_next) { unsigned stack_off; - WARN("Failed %08x in resume next mode\n", hres); + WARN("Failed %08lx in resume next mode\n", ctx->ei.scode); /* * Unwinding here is simple. We need to find the next OP_catch, which contains @@ -2191,6 +2556,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd TRACE("unwind jmp %d stack_off %d\n", exec.instr->arg1.uint, exec.instr->arg2.uint); + clear_error_loc(ctx); stack_off = exec.instr->arg2.uint; instr_jmp(&exec, exec.instr->arg1.uint); @@ -2209,7 +2575,11 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd continue; }else { - WARN("Failed %08x\n", hres); + if(!ctx->error_loc_code) { + grab_vbscode(exec.code); + ctx->error_loc_code = exec.code; + ctx->error_loc_offset = exec.instr->loc; + } stack_popn(&exec, exec.top); break; } @@ -2221,12 +2591,13 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd assert(!exec.top); if(extern_caller) { - IActiveScriptSite_OnLeaveScript(ctx->site); if(FAILED(hres)) { if(!ctx->ei.scode) ctx->ei.scode = hres; - hres = report_script_error(ctx); + hres = report_script_error(ctx, ctx->error_loc_code, ctx->error_loc_offset); + clear_error_loc(ctx); } + IActiveScriptSite_OnLeaveScript(ctx->site); } if(SUCCEEDED(hres) && res) { diff --git a/dll/win32/vbscript/lex.c b/dll/win32/vbscript/lex.c index 26b3d45a727..ae4c709da8e 100644 --- a/dll/win32/vbscript/lex.c +++ b/dll/win32/vbscript/lex.c @@ -32,125 +32,70 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); -static const WCHAR andW[] = {'a','n','d',0}; -static const WCHAR byrefW[] = {'b','y','r','e','f',0}; -static const WCHAR byvalW[] = {'b','y','v','a','l',0}; -static const WCHAR callW[] = {'c','a','l','l',0}; -static const WCHAR caseW[] = {'c','a','s','e',0}; -static const WCHAR classW[] = {'c','l','a','s','s',0}; -static const WCHAR constW[] = {'c','o','n','s','t',0}; -static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0}; -static const WCHAR dimW[] = {'d','i','m',0}; -static const WCHAR doW[] = {'d','o',0}; -static const WCHAR eachW[] = {'e','a','c','h',0}; -static const WCHAR elseW[] = {'e','l','s','e',0}; -static const WCHAR elseifW[] = {'e','l','s','e','i','f',0}; -static const WCHAR emptyW[] = {'e','m','p','t','y',0}; -static const WCHAR endW[] = {'e','n','d',0}; -static const WCHAR eqvW[] = {'e','q','v',0}; -static const WCHAR errorW[] = {'e','r','r','o','r',0}; -static const WCHAR exitW[] = {'e','x','i','t',0}; -static const WCHAR explicitW[] = {'e','x','p','l','i','c','i','t',0}; -static const WCHAR falseW[] = {'f','a','l','s','e',0}; -static const WCHAR forW[] = {'f','o','r',0}; -static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0}; -static const WCHAR getW[] = {'g','e','t',0}; -static const WCHAR gotoW[] = {'g','o','t','o',0}; -static const WCHAR ifW[] = {'i','f',0}; -static const WCHAR impW[] = {'i','m','p',0}; -static const WCHAR inW[] = {'i','n',0}; -static const WCHAR isW[] = {'i','s',0}; -static const WCHAR letW[] = {'l','e','t',0}; -static const WCHAR loopW[] = {'l','o','o','p',0}; -static const WCHAR meW[] = {'m','e',0}; -static const WCHAR modW[] = {'m','o','d',0}; -static const WCHAR newW[] = {'n','e','w',0}; -static const WCHAR nextW[] = {'n','e','x','t',0}; -static const WCHAR notW[] = {'n','o','t',0}; -static const WCHAR nothingW[] = {'n','o','t','h','i','n','g',0}; -static const WCHAR nullW[] = {'n','u','l','l',0}; -static const WCHAR onW[] = {'o','n',0}; -static const WCHAR optionW[] = {'o','p','t','i','o','n',0}; -static const WCHAR orW[] = {'o','r',0}; -static const WCHAR privateW[] = {'p','r','i','v','a','t','e',0}; -static const WCHAR propertyW[] = {'p','r','o','p','e','r','t','y',0}; -static const WCHAR publicW[] = {'p','u','b','l','i','c',0}; -static const WCHAR remW[] = {'r','e','m',0}; -static const WCHAR resumeW[] = {'r','e','s','u','m','e',0}; -static const WCHAR selectW[] = {'s','e','l','e','c','t',0}; -static const WCHAR setW[] = {'s','e','t',0}; -static const WCHAR stepW[] = {'s','t','e','p',0}; -static const WCHAR stopW[] = {'s','t','o','p',0}; -static const WCHAR subW[] = {'s','u','b',0}; -static const WCHAR thenW[] = {'t','h','e','n',0}; -static const WCHAR toW[] = {'t','o',0}; -static const WCHAR trueW[] = {'t','r','u','e',0}; -static const WCHAR untilW[] = {'u','n','t','i','l',0}; -static const WCHAR wendW[] = {'w','e','n','d',0}; -static const WCHAR whileW[] = {'w','h','i','l','e',0}; -static const WCHAR xorW[] = {'x','o','r',0}; - static const struct { const WCHAR *word; int token; } keywords[] = { - {andW, tAND}, - {byrefW, tBYREF}, - {byvalW, tBYVAL}, - {callW, tCALL}, - {caseW, tCASE}, - {classW, tCLASS}, - {constW, tCONST}, - {defaultW, tDEFAULT}, - {dimW, tDIM}, - {doW, tDO}, - {eachW, tEACH}, - {elseW, tELSE}, - {elseifW, tELSEIF}, - {emptyW, tEMPTY}, - {endW, tEND}, - {eqvW, tEQV}, - {errorW, tERROR}, - {exitW, tEXIT}, - {explicitW, tEXPLICIT}, - {falseW, tFALSE}, - {forW, tFOR}, - {functionW, tFUNCTION}, - {getW, tGET}, - {gotoW, tGOTO}, - {ifW, tIF}, - {impW, tIMP}, - {inW, tIN}, - {isW, tIS}, - {letW, tLET}, - {loopW, tLOOP}, - {meW, tME}, - {modW, tMOD}, - {newW, tNEW}, - {nextW, tNEXT}, - {notW, tNOT}, - {nothingW, tNOTHING}, - {nullW, tNULL}, - {onW, tON}, - {optionW, tOPTION}, - {orW, tOR}, - {privateW, tPRIVATE}, - {propertyW, tPROPERTY}, - {publicW, tPUBLIC}, - {remW, tREM}, - {resumeW, tRESUME}, - {selectW, tSELECT}, - {setW, tSET}, - {stepW, tSTEP}, - {stopW, tSTOP}, - {subW, tSUB}, - {thenW, tTHEN}, - {toW, tTO}, - {trueW, tTRUE}, - {untilW, tUNTIL}, - {wendW, tWEND}, - {whileW, tWHILE}, - {xorW, tXOR} + {L"and", tAND}, + {L"byref", tBYREF}, + {L"byval", tBYVAL}, + {L"call", tCALL}, + {L"case", tCASE}, + {L"class", tCLASS}, + {L"const", tCONST}, + {L"default", tDEFAULT}, + {L"dim", tDIM}, + {L"do", tDO}, + {L"each", tEACH}, + {L"else", tELSE}, + {L"elseif", tELSEIF}, + {L"empty", tEMPTY}, + {L"end", tEND}, + {L"eqv", tEQV}, + {L"error", tERROR}, + {L"exit", tEXIT}, + {L"explicit", tEXPLICIT}, + {L"false", tFALSE}, + {L"for", tFOR}, + {L"function", tFUNCTION}, + {L"get", tGET}, + {L"goto", tGOTO}, + {L"if", tIF}, + {L"imp", tIMP}, + {L"in", tIN}, + {L"is", tIS}, + {L"let", tLET}, + {L"loop", tLOOP}, + {L"me", tME}, + {L"mod", tMOD}, + {L"new", tNEW}, + {L"next", tNEXT}, + {L"not", tNOT}, + {L"nothing", tNOTHING}, + {L"null", tNULL}, + {L"on", tON}, + {L"option", tOPTION}, + {L"or", tOR}, + {L"preserve", tPRESERVE}, + {L"private", tPRIVATE}, + {L"property", tPROPERTY}, + {L"public", tPUBLIC}, + {L"redim", tREDIM}, + {L"rem", tREM}, + {L"resume", tRESUME}, + {L"select", tSELECT}, + {L"set", tSET}, + {L"step", tSTEP}, + {L"stop", tSTOP}, + {L"sub", tSUB}, + {L"then", tTHEN}, + {L"to", tTO}, + {L"true", tTRUE}, + {L"until", tUNTIL}, + {L"wend", tWEND}, + {L"while", tWHILE}, + {L"with", tWITH}, + {L"xor", tXOR} }; static inline BOOL is_identifier_char(WCHAR c) @@ -263,6 +208,48 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret) return tString; } +static int parse_date_literal(parser_ctx_t *ctx, DATE *ret) +{ + const WCHAR *ptr = ++ctx->ptr; + WCHAR *rptr; + int len = 0; + HRESULT res; + + while(ctx->ptr < ctx->end) { + if(*ctx->ptr == '\n' || *ctx->ptr == '\r') { + FIXME("newline inside date literal\n"); + return 0; + } + + if(*ctx->ptr == '#') + break; + ctx->ptr++; + } + + if(ctx->ptr == ctx->end) { + FIXME("unterminated date literal\n"); + return 0; + } + + len += ctx->ptr-ptr; + + rptr = malloc((len+1)*sizeof(WCHAR)); + if(!rptr) + return 0; + + memcpy( rptr, ptr, len * sizeof(WCHAR)); + rptr[len] = 0; + res = VarDateFromStr(rptr, ctx->lcid, 0, ret); + free(rptr); + if (FAILED(res)) { + FIXME("Invalid date literal\n"); + return 0; + } + + ctx->ptr++; + return tDate; +} + static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) { BOOL use_int = TRUE; @@ -273,7 +260,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) if(*ctx->ptr == '0' && !('0' <= ctx->ptr[1] && ctx->ptr[1] <= '9') && ctx->ptr[1] != '.') return *ctx->ptr++; - while(ctx->ptr < ctx->end && iswdigit(*ctx->ptr)) { + while(ctx->ptr < ctx->end && is_digit(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) { exp++; @@ -282,7 +269,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) else d = hlp; } - while(ctx->ptr < ctx->end && iswdigit(*ctx->ptr)) { + while(ctx->ptr < ctx->end && is_digit(*ctx->ptr)) { exp++; ctx->ptr++; } @@ -291,7 +278,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) use_int = FALSE; ctx->ptr++; - while(ctx->ptr < ctx->end && iswdigit(*ctx->ptr)) { + while(ctx->ptr < ctx->end && is_digit(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) break; @@ -299,7 +286,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) d = hlp; exp--; } - while(ctx->ptr < ctx->end && iswdigit(*ctx->ptr)) + while(ctx->ptr < ctx->end && is_digit(*ctx->ptr)) ctx->ptr++; } @@ -314,7 +301,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) ctx->ptr++; } - if(!iswdigit(*ctx->ptr)) { + if(!is_digit(*ctx->ptr)) { FIXME("Invalid numeric literal\n"); return 0; } @@ -325,7 +312,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) e = e*10 + *(ctx->ptr++) - '0'; if(sign == -1 && -e+exp < -(INT_MAX/100)) { /* The literal will be rounded to 0 anyway. */ - while(iswdigit(*ctx->ptr)) + while(is_digit(*ctx->ptr)) ctx->ptr++; *(double*)ret = 0; return tDouble; @@ -335,7 +322,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) FIXME("Invalid numeric literal\n"); return 0; } - } while(iswdigit(*ctx->ptr)); + } while(is_digit(*ctx->ptr)); exp += sign*e; } @@ -369,20 +356,22 @@ static int hex_to_int(WCHAR c) static int parse_hex_literal(parser_ctx_t *ctx, LONG *ret) { const WCHAR *begin = ctx->ptr; - LONG l = 0, d; + unsigned l = 0, d; while((d = hex_to_int(*++ctx->ptr)) != -1) l = l*16 + d; - if(begin + 9 /* max digits+1 */ < ctx->ptr || (*ctx->ptr != '&' && is_identifier_char(*ctx->ptr))) { + if(begin + 9 /* max digits+1 */ < ctx->ptr) { FIXME("invalid literal\n"); return 0; } - if(*ctx->ptr == '&') + if(*ctx->ptr == '&') { ctx->ptr++; - - *ret = l; + *ret = l; + }else { + *ret = l == (UINT16)l ? (INT16)l : l; + } return tInt; } @@ -394,8 +383,7 @@ static void skip_spaces(parser_ctx_t *ctx) static int comment_line(parser_ctx_t *ctx) { - static const WCHAR newlineW[] = {'\n','\r',0}; - ctx->ptr = wcspbrk(ctx->ptr, newlineW); + ctx->ptr = wcspbrk(ctx->ptr, L"\n\r"); if(ctx->ptr) ctx->ptr++; else @@ -403,13 +391,14 @@ static int comment_line(parser_ctx_t *ctx) return tNL; } -static int parse_next_token(void *lval, parser_ctx_t *ctx) +static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) { WCHAR c; skip_spaces(ctx); + *loc = ctx->ptr - ctx->code; if(ctx->ptr == ctx->end) - return ctx->last_token == tNL ? tEOF : tNL; + return ctx->last_token == tNL ? 0 : tNL; c = *ctx->ptr; @@ -417,7 +406,9 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx) return parse_numeric_literal(ctx, lval); if(iswalpha(c)) { - int ret = check_keywords(ctx, lval); + int ret = 0; + if(ctx->last_token != '.' && ctx->last_token != tDOT) + ret = check_keywords(ctx, lval); if(!ret) return parse_identifier(ctx, lval); if(ret != tREM) @@ -435,15 +426,29 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx) case ':': case ')': case ',': - case '=': case '+': case '*': case '/': case '^': case '\\': - case '.': case '_': return *ctx->ptr++; + case '.': + /* + * We need to distinguish between '.' used as part of a member expression and + * a beginning of a dot expression (a member expression accessing with statement + * expression) and a floating point number like ".2" . + */ + c = ctx->ptr > ctx->code ? ctx->ptr[-1] : '\n'; + if (is_identifier_char(c) || c == ')') { + ctx->ptr++; + return '.'; + } + c = ctx->ptr[1]; + if('0' <= c && c <= '9') + return parse_numeric_literal(ctx, lval); + ctx->ptr++; + return tDOT; case '-': if(ctx->is_html && ctx->ptr[1] == '-' && ctx->ptr[2] == '>') return comment_line(ctx); @@ -460,13 +465,31 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx) ctx->ptr++; return tEMPTYBRACKETS; } - return '('; + /* + * Parser can't predict if bracket is part of argument expression or an argument + * in call expression. We predict it here instead. + */ + if(ctx->last_token == tIdentifier || ctx->last_token == ')') + return '('; + return tEXPRLBRACKET; case '"': return parse_string_literal(ctx, lval); + case '#': + return parse_date_literal(ctx, lval); case '&': - if(*++ctx->ptr == 'h' || *ctx->ptr == 'H') + if((*++ctx->ptr == 'h' || *ctx->ptr == 'H') && hex_to_int(ctx->ptr[1]) != -1) return parse_hex_literal(ctx, lval); return '&'; + case '=': + switch(*++ctx->ptr) { + case '<': + ctx->ptr++; + return tLTEQ; + case '>': + ctx->ptr++; + return tGTEQ; + } + return '='; case '<': switch(*++ctx->ptr) { case '>': @@ -481,9 +504,13 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx) } return '<'; case '>': - if(*++ctx->ptr == '=') { + switch(*++ctx->ptr) { + case '=': ctx->ptr++; return tGTEQ; + case '<': + ctx->ptr++; + return tNEQ; } return '>'; default: @@ -493,7 +520,7 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx) return 0; } -int parser_lex(void *lval, parser_ctx_t *ctx) +int parser_lex(void *lval, unsigned *loc, parser_ctx_t *ctx) { int ret; @@ -504,7 +531,7 @@ int parser_lex(void *lval, parser_ctx_t *ctx) } while(1) { - ret = parse_next_token(lval, ctx); + ret = parse_next_token(lval, loc, ctx); if(ret == '_') { skip_spaces(ctx); if(*ctx->ptr != '\n' && *ctx->ptr != '\r') { diff --git a/dll/win32/vbscript/parse.h b/dll/win32/vbscript/parse.h index 6e5188c8c5e..1a2bd03ee94 100644 --- a/dll/win32/vbscript/parse.h +++ b/dll/win32/vbscript/parse.h @@ -23,8 +23,11 @@ typedef enum { EXPR_AND, EXPR_BOOL, EXPR_BRACKETS, + EXPR_CALL, EXPR_CONCAT, + EXPR_DATE, EXPR_DIV, + EXPR_DOT, EXPR_DOUBLE, EXPR_EMPTY, EXPR_EQUAL, @@ -70,6 +73,11 @@ typedef struct { LONG value; } int_expression_t; +typedef struct { + expression_t expr; + DATE value; +} date_expression_t; + typedef struct { expression_t expr; double value; @@ -95,9 +103,14 @@ typedef struct { expression_t expr; expression_t *obj_expr; const WCHAR *identifier; - expression_t *args; } member_expression_t; +typedef struct { + expression_t expr; + expression_t *call_expr; + expression_t *args; +} call_expression_t; + typedef enum { STAT_ASSIGN, STAT_CALL, @@ -115,29 +128,31 @@ typedef enum { STAT_FUNC, STAT_IF, STAT_ONERROR, + STAT_REDIM, STAT_SELECT, STAT_SET, STAT_STOP, STAT_UNTIL, STAT_WHILE, STAT_WHILELOOP, + STAT_WITH, STAT_RETVAL } statement_type_t; typedef struct _statement_t { statement_type_t type; + unsigned loc; struct _statement_t *next; } statement_t; typedef struct { statement_t stat; - member_expression_t *expr; - BOOL is_strict; + call_expression_t *expr; } call_statement_t; typedef struct { statement_t stat; - member_expression_t *member_expr; + expression_t *left_expr; expression_t *value_expr; } assign_statement_t; @@ -159,6 +174,18 @@ typedef struct _dim_statement_t { dim_decl_t *dim_decls; } dim_statement_t; +typedef struct _redim_decl_t { + const WCHAR *identifier; + expression_t *dims; + struct _redim_decl_t *next; +} redim_decl_t; + +typedef struct { + statement_t stat; + BOOL preserve; + redim_decl_t *redim_decls; +} redim_statement_t; + typedef struct _arg_decl_t { const WCHAR *name; BOOL by_ref; @@ -169,6 +196,7 @@ typedef struct _function_decl_t { const WCHAR *name; function_type_t type; BOOL is_public; + BOOL is_default; arg_decl_t *args; statement_t *body; struct _function_decl_t *next; @@ -190,6 +218,7 @@ typedef struct _class_decl_t { typedef struct _elseif_decl_t { expression_t *expr; statement_t *stat; + unsigned loc; struct _elseif_decl_t *next; } elseif_decl_t; @@ -251,6 +280,12 @@ typedef struct { case_clausule_t *case_clausules; } select_statement_t; +typedef struct { + statement_t stat; + expression_t *expr; + statement_t *body; +} with_statement_t; + typedef struct { statement_t stat; expression_t *expr; @@ -262,9 +297,10 @@ typedef struct { const WCHAR *end; BOOL option_explicit; - BOOL parse_complete; BOOL is_html; HRESULT hres; + int error_loc; + LCID lcid; int last_token; unsigned last_nl; @@ -276,7 +312,7 @@ typedef struct { heap_pool_t heap; } parser_ctx_t; -HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*,DWORD) DECLSPEC_HIDDEN; -void parser_release(parser_ctx_t*) DECLSPEC_HIDDEN; -int parser_lex(void*,parser_ctx_t*) DECLSPEC_HIDDEN; -void *parser_alloc(parser_ctx_t*,size_t) DECLSPEC_HIDDEN; +HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*,DWORD); +void parser_release(parser_ctx_t*); +int parser_lex(void*,unsigned*,parser_ctx_t*); +void *parser_alloc(parser_ctx_t*,size_t); diff --git a/dll/win32/vbscript/parser.y b/dll/win32/vbscript/parser.y index 8ecdf47c08c..09d60bff5d9 100644 --- a/dll/win32/vbscript/parser.y +++ b/dll/win32/vbscript/parser.y @@ -25,9 +25,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); -static int parser_error(parser_ctx_t *,const char*); +static int parser_error(unsigned*,parser_ctx_t*,const char*); -static void parse_complete(parser_ctx_t*,BOOL); static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr); static void source_add_statement(parser_ctx_t*,statement_t*); @@ -35,6 +34,7 @@ static void source_add_class(parser_ctx_t*,class_decl_t*); static void *new_expression(parser_ctx_t*,expression_type_t,size_t); static expression_t *new_bool_expression(parser_ctx_t*,VARIANT_BOOL); +static expression_t *new_date_expression(parser_ctx_t*,DATE); static expression_t *new_string_expression(parser_ctx_t*,const WCHAR*); static expression_t *new_long_expression(parser_ctx_t*,expression_type_t,LONG); static expression_t *new_double_expression(parser_ctx_t*,double); @@ -43,24 +43,29 @@ static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expre static expression_t *new_new_expression(parser_ctx_t*,const WCHAR*); static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*); +static call_expression_t *new_call_expression(parser_ctx_t*,expression_t*,expression_t*); +static call_expression_t *make_call_expression(parser_ctx_t*,expression_t*,expression_t*); -static void *new_statement(parser_ctx_t*,statement_type_t,size_t); -static statement_t *new_call_statement(parser_ctx_t*,BOOL,member_expression_t*); -static statement_t *new_assign_statement(parser_ctx_t*,member_expression_t*,expression_t*); -static statement_t *new_set_statement(parser_ctx_t*,member_expression_t*,expression_t*); -static statement_t *new_dim_statement(parser_ctx_t*,dim_decl_t*); -static statement_t *new_while_statement(parser_ctx_t*,statement_type_t,expression_t*,statement_t*); -static statement_t *new_forto_statement(parser_ctx_t*,const WCHAR*,expression_t*,expression_t*,expression_t*,statement_t*); -static statement_t *new_foreach_statement(parser_ctx_t*,const WCHAR*,expression_t*,statement_t*); -static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,elseif_decl_t*,statement_t*); -static statement_t *new_function_statement(parser_ctx_t*,function_decl_t*); -static statement_t *new_onerror_statement(parser_ctx_t*,BOOL); -static statement_t *new_const_statement(parser_ctx_t*,const_decl_t*); -static statement_t *new_select_statement(parser_ctx_t*,expression_t*,case_clausule_t*); +static void *new_statement(parser_ctx_t*,statement_type_t,size_t,unsigned); +static statement_t *new_call_statement(parser_ctx_t*,unsigned,expression_t*); +static statement_t *new_assign_statement(parser_ctx_t*,unsigned,expression_t*,expression_t*); +static statement_t *new_set_statement(parser_ctx_t*,unsigned,expression_t*,expression_t*); +static statement_t *new_dim_statement(parser_ctx_t*,unsigned,dim_decl_t*); +static statement_t *new_redim_statement(parser_ctx_t*,unsigned,BOOL,redim_decl_t*); +static statement_t *new_while_statement(parser_ctx_t*,unsigned,statement_type_t,expression_t*,statement_t*); +static statement_t *new_forto_statement(parser_ctx_t*,unsigned,const WCHAR*,expression_t*,expression_t*,expression_t*,statement_t*); +static statement_t *new_foreach_statement(parser_ctx_t*,unsigned,const WCHAR*,expression_t*,statement_t*); +static statement_t *new_if_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*,elseif_decl_t*,statement_t*); +static statement_t *new_function_statement(parser_ctx_t*,unsigned,function_decl_t*); +static statement_t *new_onerror_statement(parser_ctx_t*,unsigned,BOOL); +static statement_t *new_const_statement(parser_ctx_t*,unsigned,const_decl_t*); +static statement_t *new_select_statement(parser_ctx_t*,unsigned,expression_t*,case_clausule_t*); +static statement_t *new_with_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*); static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,BOOL,dim_list_t*); static dim_list_t *new_dim(parser_ctx_t*,unsigned,dim_list_t*); -static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*); +static redim_decl_t *new_redim_decl(parser_ctx_t*,const WCHAR*,expression_t*); +static elseif_decl_t *new_elseif_decl(parser_ctx_t*,unsigned,expression_t*,statement_t*); static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,unsigned,arg_decl_t*,statement_t*); static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL); static const_decl_t *new_const_decl(parser_ctx_t*,const WCHAR*,expression_t*); @@ -77,11 +82,15 @@ static statement_t *link_statements(statement_t*,statement_t*); #define CHECK_ERROR if(((parser_ctx_t*)ctx)->hres != S_OK) YYABORT +#define PARSER_LTYPE unsigned +#define YYLLOC_DEFAULT(Cur, Rhs, N) Cur = YYRHSLOC((Rhs), (N) ? 1 : 0) + %} %lex-param { parser_ctx_t *ctx } %parse-param { parser_ctx_t *ctx } -%pure-parser +%define api.prefix {parser_} +%define api.pure %start Program %union { @@ -92,6 +101,7 @@ static statement_t *link_statements(statement_t*,statement_t*); elseif_decl_t *elseif; dim_decl_t *dim_decl; dim_list_t *dim_list; + redim_decl_t *redim_decl; function_decl_t *func_decl; arg_decl_t *arg_decl; class_decl_t *class_decl; @@ -101,18 +111,20 @@ static statement_t *link_statements(statement_t*,statement_t*); LONG integer; BOOL boolean; double dbl; + DATE date; } -%token tEXPRESSION tEOF tNL tEMPTYBRACKETS +%token tEXPRESSION tNL tEMPTYBRACKETS tEXPRLBRACKET %token tLTEQ tGTEQ tNEQ -%token tSTOP tME tREM +%token tSTOP tME tREM tDOT %token tTRUE tFALSE %token tNOT tAND tOR tXOR tEQV tIMP %token tIS tMOD -%token tCALL tDIM tSUB tFUNCTION tGET tLET tCONST +%token tCALL tSUB tFUNCTION tGET tLET tCONST +%token tDIM tREDIM tPRESERVE %token tIF tELSE tELSEIF tEND tTHEN tEXIT %token tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN -%token tSELECT tCASE +%token tSELECT tCASE tWITH %token tBYREF tBYVAL %token tOPTION %token tNOTHING tEMPTY tNULL @@ -122,41 +134,54 @@ static statement_t *link_statements(statement_t*,statement_t*); %token tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP %token tInt %token tDouble +%token tDate %type Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt +%type GlobalDimDeclaration %type Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt %type ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression -%type NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression +%type NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression SignExpression %type ConstExpression NumericLiteralExpression %type MemberExpression -%type Arguments_opt ArgumentList ArgumentList_opt Step_opt ExpressionList -%type OptionExplicit_opt DoType -%type ArgumentsDecl_opt ArgumentDeclList ArgumentDecl +%type Arguments ArgumentList ArgumentList_opt Step_opt ExpressionList +%type DoType Preserve_opt +%type ArgumentsDecl ArgumentsDecl_opt ArgumentDeclList ArgumentDecl %type FunctionDecl PropertyDecl %type ElseIfs_opt ElseIfs ElseIf %type ClassDeclaration ClassBody %type Storage Storage_opt IntegerValue %type DimDeclList DimDecl %type DimList +%type ReDimDeclList ReDimDecl %type ConstDecl ConstDeclList -%type Identifier DotIdentifier +%type Identifier %type CaseClausules %% Program - : OptionExplicit_opt SourceElements tEOF { parse_complete(ctx, $1); } - | tEXPRESSION ExpressionNl_opt tEOF { handle_isexpression_script(ctx, $2); } + : OptionExplicit_opt SourceElements + | tEXPRESSION ExpressionNl_opt { handle_isexpression_script(ctx, $2); } OptionExplicit_opt - : /* empty */ { $$ = FALSE; } - | tOPTION tEXPLICIT StSep { $$ = TRUE; } + : /* empty */ + | tOPTION tEXPLICIT StSep { ctx->option_explicit = TRUE; } SourceElements : /* empty */ + | SourceElements GlobalDimDeclaration StSep + { source_add_statement(ctx, $2); } | SourceElements StatementNl { source_add_statement(ctx, $2); } | SourceElements ClassDeclaration { source_add_class(ctx, $2); } +GlobalDimDeclaration + : tPRIVATE tCONST ConstDeclList { $$ = new_const_statement(ctx, @$, $3); CHECK_ERROR; } + | tPUBLIC tCONST ConstDeclList { $$ = new_const_statement(ctx, @$, $3); CHECK_ERROR; } + | tPRIVATE DimDeclList { $$ = new_dim_statement(ctx, @$, $2); CHECK_ERROR; } + | tPUBLIC DimDeclList { $$ = new_dim_statement(ctx, @$, $2); + (void)parser_nerrs; /* avoid unused variable warning */ + CHECK_ERROR; } + ExpressionNl_opt : /* empty */ { $$ = NULL; } | Expression tNL { $$ = $1; } @@ -171,8 +196,8 @@ StatementsNl_opt | StatementsNl { $$ = $1; } StatementsNl - : StatementNl { $$ = $1; } - | StatementNl StatementsNl { $$ = link_statements($1, $2); } + : SimpleStatement StSep { $$ = $1; } + | SimpleStatement StSep StatementsNl { $$ = link_statements($1, $3); } StatementNl : Statement tNL { $$ = $1; } @@ -185,43 +210,59 @@ Statement | SimpleStatement ':' { $$ = $1; } SimpleStatement - : MemberExpression ArgumentList_opt { $1->args = $2; $$ = new_call_statement(ctx, FALSE, $1); CHECK_ERROR; } - | tCALL MemberExpression Arguments_opt { $2->args = $3; $$ = new_call_statement(ctx, TRUE, $2); CHECK_ERROR; } - | MemberExpression Arguments_opt '=' Expression - { $1->args = $2; $$ = new_assign_statement(ctx, $1, $4); CHECK_ERROR; } - | tDIM DimDeclList { $$ = new_dim_statement(ctx, $2); CHECK_ERROR; } + : CallExpression ArgumentList_opt { call_expression_t *call_expr = make_call_expression(ctx, $1, $2); CHECK_ERROR; + $$ = new_call_statement(ctx, @$, &call_expr->expr); CHECK_ERROR; } + | tCALL UnaryExpression { $$ = new_call_statement(ctx, @$, $2); CHECK_ERROR; } + | CallExpression '=' Expression + { $$ = new_assign_statement(ctx, @$, $1, $3); CHECK_ERROR; } + | tDIM DimDeclList { $$ = new_dim_statement(ctx, @$, $2); CHECK_ERROR; } + | tREDIM Preserve_opt ReDimDeclList { $$ = new_redim_statement(ctx, @$, $2, $3); CHECK_ERROR; } | IfStatement { $$ = $1; } | tWHILE Expression StSep StatementsNl_opt tWEND - { $$ = new_while_statement(ctx, STAT_WHILE, $2, $4); CHECK_ERROR; } + { $$ = new_while_statement(ctx, @$, STAT_WHILE, $2, $4); CHECK_ERROR; } | tDO DoType Expression StSep StatementsNl_opt tLOOP - { $$ = new_while_statement(ctx, $2 ? STAT_WHILELOOP : STAT_UNTIL, $3, $5); + { $$ = new_while_statement(ctx, @$, $2 ? STAT_WHILELOOP : STAT_UNTIL, $3, $5); CHECK_ERROR; } | tDO StSep StatementsNl_opt tLOOP DoType Expression - { $$ = new_while_statement(ctx, $5 ? STAT_DOWHILE : STAT_DOUNTIL, $6, $3); + { $$ = new_while_statement(ctx, @4, $5 ? STAT_DOWHILE : STAT_DOUNTIL, $6, $3); CHECK_ERROR; } - | tDO StSep StatementsNl_opt tLOOP { $$ = new_while_statement(ctx, STAT_DOWHILE, NULL, $3); CHECK_ERROR; } - | FunctionDecl { $$ = new_function_statement(ctx, $1); CHECK_ERROR; } - | tEXIT tDO { $$ = new_statement(ctx, STAT_EXITDO, 0); CHECK_ERROR; } - | tEXIT tFOR { $$ = new_statement(ctx, STAT_EXITFOR, 0); CHECK_ERROR; } - | tEXIT tFUNCTION { $$ = new_statement(ctx, STAT_EXITFUNC, 0); CHECK_ERROR; } - | tEXIT tPROPERTY { $$ = new_statement(ctx, STAT_EXITPROP, 0); CHECK_ERROR; } - | tEXIT tSUB { $$ = new_statement(ctx, STAT_EXITSUB, 0); CHECK_ERROR; } - | tSET MemberExpression Arguments_opt '=' Expression - { $2->args = $3; $$ = new_set_statement(ctx, $2, $5); CHECK_ERROR; } - | tSTOP { $$ = new_statement(ctx, STAT_STOP, 0); CHECK_ERROR; } - | tON tERROR tRESUME tNEXT { $$ = new_onerror_statement(ctx, TRUE); CHECK_ERROR; } - | tON tERROR tGOTO '0' { $$ = new_onerror_statement(ctx, FALSE); CHECK_ERROR; } - | tCONST ConstDeclList { $$ = new_const_statement(ctx, $2); CHECK_ERROR; } + | tDO StSep StatementsNl_opt tLOOP { $$ = new_while_statement(ctx, @$, STAT_DOWHILE, NULL, $3); CHECK_ERROR; } + | FunctionDecl { $$ = new_function_statement(ctx, @$, $1); CHECK_ERROR; } + | tEXIT tDO { $$ = new_statement(ctx, STAT_EXITDO, 0, @$); CHECK_ERROR; } + | tEXIT tFOR { $$ = new_statement(ctx, STAT_EXITFOR, 0, @$); CHECK_ERROR; } + | tEXIT tFUNCTION { $$ = new_statement(ctx, STAT_EXITFUNC, 0, @$); CHECK_ERROR; } + | tEXIT tPROPERTY { $$ = new_statement(ctx, STAT_EXITPROP, 0, @$); CHECK_ERROR; } + | tEXIT tSUB { $$ = new_statement(ctx, STAT_EXITSUB, 0, @$); CHECK_ERROR; } + | tSET CallExpression '=' Expression { $$ = new_set_statement(ctx, @$, $2, $4); CHECK_ERROR; } + | tSTOP { $$ = new_statement(ctx, STAT_STOP, 0, @$); CHECK_ERROR; } + | tON tERROR tRESUME tNEXT { $$ = new_onerror_statement(ctx, @$, TRUE); CHECK_ERROR; } + | tON tERROR tGOTO '0' { $$ = new_onerror_statement(ctx, @$, FALSE); CHECK_ERROR; } + | tCONST ConstDeclList { $$ = new_const_statement(ctx, @$, $2); CHECK_ERROR; } | tFOR Identifier '=' Expression tTO Expression Step_opt StSep StatementsNl_opt tNEXT - { $$ = new_forto_statement(ctx, $2, $4, $6, $7, $9); CHECK_ERROR; } + { $$ = new_forto_statement(ctx, @$, $2, $4, $6, $7, $9); CHECK_ERROR; } | tFOR tEACH Identifier tIN Expression StSep StatementsNl_opt tNEXT - { $$ = new_foreach_statement(ctx, $3, $5, $7); } + { $$ = new_foreach_statement(ctx, @$, $3, $5, $7); } | tSELECT tCASE Expression StSep CaseClausules tEND tSELECT - { $$ = new_select_statement(ctx, $3, $5); } + { $$ = new_select_statement(ctx, @$, $3, $5); } + | tWITH Expression StSep StatementsNl_opt tEND tWITH + { $$ = new_with_statement(ctx, @$, $2, $4); } MemberExpression : Identifier { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; } - | CallExpression '.' DotIdentifier { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; } + | CallExpression '.' tIdentifier { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; } + | tDOT tIdentifier { expression_t *dot_expr = new_expression(ctx, EXPR_DOT, sizeof(*dot_expr)); CHECK_ERROR; + $$ = new_member_expression(ctx, dot_expr, $2); CHECK_ERROR; } + +Preserve_opt + : /* empty */ { $$ = FALSE; } + | tPRESERVE { $$ = TRUE; } + +ReDimDecl + : tIdentifier '(' ArgumentList ')' { $$ = new_redim_decl(ctx, $1, $3); CHECK_ERROR; } + +ReDimDeclList + : ReDimDecl { $$ = $1; } + | ReDimDecl ',' ReDimDeclList { $1->next = $3; $$ = $1; } DimDeclList : DimDecl { $$ = $1; } @@ -257,10 +298,10 @@ Step_opt IfStatement : tIF Expression tTHEN tNL StatementsNl_opt ElseIfs_opt Else_opt tEND tIF - { $$ = new_if_statement(ctx, $2, $5, $6, $7); CHECK_ERROR; } - | tIF Expression tTHEN Statement EndIf_opt { $$ = new_if_statement(ctx, $2, $4, NULL, NULL); CHECK_ERROR; } + { $$ = new_if_statement(ctx, @$, $2, $5, $6, $7); CHECK_ERROR; } + | tIF Expression tTHEN Statement EndIf_opt { $$ = new_if_statement(ctx, @$, $2, $4, NULL, NULL); CHECK_ERROR; } | tIF Expression tTHEN Statement tELSE Statement EndIf_opt - { $$ = new_if_statement(ctx, $2, $4, NULL, $6); CHECK_ERROR; } + { $$ = new_if_statement(ctx, @$, $2, $4, NULL, $6); CHECK_ERROR; } EndIf_opt : /* empty */ @@ -275,25 +316,24 @@ ElseIfs | ElseIf ElseIfs { $1->next = $2; $$ = $1; } ElseIf - : tELSEIF Expression tTHEN tNL StatementsNl_opt - { $$ = new_elseif_decl(ctx, $2, $5); } + : tELSEIF Expression tTHEN StSep_opt StatementsNl_opt + { $$ = new_elseif_decl(ctx, @$, $2, $5); } Else_opt : /* empty */ { $$ = NULL; } - | tELSE tNL StatementsNl_opt { $$ = $3; } + | tELSE StSep_opt StatementsNl_opt { $$ = $3; } CaseClausules - : /* empty */ { $$ = NULL; } - | tCASE tELSE StSep StatementsNl { $$ = new_case_clausule(ctx, NULL, $4, NULL); } - | tCASE ExpressionList StSep StatementsNl_opt CaseClausules - { $$ = new_case_clausule(ctx, $2, $4, $5); } + : /* empty */ { $$ = NULL; } + | tCASE tELSE StSep_opt StatementsNl_opt { $$ = new_case_clausule(ctx, NULL, $4, NULL); } + | tCASE ExpressionList StSep_opt StatementsNl_opt CaseClausules { $$ = new_case_clausule(ctx, $2, $4, $5); } -Arguments_opt - : EmptyBrackets_opt { $$ = NULL; } +Arguments + : tEMPTYBRACKETS { $$ = NULL; } | '(' ArgumentList ')' { $$ = $2; } ArgumentList_opt - : EmptyBrackets_opt { $$ = NULL; } + : /* empty */ { $$ = NULL; } | ArgumentList { $$ = $1; } ArgumentList @@ -369,24 +409,30 @@ MultiplicativeExpression { $$ = new_binary_expression(ctx, EXPR_DIV, $1, $3); CHECK_ERROR; } ExpExpression - : UnaryExpression { $$ = $1; } - | ExpExpression '^' UnaryExpression { $$ = new_binary_expression(ctx, EXPR_EXP, $1, $3); CHECK_ERROR; } + : SignExpression { $$ = $1; } + | ExpExpression '^' SignExpression { $$ = new_binary_expression(ctx, EXPR_EXP, $1, $3); CHECK_ERROR; } + +SignExpression + : UnaryExpression { $$ = $1; } + | '-' SignExpression { $$ = new_unary_expression(ctx, EXPR_NEG, $2); CHECK_ERROR; } + | '+' SignExpression { $$ = $2; } UnaryExpression : LiteralExpression { $$ = $1; } | CallExpression { $$ = $1; } | tNEW Identifier { $$ = new_new_expression(ctx, $2); CHECK_ERROR; } - | '-' UnaryExpression { $$ = new_unary_expression(ctx, EXPR_NEG, $2); CHECK_ERROR; } - | '+' UnaryExpression { $$ = $2; } CallExpression - : PrimaryExpression { $$ = $1; } - | MemberExpression Arguments_opt { $1->args = $2; $$ = &$1->expr; } + : PrimaryExpression { $$ = $1; } + | MemberExpression { $$ = &$1->expr; } + | CallExpression Arguments { call_expression_t *expr = new_call_expression(ctx, $1, $2); CHECK_ERROR; + $$ = &expr->expr; } LiteralExpression : tTRUE { $$ = new_bool_expression(ctx, VARIANT_TRUE); CHECK_ERROR; } | tFALSE { $$ = new_bool_expression(ctx, VARIANT_FALSE); CHECK_ERROR; } | tString { $$ = new_string_expression(ctx, $1); CHECK_ERROR; } + | tDate { $$ = new_date_expression(ctx, $1); CHECK_ERROR; } | NumericLiteralExpression { $$ = $1; } | tEMPTY { $$ = new_expression(ctx, EXPR_EMPTY, 0); CHECK_ERROR; } | tNULL { $$ = new_expression(ctx, EXPR_NULL, 0); CHECK_ERROR; } @@ -402,7 +448,7 @@ IntegerValue | tInt { $$ = $1; } PrimaryExpression - : '(' Expression ')' { $$ = new_unary_expression(ctx, EXPR_BRACKETS, $2); } + : tEXPRLBRACKET Expression ')' { $$ = new_unary_expression(ctx, EXPR_BRACKETS, $2); } | tME { $$ = new_expression(ctx, EXPR_ME, 0); CHECK_ERROR; } ClassDeclaration @@ -423,17 +469,21 @@ ClassBody | PropertyDecl StSep ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; } PropertyDecl - : Storage_opt tPROPERTY tGET tIdentifier ArgumentsDecl_opt StSep BodyStatements tEND tPROPERTY + : Storage_opt tPROPERTY tGET Identifier ArgumentsDecl_opt StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPGET, $1, $5, $7); CHECK_ERROR; } - | Storage_opt tPROPERTY tLET tIdentifier '(' ArgumentDecl ')' StSep BodyStatements tEND tPROPERTY + | Storage_opt tPROPERTY tLET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPLET, $1, $6, $9); CHECK_ERROR; } - | Storage_opt tPROPERTY tSET tIdentifier '(' ArgumentDecl ')' StSep BodyStatements tEND tPROPERTY + | Storage_opt tPROPERTY tSET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPSET, $1, $6, $9); CHECK_ERROR; } FunctionDecl - : Storage_opt tSUB Identifier ArgumentsDecl_opt StSep BodyStatements tEND tSUB + : Storage_opt tSUB Identifier StSep BodyStatements tEND tSUB + { $$ = new_function_decl(ctx, $3, FUNC_SUB, $1, NULL, $5); CHECK_ERROR; } + | Storage_opt tSUB Identifier ArgumentsDecl Nl_opt BodyStatements tEND tSUB { $$ = new_function_decl(ctx, $3, FUNC_SUB, $1, $4, $6); CHECK_ERROR; } - | Storage_opt tFUNCTION Identifier ArgumentsDecl_opt StSep BodyStatements tEND tFUNCTION + | Storage_opt tFUNCTION Identifier StSep BodyStatements tEND tFUNCTION + { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, $1, NULL, $5); CHECK_ERROR; } + | Storage_opt tFUNCTION Identifier ArgumentsDecl Nl_opt BodyStatements tEND tFUNCTION { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, $1, $4, $6); CHECK_ERROR; } Storage_opt @@ -446,7 +496,11 @@ Storage | tPRIVATE { $$ = STORAGE_IS_PRIVATE; } ArgumentsDecl_opt - : EmptyBrackets_opt { $$ = NULL; } + : /* empty*/ { $$ = 0; } + | ArgumentsDecl { $$ = $1; } + +ArgumentsDecl + : tEMPTYBRACKETS { $$ = NULL; } | '(' ArgumentDeclList ')' { $$ = $2; } ArgumentDeclList @@ -461,64 +515,19 @@ ArgumentDecl /* these keywords may also be an identifier, depending on context */ Identifier : tIdentifier { $$ = $1; } - | tDEFAULT { $$ = $1; } - | tERROR { $$ = $1; } - | tEXPLICIT { $$ = $1; } - | tPROPERTY { $$ = $1; } - | tSTEP { $$ = $1; } + | tDEFAULT { ctx->last_token = tIdentifier; $$ = $1; } + | tERROR { ctx->last_token = tIdentifier; $$ = $1; } + | tEXPLICIT { ctx->last_token = tIdentifier; $$ = $1; } + | tPROPERTY { ctx->last_token = tIdentifier; $$ = $1; } + | tSTEP { ctx->last_token = tIdentifier; $$ = $1; } -/* most keywords can be an identifier after a dot */ -DotIdentifier - : Identifier { $$ = $1; } - | tTRUE { $$ = $1; } - | tFALSE { $$ = $1; } - | tNOT { $$ = $1; } - | tAND { $$ = $1; } - | tOR { $$ = $1; } - | tXOR { $$ = $1; } - | tEQV { $$ = $1; } - | tIMP { $$ = $1; } - | tIS { $$ = $1; } - | tMOD { $$ = $1; } - | tCALL { $$ = $1; } - | tDIM { $$ = $1; } - | tSUB { $$ = $1; } - | tFUNCTION { $$ = $1; } - | tGET { $$ = $1; } - | tLET { $$ = $1; } - | tCONST { $$ = $1; } - | tIF { $$ = $1; } - | tELSE { $$ = $1; } - | tELSEIF { $$ = $1; } - | tEND { $$ = $1; } - | tTHEN { $$ = $1; } - | tEXIT { $$ = $1; } - | tWHILE { $$ = $1; } - | tWEND { $$ = $1; } - | tDO { $$ = $1; } - | tLOOP { $$ = $1; } - | tUNTIL { $$ = $1; } - | tFOR { $$ = $1; } - | tTO { $$ = $1; } - | tEACH { $$ = $1; } - | tIN { $$ = $1; } - | tSELECT { $$ = $1; } - | tCASE { $$ = $1; } - | tBYREF { $$ = $1; } - | tBYVAL { $$ = $1; } - | tOPTION { $$ = $1; } - | tNOTHING { $$ = $1; } - | tEMPTY { $$ = $1; } - | tNULL { $$ = $1; } - | tCLASS { $$ = $1; } - | tSET { $$ = $1; } - | tNEW { $$ = $1; } - | tPUBLIC { $$ = $1; } - | tPRIVATE { $$ = $1; } - | tNEXT { $$ = $1; } - | tON { $$ = $1; } - | tRESUME { $$ = $1; } - | tGOTO { $$ = $1; } +StSep_opt + : /* empty */ + | StSep + +Nl_opt + : /* empty */ + | tNL Nl_opt /* Most statements accept both new line and ':' as separators */ StSep @@ -529,8 +538,16 @@ StSep %% -static int parser_error(parser_ctx_t *ctx, const char *str) +static int parser_error(unsigned *loc, parser_ctx_t *ctx, const char *str) { + if(ctx->error_loc == -1) + ctx->error_loc = *loc; + if(ctx->hres == S_OK) { + FIXME("%s: %s\n", debugstr_w(ctx->code + *loc), debugstr_a(str)); + ctx->hres = E_FAIL; + }else { + WARN("%s: %08lx\n", debugstr_w(ctx->code + *loc), ctx->hres); + } return 0; } @@ -539,12 +556,17 @@ static void source_add_statement(parser_ctx_t *ctx, statement_t *stat) if(!stat) return; + /* concatenate both linked lists */ if(ctx->stats) { ctx->stats_tail->next = stat; ctx->stats_tail = stat; }else { ctx->stats = ctx->stats_tail = stat; } + /* find new tail */ + while(ctx->stats_tail->next) { + ctx->stats_tail=ctx->stats_tail->next; + } } static void source_add_class(parser_ctx_t *ctx, class_decl_t *class_decl) @@ -553,21 +575,14 @@ static void source_add_class(parser_ctx_t *ctx, class_decl_t *class_decl) ctx->class_decls = class_decl; } -static void parse_complete(parser_ctx_t *ctx, BOOL option_explicit) -{ - ctx->parse_complete = TRUE; - ctx->option_explicit = option_explicit; -} - static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr) { retval_statement_t *stat; - ctx->parse_complete = TRUE; if(!expr) return; - stat = new_statement(ctx, STAT_RETVAL, sizeof(*stat)); + stat = new_statement(ctx, STAT_RETVAL, sizeof(*stat), 0); if(!stat) return; @@ -612,6 +627,18 @@ static expression_t *new_string_expression(parser_ctx_t *ctx, const WCHAR *value return &expr->expr; } +static expression_t *new_date_expression(parser_ctx_t *ctx, DATE value) +{ + date_expression_t *expr; + + expr = new_expression(ctx, EXPR_DATE, sizeof(*expr)); + if(!expr) + return NULL; + + expr->value = value; + return &expr->expr; +} + static expression_t *new_long_expression(parser_ctx_t *ctx, expression_type_t type, LONG value) { int_expression_t *expr; @@ -671,10 +698,61 @@ static member_expression_t *new_member_expression(parser_ctx_t *ctx, expression_ expr->obj_expr = obj_expr; expr->identifier = identifier; - expr->args = NULL; return expr; } +static call_expression_t *new_call_expression(parser_ctx_t *ctx, expression_t *expr, expression_t *arguments) +{ + call_expression_t *call_expr; + + call_expr = new_expression(ctx, EXPR_CALL, sizeof(*call_expr)); + if(!call_expr) + return NULL; + + call_expr->call_expr = expr; + call_expr->args = arguments; + return call_expr; +} + +static call_expression_t *make_call_expression(parser_ctx_t *ctx, expression_t *callee_expr, expression_t *arguments) +{ + call_expression_t *call_expr; + + if(callee_expr->type == EXPR_MEMBER) + return new_call_expression(ctx, callee_expr, arguments); + if(callee_expr->type != EXPR_CALL) { + FIXME("Unhandled for expr type %u\n", callee_expr->type); + ctx->hres = E_FAIL; + return NULL; + } + call_expr = (call_expression_t*)callee_expr; + if(!call_expr->args) { + call_expr->args = arguments; + return call_expr; + } + + if(call_expr->args->next) { + FIXME("Invalid syntax: invalid use of parentheses for arguments\n"); + ctx->hres = E_FAIL; + return NULL; + } + + call_expr->args = new_unary_expression(ctx, EXPR_BRACKETS, call_expr->args); + if(!call_expr->args) + return NULL; + if(!arguments) + return call_expr; + + if(arguments->type != EXPR_NOARG) { + FIXME("Invalid syntax: missing comma\n"); + ctx->hres = E_FAIL; + return NULL; + } + + call_expr->args->next = arguments->next; + return call_expr; +} + static expression_t *new_new_expression(parser_ctx_t *ctx, const WCHAR *identifier) { string_expression_t *expr; @@ -687,55 +765,72 @@ static expression_t *new_new_expression(parser_ctx_t *ctx, const WCHAR *identifi return &expr->expr; } -static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size) +static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size, unsigned loc) { statement_t *stat; stat = parser_alloc(ctx, size ? size : sizeof(*stat)); if(stat) { stat->type = type; + stat->loc = loc; stat->next = NULL; } return stat; } -static statement_t *new_call_statement(parser_ctx_t *ctx, BOOL is_strict, member_expression_t *expr) +static statement_t *new_call_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr) { + call_expression_t *call_expr = NULL; call_statement_t *stat; - stat = new_statement(ctx, STAT_CALL, sizeof(*stat)); + stat = new_statement(ctx, STAT_CALL, sizeof(*stat), loc); if(!stat) return NULL; - stat->expr = expr; - stat->is_strict = is_strict; + switch(expr->type) { + case EXPR_MEMBER: + call_expr = new_call_expression(ctx, expr, NULL); + break; + case EXPR_CALL: + call_expr = (call_expression_t*)expr; + break; + default: + FIXME("Unsupported expr type %u\n", expr->type); + ctx->hres = E_NOTIMPL; + } + if(!call_expr) + return NULL; + + stat->expr = call_expr; return &stat->stat; } -static statement_t *new_assign_statement(parser_ctx_t *ctx, member_expression_t *left, expression_t *right) +static statement_t *new_assign_statement(parser_ctx_t *ctx, unsigned loc, expression_t *left, expression_t *right) { assign_statement_t *stat; - stat = new_statement(ctx, STAT_ASSIGN, sizeof(*stat)); + stat = new_statement(ctx, STAT_ASSIGN, sizeof(*stat), loc); if(!stat) return NULL; - stat->member_expr = left; + stat->left_expr = left; stat->value_expr = right; + return &stat->stat; } -static statement_t *new_set_statement(parser_ctx_t *ctx, member_expression_t *left, expression_t *right) +static statement_t *new_set_statement(parser_ctx_t *ctx, unsigned loc, expression_t *left, expression_t *right) { assign_statement_t *stat; - stat = new_statement(ctx, STAT_SET, sizeof(*stat)); + stat = new_statement(ctx, STAT_SET, sizeof(*stat), loc); if(!stat) return NULL; - stat->member_expr = left; + stat->left_expr = left; stat->value_expr = right; + return &stat->stat; } @@ -767,11 +862,11 @@ static dim_list_t *new_dim(parser_ctx_t *ctx, unsigned val, dim_list_t *next) return ret; } -static statement_t *new_dim_statement(parser_ctx_t *ctx, dim_decl_t *decls) +static statement_t *new_dim_statement(parser_ctx_t *ctx, unsigned loc, dim_decl_t *decls) { dim_statement_t *stat; - stat = new_statement(ctx, STAT_DIM, sizeof(*stat)); + stat = new_statement(ctx, STAT_DIM, sizeof(*stat), loc); if(!stat) return NULL; @@ -779,7 +874,34 @@ static statement_t *new_dim_statement(parser_ctx_t *ctx, dim_decl_t *decls) return &stat->stat; } -static elseif_decl_t *new_elseif_decl(parser_ctx_t *ctx, expression_t *expr, statement_t *stat) +static redim_decl_t *new_redim_decl(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *dims) +{ + redim_decl_t *decl; + + decl = parser_alloc(ctx, sizeof(*decl)); + if(!decl) + return NULL; + + decl->identifier = identifier; + decl->dims = dims; + decl->next = NULL; + return decl; +} + +static statement_t *new_redim_statement(parser_ctx_t *ctx, unsigned loc, BOOL preserve, redim_decl_t *decls) +{ + redim_statement_t *stat; + + stat = new_statement(ctx, STAT_REDIM, sizeof(*stat), loc); + if(!stat) + return NULL; + + stat->preserve = preserve; + stat->redim_decls = decls; + return &stat->stat; +} + +static elseif_decl_t *new_elseif_decl(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_t *stat) { elseif_decl_t *decl; @@ -789,15 +911,16 @@ static elseif_decl_t *new_elseif_decl(parser_ctx_t *ctx, expression_t *expr, sta decl->expr = expr; decl->stat = stat; + decl->loc = loc; decl->next = NULL; return decl; } -static statement_t *new_while_statement(parser_ctx_t *ctx, statement_type_t type, expression_t *expr, statement_t *body) +static statement_t *new_while_statement(parser_ctx_t *ctx, unsigned loc, statement_type_t type, expression_t *expr, statement_t *body) { while_statement_t *stat; - stat = new_statement(ctx, type, sizeof(*stat)); + stat = new_statement(ctx, type, sizeof(*stat), loc); if(!stat) return NULL; @@ -806,12 +929,12 @@ static statement_t *new_while_statement(parser_ctx_t *ctx, statement_type_t type return &stat->stat; } -static statement_t *new_forto_statement(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *from_expr, +static statement_t *new_forto_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier, expression_t *from_expr, expression_t *to_expr, expression_t *step_expr, statement_t *body) { forto_statement_t *stat; - stat = new_statement(ctx, STAT_FORTO, sizeof(*stat)); + stat = new_statement(ctx, STAT_FORTO, sizeof(*stat), loc); if(!stat) return NULL; @@ -823,12 +946,12 @@ static statement_t *new_forto_statement(parser_ctx_t *ctx, const WCHAR *identifi return &stat->stat; } -static statement_t *new_foreach_statement(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *group_expr, +static statement_t *new_foreach_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier, expression_t *group_expr, statement_t *body) { foreach_statement_t *stat; - stat = new_statement(ctx, STAT_FOREACH, sizeof(*stat)); + stat = new_statement(ctx, STAT_FOREACH, sizeof(*stat), loc); if(!stat) return NULL; @@ -838,12 +961,12 @@ static statement_t *new_foreach_statement(parser_ctx_t *ctx, const WCHAR *identi return &stat->stat; } -static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *if_stat, elseif_decl_t *elseif_decl, +static statement_t *new_if_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_t *if_stat, elseif_decl_t *elseif_decl, statement_t *else_stat) { if_statement_t *stat; - stat = new_statement(ctx, STAT_IF, sizeof(*stat)); + stat = new_statement(ctx, STAT_IF, sizeof(*stat), loc); if(!stat) return NULL; @@ -854,11 +977,11 @@ static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, stat return &stat->stat; } -static statement_t *new_select_statement(parser_ctx_t *ctx, expression_t *expr, case_clausule_t *case_clausules) +static statement_t *new_select_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr, case_clausule_t *case_clausules) { select_statement_t *stat; - stat = new_statement(ctx, STAT_SELECT, sizeof(*stat)); + stat = new_statement(ctx, STAT_SELECT, sizeof(*stat), loc); if(!stat) return NULL; @@ -867,6 +990,19 @@ static statement_t *new_select_statement(parser_ctx_t *ctx, expression_t *expr, return &stat->stat; } +static statement_t *new_with_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_t *body) +{ + with_statement_t *stat; + + stat = new_statement(ctx, STAT_WITH, sizeof(*stat), loc); + if(!stat) + return NULL; + + stat->expr = expr; + stat->body = body; + return &stat->stat; +} + static case_clausule_t *new_case_clausule(parser_ctx_t *ctx, expression_t *expr, statement_t *stat, case_clausule_t *next) { case_clausule_t *ret; @@ -881,11 +1017,11 @@ static case_clausule_t *new_case_clausule(parser_ctx_t *ctx, expression_t *expr, return ret; } -static statement_t *new_onerror_statement(parser_ctx_t *ctx, BOOL resume_next) +static statement_t *new_onerror_statement(parser_ctx_t *ctx, unsigned loc, BOOL resume_next) { onerror_statement_t *stat; - stat = new_statement(ctx, STAT_ONERROR, sizeof(*stat)); + stat = new_statement(ctx, STAT_ONERROR, sizeof(*stat), loc); if(!stat) return NULL; @@ -911,10 +1047,11 @@ static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, unsigned storage_flags, arg_decl_t *arg_decl, statement_t *body) { function_decl_t *decl; + BOOL is_default = FALSE; if(storage_flags & STORAGE_IS_DEFAULT) { - if(type == FUNC_PROPGET) { - type = FUNC_DEFGET; + if(type == FUNC_PROPGET || type == FUNC_FUNCTION || type == FUNC_SUB) { + is_default = TRUE; }else { FIXME("Invalid default property\n"); ctx->hres = E_FAIL; @@ -929,6 +1066,7 @@ static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, decl->name = name; decl->type = type; decl->is_public = !(storage_flags & STORAGE_IS_PRIVATE); + decl->is_default = is_default; decl->args = arg_decl; decl->body = body; decl->next = NULL; @@ -936,11 +1074,11 @@ static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, return decl; } -static statement_t *new_function_statement(parser_ctx_t *ctx, function_decl_t *decl) +static statement_t *new_function_statement(parser_ctx_t *ctx, unsigned loc, function_decl_t *decl) { function_statement_t *stat; - stat = new_statement(ctx, STAT_FUNC, sizeof(*stat)); + stat = new_statement(ctx, STAT_FUNC, sizeof(*stat), loc); if(!stat) return NULL; @@ -998,7 +1136,7 @@ static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_d static class_decl_t *add_dim_prop(parser_ctx_t *ctx, class_decl_t *class_decl, dim_decl_t *dim_decl, unsigned storage_flags) { if(storage_flags & STORAGE_IS_DEFAULT) { - FIXME("variant prop van't be default value\n"); + FIXME("variant prop can't be default value\n"); ctx->hres = E_FAIL; return NULL; } @@ -1023,11 +1161,11 @@ static const_decl_t *new_const_decl(parser_ctx_t *ctx, const WCHAR *name, expres return decl; } -static statement_t *new_const_statement(parser_ctx_t *ctx, const_decl_t *decls) +static statement_t *new_const_statement(parser_ctx_t *ctx, unsigned loc, const_decl_t *decls) { const_statement_t *stat; - stat = new_statement(ctx, STAT_CONST, sizeof(*stat)); + stat = new_statement(ctx, STAT_CONST, sizeof(*stat), loc); if(!stat) return NULL; @@ -1039,6 +1177,8 @@ static statement_t *link_statements(statement_t *head, statement_t *tail) { statement_t *iter; + if (!head) return tail; + for(iter = head; iter->next; iter = iter->next); iter->next = tail; @@ -1057,36 +1197,26 @@ void *parser_alloc(parser_ctx_t *ctx, size_t size) HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, DWORD flags) { - static const WCHAR html_delimiterW[] = {'<','/','s','c','r','i','p','t','>',0}; - ctx->code = ctx->ptr = code; ctx->end = ctx->code + lstrlenW(ctx->code); heap_pool_init(&ctx->heap); - ctx->parse_complete = FALSE; ctx->hres = S_OK; - + ctx->error_loc = -1; ctx->last_token = tNL; ctx->last_nl = 0; ctx->stats = ctx->stats_tail = NULL; ctx->class_decls = NULL; ctx->option_explicit = FALSE; - ctx->is_html = delimiter && !wcsicmp(delimiter, html_delimiterW); + ctx->is_html = delimiter && !wcsicmp(delimiter, L""); if(flags & SCRIPTTEXT_ISEXPRESSION) ctx->last_token = tEXPRESSION; parser_parse(ctx); - if(FAILED(ctx->hres)) - return ctx->hres; - if(!ctx->parse_complete) { - FIXME("parser failed around %s\n", debugstr_w(ctx->code+20 > ctx->ptr ? ctx->code : ctx->ptr-20)); - return E_FAIL; - } - - return S_OK; + return ctx->hres; } void parser_release(parser_ctx_t *ctx) diff --git a/dll/win32/vbscript/precomp.h b/dll/win32/vbscript/precomp.h index 94c165333db..05190b66085 100644 --- a/dll/win32/vbscript/precomp.h +++ b/dll/win32/vbscript/precomp.h @@ -10,6 +10,7 @@ #include "vbscript.h" +#include #include #include diff --git a/dll/win32/vbscript/regexp.c b/dll/win32/vbscript/regexp.c index 33eec2aa848..01e32e9916f 100644 --- a/dll/win32/vbscript/regexp.c +++ b/dll/win32/vbscript/regexp.c @@ -482,7 +482,7 @@ EmitREBytecode(CompilerState *state, regexp_t *re, size_t treeDepth, if (treeDepth == 0) { emitStateStack = NULL; } else { - emitStateStack = heap_alloc(sizeof(EmitStateStackEntry) * treeDepth); + emitStateStack = malloc(sizeof(EmitStateStackEntry) * treeDepth); if (!emitStateStack) return NULL; } @@ -788,7 +788,7 @@ EmitREBytecode(CompilerState *state, regexp_t *re, size_t treeDepth, } cleanup: - heap_free(emitStateStack); + free(emitStateStack); return pc; jump_too_big: @@ -1667,11 +1667,11 @@ ParseRegExp(CompilerState *state) return (state->result != NULL); } - operatorStack = heap_alloc(sizeof(REOpData) * operatorStackSize); + operatorStack = malloc(sizeof(REOpData) * operatorStackSize); if (!operatorStack) return FALSE; - operandStack = heap_alloc(sizeof(RENode *) * operandStackSize); + operandStack = malloc(sizeof(RENode *) * operandStackSize); if (!operandStack) goto out; @@ -1762,7 +1762,7 @@ pushOperand: if (operandSP == operandStackSize) { RENode **tmp; operandStackSize += operandStackSize; - tmp = heap_realloc(operandStack, sizeof(RENode *) * operandStackSize); + tmp = realloc(operandStack, sizeof(RENode *) * operandStackSize); if (!tmp) goto out; operandStack = tmp; @@ -1895,7 +1895,7 @@ pushOperator: if (operatorSP == operatorStackSize) { REOpData *tmp; operatorStackSize += operatorStackSize; - tmp = heap_realloc(operatorStack, sizeof(REOpData) * operatorStackSize); + tmp = realloc(operatorStack, sizeof(REOpData) * operatorStackSize); if (!tmp) goto out; operatorStack = tmp; @@ -1907,8 +1907,8 @@ pushOperator: } } out: - heap_free(operatorStack); - heap_free(operandStack); + free(operatorStack); + free(operandStack); return result; } @@ -1935,7 +1935,7 @@ PushBackTrackState(REGlobalData *gData, REOp op, ptrdiff_t btincr = ((char *)result + sz) - ((char *)gData->backTrackStack + btsize); - TRACE("\tBT_Push: %lu,%lu\n", (ULONG_PTR)parenIndex, (ULONG_PTR)parenCount); + TRACE("\tBT_Push: %Iu,%Iu\n", (ULONG_PTR)parenIndex, (ULONG_PTR)parenCount); JS_COUNT_OPERATION(gData->cx, JSOW_JUMP * (1 + parenCount)); if (btincr > 0) { @@ -2111,7 +2111,7 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet) assert(src[-1] == '[' && end[0] == ']'); byteLength = (charSet->length >> 3) + 1; - charSet->u.bits = heap_alloc(byteLength); + charSet->u.bits = malloc(byteLength); if (!charSet->u.bits) { JS_ReportOutOfMemory(gData->cx); gData->ok = FALSE; @@ -2684,7 +2684,7 @@ ExecuteREBytecode(REGlobalData *gData, match_state_t *x) case REOP_LPAREN: pc = ReadCompactIndex(pc, &parenIndex); - TRACE("[ %lu ]\n", (ULONG_PTR)parenIndex); + TRACE("[ %Iu ]\n", (ULONG_PTR)parenIndex); assert(parenIndex < gData->regexp->parenCount); if (parenIndex + 1 > parenSoFar) parenSoFar = parenIndex + 1; @@ -3047,7 +3047,7 @@ ExecuteREBytecode(REGlobalData *gData, match_state_t *x) parenSoFar = curState->parenSoFar; } - TRACE("\tBT_Pop: %ld,%ld\n", + TRACE("\tBT_Pop: %Id,%Id\n", (ULONG_PTR)backTrackData->parenIndex, (ULONG_PTR)backTrackData->parenCount); continue; @@ -3184,12 +3184,12 @@ void regexp_destroy(regexp_t *re) UINT i; for (i = 0; i < re->classCount; i++) { if (re->classList[i].converted) - heap_free(re->classList[i].u.bits); + free(re->classList[i].u.bits); re->classList[i].u.bits = NULL; } - heap_free(re->classList); + free(re->classList); } - heap_free(re); + free(re); } regexp_t* regexp_new(void *cx, heap_pool_t *pool, const WCHAR *str, @@ -3238,14 +3238,14 @@ regexp_t* regexp_new(void *cx, heap_pool_t *pool, const WCHAR *str, goto out; } resize = offsetof(regexp_t, program) + state.progLength + 1; - re = heap_alloc(resize); + re = malloc(resize); if (!re) goto out; assert(state.classBitmapsMem <= CLASS_BITMAPS_MEM_LIMIT); re->classCount = state.classCount; if (re->classCount) { - re->classList = heap_alloc(re->classCount * sizeof(RECharSet)); + re->classList = malloc(re->classCount * sizeof(RECharSet)); if (!re->classList) { regexp_destroy(re); re = NULL; @@ -3272,7 +3272,7 @@ regexp_t* regexp_new(void *cx, heap_pool_t *pool, const WCHAR *str, regexp_t *tmp; assert((size_t)(endPC - re->program) < state.progLength + 1); resize = offsetof(regexp_t, program) + (endPC - re->program); - tmp = heap_realloc(re, resize); + tmp = realloc(re, resize); if (tmp) re = tmp; } diff --git a/dll/win32/vbscript/regexp.h b/dll/win32/vbscript/regexp.h index d8738e18026..f6887a7c4de 100644 --- a/dll/win32/vbscript/regexp.h +++ b/dll/win32/vbscript/regexp.h @@ -63,11 +63,11 @@ typedef struct regexp_t { jsbytecode program[1]; /* regular expression bytecode */ } regexp_t; -regexp_t* regexp_new(void*, heap_pool_t*, const WCHAR*, DWORD, WORD, BOOL) DECLSPEC_HIDDEN; -void regexp_destroy(regexp_t*) DECLSPEC_HIDDEN; +regexp_t* regexp_new(void*, heap_pool_t*, const WCHAR*, DWORD, WORD, BOOL); +void regexp_destroy(regexp_t*); HRESULT regexp_execute(regexp_t*, void*, heap_pool_t*, const WCHAR*, - DWORD, match_state_t*) DECLSPEC_HIDDEN; -HRESULT regexp_set_flags(regexp_t**, void*, heap_pool_t*, WORD) DECLSPEC_HIDDEN; + DWORD, match_state_t*); +HRESULT regexp_set_flags(regexp_t**, void*, heap_pool_t*, WORD); static inline match_state_t* alloc_match_state(regexp_t *regexp, heap_pool_t *pool, const WCHAR *pos) @@ -75,7 +75,7 @@ static inline match_state_t* alloc_match_state(regexp_t *regexp, size_t size = offsetof(match_state_t, parens) + regexp->parenCount*sizeof(RECapture); match_state_t *ret; - ret = pool ? heap_pool_alloc(pool, size) : heap_alloc(size); + ret = pool ? heap_pool_alloc(pool, size) : malloc(size); if(!ret) return NULL; diff --git a/dll/win32/vbscript/utils.c b/dll/win32/vbscript/utils.c index d30842c52eb..4bfc2c65a0a 100644 --- a/dll/win32/vbscript/utils.c +++ b/dll/win32/vbscript/utils.c @@ -28,6 +28,7 @@ typedef struct { LONG ref; SAFEARRAY *sa; + BOOL owned; ULONG i, size; } safearray_iter; @@ -62,7 +63,7 @@ static ULONG WINAPI safearray_iter_IEnumVARIANT_AddRef(IEnumVARIANT *iface) safearray_iter *This = impl_from_IEnumVARIANT(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -72,12 +73,15 @@ static ULONG WINAPI safearray_iter_IEnumVARIANT_Release(IEnumVARIANT *iface) safearray_iter *This = impl_from_IEnumVARIANT(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", iface, ref); + TRACE("(%p) ref=%ld\n", iface, ref); if(!ref) { - if(This->sa) + if(This->sa) { SafeArrayUnlock(This->sa); - heap_free(This); + if(This->owned) + SafeArrayDestroy(This->sa); + } + free(This); } return ref; @@ -90,7 +94,7 @@ static HRESULT WINAPI safearray_iter_IEnumVARIANT_Next(IEnumVARIANT *iface, HRESULT hres; VARIANT *v; - TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched); + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); if(celt != 1) { FIXME("celt != 1\n"); @@ -160,7 +164,7 @@ static ULONG get_safearray_size(SAFEARRAY *sa) return ret; } -HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) +HRESULT create_safearray_iter(SAFEARRAY *sa, BOOL owned, IEnumVARIANT **ev) { safearray_iter *iter; HRESULT hres; @@ -170,14 +174,14 @@ HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) return E_NOTIMPL; } - iter = heap_alloc(sizeof(*iter)); + iter = malloc(sizeof(*iter)); if(!iter) return E_OUTOFMEMORY; if(sa) { hres = SafeArrayLock(sa); if(FAILED(hres)) { - heap_free(iter); + free(iter); return hres; } } @@ -185,6 +189,7 @@ HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) iter->IEnumVARIANT_iface.lpVtbl = &safearray_iter_EnumVARIANTVtbl; iter->ref = 1; iter->sa = sa; + iter->owned = owned; iter->i = 0; iter->size = get_safearray_size(sa); diff --git a/dll/win32/vbscript/vbdisp.c b/dll/win32/vbscript/vbdisp.c index a6896eb0268..0ede0cfd6ba 100644 --- a/dll/win32/vbscript/vbdisp.c +++ b/dll/win32/vbscript/vbdisp.c @@ -24,6 +24,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); +static const GUID GUID_VBScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}}; + +#define DISPID_FUNCTION_MASK 0x20000000 #define FDEX_VERSION_MASK 0xf0000000 static inline BOOL is_func_id(vbdisp_t *This, DISPID id) @@ -35,19 +38,17 @@ static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, vbdisp_invoke_type_t { unsigned i; - for(i = invoke_type == VBDISP_ANY ? 0 : 1; i < This->desc->func_cnt; i++) { + for(i = 0; i < This->desc->func_cnt; i++) { if(invoke_type == VBDISP_ANY) { if(!search_private && !This->desc->funcs[i].is_public) continue; - if(!i && !This->desc->funcs[0].name) /* default value may not exist */ - continue; }else { if(!This->desc->funcs[i].entries[invoke_type] || (!search_private && !This->desc->funcs[i].entries[invoke_type]->is_public)) continue; } - if(!wcsicmp(This->desc->funcs[i].name, name)) { + if(This->desc->funcs[i].name && !wcsicmp(This->desc->funcs[i].name, name)) { *id = i; return TRUE; } @@ -121,8 +122,17 @@ static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DI case DISPATCH_PROPERTYGET|DISPATCH_METHOD: case DISPATCH_PROPERTYGET: if(dp->cArgs) { - WARN("called with arguments\n"); - return DISP_E_MEMBERNOTFOUND; /* That's what tests show */ + if (!V_ISARRAY(v)) + { + WARN("called with arguments for non-array property\n"); + return DISP_E_MEMBERNOTFOUND; /* That's what tests show */ + } + + if (FAILED(hres = array_access(V_ARRAY(v), dp, &v))) + { + WARN("failed to access array element\n"); + return hres; + } } hres = VariantCopyInd(res, v); @@ -174,7 +184,7 @@ static HRESULT invoke_vbdisp(vbdisp_t *This, DISPID id, DWORD flags, BOOL extern switch(flags) { case DISPATCH_PROPERTYGET: func = This->desc->funcs[id].entries[VBDISP_CALLGET]; - if(!func || (func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)) { + if(!func || func->type != FUNC_PROPGET) { WARN("no getter\n"); return DISP_E_MEMBERNOTFOUND; } @@ -196,32 +206,47 @@ static HRESULT invoke_vbdisp(vbdisp_t *This, DISPID id, DWORD flags, BOOL extern case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: { DISPPARAMS dp = {NULL, NULL, 1, 0}; BOOL needs_release; - VARIANT put_val; + VARIANT buf[6]; HRESULT hres; + INT i; - if(arg_cnt(params)) { - FIXME("arguments not implemented\n"); - return E_NOTIMPL; + dp.cArgs = arg_cnt(params) + 1; + if(dp.cArgs > ARRAY_SIZE(buf)) { + dp.rgvarg = malloc(dp.cArgs*sizeof(VARIANT)); + if(!dp.rgvarg) + return E_OUTOFMEMORY; + }else { + dp.rgvarg = buf; } - hres = get_propput_arg(This->desc->ctx, params, flags, &put_val, &needs_release); - if(FAILED(hres)) + hres = get_propput_arg(This->desc->ctx, params, flags, dp.rgvarg, &needs_release); + if(FAILED(hres)) { + if(dp.rgvarg != buf) + free(dp.rgvarg); return hres; + } - dp.rgvarg = &put_val; - func = This->desc->funcs[id].entries[V_VT(&put_val) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET]; + func = This->desc->funcs[id].entries[V_VT(dp.rgvarg) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET]; if(!func) { FIXME("no letter/setter\n"); + if(dp.rgvarg != buf) + free(dp.rgvarg); return DISP_E_MEMBERNOTFOUND; } + for(i=1; i < dp.cArgs; i++) { + dp.rgvarg[i]=params->rgvarg[params->cNamedArgs+i-1]; + } + hres = exec_script(This->desc->ctx, extern_caller, func, This, &dp, NULL); if(needs_release) - VariantClear(&put_val); + VariantClear(dp.rgvarg); + if(dp.rgvarg != buf) + free(dp.rgvarg); return hres; } default: - FIXME("flags %x\n", flags); + FIXME("flags %lx\n", flags); return DISP_E_MEMBERNOTFOUND; } } @@ -301,7 +326,7 @@ static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) vbdisp_t *This = impl_from_IDispatchEx(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -311,13 +336,13 @@ static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) vbdisp_t *This = impl_from_IDispatchEx(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref && run_terminator(This)) { clean_props(This); list_remove(&This->entry); - heap_free(This->arrays); - heap_free(This); + free(This->arrays); + free(This); } return ref; @@ -337,7 +362,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC ITypeInfo **ppTInfo) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); return E_NOTIMPL; } @@ -346,7 +371,7 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, DISPID *rgDispId) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, + FIXME("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return E_NOTIMPL; } @@ -357,7 +382,7 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, { vbdisp_t *This = impl_from_IDispatchEx(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL); @@ -367,7 +392,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW { vbdisp_t *This = impl_from_IDispatchEx(iface); - TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); + TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); grfdex &= ~FDEX_VERSION_MASK; @@ -377,7 +402,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW /* Tests show that fdexNameCaseSensitive is ignored */ if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive|fdexNameCaseSensitive)) { - FIXME("unsupported flags %x\n", grfdex); + FIXME("unsupported flags %lx\n", grfdex); return E_NOTIMPL; } @@ -388,8 +413,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { vbdisp_t *This = impl_from_IDispatchEx(iface); + IServiceProvider *prev_caller; + HRESULT hres; - TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); if(!This->desc) return E_UNEXPECTED; @@ -397,41 +424,51 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(pvarRes) V_VT(pvarRes) = VT_EMPTY; - return invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes); + prev_caller = This->desc->ctx->vbcaller->caller; + This->desc->ctx->vbcaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + + hres = invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes); + + This->desc->ctx->vbcaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); + return hres; } static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex); + FIXME("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex); return E_NOTIMPL; } static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%x)\n", This, id); + FIXME("(%p)->(%lx)\n", This, id); return E_NOTIMPL; } static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex); + FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); return E_NOTIMPL; } static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%x %p)\n", This, id, pbstrName); + FIXME("(%p)->(%lx %p)\n", This, id, pbstrName); return E_NOTIMPL; } static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) { vbdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid); + FIXME("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid); return E_NOTIMPL; } @@ -463,7 +500,7 @@ static IDispatchExVtbl DispatchExVtbl = { static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface) { return iface->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl - ? CONTAINING_RECORD((IDispatchEx *)iface, vbdisp_t, IDispatchEx_iface) + ? CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface) : NULL; } @@ -472,7 +509,7 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) vbdisp_t *vbdisp; HRESULT hres = S_OK; - vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] )); + vbdisp = calloc( 1, FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] )); if(!vbdisp) return E_OUTOFMEMORY; @@ -483,7 +520,7 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) list_add_tail(&desc->ctx->objects, &vbdisp->entry); if(desc->array_cnt) { - vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays)); + vbdisp->arrays = calloc(desc->array_cnt, sizeof(*vbdisp->arrays)); if(vbdisp->arrays) { unsigned i, j; @@ -526,49 +563,678 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) return S_OK; } -struct _ident_map_t { - const WCHAR *name; - BOOL is_var; - union { - dynamic_var_t *var; - function_t *func; - } u; +struct typeinfo_func { + function_t *func; + MEMBERID memid; }; -static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident) +typedef struct { + ITypeInfo ITypeInfo_iface; + ITypeComp ITypeComp_iface; + LONG ref; + + UINT num_vars; + UINT num_funcs; + struct typeinfo_func *funcs; + + ScriptDisp *disp; +} ScriptTypeInfo; + +static function_t *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid) { - return (ident-This->ident_map)+1; + UINT a = 0, b = typeinfo->num_funcs; + + if (!(memid & DISPID_FUNCTION_MASK)) return NULL; + + while (a < b) + { + UINT i = (a + b - 1) / 2; + + if (memid == typeinfo->funcs[i].memid) + return typeinfo->funcs[i].func; + else if (memid < typeinfo->funcs[i].memid) + b = i; + else + a = i + 1; + } + return NULL; } -static inline ident_map_t *id_to_ident(ScriptDisp *This, DISPID id) +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) { - return 0 < id && id <= This->ident_map_cnt ? This->ident_map+id-1 : NULL; + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); } -static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name) +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface) { - ident_map_t *ret; + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface); +} - if(!This->ident_map_size) { - This->ident_map = heap_alloc(4 * sizeof(*This->ident_map)); - if(!This->ident_map) - return NULL; - This->ident_map_size = 4; - }else if(This->ident_map_cnt == This->ident_map_size) { - ident_map_t *new_map; +static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); - new_map = heap_realloc(This->ident_map, 2*This->ident_map_size*sizeof(*new_map)); - if(!new_map) - return NULL; - This->ident_map = new_map; - This->ident_map_size *= 2; + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) + *ppv = &This->ITypeInfo_iface; + else if (IsEqualGUID(&IID_ITypeComp, riid)) + *ppv = &This->ITypeComp_iface; + else + { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; } - ret = This->ident_map + This->ident_map_cnt++; - ret->name = name; - return ret; + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; } +static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedDecrement(&This->ref); + UINT i; + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) + { + for (i = 0; i < This->num_funcs; i++) + release_vbscode(This->funcs[i].func->code_ctx); + + IDispatchEx_Release(&This->disp->IDispatchEx_iface); + free(This->funcs); + free(This); + } + return ref; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + TYPEATTR *attr; + + TRACE("(%p)->(%p)\n", This, ppTypeAttr); + + if (!ppTypeAttr) return E_INVALIDARG; + + attr = calloc(1, sizeof(*attr)); + if (!attr) return E_OUTOFMEMORY; + + attr->guid = GUID_VBScriptTypeInfo; + attr->lcid = LOCALE_USER_DEFAULT; + attr->memidConstructor = MEMBERID_NIL; + attr->memidDestructor = MEMBERID_NIL; + attr->cbSizeInstance = 4; + attr->typekind = TKIND_DISPATCH; + attr->cFuncs = This->num_funcs; + attr->cVars = This->num_vars; + attr->cImplTypes = 1; + attr->cbSizeVft = sizeof(IDispatchVtbl); + attr->cbAlignment = 4; + attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE; + attr->wMajorVerNum = VBSCRIPT_MAJOR_VERSION; + attr->wMinorVerNum = VBSCRIPT_MINOR_VERSION; + + *ppTypeAttr = attr; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, ppTComp); + + if (!ppTComp) return E_INVALIDARG; + + *ppTComp = &This->ITypeComp_iface; + ITypeInfo_AddRef(iface); + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + function_t *func; + FUNCDESC *desc; + UINT i; + + TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc); + + if (!ppFuncDesc) return E_INVALIDARG; + if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND; + func = This->funcs[index].func; + + /* Store the parameter array after the FUNCDESC structure */ + desc = calloc(1, sizeof(*desc) + sizeof(ELEMDESC) * func->arg_cnt); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = This->funcs[index].memid; + desc->funckind = FUNC_DISPATCH; + desc->invkind = INVOKE_FUNC; + desc->callconv = CC_STDCALL; + desc->cParams = func->arg_cnt; + desc->elemdescFunc.tdesc.vt = (func->type == FUNC_SUB) ? VT_VOID : VT_VARIANT; + + if (func->arg_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1); + for (i = 0; i < func->arg_cnt; i++) + desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT; + + *ppFuncDesc = desc; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + VARDESC *desc; + + TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc); + + if (!ppVarDesc) return E_INVALIDARG; + if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND; + + desc = calloc(1, sizeof(*desc)); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = index + 1; + desc->varkind = VAR_DISPATCH; + desc->elemdescVar.tdesc.vt = VT_VARIANT; + + *ppVarDesc = desc; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, + UINT cMaxNames, UINT *pcNames) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + function_t *func; + HRESULT hr; + UINT i = 0; + + TRACE("(%p)->(%ld %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); + + if (!rgBstrNames || !pcNames) return E_INVALIDARG; + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + func = get_func_from_memid(This, memid); + if (!func && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames); + } + + *pcNames = 0; + if (!cMaxNames) return S_OK; + + if (func) + { + UINT num = min(cMaxNames, func->arg_cnt + 1); + + rgBstrNames[0] = SysAllocString(func->name); + if (!rgBstrNames[0]) return E_OUTOFMEMORY; + + for (i = 1; i < num; i++) + { + if (!(rgBstrNames[i] = SysAllocString(func->args[i - 1].name))) + { + do SysFreeString(rgBstrNames[--i]); while (i); + return E_OUTOFMEMORY; + } + } + } + else + { + rgBstrNames[0] = SysAllocString(This->disp->global_vars[memid - 1]->name); + if (!rgBstrNames[0]) return E_OUTOFMEMORY; + i++; + } + + *pcNames = i; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pRefType); + + /* We only inherit from IDispatch */ + if (!pRefType) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pRefType = 1; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags); + + if (!pImplTypeFlags) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pImplTypeFlags = 0; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames, + MEMBERID *pMemId) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + const WCHAR *name; + HRESULT hr = S_OK; + int i, j, arg; + + TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + + if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG; + + for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL; + name = rgszNames[0]; + + for (i = 0; i < This->num_funcs; i++) + { + function_t *func = This->funcs[i].func; + + if (wcsicmp(name, func->name)) continue; + pMemId[0] = This->funcs[i].memid; + + for (j = 1; j < cNames; j++) + { + name = rgszNames[j]; + for (arg = func->arg_cnt; --arg >= 0;) + if (!wcsicmp(name, func->args[arg].name)) + break; + if (arg >= 0) + pMemId[j] = arg; + else + hr = DISP_E_UNKNOWNNAME; + } + return hr; + } + + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(name, This->disp->global_vars[i]->name)) continue; + pMemId[0] = i + 1; + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId); +} + +static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + IDispatch *disp; + HRESULT hr; + + TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This, pvInstance, memid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!pvInstance) return E_INVALIDARG; + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + if (!get_func_from_memid(This, memid) && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); + } + + hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp); + if (FAILED(hr)) return hr; + + hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + IDispatch_Release(disp); + + return hr; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName, + BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + function_t *func; + HRESULT hr; + + TRACE("(%p)->(%ld %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + if (pBstrDocString) *pBstrDocString = NULL; + if (pdwHelpContext) *pdwHelpContext = 0; + if (pBstrHelpFile) *pBstrHelpFile = NULL; + + if (memid == MEMBERID_NIL) + { + if (pBstrName && !(*pBstrName = SysAllocString(L"VBScriptTypeInfo"))) + return E_OUTOFMEMORY; + if (pBstrDocString && + !(*pBstrDocString = SysAllocString(L"Visual Basic Scripting Type Info"))) + { + if (pBstrName) SysFreeString(*pBstrName); + return E_OUTOFMEMORY; + } + return S_OK; + } + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + func = get_func_from_memid(This, memid); + if (!func && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString, + pdwHelpContext, pBstrHelpFile); + } + + if (pBstrName) + { + *pBstrName = SysAllocString(func ? func->name : This->disp->global_vars[memid - 1]->name); + if (!*pBstrName) return E_OUTOFMEMORY; + } + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, + BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + if (pBstrDllName) *pBstrDllName = NULL; + if (pBstrName) *pBstrName = NULL; + if (pwOrdinal) *pwOrdinal = 0; + + if (!get_func_from_memid(This, memid) && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + } + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + HRESULT hr; + + TRACE("(%p)->(%lx %p)\n", This, hRefType, ppTInfo); + + if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG; + + if (hRefType & ~3) return E_FAIL; + if (hRefType & 1) + { + hr = get_dispatch_typeinfo(ppTInfo); + if (FAILED(hr)) return hr; + } + else + *ppTInfo = iface; + + ITypeInfo_AddRef(*ppTInfo); + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %d %p)\n", This, memid, invKind, ppv); + + if (!ppv) return E_INVALIDARG; + *ppv = NULL; + + if (!get_func_from_memid(This, memid) && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv); + } + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj); + + if (!ppvObj) return E_INVALIDARG; + + *ppvObj = NULL; + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %p)\n", This, memid, pBstrMops); + + if (!pBstrMops) return E_INVALIDARG; + + if (!get_func_from_memid(This, memid) && memid > This->num_vars) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops); + } + + *pBstrMops = NULL; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex); + + return E_NOTIMPL; +} + +static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pTypeAttr); + + free(pTypeAttr); +} + +static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pFuncDesc); + + free(pFuncDesc); +} + +static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pVarDesc); + + free(pVarDesc); +} + +static const ITypeInfoVtbl ScriptTypeInfoVtbl = { + ScriptTypeInfo_QueryInterface, + ScriptTypeInfo_AddRef, + ScriptTypeInfo_Release, + ScriptTypeInfo_GetTypeAttr, + ScriptTypeInfo_GetTypeComp, + ScriptTypeInfo_GetFuncDesc, + ScriptTypeInfo_GetVarDesc, + ScriptTypeInfo_GetNames, + ScriptTypeInfo_GetRefTypeOfImplType, + ScriptTypeInfo_GetImplTypeFlags, + ScriptTypeInfo_GetIDsOfNames, + ScriptTypeInfo_Invoke, + ScriptTypeInfo_GetDocumentation, + ScriptTypeInfo_GetDllEntry, + ScriptTypeInfo_GetRefTypeInfo, + ScriptTypeInfo_AddressOfMember, + ScriptTypeInfo_CreateInstance, + ScriptTypeInfo_GetMops, + ScriptTypeInfo_GetContainingTypeLib, + ScriptTypeInfo_ReleaseTypeAttr, + ScriptTypeInfo_ReleaseFuncDesc, + ScriptTypeInfo_ReleaseVarDesc +}; + +static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv); +} + +static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_AddRef(&This->ITypeInfo_iface); +} + +static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_Release(&This->ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags, + ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + UINT flags = wFlags ? wFlags : ~0; + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr; + UINT i; + + TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, + wFlags, ppTInfo, pDescKind, pBindPtr); + + if (!szName || !ppTInfo || !pDescKind || !pBindPtr) + return E_INVALIDARG; + + for (i = 0; i < This->num_funcs; i++) + { + if (wcsicmp(szName, This->funcs[i].func->name)) continue; + if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_FUNCDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(szName, This->disp->global_vars[i]->name)) continue; + if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH; + + hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_VARDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; + } + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr); + ITypeComp_Release(disp_typecomp); + return hr; +} + +static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, + ITypeInfo **ppTInfo, ITypeComp **ppTComp) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr; + + TRACE("(%p)->(%s %08lx %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp); + + if (!szName || !ppTInfo || !ppTComp) + return E_INVALIDARG; + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp); + ITypeComp_Release(disp_typecomp); + return hr; +} + +static const ITypeCompVtbl ScriptTypeCompVtbl = { + ScriptTypeComp_QueryInterface, + ScriptTypeComp_AddRef, + ScriptTypeComp_Release, + ScriptTypeComp_Bind, + ScriptTypeComp_BindType +}; + static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface); @@ -602,7 +1268,7 @@ static ULONG WINAPI ScriptDisp_AddRef(IDispatchEx *iface) ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -611,13 +1277,20 @@ static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); LONG ref = InterlockedDecrement(&This->ref); + unsigned i; - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { assert(!This->ctx); - heap_free(This->ident_map); - heap_free(This); + + for (i = 0; i < This->global_vars_cnt; i++) + release_dynamic_var(This->global_vars[i]); + + heap_pool_free(&This->heap); + free(This->global_vars); + free(This->global_funcs); + free(This); } return ref; @@ -633,12 +1306,53 @@ static HRESULT WINAPI ScriptDisp_GetTypeInfoCount(IDispatchEx *iface, UINT *pcti return S_OK; } -static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, - ITypeInfo **ppTInfo) +static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ret) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; + ScriptTypeInfo *type_info; + UINT num_funcs = 0; + unsigned i, j; + + TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ret); + + if(iTInfo) + return DISP_E_BADINDEX; + + if(!(type_info = calloc(1, sizeof(*type_info)))) + return E_OUTOFMEMORY; + + for(i = 0; i < This->global_funcs_cnt; i++) + if(This->global_funcs[i]->is_public) + num_funcs++; + + type_info->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + type_info->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl; + type_info->ref = 1; + type_info->num_funcs = num_funcs; + type_info->num_vars = This->global_vars_cnt; + type_info->disp = This; + + type_info->funcs = calloc(num_funcs, sizeof(*type_info->funcs)); + if(!type_info->funcs) + { + free(type_info); + return E_OUTOFMEMORY; + } + + for(j = 0, i = 0; i < This->global_funcs_cnt; i++) + { + if(!This->global_funcs[i]->is_public) continue; + + type_info->funcs[j].memid = i + 1 + DISPID_FUNCTION_MASK; + type_info->funcs[j].func = This->global_funcs[i]; + grab_vbscode(This->global_funcs[i]->code_ctx); + j++; + } + + IDispatchEx_AddRef(&This->IDispatchEx_iface); + + *ret = &type_info->ITypeInfo_iface; + return S_OK; } static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid, @@ -648,16 +1362,24 @@ static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid, UINT i; HRESULT hres; - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); - for(i=0; i < cNames; i++) { - hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i); - if(FAILED(hres)) - return hres; + if(cNames == 0) + return S_OK; + + hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[0], 0, rgDispId); + if(FAILED(hres)) + return hres; + + /* DISPIDs for parameters don't seem to be supported */ + if(cNames > 1) { + for(i = 1; i < cNames; i++) + rgDispId[i] = DISPID_UNKNOWN; + hres = DISP_E_UNKNOWNNAME; } - return S_OK; + return hres; } static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, @@ -665,7 +1387,7 @@ static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, @@ -675,44 +1397,23 @@ static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - dynamic_var_t *var; - ident_map_t *ident; - function_t *func; + unsigned i; - TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); + TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); if(!This->ctx) return E_UNEXPECTED; - for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) { - if(!wcsicmp(ident->name, bstrName)) { - *pid = ident_to_id(This, ident); + for(i = 0; i < This->global_vars_cnt; i++) { + if(!wcsicmp(This->global_vars[i]->name, bstrName)) { + *pid = i + 1; return S_OK; } } - for(var = This->ctx->global_vars; var; var = var->next) { - if(!wcsicmp(var->name, bstrName)) { - ident = add_ident(This, var->name); - if(!ident) - return E_OUTOFMEMORY; - - ident->is_var = TRUE; - ident->u.var = var; - *pid = ident_to_id(This, ident); - return S_OK; - } - } - - for(func = This->ctx->global_funcs; func; func = func->next) { - if(!wcsicmp(func->name, bstrName)) { - ident = add_ident(This, func->name); - if(!ident) - return E_OUTOFMEMORY; - - ident->is_var = FALSE; - ident->u.func = func; - *pid = ident_to_id(This, ident); + for(i = 0; i < This->global_funcs_cnt; i++) { + if(!wcsicmp(This->global_funcs[i]->name, bstrName)) { + *pid = i + 1 + DISPID_FUNCTION_MASK; return S_OK; } } @@ -725,69 +1426,94 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - ident_map_t *ident; + IServiceProvider *prev_caller; HRESULT hres; - TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - ident = id_to_ident(This, id); - if(!ident) - return DISP_E_MEMBERNOTFOUND; + if (!This->ctx) + return E_UNEXPECTED; - if(ident->is_var) { - if(ident->u.var->is_const) { - FIXME("const not supported\n"); - return E_NOTIMPL; + prev_caller = This->ctx->vbcaller->caller; + This->ctx->vbcaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + + if (id & DISPID_FUNCTION_MASK) + { + id &= ~DISPID_FUNCTION_MASK; + if (id > This->global_funcs_cnt) { + hres = DISP_E_MEMBERNOTFOUND; + goto done; } - return invoke_variant_prop(This->ctx, &ident->u.var->v, wFlags, pdp, pvarRes); + switch (wFlags) + { + case DISPATCH_METHOD: + case DISPATCH_METHOD | DISPATCH_PROPERTYGET: + hres = exec_script(This->ctx, TRUE, This->global_funcs[id - 1], NULL, pdp, pvarRes); + break; + default: + FIXME("Unsupported flags %x\n", wFlags); + hres = E_NOTIMPL; + } + + goto done; } - switch(wFlags) { - case DISPATCH_METHOD: - case DISPATCH_METHOD|DISPATCH_PROPERTYGET: - hres = exec_script(This->ctx, TRUE, ident->u.func, NULL, pdp, pvarRes); - break; - default: - FIXME("Unsupported flags %x\n", wFlags); + if (id > This->global_vars_cnt) { + hres = DISP_E_MEMBERNOTFOUND; + goto done; + } + + if (This->global_vars[id - 1]->is_const) + { + FIXME("const not supported\n"); hres = E_NOTIMPL; + goto done; } + hres = invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes); + +done: + This->ctx->vbcaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); return hres; } static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex); + FIXME("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex); return E_NOTIMPL; } static HRESULT WINAPI ScriptDisp_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%x)\n", This, id); + FIXME("(%p)->(%lx)\n", This, id); return E_NOTIMPL; } static HRESULT WINAPI ScriptDisp_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex); + FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); return E_NOTIMPL; } static HRESULT WINAPI ScriptDisp_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%x %p)\n", This, id, pbstrName); + FIXME("(%p)->(%lx %p)\n", This, id, pbstrName); return E_NOTIMPL; } static HRESULT WINAPI ScriptDisp_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); - FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid); + FIXME("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid); return E_NOTIMPL; } @@ -820,13 +1546,15 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret) { ScriptDisp *script_disp; - script_disp = heap_alloc_zero(sizeof(*script_disp)); + script_disp = calloc(1, sizeof(*script_disp)); if(!script_disp) return E_OUTOFMEMORY; script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl; script_disp->ref = 1; script_disp->ctx = ctx; + heap_pool_init(&script_disp->heap); + script_disp->rnd = 0x50000; *ret = script_disp; return S_OK; @@ -874,65 +1602,74 @@ HRESULT disp_get_id(IDispatch *disp, BSTR name, vbdisp_invoke_type_t invoke_type #define RPC_E_SERVER_UNAVAILABLE 0x800706ba -HRESULT map_hres(HRESULT hres) +void map_vbs_exception(EXCEPINFO *ei) { - if(SUCCEEDED(hres) || HRESULT_FACILITY(hres) == FACILITY_VBS) - return hres; + int vbse_number; - switch(hres) { - case E_NOTIMPL: return MAKE_VBSERROR(VBSE_ACTION_NOT_SUPPORTED); - case E_NOINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NOT_SUPPORTED); - case DISP_E_UNKNOWNINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD); - case DISP_E_MEMBERNOTFOUND: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD); - case DISP_E_PARAMNOTFOUND: return MAKE_VBSERROR(VBSE_NAMED_PARAM_NOT_FOUND); - case DISP_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); - case DISP_E_UNKNOWNNAME: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD); - case DISP_E_NONAMEDARGS: return MAKE_VBSERROR(VBSE_NAMED_ARGS_NOT_SUPPORTED); - case DISP_E_BADVARTYPE: return MAKE_VBSERROR(VBSE_INVALID_TYPELIB_VARIABLE); - case DISP_E_OVERFLOW: return MAKE_VBSERROR(VBSE_OVERFLOW); - case DISP_E_BADINDEX: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); - case DISP_E_UNKNOWNLCID: return MAKE_VBSERROR(VBSE_LOCALE_SETTING_NOT_SUPPORTED); - case DISP_E_ARRAYISLOCKED: return MAKE_VBSERROR(VBSE_ARRAY_LOCKED); - case DISP_E_BADPARAMCOUNT: return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH); - case DISP_E_PARAMNOTOPTIONAL: return MAKE_VBSERROR(VBSE_PARAMETER_NOT_OPTIONAL); - case DISP_E_NOTACOLLECTION: return MAKE_VBSERROR(VBSE_NOT_ENUM); - case TYPE_E_DLLFUNCTIONNOTFOUND: return MAKE_VBSERROR(VBSE_INVALID_DLL_FUNCTION_NAME); - case TYPE_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH); - case TYPE_E_OUTOFBOUNDS: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS); - case TYPE_E_IOERROR: return MAKE_VBSERROR(VBSE_IO_ERROR); - case TYPE_E_CANTCREATETMPFILE: return MAKE_VBSERROR(VBSE_CANT_CREATE_TMP_FILE); - case STG_E_FILENOTFOUND: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND); - case STG_E_PATHNOTFOUND: return MAKE_VBSERROR(VBSE_PATH_NOT_FOUND); - case STG_E_TOOMANYOPENFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES); - case STG_E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case STG_E_INSUFFICIENTMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY); - case STG_E_NOMOREFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES); - case STG_E_DISKISWRITEPROTECTED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case STG_E_WRITEFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR); - case STG_E_READFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR); - case STG_E_SHAREVIOLATION: return MAKE_VBSERROR(VBSE_PATH_FILE_ACCESS); - case STG_E_LOCKVIOLATION: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case STG_E_FILEALREADYEXISTS: return MAKE_VBSERROR(VBSE_FILE_ALREADY_EXISTS); - case STG_E_MEDIUMFULL: return MAKE_VBSERROR(VBSE_DISK_FULL); - case STG_E_INVALIDNAME: return MAKE_VBSERROR(VBSE_FILE_NOT_FOUND); - case STG_E_INUSE: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case STG_E_NOTCURRENT: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case STG_E_CANTSAVE: return MAKE_VBSERROR(VBSE_IO_ERROR); - case REGDB_E_CLASSNOTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); - case MK_E_UNAVAILABLE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); - case MK_E_INVALIDEXTENSION: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND); - case MK_E_CANTOPENFILE: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND); - case CO_E_CLASSSTRING: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); - case CO_E_APPNOTFOUND: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); - case CO_E_APPDIDNTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); - case E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED); - case E_OUTOFMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY); - case E_INVALIDARG: return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); - case RPC_E_SERVER_UNAVAILABLE: return MAKE_VBSERROR(VBSE_SERVER_NOT_FOUND); - case CO_E_SERVER_EXEC_FAILURE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT); + if(HRESULT_FACILITY(ei->scode) == FACILITY_VBS) + vbse_number = HRESULT_CODE(ei->scode); + else + { + switch(ei->scode) { + case E_NOTIMPL: vbse_number = VBSE_ACTION_NOT_SUPPORTED; break; + case E_NOINTERFACE: vbse_number = VBSE_OLE_NOT_SUPPORTED; break; + case DISP_E_UNKNOWNINTERFACE: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break; + case DISP_E_MEMBERNOTFOUND: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break; + case DISP_E_PARAMNOTFOUND: vbse_number = VBSE_NAMED_PARAM_NOT_FOUND; break; + case DISP_E_TYPEMISMATCH: vbse_number = VBSE_TYPE_MISMATCH; break; + case DISP_E_UNKNOWNNAME: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break; + case DISP_E_NONAMEDARGS: vbse_number = VBSE_NAMED_ARGS_NOT_SUPPORTED; break; + case DISP_E_BADVARTYPE: vbse_number = VBSE_INVALID_TYPELIB_VARIABLE; break; + case DISP_E_OVERFLOW: vbse_number = VBSE_OVERFLOW; break; + case DISP_E_BADINDEX: vbse_number = VBSE_OUT_OF_BOUNDS; break; + case DISP_E_UNKNOWNLCID: vbse_number = VBSE_LOCALE_SETTING_NOT_SUPPORTED; break; + case DISP_E_ARRAYISLOCKED: vbse_number = VBSE_ARRAY_LOCKED; break; + case DISP_E_BADPARAMCOUNT: vbse_number = VBSE_FUNC_ARITY_MISMATCH; break; + case DISP_E_PARAMNOTOPTIONAL: vbse_number = VBSE_PARAMETER_NOT_OPTIONAL; break; + case DISP_E_NOTACOLLECTION: vbse_number = VBSE_NOT_ENUM; break; + case TYPE_E_DLLFUNCTIONNOTFOUND: vbse_number = VBSE_INVALID_DLL_FUNCTION_NAME; break; + case TYPE_E_TYPEMISMATCH: vbse_number = VBSE_TYPE_MISMATCH; break; + case TYPE_E_OUTOFBOUNDS: vbse_number = VBSE_OUT_OF_BOUNDS; break; + case TYPE_E_IOERROR: vbse_number = VBSE_IO_ERROR; break; + case TYPE_E_CANTCREATETMPFILE: vbse_number = VBSE_CANT_CREATE_TMP_FILE; break; + case STG_E_FILENOTFOUND: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break; + case STG_E_PATHNOTFOUND: vbse_number = VBSE_PATH_NOT_FOUND; break; + case STG_E_TOOMANYOPENFILES: vbse_number = VBSE_TOO_MANY_FILES; break; + case STG_E_ACCESSDENIED: vbse_number = VBSE_PERMISSION_DENIED; break; + case STG_E_INSUFFICIENTMEMORY: vbse_number = VBSE_OUT_OF_MEMORY; break; + case STG_E_NOMOREFILES: vbse_number = VBSE_TOO_MANY_FILES; break; + case STG_E_DISKISWRITEPROTECTED: vbse_number = VBSE_PERMISSION_DENIED; break; + case STG_E_WRITEFAULT: vbse_number = VBSE_IO_ERROR; break; + case STG_E_READFAULT: vbse_number = VBSE_IO_ERROR; break; + case STG_E_SHAREVIOLATION: vbse_number = VBSE_PATH_FILE_ACCESS; break; + case STG_E_LOCKVIOLATION: vbse_number = VBSE_PERMISSION_DENIED; break; + case STG_E_FILEALREADYEXISTS: vbse_number = VBSE_FILE_ALREADY_EXISTS; break; + case STG_E_MEDIUMFULL: vbse_number = VBSE_DISK_FULL; break; + case STG_E_INVALIDNAME: vbse_number = VBSE_FILE_NOT_FOUND; break; + case STG_E_INUSE: vbse_number = VBSE_PERMISSION_DENIED; break; + case STG_E_NOTCURRENT: vbse_number = VBSE_PERMISSION_DENIED; break; + case STG_E_CANTSAVE: vbse_number = VBSE_IO_ERROR; break; + case REGDB_E_CLASSNOTREG: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + case MK_E_UNAVAILABLE: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + case MK_E_INVALIDEXTENSION: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break; + case MK_E_CANTOPENFILE: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break; + case CO_E_CLASSSTRING: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + case CO_E_APPNOTFOUND: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + case CO_E_APPDIDNTREG: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + case E_ACCESSDENIED: vbse_number = VBSE_PERMISSION_DENIED; break; + case E_OUTOFMEMORY: vbse_number = VBSE_OUT_OF_MEMORY; break; + case E_INVALIDARG: vbse_number = VBSE_ILLEGAL_FUNC_CALL; break; + case RPC_E_SERVER_UNAVAILABLE: vbse_number = VBSE_SERVER_NOT_FOUND; break; + case CO_E_SERVER_EXEC_FAILURE: vbse_number = VBSE_CANT_CREATE_OBJECT; break; + default: return; /* early return, all other HRESULT left as-is */ + } + ei->scode = MAKE_VBSERROR(vbse_number); } - - return hres; + if(!ei->bstrSource) + ei->bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR); + if(!ei->bstrDescription) + if(!(ei->bstrDescription = get_vbscript_string(vbse_number))) + ei->bstrDescription = get_vbscript_string(VBS_UNKNOWN_RUNTIME_ERROR); } HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, VARIANT *retv) @@ -952,15 +1689,21 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, return invoke_vbdisp(vbdisp, id, flags, FALSE, dp, retv); hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(FAILED(hres)) { + if(SUCCEEDED(hres)) { + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, &ctx->vbcaller->IServiceProvider_iface); + IDispatchEx_Release(dispex); + }else { UINT err = 0; TRACE("using IDispatch\n"); - return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err); + hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err); } - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */); - IDispatchEx_Release(dispex); + if(hres == DISP_E_EXCEPTION) { + clear_ei(&ctx->ei); + ctx->ei = ei; + hres = SCRIPT_E_RECORDED; + } return hres; } @@ -985,14 +1728,19 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, NULL /* FIXME! */); + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, &ctx->vbcaller->IServiceProvider_iface); IDispatchEx_Release(dispex); }else { - ULONG err = 0; + UINT err = 0; TRACE("using IDispatch\n"); hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, NULL, &ei, &err); } + if(hres == DISP_E_EXCEPTION) { + clear_ei(&ctx->ei); + ctx->ei = ei; + hres = SCRIPT_E_RECORDED; + } return hres; } diff --git a/dll/win32/vbscript/vbregexp.c b/dll/win32/vbscript/vbregexp.c index 3400e81066d..4a56875ef14 100644 --- a/dll/win32/vbscript/vbregexp.c +++ b/dll/win32/vbscript/vbregexp.c @@ -19,6 +19,7 @@ #include "vbscript.h" #include "regexp.h" #include "vbsregexp55.h" +#include "wchar.h" #include "wine/debug.h" @@ -51,12 +52,11 @@ static HRESULT init_regexp_typeinfo(regexp_tid_t tid) HRESULT hres; if(!typelib) { - static const WCHAR vbscript_dll3W[] = {'v','b','s','c','r','i','p','t','.','d','l','l','\\','3',0}; ITypeLib *tl; - hres = LoadTypeLib(vbscript_dll3W, &tl); + hres = LoadTypeLib(L"vbscript.dll\\3", &tl); if(FAILED(hres)) { - ERR("LoadRegTypeLib failed: %08x\n", hres); + ERR("LoadRegTypeLib failed: %08lx\n", hres); return hres; } @@ -69,7 +69,7 @@ static HRESULT init_regexp_typeinfo(regexp_tid_t tid) hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti); if(FAILED(hres)) { - ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres); + ERR("GetTypeInfoOfGuid(%s) failed: %08lx\n", debugstr_guid(tid_ids[tid]), hres); return hres; } @@ -170,7 +170,7 @@ static ULONG WINAPI SubMatches_AddRef(ISubMatches *iface) SubMatches *This = impl_from_ISubMatches(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -180,12 +180,12 @@ static ULONG WINAPI SubMatches_Release(ISubMatches *iface) SubMatches *This = impl_from_ISubMatches(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { - heap_free(This->match); - heap_free(This->result); - heap_free(This); + free(This->match); + free(This->result); + free(This); } return ref; @@ -205,7 +205,7 @@ static HRESULT WINAPI SubMatches_GetTypeInfo(ISubMatches *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { SubMatches *This = impl_from_ISubMatches(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); return E_NOTIMPL; } @@ -214,7 +214,7 @@ static HRESULT WINAPI SubMatches_GetIDsOfNames(ISubMatches *iface, { SubMatches *This = impl_from_ISubMatches(iface); - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return ITypeInfo_GetIDsOfNames(typeinfos[SubMatches_tid], rgszNames, cNames, rgDispId); @@ -226,7 +226,7 @@ static HRESULT WINAPI SubMatches_Invoke(ISubMatches *iface, DISPID dispIdMember, { SubMatches *This = impl_from_ISubMatches(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return ITypeInfo_Invoke(typeinfos[SubMatches_tid], iface, dispIdMember, wFlags, @@ -238,7 +238,7 @@ static HRESULT WINAPI SubMatches_get_Item(ISubMatches *iface, { SubMatches *This = impl_from_ISubMatches(iface); - TRACE("(%p)->(%d %p)\n", This, index, pSubMatch); + TRACE("(%p)->(%ld %p)\n", This, index, pSubMatch); if(!pSubMatch) return E_POINTER; @@ -307,7 +307,7 @@ static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches * if(FAILED(hres)) return hres; - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; @@ -315,9 +315,9 @@ static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches * ret->result = result; if(result) { - ret->match = heap_alloc((result->match_len+1) * sizeof(WCHAR)); + ret->match = malloc((result->match_len+1) * sizeof(WCHAR)); if(!ret->match) { - heap_free(ret); + free(ret); return E_OUTOFMEMORY; } memcpy(ret->match, result->cp-result->match_len, result->match_len*sizeof(WCHAR)); @@ -377,7 +377,7 @@ static ULONG WINAPI Match2_AddRef(IMatch2 *iface) Match2 *This = impl_from_IMatch2(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -387,11 +387,11 @@ static ULONG WINAPI Match2_Release(IMatch2 *iface) Match2 *This = impl_from_IMatch2(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { ISubMatches_Release(&This->sub_matches->ISubMatches_iface); - heap_free(This); + free(This); } return ref; @@ -411,7 +411,7 @@ static HRESULT WINAPI Match2_GetTypeInfo(IMatch2 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { Match2 *This = impl_from_IMatch2(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); return E_NOTIMPL; } @@ -420,7 +420,7 @@ static HRESULT WINAPI Match2_GetIDsOfNames(IMatch2 *iface, { Match2 *This = impl_from_IMatch2(iface); - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return ITypeInfo_GetIDsOfNames(typeinfos[Match2_tid], rgszNames, cNames, rgDispId); @@ -432,7 +432,7 @@ static HRESULT WINAPI Match2_Invoke(IMatch2 *iface, DISPID dispIdMember, { Match2 *This = impl_from_IMatch2(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return ITypeInfo_Invoke(typeinfos[Match2_tid], iface, dispIdMember, wFlags, @@ -605,14 +605,14 @@ static HRESULT create_match2(DWORD pos, match_state_t **result, IMatch2 **match) if(FAILED(hres)) return hres; - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; ret->index = pos; hres = create_sub_matches(pos, result ? *result : NULL, &ret->sub_matches); if(FAILED(hres)) { - heap_free(ret); + free(ret); return hres; } if(result) @@ -657,7 +657,7 @@ static ULONG WINAPI MatchCollectionEnum_AddRef(IEnumVARIANT *iface) MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -667,11 +667,11 @@ static ULONG WINAPI MatchCollectionEnum_Release(IEnumVARIANT *iface) MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { IMatchCollection2_Release(This->mc); - heap_free(This); + free(This); } return ref; @@ -684,7 +684,7 @@ static HRESULT WINAPI MatchCollectionEnum_Next(IEnumVARIANT *iface, DWORD i; HRESULT hres = S_OK; - TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched); + TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); if(This->pos>=This->count) { if(pCeltFetched) @@ -714,7 +714,7 @@ static HRESULT WINAPI MatchCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt) { MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface); - TRACE("(%p)->(%u)\n", This, celt); + TRACE("(%p)->(%lu)\n", This, celt); if(This->pos+celt <= This->count) This->pos += celt; @@ -754,7 +754,7 @@ static HRESULT create_enum_variant_mc2(IMatchCollection2 *mc, ULONG pos, IEnumVA { MatchCollectionEnum *ret; - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; @@ -810,7 +810,7 @@ static ULONG WINAPI MatchCollection2_AddRef(IMatchCollection2 *iface) MatchCollection2 *This = impl_from_IMatchCollection2(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -820,16 +820,16 @@ static ULONG WINAPI MatchCollection2_Release(IMatchCollection2 *iface) MatchCollection2 *This = impl_from_IMatchCollection2(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { DWORD i; for(i=0; icount; i++) IMatch2_Release(This->matches[i]); - heap_free(This->matches); + free(This->matches); - heap_free(This); + free(This); } return ref; @@ -849,7 +849,7 @@ static HRESULT WINAPI MatchCollection2_GetTypeInfo(IMatchCollection2 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { MatchCollection2 *This = impl_from_IMatchCollection2(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); return E_NOTIMPL; } @@ -858,7 +858,7 @@ static HRESULT WINAPI MatchCollection2_GetIDsOfNames(IMatchCollection2 *iface, { MatchCollection2 *This = impl_from_IMatchCollection2(iface); - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return ITypeInfo_GetIDsOfNames(typeinfos[MatchCollection2_tid], rgszNames, cNames, rgDispId); @@ -870,7 +870,7 @@ static HRESULT WINAPI MatchCollection2_Invoke(IMatchCollection2 *iface, DISPID d { MatchCollection2 *This = impl_from_IMatchCollection2(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return ITypeInfo_Invoke(typeinfos[MatchCollection2_tid], iface, dispIdMember, wFlags, @@ -1024,12 +1024,12 @@ static HRESULT add_match(IMatchCollection2 *iface, IMatch2 *add) TRACE("(%p)->(%p)\n", This, add); if(!This->size) { - This->matches = heap_alloc(8*sizeof(IMatch*)); + This->matches = malloc(8 * sizeof(*This->matches)); if(!This->matches) return E_OUTOFMEMORY; This->size = 8; }else if(This->size == This->count) { - IMatch2 **new_matches = heap_realloc(This->matches, 2*This->size*sizeof(IMatch*)); + IMatch2 **new_matches = realloc(This->matches, 2 * This->size * sizeof(*This->matches)); if(!new_matches) return E_OUTOFMEMORY; @@ -1051,7 +1051,7 @@ static HRESULT create_match_collection2(IMatchCollection2 **match_collection) if(FAILED(hres)) return hres; - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; @@ -1103,7 +1103,7 @@ static ULONG WINAPI RegExp2_AddRef(IRegExp2 *iface) RegExp2 *This = impl_from_IRegExp2(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -1113,14 +1113,14 @@ static ULONG WINAPI RegExp2_Release(IRegExp2 *iface) RegExp2 *This = impl_from_IRegExp2(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { - heap_free(This->pattern); + free(This->pattern); if(This->regexp) regexp_destroy(This->regexp); heap_pool_free(&This->pool); - heap_free(This); + free(This); } return ref; @@ -1140,8 +1140,12 @@ static HRESULT WINAPI RegExp2_GetTypeInfo(IRegExp2 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { RegExp2 *This = impl_from_IRegExp2(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; + + TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); + + *ppTInfo = typeinfos[RegExp2_tid]; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; } static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid, @@ -1149,7 +1153,7 @@ static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid, { RegExp2 *This = impl_from_IRegExp2(iface); - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId); @@ -1161,7 +1165,7 @@ static HRESULT WINAPI RegExp2_Invoke(IRegExp2 *iface, DISPID dispIdMember, { RegExp2 *This = impl_from_IRegExp2(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags, @@ -1195,7 +1199,7 @@ static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern) if(pattern && *pattern) { SIZE_T size = (SysStringLen(pattern)+1) * sizeof(WCHAR); - new_pattern = heap_alloc(size); + new_pattern = malloc(size); if(!new_pattern) return E_OUTOFMEMORY; memcpy(new_pattern, pattern, size); @@ -1203,7 +1207,7 @@ static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern) new_pattern = NULL; } - heap_free(This->pattern); + free(This->pattern); This->pattern = new_pattern; if(This->regexp) { @@ -1316,9 +1320,9 @@ static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface, break; hres = add_match(match_collection, add); + IMatch2_Release(add); if(FAILED(hres)) break; - IMatch2_Release(add); if(!(This->flags & REG_GLOB)) break; @@ -1359,13 +1363,13 @@ static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface, hres = regexp_execute(This->regexp, NULL, &This->pool, sourceString, SysStringLen(sourceString), result); if(hres != S_OK) { - heap_free(result); + free(result); break; } pos = result->cp; hres = create_match2(result->cp-result->match_len-sourceString, &result, &add); - heap_free(result); + free(result); if(FAILED(hres)) break; hres = add_match(match_collection, add); @@ -1432,13 +1436,179 @@ static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_B return hres; } -static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR sourceString, - VARIANT replaceVar, BSTR *pDestString) +typedef struct { + WCHAR *buf; + DWORD size; + DWORD len; +} strbuf_t; + +static BOOL strbuf_ensure_size(strbuf_t *buf, unsigned len) +{ + WCHAR *new_buf; + DWORD new_size; + + if(len <= buf->size) + return TRUE; + + new_size = buf->size ? buf->size<<1 : 16; + if(new_size < len) + new_size = len; + if(buf->buf) + new_buf = realloc(buf->buf, new_size*sizeof(WCHAR)); + else + new_buf = malloc(new_size*sizeof(WCHAR)); + if(!new_buf) + return FALSE; + + buf->buf = new_buf; + buf->size = new_size; + return TRUE; +} + +static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len) +{ + if(!len) + return S_OK; + + if(!strbuf_ensure_size(buf, buf->len+len)) + return E_OUTOFMEMORY; + + memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR)); + buf->len += len; + return S_OK; +} + +static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR source, VARIANT replaceVar, BSTR *ret) { RegExp2 *This = impl_from_IRegExp2(iface); - FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(sourceString), - debugstr_variant(&replaceVar), pDestString); - return E_NOTIMPL; + const WCHAR *cp, *prev_cp = NULL, *ptr, *prev_ptr; + size_t match_len = 0, source_len, replace_len; + strbuf_t buf = { NULL, 0, 0 }; + match_state_t *state = NULL; + heap_pool_t *mark; + VARIANT strv; + BSTR replace; + HRESULT hres; + + TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(source), debugstr_variant(&replaceVar), ret); + + if(This->pattern) { + if(!This->regexp) { + This->regexp = regexp_new(NULL, &This->pool, This->pattern, + lstrlenW(This->pattern), This->flags, FALSE); + if(!This->regexp) + return E_OUTOFMEMORY; + }else { + hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags); + if(FAILED(hres)) + return hres; + } + } + + V_VT(&strv) = VT_EMPTY; + hres = VariantChangeType(&strv, &replaceVar, 0, VT_BSTR); + if(FAILED(hres)) + return hres; + replace = V_BSTR(&strv); + replace_len = SysStringLen(replace); + source_len = SysStringLen(source); + + mark = heap_pool_mark(&This->pool); + cp = source; + if(This->regexp && !(state = alloc_match_state(This->regexp, &This->pool, cp))) + hres = E_OUTOFMEMORY; + + while(SUCCEEDED(hres)) { + if(This->regexp) { + prev_cp = cp; + hres = regexp_execute(This->regexp, NULL, &This->pool, source, source_len, state); + if(hres != S_OK) break; + cp = state->cp; + match_len = state->match_len; + }else if(prev_cp) { + if(cp == source + source_len) + break; + prev_cp = cp++; + }else { + prev_cp = cp; + } + + hres = strbuf_append(&buf, prev_cp, cp - prev_cp - match_len); + if(FAILED(hres)) + break; + + prev_ptr = replace; + while((ptr = wmemchr(prev_ptr, '$', replace + replace_len - prev_ptr))) { + hres = strbuf_append(&buf, prev_ptr, ptr - prev_ptr); + if(FAILED(hres)) + break; + + switch(ptr[1]) { + case '$': + hres = strbuf_append(&buf, ptr, 1); + prev_ptr = ptr + 2; + break; + case '&': + hres = strbuf_append(&buf, cp - match_len, match_len); + prev_ptr = ptr + 2; + break; + case '`': + hres = strbuf_append(&buf, source, cp - source - match_len); + prev_ptr = ptr + 2; + break; + case '\'': + hres = strbuf_append(&buf, cp, source + source_len - cp); + prev_ptr = ptr + 2; + break; + default: { + DWORD idx; + + if(!is_digit(ptr[1])) { + hres = strbuf_append(&buf, ptr, 1); + prev_ptr = ptr + 1; + break; + } + + idx = ptr[1] - '0'; + if(is_digit(ptr[2]) && idx * 10 + (ptr[2] - '0') <= state->paren_count) { + idx = idx * 10 + (ptr[2] - '0'); + prev_ptr = ptr + 3; + }else if(idx && idx <= state->paren_count) { + prev_ptr = ptr + 2; + }else { + hres = strbuf_append(&buf, ptr, 1); + prev_ptr = ptr + 1; + break; + } + + if(state->parens[idx - 1].index != -1) + hres = strbuf_append(&buf, source + state->parens[idx - 1].index, + state->parens[idx - 1].length); + break; + } + } + if(FAILED(hres)) + break; + } + if(SUCCEEDED(hres)) + hres = strbuf_append(&buf, prev_ptr, replace + replace_len - prev_ptr); + if(FAILED(hres)) + break; + + if(!(This->flags & REG_GLOB)) + break; + } + + if(SUCCEEDED(hres)) { + hres = strbuf_append(&buf, cp, source + source_len - cp); + if(SUCCEEDED(hres) && !(*ret = SysAllocStringLen(buf.buf, buf.len))) + hres = E_OUTOFMEMORY; + } + + heap_pool_clear(mark); + free(buf.buf); + SysFreeString(replace); + return hres; } static const IRegExp2Vtbl RegExp2Vtbl = { @@ -1462,6 +1632,51 @@ static const IRegExp2Vtbl RegExp2Vtbl = { RegExp2_Replace }; +BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt, int mode) +{ + const WCHAR *ptr, *string_end; + strbuf_t buf = { NULL, 0, 0 }; + size_t replace_len, find_len; + BSTR ret = NULL; + HRESULT hres = S_OK; + int pos; + + string_end = string + SysStringLen(string); + ptr = from > SysStringLen(string) ? string_end : string + from; + + find_len = SysStringLen(find); + replace_len = SysStringLen(replace); + + while(string_end - ptr >= find_len && cnt && find_len) { + pos = FindStringOrdinal(FIND_FROMSTART, ptr, string_end - ptr, + find, find_len, mode); + + if(pos == -1) + break; + else { + hres = strbuf_append(&buf, ptr, pos); + if(FAILED(hres)) + break; + hres = strbuf_append(&buf, replace, replace_len); + if(FAILED(hres)) + break; + + ptr = ptr + pos + find_len; + if(cnt != -1) + cnt--; + } + } + + if(SUCCEEDED(hres)) { + hres = strbuf_append(&buf, ptr, string_end - ptr); + if(SUCCEEDED(hres)) + ret = SysAllocStringLen(buf.buf, buf.len); + } + + free(buf.buf); + return ret; +} + static inline RegExp2 *impl_from_IRegExp(IRegExp *iface) { return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface); @@ -1602,7 +1817,7 @@ HRESULT create_regexp(IDispatch **ret) if(FAILED(hres)) return hres; - regexp = heap_alloc_zero(sizeof(*regexp)); + regexp = calloc(1, sizeof(*regexp)); if(!regexp) return E_OUTOFMEMORY; diff --git a/dll/win32/vbscript/vbscript.c b/dll/win32/vbscript/vbscript.c index 56c53b40150..84a8e0bb97f 100644 --- a/dll/win32/vbscript/vbscript.c +++ b/dll/win32/vbscript/vbscript.c @@ -61,8 +61,19 @@ typedef struct { IActiveScriptError IActiveScriptError_iface; LONG ref; EXCEPINFO ei; + DWORD_PTR cookie; + unsigned line; + unsigned character; } VBScriptError; +static inline WCHAR *heap_pool_strdup(heap_pool_t *heap, const WCHAR *str) +{ + size_t size = (lstrlenW(str) + 1) * sizeof(WCHAR); + WCHAR *ret = heap_pool_alloc(heap, size); + if (ret) memcpy(ret, str, size); + return ret; +} + static void change_state(VBScript *This, SCRIPTSTATE state) { if(This->state == state) @@ -82,8 +93,105 @@ static inline BOOL is_started(VBScript *This) static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { + ScriptDisp *obj = ctx->script_obj; + function_t *func_iter, **new_funcs; + dynamic_var_t *var, **new_vars; + IServiceProvider *prev_caller; + size_t cnt, i; + HRESULT hres; + + if(code->named_item) { + if(!code->named_item->script_obj) { + hres = create_script_disp(ctx, &code->named_item->script_obj); + if(FAILED(hres)) return hres; + } + obj = code->named_item->script_obj; + } + + cnt = obj->global_vars_cnt + code->main_code.var_cnt; + if (cnt > obj->global_vars_size) + { + if (obj->global_vars) + new_vars = realloc(obj->global_vars, cnt * sizeof(*new_vars)); + else + new_vars = malloc(cnt * sizeof(*new_vars)); + if (!new_vars) + return E_OUTOFMEMORY; + obj->global_vars = new_vars; + obj->global_vars_size = cnt; + } + + cnt = obj->global_funcs_cnt; + for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) + cnt++; + if (cnt > obj->global_funcs_size) + { + if (obj->global_funcs) + new_funcs = realloc(obj->global_funcs, cnt * sizeof(*new_funcs)); + else + new_funcs = malloc(cnt * sizeof(*new_funcs)); + if (!new_funcs) + return E_OUTOFMEMORY; + obj->global_funcs = new_funcs; + obj->global_funcs_size = cnt; + } + + for (i = 0; i < code->main_code.var_cnt; i++) + { + if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var)))) + return E_OUTOFMEMORY; + + var->name = heap_pool_strdup(&obj->heap, code->main_code.vars[i].name); + if (!var->name) + return E_OUTOFMEMORY; + V_VT(&var->v) = VT_EMPTY; + var->is_const = FALSE; + var->array = NULL; + + obj->global_vars[obj->global_vars_cnt + i] = var; + } + + obj->global_vars_cnt += code->main_code.var_cnt; + + for (func_iter = code->funcs; func_iter; func_iter = func_iter->next) + { + for (i = 0; i < obj->global_funcs_cnt; i++) + { + if (!wcsicmp(obj->global_funcs[i]->name, func_iter->name)) + { + /* global function already exists, replace it */ + obj->global_funcs[i] = func_iter; + break; + } + } + if (i == obj->global_funcs_cnt) + obj->global_funcs[obj->global_funcs_cnt++] = func_iter; + } + + if (code->classes) + { + class_desc_t *class = code->classes; + + while (1) + { + class->ctx = ctx; + if (!class->next) + break; + class = class->next; + } + + class->next = obj->classes; + obj->classes = code->classes; + code->last_class = class; + } + code->pending_exec = FALSE; - return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); + + prev_caller = ctx->vbcaller->caller; + ctx->vbcaller->caller = SP_CALLER_UNINITIALIZED; + hres = exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); + ctx->vbcaller->caller = prev_caller; + return hres; } static void exec_queued_code(script_ctx_t *ctx) @@ -96,68 +204,104 @@ static void exec_queued_code(script_ctx_t *ctx) } } -IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) +static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *item) +{ + IUnknown *unk; + HRESULT hres; + + hres = IActiveScriptSite_GetItemInfo(site, item->name, SCRIPTINFO_IUNKNOWN, &unk, NULL); + if(FAILED(hres)) { + WARN("GetItemInfo failed: %08lx\n", hres); + return hres; + } + + hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); + IUnknown_Release(unk); + if(FAILED(hres)) { + WARN("object does not implement IDispatch\n"); + return hres; + } + + return S_OK; +} + +named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags) { named_item_t *item; HRESULT hres; LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { if((item->flags & flags) == flags && !wcsicmp(item->name, name)) { - if(!item->disp) { - IUnknown *unk; - - hres = IActiveScriptSite_GetItemInfo(ctx->site, item->name, - SCRIPTINFO_IUNKNOWN, &unk, NULL); - if(FAILED(hres)) { - WARN("GetItemInfo failed: %08x\n", hres); - continue; - } - - hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); - IUnknown_Release(unk); - if(FAILED(hres)) { - WARN("object does not implement IDispatch\n"); - continue; - } + if(!item->script_obj && !(item->flags & SCRIPTITEM_GLOBALMEMBERS)) { + hres = create_script_disp(ctx, &item->script_obj); + if(FAILED(hres)) return NULL; } - return item->disp; + if(!item->disp && (flags || !(item->flags & SCRIPTITEM_CODEONLY))) { + hres = retrieve_named_item_disp(ctx->site, item); + if(FAILED(hres)) continue; + } + + return item; } } return NULL; } +static void release_named_item_script_obj(named_item_t *item) +{ + if(!item->script_obj) return; + + item->script_obj->ctx = NULL; + IDispatchEx_Release(&item->script_obj->IDispatchEx_iface); + item->script_obj = NULL; +} + +void release_named_item(named_item_t *item) +{ + if(--item->ref) return; + + free(item->name); + free(item); +} + static void release_script(script_ctx_t *ctx) { - class_desc_t *class_desc; + named_item_t *item, *item_next; + vbscode_t *code, *code_next; collect_objects(ctx); clear_ei(&ctx->ei); - release_dynamic_vars(ctx->global_vars); - ctx->global_vars = NULL; - - while(!list_empty(&ctx->named_items)) { - named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry); - - list_remove(&iter->entry); - if(iter->disp) - IDispatch_Release(iter->disp); - heap_free(iter->name); - heap_free(iter); + LIST_FOR_EACH_ENTRY_SAFE(code, code_next, &ctx->code_list, vbscode_t, entry) + { + if(code->is_persistent) + { + code->pending_exec = TRUE; + if(code->last_class) code->last_class->next = NULL; + if(code->named_item) release_named_item_script_obj(code->named_item); + } + else + { + list_remove(&code->entry); + release_vbscode(code); + } } - while(ctx->procs) { - class_desc = ctx->procs; - ctx->procs = class_desc->next; - - heap_free(class_desc); - } - - if(ctx->host_global) { - IDispatch_Release(ctx->host_global); - ctx->host_global = NULL; + LIST_FOR_EACH_ENTRY_SAFE(item, item_next, &ctx->named_items, named_item_t, entry) + { + if(item->disp) + { + IDispatch_Release(item->disp); + item->disp = NULL; + } + release_named_item_script_obj(item); + if(!(item->flags & SCRIPTITEM_ISPERSISTENT)) + { + list_remove(&item->entry); + release_named_item(item); + } } if(ctx->secmgr) { @@ -177,19 +321,25 @@ static void release_script(script_ctx_t *ctx) script_obj->ctx = NULL; IDispatchEx_Release(&script_obj->IDispatchEx_iface); } - - detach_global_objects(ctx); - heap_pool_free(&ctx->heap); - heap_pool_init(&ctx->heap); } -static void destroy_script(script_ctx_t *ctx) +static void release_code_list(script_ctx_t *ctx) { - while(!list_empty(&ctx->code_list)) - release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry)); + while(!list_empty(&ctx->code_list)) { + vbscode_t *iter = LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry); - release_script(ctx); - heap_free(ctx); + list_remove(&iter->entry); + release_vbscode(iter); + } +} + +static void release_named_item_list(script_ctx_t *ctx) +{ + while(!list_empty(&ctx->named_items)) { + named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry); + list_remove(&iter->entry); + release_named_item(iter); + } } static void decrease_state(VBScript *This, SCRIPTSTATE state) @@ -202,16 +352,19 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) /* FALLTHROUGH */ case SCRIPTSTATE_STARTED: case SCRIPTSTATE_DISCONNECTED: - if(This->state == SCRIPTSTATE_DISCONNECTED) - change_state(This, SCRIPTSTATE_INITIALIZED); - if(state == SCRIPTSTATE_INITIALIZED) - break; + change_state(This, SCRIPTSTATE_INITIALIZED); /* FALLTHROUGH */ case SCRIPTSTATE_INITIALIZED: case SCRIPTSTATE_UNINITIALIZED: change_state(This, state); + if(state == SCRIPTSTATE_INITIALIZED) + break; release_script(This->ctx); This->thread_id = 0; + if(state == SCRIPTSTATE_CLOSED) { + release_code_list(This->ctx); + release_named_item_list(This->ctx); + } break; case SCRIPTSTATE_CLOSED: break; @@ -219,6 +372,97 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) } } +static inline struct vbcaller *vbcaller_from_IServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, struct vbcaller, IServiceProvider_iface); +} + +static HRESULT WINAPI vbcaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) { + *ppv = &This->IServiceProvider_iface; + }else { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI vbcaller_AddRef(IServiceProvider *iface) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI vbcaller_Release(IServiceProvider *iface) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) + free(This); + + return ref; +} + +static HRESULT WINAPI vbcaller_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + TRACE("(%p)->(IID_IActiveScriptSite)\n", This); + if(This->ctx->site) + return IActiveScriptSite_QueryInterface(This->ctx->site, riid, ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + TRACE("(%p)->(SID_GetCaller)\n", This); + *ppv = NULL; + if(!This->caller) + return S_OK; + return (This->caller == SP_CALLER_UNINITIALIZED) ? E_NOINTERFACE : IServiceProvider_QueryInterface(This->caller, riid, ppv); + } + + FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); + + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl ServiceProviderVtbl = { + vbcaller_QueryInterface, + vbcaller_AddRef, + vbcaller_Release, + vbcaller_QueryService +}; + +static struct vbcaller *create_vbcaller(void) +{ + struct vbcaller *ret; + + ret = malloc(sizeof(*ret)); + if(ret) { + ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; + ret->ref = 1; + ret->caller = SP_CALLER_UNINITIALIZED; + } + return ret; +} + static inline VBScriptError *impl_from_IActiveScriptError(IActiveScriptError *iface) { return CONTAINING_RECORD(iface, VBScriptError, IActiveScriptError_iface); @@ -249,7 +493,7 @@ static ULONG WINAPI VBScriptError_AddRef(IActiveScriptError *iface) VBScriptError *This = impl_from_IActiveScriptError(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -259,11 +503,10 @@ static ULONG WINAPI VBScriptError_Release(IActiveScriptError *iface) VBScriptError *This = impl_from_IActiveScriptError(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); - if(!ref) { - heap_free(This); - } + if(!ref) + free(This); return ref; } @@ -285,14 +528,14 @@ static HRESULT WINAPI VBScriptError_GetSourcePosition(IActiveScriptError *iface, { VBScriptError *This = impl_from_IActiveScriptError(iface); - FIXME("(%p)->(%p %p %p)\n", This, source_context, line, character); + TRACE("(%p)->(%p %p %p)\n", This, source_context, line, character); if(source_context) - *source_context = 0; + *source_context = This->cookie; if(line) - *line = 0; + *line = This->line; if(character) - *character = 0; + *character = This->character; return S_OK; } @@ -312,12 +555,13 @@ static const IActiveScriptErrorVtbl VBScriptErrorVtbl = { VBScriptError_GetSourceLineText }; -HRESULT report_script_error(script_ctx_t *ctx) +HRESULT report_script_error(script_ctx_t *ctx, const vbscode_t *code, unsigned loc) { VBScriptError *error; + const WCHAR *p, *nl; HRESULT hres, result; - if(!(error = heap_alloc(sizeof(*error)))) + if(!(error = malloc(sizeof(*error)))) return E_OUTOFMEMORY; error->IActiveScriptError_iface.lpVtbl = &VBScriptErrorVtbl; @@ -326,6 +570,16 @@ HRESULT report_script_error(script_ctx_t *ctx) memset(&ctx->ei, 0, sizeof(ctx->ei)); result = error->ei.scode; + p = code->source; + error->cookie = code->cookie; + error->line = code->start_line; + for(nl = p = code->source; p < code->source + loc; p++) { + if(*p != '\n') continue; + error->line++; + nl = p + 1; + } + error->character = code->source + loc - nl; + hres = IActiveScriptSite_OnScriptError(ctx->site, &error->IActiveScriptError_iface); IActiveScriptError_Release(&error->IActiveScriptError_iface); return hres == S_OK ? SCRIPT_E_REPORTED : result; @@ -359,7 +613,7 @@ static HRESULT WINAPI VBScript_QueryInterface(IActiveScript *iface, REFIID riid, TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv); *ppv = &This->IObjectSafety_iface; }else { - FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); *ppv = NULL; return E_NOINTERFACE; } @@ -373,7 +627,7 @@ static ULONG WINAPI VBScript_AddRef(IActiveScript *iface) VBScript *This = impl_from_IActiveScript(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -383,12 +637,14 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) VBScript *This = impl_from_IActiveScript(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", iface, ref); + TRACE("(%p) ref=%ld\n", iface, ref); if(!ref) { decrease_state(This, SCRIPTSTATE_CLOSED); - destroy_script(This->ctx); - heap_free(This); + detach_global_objects(This->ctx); + IServiceProvider_Release(&This->ctx->vbcaller->IServiceProvider_iface); + free(This->ctx); + free(This); } return ref; @@ -397,7 +653,8 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { VBScript *This = impl_from_IActiveScript(iface); - LCID lcid; + LCID lcid = LOCALE_USER_DEFAULT; + named_item_t *item; HRESULT hres; TRACE("(%p)->(%p)\n", This, pass); @@ -411,6 +668,19 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0)) return E_UNEXPECTED; + /* Retrieve new dispatches for persistent named items */ + LIST_FOR_EACH_ENTRY(item, &This->ctx->named_items, named_item_t, entry) + { + if(!item->disp) + { + hres = retrieve_named_item_disp(pass, item); + if(FAILED(hres)) return hres; + } + + /* For some reason, CODEONLY flag is lost in re-initialized scripts */ + item->flags &= ~SCRIPTITEM_CODEONLY; + } + hres = create_script_disp(This->ctx, &This->ctx->script_obj); if(FAILED(hres)) return hres; @@ -418,9 +688,12 @@ static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScript This->ctx->site = pass; IActiveScriptSite_AddRef(This->ctx->site); - hres = IActiveScriptSite_GetLCID(This->ctx->site, &lcid); - if(hres == S_OK) - This->ctx->lcid = lcid; + IActiveScriptSite_GetLCID(This->ctx->site, &lcid); + This->ctx->lcid = IsValidLocale(lcid, 0) ? lcid : GetUserDefaultLCID(); + GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&This->ctx->codepage, + sizeof(This->ctx->codepage)/sizeof(WCHAR)); + if (!This->ctx->codepage) + This->ctx->codepage = CP_UTF8; if(This->is_initialized) change_state(This, SCRIPTSTATE_INITIALIZED); @@ -452,7 +725,7 @@ static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE return S_OK; } - if(!This->is_initialized) + if(!This->is_initialized || (!This->ctx->site && ss != SCRIPTSTATE_CLOSED)) return E_UNEXPECTED; switch(ss) { @@ -464,7 +737,10 @@ static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE exec_queued_code(This->ctx); break; case SCRIPTSTATE_INITIALIZED: - FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n"); + decrease_state(This, SCRIPTSTATE_INITIALIZED); + return S_OK; + case SCRIPTSTATE_CLOSED: + decrease_state(This, SCRIPTSTATE_CLOSED); return S_OK; case SCRIPTSTATE_DISCONNECTED: FIXME("unimplemented SCRIPTSTATE_DISCONNECTED\n"); @@ -514,7 +790,7 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr IDispatch *disp = NULL; HRESULT hres; - TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags); + TRACE("(%p)->(%s %lx)\n", This, debugstr_w(pstrName), dwFlags); if(This->thread_id != GetCurrentThreadId() || !This->ctx->site) return E_UNEXPECTED; @@ -524,7 +800,7 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr hres = IActiveScriptSite_GetItemInfo(This->ctx->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL); if(FAILED(hres)) { - WARN("GetItemInfo failed: %08x\n", hres); + WARN("GetItemInfo failed: %08lx\n", hres); return hres; } @@ -534,27 +810,24 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr WARN("object does not implement IDispatch\n"); return hres; } - - if(This->ctx->host_global) - IDispatch_Release(This->ctx->host_global); - IDispatch_AddRef(disp); - This->ctx->host_global = disp; } - item = heap_alloc(sizeof(*item)); + item = malloc(sizeof(*item)); if(!item) { if(disp) IDispatch_Release(disp); return E_OUTOFMEMORY; } + item->ref = 1; item->disp = disp; item->flags = dwFlags; - item->name = heap_strdupW(pstrName); + item->script_obj = NULL; + item->name = wcsdup(pstrName); if(!item->name) { if(disp) IDispatch_Release(disp); - heap_free(item); + free(item); return E_OUTOFMEMORY; } @@ -566,15 +839,16 @@ static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTyp DWORD dwMajor, DWORD dwMinor, DWORD dwFlags) { VBScript *This = impl_from_IActiveScript(iface); - FIXME("(%p)->()\n", This); + FIXME("(%p)->(%s %ld %ld %ld)\n", This, debugstr_guid(rguidTypeLib), dwMajor, dwMinor, dwFlags); return E_NOTIMPL; } static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp) { VBScript *This = impl_from_IActiveScript(iface); + ScriptDisp *script_obj; - TRACE("(%p)->(%p)\n", This, ppdisp); + TRACE("(%p)->(%s %p)\n", This, debugstr_w(pstrItemName), ppdisp); if(!ppdisp) return E_POINTER; @@ -584,7 +858,14 @@ static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR return E_UNEXPECTED; } - *ppdisp = (IDispatch*)&This->ctx->script_obj->IDispatchEx_iface; + script_obj = This->ctx->script_obj; + if(pstrItemName) { + named_item_t *item = lookup_named_item(This->ctx, pstrItemName, 0); + if(!item) return E_INVALIDARG; + if(item->script_obj) script_obj = item->script_obj; + } + + *ppdisp = (IDispatch*)&script_obj->IDispatchEx_iface; IDispatch_AddRef(*ppdisp); return S_OK; } @@ -674,7 +955,7 @@ static HRESULT WINAPI VBScriptDebug_GetScriptTextAttributes(IActiveScriptDebug * LPCOLESTR code, ULONG len, LPCOLESTR delimiter, DWORD flags, SOURCE_TEXT_ATTR *attr) { VBScript *This = impl_from_IActiveScriptDebug(iface); - FIXME("(%p)->(%s %u %s %#x %p)\n", This, debugstr_w(code), len, + FIXME("(%p)->(%s %lu %s %#lx %p)\n", This, debugstr_w(code), len, debugstr_w(delimiter), flags, attr); return E_NOTIMPL; } @@ -683,7 +964,7 @@ static HRESULT WINAPI VBScriptDebug_GetScriptletTextAttributes(IActiveScriptDebu LPCOLESTR code, ULONG len, LPCOLESTR delimiter, DWORD flags, SOURCE_TEXT_ATTR *attr) { VBScript *This = impl_from_IActiveScriptDebug(iface); - FIXME("(%p)->(%s %u %s %#x %p)\n", This, debugstr_w(code), len, + FIXME("(%p)->(%s %lu %s %#lx %p)\n", This, debugstr_w(code), len, debugstr_w(delimiter), flags, attr); return E_NOTIMPL; } @@ -692,7 +973,7 @@ static HRESULT WINAPI VBScriptDebug_EnumCodeContextsOfPosition(IActiveScriptDebu CTXARG_T source, ULONG offset, ULONG len, IEnumDebugCodeContexts **ret) { VBScript *This = impl_from_IActiveScriptDebug(iface); - FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(source), offset, len, ret); + FIXME("(%p)->(%s %lu %lu %p)\n", This, wine_dbgstr_longlong(source), offset, len, ret); return E_NOTIMPL; } @@ -750,7 +1031,7 @@ static HRESULT WINAPI VBScriptParse_AddScriptlet(IActiveScriptParse *iface, BSTR *pbstrName, EXCEPINFO *pexcepinfo) { VBScript *This = impl_from_IActiveScriptParse(iface); - FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName), + FIXME("(%p)->(%s %s %s %s %s %s %s %lu %lx %p %p)\n", This, debugstr_w(pstrDefaultName), debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName), debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo); @@ -763,32 +1044,21 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) { VBScript *This = impl_from_IActiveScriptParse(iface); - IDispatch *context = NULL; vbscode_t *code; HRESULT hres; - TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode), + TRACE("(%p)->(%s %s %p %s %s %lu %lx %p %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo); if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; - if(pstrItemName) { - context = lookup_named_item(This->ctx, pstrItemName, 0); - if(!context) { - WARN("Inknown context %s\n", debugstr_w(pstrItemName)); - return E_INVALIDARG; - } - } - - hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code); + hres = compile_script(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie, + ulStartingLine, dwFlags, &code); if(FAILED(hres)) return hres; - if(context) - IDispatch_AddRef(code->context = context); - if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) { code->pending_exec = TRUE; return S_OK; @@ -839,14 +1109,15 @@ static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptPar vbdisp_t *vbdisp; HRESULT hres; - TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams), + TRACE("(%p)->(%s %s %s %s %p %s %s %lu %lx %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams), debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp); if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; - hres = compile_procedure(This->ctx, pstrCode, pstrDelimiter, dwFlags, &desc); + hres = compile_procedure(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie, + ulStartingLineNumber, dwFlags, &desc); if(FAILED(hres)) return hres; @@ -910,7 +1181,7 @@ static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *if { VBScript *This = impl_from_IObjectSafety(iface); - TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions); + TRACE("(%p)->(%s %lx %lx)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions); if(dwOptionSetMask & ~SUPPORTED_OPTIONS) return E_FAIL; @@ -929,16 +1200,22 @@ static const IObjectSafetyVtbl VBScriptSafetyVtbl = { HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { + struct vbcaller *vbcaller; script_ctx_t *ctx; VBScript *ret; HRESULT hres; TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv); - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; + if(!(vbcaller = create_vbcaller())) { + free(ret); + return E_OUTOFMEMORY; + } + ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl; ret->IActiveScriptDebug_iface.lpVtbl = &VBScriptDebugVtbl; ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl; @@ -948,14 +1225,16 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU ret->ref = 1; ret->state = SCRIPTSTATE_UNINITIALIZED; - ctx = ret->ctx = heap_alloc_zero(sizeof(*ctx)); + ctx = ret->ctx = calloc(1, sizeof(*ctx)); if(!ctx) { - heap_free(ret); + IServiceProvider_Release(&vbcaller->IServiceProvider_iface); + free(ret); return E_OUTOFMEMORY; } + vbcaller->ctx = ctx; + ctx->vbcaller = vbcaller; ctx->safeopt = INTERFACE_USES_DISPEX; - heap_pool_init(&ctx->heap); list_init(&ctx->objects); list_init(&ctx->code_list); list_init(&ctx->named_items); @@ -1009,7 +1288,7 @@ static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface) AXSite *This = impl_from_IServiceProvider(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -1019,10 +1298,10 @@ static ULONG WINAPI AXSite_Release(IServiceProvider *iface) AXSite *This = impl_from_IServiceProvider(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) - heap_free(This); + free(This); return ref; } @@ -1052,11 +1331,11 @@ IUnknown *create_ax_site(script_ctx_t *ctx) hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp); if(FAILED(hres)) { - ERR("Could not get IServiceProvider iface: %08x\n", hres); + ERR("Could not get IServiceProvider iface: %08lx\n", hres); return NULL; } - ret = heap_alloc(sizeof(*ret)); + ret = malloc(sizeof(*ret)); if(!ret) { IServiceProvider_Release(sp); return NULL; diff --git a/dll/win32/vbscript/vbscript.h b/dll/win32/vbscript/vbscript.h index 2fcb545ae13..941f8f45b46 100644 --- a/dll/win32/vbscript/vbscript.h +++ b/dll/win32/vbscript/vbscript.h @@ -30,13 +30,9 @@ #include "activscp.h" #include "activdbg.h" -#ifdef __REACTOS__ -#include -#endif #include "vbscript_classes.h" #include "vbscript_defs.h" -#include "wine/heap.h" #include "wine/list.h" typedef struct { @@ -48,26 +44,18 @@ typedef struct { struct list custom_blocks; } heap_pool_t; -void heap_pool_init(heap_pool_t*) DECLSPEC_HIDDEN; -void *heap_pool_alloc(heap_pool_t*,size_t) __WINE_ALLOC_SIZE(2) DECLSPEC_HIDDEN; -void *heap_pool_grow(heap_pool_t*,void*,DWORD,DWORD) DECLSPEC_HIDDEN; -void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN; -void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN; -heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN; +void heap_pool_init(heap_pool_t*); +void *heap_pool_alloc(heap_pool_t*,size_t) __WINE_ALLOC_SIZE(2); +void *heap_pool_grow(heap_pool_t*,void*,DWORD,DWORD); +void heap_pool_clear(heap_pool_t*); +void heap_pool_free(heap_pool_t*); +heap_pool_t *heap_pool_mark(heap_pool_t*); typedef struct _function_t function_t; typedef struct _vbscode_t vbscode_t; typedef struct _script_ctx_t script_ctx_t; typedef struct _vbdisp_t vbdisp_t; -typedef struct named_item_t { - IDispatch *disp; - DWORD flags; - LPWSTR name; - - struct list entry; -} named_item_t; - typedef enum { VBDISP_CALLGET, VBDISP_LET, @@ -125,17 +113,32 @@ struct _vbdisp_t { VARIANT props[1]; }; -typedef struct _ident_map_t ident_map_t; +typedef struct _dynamic_var_t { + struct _dynamic_var_t *next; + VARIANT v; + const WCHAR *name; + BOOL is_const; + SAFEARRAY *array; +} dynamic_var_t; typedef struct { IDispatchEx IDispatchEx_iface; LONG ref; - ident_map_t *ident_map; - unsigned ident_map_cnt; - unsigned ident_map_size; + dynamic_var_t **global_vars; + size_t global_vars_cnt; + size_t global_vars_size; + + function_t **global_funcs; + size_t global_funcs_cnt; + size_t global_funcs_size; + + class_desc_t *classes; script_ctx_t *ctx; + heap_pool_t heap; + + unsigned int rnd; } ScriptDisp; typedef struct _builtin_prop_t builtin_prop_t; @@ -148,16 +151,26 @@ typedef struct { script_ctx_t *ctx; } BuiltinDisp; -HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**) DECLSPEC_HIDDEN; -HRESULT disp_get_id(IDispatch*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*) DECLSPEC_HIDDEN; -HRESULT vbdisp_get_id(vbdisp_t*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*) DECLSPEC_HIDDEN; -HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN; -HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*) DECLSPEC_HIDDEN; -HRESULT get_disp_value(script_ctx_t*,IDispatch*,VARIANT*) DECLSPEC_HIDDEN; -void collect_objects(script_ctx_t*) DECLSPEC_HIDDEN; -HRESULT create_script_disp(script_ctx_t*,ScriptDisp**) DECLSPEC_HIDDEN; +typedef struct named_item_t { + ScriptDisp *script_obj; + IDispatch *disp; + unsigned ref; + DWORD flags; + LPWSTR name; -HRESULT to_int(VARIANT*,int*) DECLSPEC_HIDDEN; + struct list entry; +} named_item_t; + +HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**); +HRESULT disp_get_id(IDispatch*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*); +HRESULT vbdisp_get_id(vbdisp_t*,BSTR,vbdisp_invoke_type_t,BOOL,DISPID*); +HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*); +HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*); +HRESULT get_disp_value(script_ctx_t*,IDispatch*,VARIANT*); +void collect_objects(script_ctx_t*); +HRESULT create_script_disp(script_ctx_t*,ScriptDisp**); + +HRESULT to_int(VARIANT*,int*); static inline unsigned arg_cnt(const DISPPARAMS *dp) { @@ -169,45 +182,44 @@ static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i) return dp->rgvarg + dp->cArgs-i-1; } -typedef struct _dynamic_var_t { - struct _dynamic_var_t *next; - VARIANT v; - const WCHAR *name; - BOOL is_const; -} dynamic_var_t; +#define SP_CALLER_UNINITIALIZED ((IServiceProvider*)IntToPtr(-1)) + +struct vbcaller { + IServiceProvider IServiceProvider_iface; + + LONG ref; + + script_ctx_t *ctx; + IServiceProvider *caller; +}; struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; + UINT codepage; IInternetHostSecurityManager *secmgr; + struct vbcaller *vbcaller; DWORD safeopt; - IDispatch *host_global; - ScriptDisp *script_obj; BuiltinDisp *global_obj; BuiltinDisp *err_obj; EXCEPINFO ei; - - dynamic_var_t *global_vars; - function_t *global_funcs; - class_desc_t *classes; - class_desc_t *procs; - - heap_pool_t heap; + vbscode_t *error_loc_code; + unsigned error_loc_offset; struct list objects; struct list code_list; struct list named_items; }; -HRESULT init_global(script_ctx_t*) DECLSPEC_HIDDEN; -HRESULT init_err(script_ctx_t*) DECLSPEC_HIDDEN; +HRESULT init_global(script_ctx_t*); +HRESULT init_err(script_ctx_t*); -IUnknown *create_ax_site(script_ctx_t*) DECLSPEC_HIDDEN; +IUnknown *create_ax_site(script_ctx_t*); typedef enum { ARG_NONE = 0, @@ -216,7 +228,8 @@ typedef enum { ARG_INT, ARG_UINT, ARG_ADDR, - ARG_DOUBLE + ARG_DOUBLE, + ARG_DATE } instr_arg_type_t; #define OP_LIST \ @@ -225,10 +238,12 @@ typedef enum { X(assign_ident, 1, ARG_BSTR, ARG_UINT) \ X(assign_member, 1, ARG_BSTR, ARG_UINT) \ X(bool, 1, ARG_INT, 0) \ - X(catch, 1, ARG_ADDR, ARG_UINT) \ + X(catch, 1, ARG_ADDR, ARG_UINT) \ X(case, 0, ARG_ADDR, 0) \ X(concat, 1, 0, 0) \ X(const, 1, ARG_BSTR, 0) \ + X(date, 1, ARG_DATE, 0) \ + X(deref, 1, 0, 0) \ X(dim, 1, ARG_BSTR, ARG_UINT) \ X(div, 1, 0, 0) \ X(double, 1, ARG_DOUBLE, 0) \ @@ -243,6 +258,7 @@ typedef enum { X(gteq, 1, 0, 0) \ X(icall, 1, ARG_BSTR, ARG_UINT) \ X(icallv, 1, ARG_BSTR, ARG_UINT) \ + X(ident, 1, ARG_BSTR, 0) \ X(idiv, 1, 0, 0) \ X(imp, 1, 0, 0) \ X(incc, 1, ARG_BSTR, 0) \ @@ -265,17 +281,23 @@ typedef enum { X(not, 1, 0, 0) \ X(nothing, 1, 0, 0) \ X(null, 1, 0, 0) \ + X(numval, 1, 0, 0) \ X(or, 1, 0, 0) \ X(pop, 1, ARG_UINT, 0) \ + X(redim, 1, ARG_BSTR, ARG_UINT) \ + X(redim_preserve, 1, ARG_BSTR, ARG_UINT) \ X(ret, 0, 0, 0) \ X(retval, 1, 0, 0) \ X(set_ident, 1, ARG_BSTR, ARG_UINT) \ X(set_member, 1, ARG_BSTR, ARG_UINT) \ + X(stack, 1, ARG_UINT, 0) \ X(step, 0, ARG_ADDR, ARG_BSTR) \ X(stop, 1, 0, 0) \ X(string, 1, ARG_STR, 0) \ X(sub, 1, 0, 0) \ X(val, 1, 0, 0) \ + X(vcall, 1, ARG_UINT, 0) \ + X(vcallv, 1, ARG_UINT, 0) \ X(xor, 1, 0, 0) typedef enum { @@ -291,10 +313,12 @@ typedef union { unsigned uint; LONG lng; double *dbl; + DATE *date; } instr_arg_t; typedef struct { vbsop_t op; + unsigned loc; instr_arg_t arg1; instr_arg_t arg2; } instr_t; @@ -311,7 +335,6 @@ typedef enum { FUNC_PROPGET, FUNC_PROPLET, FUNC_PROPSET, - FUNC_DEFGET } function_type_t; typedef struct { @@ -335,70 +358,76 @@ struct _function_t { struct _vbscode_t { instr_t *instrs; + unsigned ref; + WCHAR *source; + DWORD_PTR cookie; + unsigned start_line; BOOL option_explicit; BOOL pending_exec; + BOOL is_persistent; function_t main_code; - IDispatch *context; + named_item_t *named_item; BSTR *bstr_pool; unsigned bstr_pool_size; unsigned bstr_cnt; heap_pool_t heap; + function_t *funcs; + class_desc_t *classes; + class_desc_t *last_class; + struct list entry; }; -void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN; -HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN; -HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,class_desc_t**) DECLSPEC_HIDDEN; -HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN; -void release_dynamic_vars(dynamic_var_t*) DECLSPEC_HIDDEN; -IDispatch *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN; -void clear_ei(EXCEPINFO*) DECLSPEC_HIDDEN; -HRESULT report_script_error(script_ctx_t*) DECLSPEC_HIDDEN; -void detach_global_objects(script_ctx_t*) DECLSPEC_HIDDEN; -HRESULT get_builtin_id(BuiltinDisp*,const WCHAR*,DISPID*) DECLSPEC_HIDDEN; +static inline void grab_vbscode(vbscode_t *code) +{ + code->ref++; +} -void release_regexp_typelib(void) DECLSPEC_HIDDEN; +void release_vbscode(vbscode_t*); +HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,vbscode_t**); +HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,class_desc_t**); +HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*); +void release_dynamic_var(dynamic_var_t*); +named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned); +void release_named_item(named_item_t*); +void clear_ei(EXCEPINFO*); +HRESULT report_script_error(script_ctx_t*,const vbscode_t*,unsigned); +void detach_global_objects(script_ctx_t*); +HRESULT get_builtin_id(BuiltinDisp*,const WCHAR*,DISPID*); +HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret); + +void release_regexp_typelib(void); +HRESULT get_dispatch_typeinfo(ITypeInfo**); static inline BOOL is_int32(double d) { return INT32_MIN <= d && d <= INT32_MAX && (double)(int)d == d; } -HRESULT create_regexp(IDispatch**) DECLSPEC_HIDDEN; +static inline BOOL is_digit(WCHAR c) +{ + return '0' <= c && c <= '9'; +} -HRESULT map_hres(HRESULT) DECLSPEC_HIDDEN; +HRESULT create_regexp(IDispatch**); +BSTR string_replace(BSTR,BSTR,BSTR,int,int,int); -HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) DECLSPEC_HIDDEN; +void map_vbs_exception(EXCEPINFO *); + +HRESULT create_safearray_iter(SAFEARRAY *sa, BOOL owned, IEnumVARIANT **ev); #define FACILITY_VBS 0xa #define MAKE_VBSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_VBS, code) -HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; -HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; +HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**); +HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**); -BSTR get_vbscript_string(int) DECLSPEC_HIDDEN; -BSTR get_vbscript_error_string(HRESULT) DECLSPEC_HIDDEN; - -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (lstrlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} +BSTR get_vbscript_string(int); #define VBSCRIPT_BUILD_VERSION 16978 #define VBSCRIPT_MAJOR_VERSION 5 diff --git a/dll/win32/vbscript/vbscript.rc b/dll/win32/vbscript/vbscript.rc index bcd3c185778..f90e6668bcb 100644 --- a/dll/win32/vbscript/vbscript.rc +++ b/dll/win32/vbscript/vbscript.rc @@ -19,6 +19,8 @@ #include #include "vbscript_defs.h" +#pragma makedep po + LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT STRINGTABLE @@ -54,6 +56,7 @@ STRINGTABLE VBSE_INVALID_DLL_FUNCTION_NAME "Specified DLL function not found" VBSE_INVALID_TYPELIB_VARIABLE "Variable uses an Automation type not supported in VBScript" VBSE_SERVER_NOT_FOUND "The remote server machine does not exist or is unavailable" + VBSE_UNQUALIFIED_REFERENCE "Invalid or unqualified reference" VBS_COMPILE_ERROR "Microsoft VBScript compilation error" VBS_RUNTIME_ERROR "Microsoft VBScript runtime error" @@ -65,15 +68,6 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL /* @makedep: vbscript.rgs */ 2 WINE_REGISTRY vbscript.rgs -3 WINE_REGISTRY "vbsglobal.rgs" -4 WINE_REGISTRY "vbsregexp10.rgs" -5 WINE_REGISTRY "vbsregexp55.rgs" -6 WINE_REGISTRY "vbscript_classes.rgs" - -1 TYPELIB "vbsglobal.tlb" -2 TYPELIB "vbsregexp10.tlb" -3 TYPELIB "vbsregexp55.tlb" - #define WINE_FILEDESCRIPTION_STR "Wine VBScript" #define WINE_FILENAME_STR "vbscript.dll" #define WINE_FILEVERSION 5,8,7601,16978 diff --git a/dll/win32/vbscript/vbscript.rgs b/dll/win32/vbscript/vbscript.rgs index 4513b4d7fb0..01d4225234e 100644 --- a/dll/win32/vbscript/vbscript.rgs +++ b/dll/win32/vbscript/vbscript.rgs @@ -63,19 +63,19 @@ HKCR { Edit { - Command = s '"%%SystemRoot%%\system32\notepad.exe" %%1' + Command = s '"%SystemRoot%\system32\notepad.exe" %%1' } Open { - Command = s '"%%SystemRoot%%\system32\wscript.exe" "%%1" %%*' + Command = s '"%SystemRoot%\system32\wscript.exe" "%%1" %%*' } Open2 { - Command = s '"%%SystemRoot%%\system32\cscript.exe" "%%1" %%*' + Command = s '"%SystemRoot%\system32\cscript.exe" "%%1" %%*' } Print { - Command = s '"%%SystemRoot%%\system32\notepad.exe" /p %%1' + Command = s '"%SystemRoot%\system32\notepad.exe" /p %%1' } } } diff --git a/dll/win32/vbscript/vbscript_classes.rgs b/dll/win32/vbscript/vbscript_classes.rgs deleted file mode 100644 index 134837107d8..00000000000 --- a/dll/win32/vbscript/vbscript_classes.rgs +++ /dev/null @@ -1,46 +0,0 @@ -HKCR -{ - NoRemove Interface - { - } - NoRemove CLSID - { - '{3F4DACA4-160D-11D2-A8E9-00104B365C9F}' = s 'VBScript Regular Expression' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } - ProgId = s 'VBScript.RegExp' - Version = s '5.5' - } - '{B54F3741-5B07-11CF-A4B0-00AA004A55E8}' = s 'VB Script Language' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'VBScript' - } - '{B54F3742-5B07-11CF-A4B0-00AA004A55E8}' = s 'VB Script Language Authoring' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'VBScript Author' - } - '{B54F3743-5B07-11CF-A4B0-00AA004A55E8}' = s 'VB Script Language Encoding' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'VBScript.Encode' - } - } - 'VBScript.RegExp' = s 'VBScript Regular Expression' - { - CLSID = s '{3F4DACA4-160D-11D2-A8E9-00104B365C9F}' - } - 'VBScript' = s 'VB Script Language' - { - CLSID = s '{B54F3741-5B07-11CF-A4B0-00AA004A55E8}' - } - 'VBScript Author' = s 'VB Script Language Authoring' - { - CLSID = s '{B54F3742-5B07-11CF-A4B0-00AA004A55E8}' - } - 'VBScript.Encode' = s 'VB Script Language Encoding' - { - CLSID = s '{B54F3743-5B07-11CF-A4B0-00AA004A55E8}' - } -} diff --git a/dll/win32/vbscript/vbscript_defs.h b/dll/win32/vbscript/vbscript_defs.h index 44f005b640f..139b71255a0 100644 --- a/dll/win32/vbscript/vbscript_defs.h +++ b/dll/win32/vbscript/vbscript_defs.h @@ -267,6 +267,7 @@ #define VBSE_INVALID_DLL_FUNCTION_NAME 453 #define VBSE_INVALID_TYPELIB_VARIABLE 458 #define VBSE_SERVER_NOT_FOUND 462 +#define VBSE_UNQUALIFIED_REFERENCE 505 #define VBS_COMPILE_ERROR 4096 #define VBS_RUNTIME_ERROR 4097 diff --git a/dll/win32/vbscript/vbscript_main.c b/dll/win32/vbscript/vbscript_main.c index 62da59975e3..fe63c7660a7 100644 --- a/dll/win32/vbscript/vbscript_main.c +++ b/dll/win32/vbscript/vbscript_main.c @@ -34,6 +34,7 @@ WINE_DECLARE_DEBUG_CHANNEL(heap); DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); static HINSTANCE vbscript_hinstance; +static ITypeInfo *dispatch_typeinfo; BSTR get_vbscript_string(int id) { @@ -42,14 +43,6 @@ BSTR get_vbscript_string(int id) return SysAllocString(buf); } -BSTR get_vbscript_error_string(HRESULT error) -{ - BSTR ret; - if(HRESULT_FACILITY(error) != FACILITY_VBS || !(ret = get_vbscript_string(HRESULT_CODE(error)))) - ret = get_vbscript_string(VBS_UNKNOWN_RUNTIME_ERROR); - return ret; -} - #define MIN_BLOCK_SIZE 128 #define ARENA_FREE_FILLER 0xaa @@ -73,12 +66,12 @@ void *heap_pool_alloc(heap_pool_t *heap, size_t size) if(!heap->block_cnt) { if(!heap->blocks) { - heap->blocks = heap_alloc(sizeof(void*)); + heap->blocks = malloc(sizeof(void*)); if(!heap->blocks) return NULL; } - tmp = heap_alloc(block_size(0)); + tmp = malloc(block_size(0)); if(!tmp) return NULL; @@ -94,12 +87,12 @@ void *heap_pool_alloc(heap_pool_t *heap, size_t size) if(size <= block_size(heap->last_block+1)) { if(heap->last_block+1 == heap->block_cnt) { - tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*)); + tmp = realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*)); if(!tmp) return NULL; heap->blocks = tmp; - heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt)); + heap->blocks[heap->block_cnt] = malloc(block_size(heap->block_cnt)); if(!heap->blocks[heap->block_cnt]) return NULL; @@ -111,7 +104,7 @@ void *heap_pool_alloc(heap_pool_t *heap, size_t size) return heap->blocks[heap->last_block]; } - list = heap_alloc(size + sizeof(struct list)); + list = malloc(size + sizeof(struct list)); if(!list) return NULL; @@ -144,7 +137,7 @@ void heap_pool_clear(heap_pool_t *heap) while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) { list_remove(tmp); - heap_free(tmp); + free(tmp); } if(WARN_ON(heap)) { @@ -165,8 +158,8 @@ void heap_pool_free(heap_pool_t *heap) heap_pool_clear(heap); for(i=0; i < heap->block_cnt; i++) - heap_free(heap->blocks[i]); - heap_free(heap->blocks); + free(heap->blocks[i]); + free(heap->blocks); heap_pool_init(heap); } @@ -180,6 +173,29 @@ heap_pool_t *heap_pool_mark(heap_pool_t *heap) return heap; } +HRESULT get_dispatch_typeinfo(ITypeInfo **out) +{ + ITypeInfo *typeinfo; + ITypeLib *typelib; + HRESULT hr; + + if (!dispatch_typeinfo) + { + hr = LoadRegTypeLib(&IID_StdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &typelib); + if (FAILED(hr)) return hr; + + hr = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IDispatch, &typeinfo); + ITypeLib_Release(typelib); + if (FAILED(hr)) return hr; + + if (InterlockedCompareExchangePointer((void**)&dispatch_typeinfo, typeinfo, NULL)) + ITypeInfo_Release(typeinfo); + } + + *out = dispatch_typeinfo; + return S_OK; +} + static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -244,20 +260,17 @@ static IClassFactory VBScriptRegExpFactory = { &VBScriptRegExpFactoryVtbl }; */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) { - TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpv); + TRACE("(%p %ld %p)\n", hInstDLL, fdwReason, lpv); switch(fdwReason) { -#ifndef __REACTOS__ - case DLL_WINE_PREATTACH: - return FALSE; /* prefer native version */ -#endif case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); vbscript_hinstance = hInstDLL; break; case DLL_PROCESS_DETACH: if (lpv) break; + if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo); release_regexp_typelib(); } @@ -280,29 +293,3 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } - -/*********************************************************************** - * DllCanUnloadNow (vbscript.@) - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return S_FALSE; -} - -/*********************************************************************** - * DllRegisterServer (vbscript.@) - */ -HRESULT WINAPI DllRegisterServer(void) -{ - TRACE("()\n"); - return __wine_register_resources(vbscript_hinstance); -} - -/*********************************************************************** - * DllUnregisterServer (vbscript.@) - */ -HRESULT WINAPI DllUnregisterServer(void) -{ - TRACE("()\n"); - return __wine_unregister_resources(vbscript_hinstance); -} diff --git a/dll/win32/vbscript/vbsglobal.rgs b/dll/win32/vbscript/vbsglobal.rgs deleted file mode 100644 index 390968d559d..00000000000 --- a/dll/win32/vbscript/vbsglobal.rgs +++ /dev/null @@ -1,32 +0,0 @@ -HKCR -{ - NoRemove Typelib - { - NoRemove '{3EEF9758-35FC-11D1-8CE4-00C04FC2B185}' - { - '1.0' = s 'Microsoft VBScript Globals' - { - '0' { win32 = s '%MODULE%' } - FLAGS = s '0' - } - } - } - NoRemove Interface - { - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B186}' = s 'GlobalObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9758-35FC-11D1-8CE4-00C04FC2B185}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B187}' = s 'ErrObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9758-35FC-11D1-8CE4-00C04FC2B185}' { val Version = s '1.0' } - } - } - NoRemove CLSID - { - } -} diff --git a/dll/win32/vbscript/vbsregexp10.idl b/dll/win32/vbscript/vbsregexp10.idl index e76ef52e563..c0304b1ed13 100644 --- a/dll/win32/vbscript/vbsregexp10.idl +++ b/dll/win32/vbscript/vbsregexp10.idl @@ -24,6 +24,7 @@ import "oaidl.idl"; [ helpstring("Microsoft VBScript Regular Expressions 1.0"), + id(2), uuid(3f4daca7-160d-11d2-a8e9-00104b365c9f), version(1.0) ] diff --git a/dll/win32/vbscript/vbsregexp10.rgs b/dll/win32/vbscript/vbsregexp10.rgs deleted file mode 100644 index da7876c4991..00000000000 --- a/dll/win32/vbscript/vbsregexp10.rgs +++ /dev/null @@ -1,38 +0,0 @@ -HKCR -{ - NoRemove Typelib - { - NoRemove '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' - { - '1.0' = s 'Microsoft VBScript Regular Expressions 1.0' - { - '0' { win32 = s '%MODULE%' } - FLAGS = s '0' - } - } - } - NoRemove Interface - { - '{3F4DACA0-160D-11D2-A8E9-00104B365C9F}' = s 'IRegExp' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '1.0' } - } - '{3F4DACA1-160D-11D2-A8E9-00104B365C9F}' = s 'IMatch' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '1.0' } - } - '{3F4DACA2-160D-11D2-A8E9-00104B365C9F}' = s 'IMatchCollection' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '1.0' } - } - } - NoRemove CLSID - { - } -} diff --git a/dll/win32/vbscript/vbsregexp55.idl b/dll/win32/vbscript/vbsregexp55.idl index 67d88de9ddd..a5cbdf05314 100644 --- a/dll/win32/vbscript/vbsregexp55.idl +++ b/dll/win32/vbscript/vbsregexp55.idl @@ -24,6 +24,7 @@ import "oaidl.idl"; [ helpstring("Microsoft VBScript Regular Expressions 5.5"), + id(3), uuid(3f4daca7-160d-11d2-a8e9-00104b365c9f), version(5.5) ] diff --git a/dll/win32/vbscript/vbsregexp55.rgs b/dll/win32/vbscript/vbsregexp55.rgs deleted file mode 100644 index b685609aea5..00000000000 --- a/dll/win32/vbscript/vbsregexp55.rgs +++ /dev/null @@ -1,62 +0,0 @@ -HKCR -{ - NoRemove Typelib - { - NoRemove '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' - { - '5.5' = s 'Microsoft VBScript Regular Expressions 5.5' - { - '0' { win32 = s '%MODULE%' } - FLAGS = s '0' - } - } - } - NoRemove Interface - { - '{3F4DACA0-160D-11D2-A8E9-00104B365C9F}' = s 'IRegExp' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACB0-160D-11D2-A8E9-00104B365C9F}' = s 'IRegExp2' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACA1-160D-11D2-A8E9-00104B365C9F}' = s 'IMatch' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACB1-160D-11D2-A8E9-00104B365C9F}' = s 'IMatch2' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACA2-160D-11D2-A8E9-00104B365C9F}' = s 'IMatchCollection' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACB2-160D-11D2-A8E9-00104B365C9F}' = s 'IMatchCollection2' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - '{3F4DACB3-160D-11D2-A8E9-00104B365C9F}' = s 'ISubMatches' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3F4DACA7-160D-11D2-A8E9-00104B365C9F}' { val Version = s '5.5' } - } - } - NoRemove CLSID - { - } -} diff --git a/media/doc/WINESYNC.txt b/media/doc/WINESYNC.txt index 0b7a63fad16..0060a163c76 100644 --- a/media/doc/WINESYNC.txt +++ b/media/doc/WINESYNC.txt @@ -207,7 +207,7 @@ dll/win32/url # Synced to WineStaging-3.3 dll/win32/urlmon # Synced to WineStaging-4.18 dll/win32/usp10 # Synced to WineStaging-4.18 dll/win32/uxtheme # Forked -dll/win32/vbscript # Synced to WineStaging-4.18 +dll/win32/vbscript # Synced to Wine-10.0 dll/win32/version # Synced to WineStaging-4.18 dll/win32/vssapi # Synced to WineStaging-4.18 dll/win32/wbemdisp # Synced to WineStaging-4.18