[PATCH v4 0/5] MR10544: vbscript: Use ASCII-only case-insensitive compare for identifier lookups.
VBScript identifiers are ASCII-only, Windows rejects all non-ASCII characters (Latin-1, Cyrillic, CJK) at the lexer level with error 1032 "Invalid character". Replace the locale-aware `wcsicmp()` with an inline ASCII-only `vbs_wcsicmp()` for all identifier comparisons. This avoids the expensive locale grab/free cycle (`get_current_locale_noalloc`/`free_locinfo`) that dominated profiling at 87–95% of CPU time in identifier lookup paths. Also restrict the lexer's `is_identifier_char()` and identifier-start check to ASCII-only, matching Windows behavior. Tests added for non-ASCII character rejection (é, ß, ü, Cyrillic) in identifiers. ### Benchmark results (best-of-3, before → after) | Benchmark | Before | After | Change | |---|---:|---:|---:| | Class prop read ×500k | 2558 ms | 160 ms | **−93.7%** | | GetRef loop ×200k | 15988 ms | 296 ms | **−98.1%** | | Empty For 10M | 4808 ms | 242 ms | **−95.0%** | | Nested For 10M | 6367 ms | 253 ms | **−96.0%** | | Local vars 10M | 9437 ms | 390 ms | **−95.9%** | | Dict.Exists ×100k | 300 ms | 113 ms | **−62.3%** | | If boolvar 10M | 7882 ms | 988 ms | **−87.5%** | | String concat ×2000 | 78 ms | 70 ms | −10.3% | Identifier-heavy operations see **10–50× speedups**. String concat (I/O-bound, not lookup-bound) is unchanged as expected. -- v4: vbscript: Replace wcsicmp with vbs_wcsicmp in compiler, globals, and dispatch. vbscript: Add vbs_wcsicmp and use it in interpreter. vbscript: Use ASCII-only case folding in check_keyword. vbscript: Handle vertical tab and form feed as whitespace in lexer. vbscript: Restrict identifier characters to ASCII-only. https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/lex.c | 7 +++++-- dlls/vbscript/tests/run.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 1f9c4c3b18c..8e3d41ba4ed 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -102,9 +102,12 @@ static const struct { {L"xor", tXOR} }; +/* VBScript identifiers are ASCII-only: [A-Za-z0-9_]. Windows rejects all + * non-ASCII characters (Latin-1, Cyrillic, CJK) at the lexer level with + * error 1032 "Invalid character". */ static inline BOOL is_identifier_char(WCHAR c) { - return iswalnum(c) || c == '_'; + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval) @@ -411,7 +414,7 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) if('0' <= c && c <= '9') return parse_numeric_literal(ctx, lval); - if(iswalpha(c)) { + if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { int ret = 0; if(ctx->last_token != '.' && ctx->last_token != tDOT) ret = check_keywords(ctx, lval); diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index da6f31ff4df..f1a0320d327 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3049,6 +3049,36 @@ static void test_parse_errors(void) L"x = 1 _x\n", 0, 7, NULL, S_OK, 1032 + }, + { + /* Non-ASCII: e-acute (chr 233) in identifier */ + L"Dim caf\x00e9\n", + 0, 7, + NULL, S_OK, 1032 + }, + { + /* Non-ASCII: sharp-s (chr 223) in identifier */ + L"Dim st\x00df" L"e\n", + 0, 6, + NULL, S_OK, 1032 + }, + { + /* Non-ASCII: u-umlaut (chr 252) in identifier */ + L"Dim x\x00fc" L"b\n", + 0, 5, + NULL, S_OK, 1032 + }, + { + /* Non-ASCII: Cyrillic a (chr 1072) as identifier start */ + L"Dim \x0430\n", + 0, 4, + NULL, S_OK, 1032 + }, + { + /* Non-ASCII: e-acute (chr 233) starting identifier */ + L"\x00e9var = 1\n", + 0, 0, + NULL, S_OK, 1032 } }; HRESULT hres; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/lex.c | 2 +- dlls/vbscript/tests/run.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 8e3d41ba4ed..71ecaa43278 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -386,7 +386,7 @@ static int parse_hex_literal(parser_ctx_t *ctx, LONG *ret) static void skip_spaces(parser_ctx_t *ctx) { - while(*ctx->ptr == ' ' || *ctx->ptr == '\t') + while(*ctx->ptr == ' ' || *ctx->ptr == '\t' || *ctx->ptr == '\v' || *ctx->ptr == '\f') ctx->ptr++; } diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index f1a0320d327..28b164bf601 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3505,6 +3505,13 @@ static void run_tests(void) parse_script_w(L""); parse_script_w(L"' empty ;"); + /* Vertical tab and form feed are valid whitespace separators */ + parse_script_w(L"dim\x0b""x\n"); + parse_script_w(L"dim\x0c""x\n"); + parse_script_w(L"dim\x0b\x0c""x\n"); + parse_script_w(L"x\x0b""=\x0b""1\n"); + parse_script_w(L"x\x0c""=\x0c""1\n"); + SET_EXPECT(global_success_d); SET_EXPECT(global_success_i); parse_script_w(L"reportSuccess"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/lex.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 71ecaa43278..12305ab671b 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -110,6 +110,10 @@ static inline BOOL is_identifier_char(WCHAR c) return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } +/* Compare the current parse position against a keyword using ASCII-only + * case-insensitive matching. Keywords are all lowercase ASCII, so we only + * need to lowercase [A-Z] in the source. Returns 0 on match, <0 or >0 + * for ordering (used by the binary search in check_keywords). */ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval) { const WCHAR *p1 = ctx->ptr; @@ -117,7 +121,8 @@ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lva WCHAR c; while(p1 < ctx->end && *p2) { - c = towlower(*p1); + c = *p1; + if(c >= 'A' && c <= 'Z') c += 'a' - 'A'; if(c != *p2) return c - *p2; p1++; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
From: Francis De Brabandere <francisdb@gmail.com> Replace locale-aware wcsicmp() with ASCII-only vbs_wcsicmp() for identifier comparisons. This avoids the expensive locale grab/free cycle that dominated profiling in identifier lookup paths. --- dlls/vbscript/interp.c | 34 +++++++++++++++++----------------- dlls/vbscript/vbscript.h | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 2a73a7fb51a..d57d29c1203 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -84,7 +84,7 @@ typedef struct { static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref) { while(var) { - if(!wcsicmp(var->name, name)) { + if(!vbs_wcsicmp(var->name, name)) { ref->type = var->is_const ? REF_CONST : REF_VAR; ref->u.v = &var->v; return TRUE; @@ -102,7 +102,7 @@ static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref size_t i, cnt = script->global_vars_cnt; for(i = 0; i < cnt; i++) { - if(!wcsicmp(vars[i]->name, name)) { + if(!vbs_wcsicmp(vars[i]->name, name)) { ref->type = vars[i]->is_const ? REF_CONST : REF_VAR; ref->u.v = &vars[i]->v; return TRUE; @@ -118,7 +118,7 @@ static BOOL lookup_global_funcs(ScriptDisp *script, const WCHAR *name, ref_t *re size_t i, cnt = script->global_funcs_cnt; for(i = 0; i < cnt; i++) { - if(!wcsicmp(funcs[i]->name, name)) { + if(!vbs_wcsicmp(funcs[i]->name, name)) { ref->type = REF_FUNC; ref->u.f = funcs[i]; return TRUE; @@ -138,7 +138,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ if(invoke_type != VBDISP_CALLGET && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET) - && !wcsicmp(name, ctx->func->name)) { + && !vbs_wcsicmp(name, ctx->func->name)) { ref->type = REF_VAR; ref->u.v = &ctx->ret_val; return S_OK; @@ -146,7 +146,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ if(ctx->func->type != FUNC_GLOBAL) { for(i=0; i < ctx->func->var_cnt; i++) { - if(!wcsicmp(ctx->func->vars[i].name, name)) { + if(!vbs_wcsicmp(ctx->func->vars[i].name, name)) { ref->type = REF_VAR; ref->u.v = ctx->vars+i; return S_OK; @@ -154,7 +154,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } for(i=0; i < ctx->func->arg_cnt; i++) { - if(!wcsicmp(ctx->func->args[i].name, name)) { + if(!vbs_wcsicmp(ctx->func->args[i].name, name)) { ref->type = REF_VAR; ref->u.v = ctx->args+i; return S_OK; @@ -167,7 +167,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ if(ctx->vbthis) { /* FIXME: Bind such identifier while generating bytecode. */ for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) { - if(!wcsicmp(ctx->vbthis->desc->props[i].name, name)) { + if(!vbs_wcsicmp(ctx->vbthis->desc->props[i].name, name)) { ref->type = REF_VAR; ref->u.v = ctx->vbthis->props+i; return S_OK; @@ -188,7 +188,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ exec_ctx_t *caller = ctx->caller; for(i=0; i < caller->func->var_cnt; i++) { - if(!wcsicmp(caller->func->vars[i].name, name)) { + if(!vbs_wcsicmp(caller->func->vars[i].name, name)) { ref->type = REF_VAR; ref->u.v = caller->vars+i; return S_OK; @@ -196,7 +196,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } for(i=0; i < caller->func->arg_cnt; i++) { - if(!wcsicmp(caller->func->args[i].name, name)) { + if(!vbs_wcsicmp(caller->func->args[i].name, name)) { ref->type = REF_VAR; ref->u.v = caller->args+i; return S_OK; @@ -845,7 +845,7 @@ static HRESULT interp_ident(exec_ctx_t *ctx) TRACE("%s\n", debugstr_w(identifier)); if((ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET) - && !wcsicmp(identifier, ctx->func->name)) { + && !vbs_wcsicmp(identifier, ctx->func->name)) { V_VT(&v) = VT_BYREF|VT_VARIANT; V_BYREF(&v) = &ctx->ret_val; return stack_push(ctx, &v); @@ -1227,7 +1227,7 @@ static HRESULT interp_new(exec_ctx_t *ctx) TRACE("%s\n", debugstr_w(arg)); - if(!wcsicmp(arg, L"regexp")) { + if(!vbs_wcsicmp(arg, L"regexp")) { V_VT(&v) = VT_DISPATCH; hres = create_regexp(&V_DISPATCH(&v)); if(FAILED(hres)) @@ -1238,11 +1238,11 @@ static HRESULT interp_new(exec_ctx_t *ctx) 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)) + if(!vbs_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)) + if(!vbs_wcsicmp(class_desc->name, arg)) break; if(!class_desc) { FIXME("Class %s not found\n", debugstr_w(arg)); @@ -1275,7 +1275,7 @@ static HRESULT interp_dim(exec_ctx_t *ctx) 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)) + if(!vbs_wcsicmp(script_obj->global_vars[i]->name, ident)) break; } assert(i < script_obj->global_vars_cnt); @@ -2599,17 +2599,17 @@ HRESULT exec_add_caller_dynamic_var(script_ctx_t *script, exec_ctx_t *ctx, const /* Skip if name already exists in caller's locals, args, or dynamic vars */ for(i = 0; i < ctx->func->var_cnt; i++) { - if(!wcsicmp(ctx->func->vars[i].name, name)) + if(!vbs_wcsicmp(ctx->func->vars[i].name, name)) return S_OK; } for(i = 0; i < ctx->func->arg_cnt; i++) { - if(!wcsicmp(ctx->func->args[i].name, name)) + if(!vbs_wcsicmp(ctx->func->args[i].name, name)) return S_OK; } { dynamic_var_t *var; for(var = ctx->dynamic_vars; var; var = var->next) { - if(!wcsicmp(var->name, name)) + if(!vbs_wcsicmp(var->name, name)) return S_OK; } } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 3bf23a34bfa..19c9260a342 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -425,6 +425,21 @@ static inline BOOL is_digit(WCHAR c) return '0' <= c && c <= '9'; } +/* ASCII-only case-insensitive compare for VBScript identifiers. + * VBScript identifiers are ASCII-only (Windows rejects all non-ASCII + * characters), so this avoids the expensive locale-aware wcsicmp. */ +static inline int vbs_wcsicmp(const WCHAR *s1, const WCHAR *s2) +{ + WCHAR c1, c2; + do { + c1 = *s1++; + c2 = *s2++; + if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A'; + if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A'; + } while (c1 && c1 == c2); + return c1 - c2; +} + HRESULT create_regexp(IDispatch**); BSTR string_replace(BSTR,BSTR,BSTR,int,int,int); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/compile.c | 30 +++++++++++++++--------------- dlls/vbscript/global.c | 26 +++++++++++++------------- dlls/vbscript/vbdisp.c | 18 +++++++++--------- dlls/vbscript/vbscript.c | 6 +++--- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 3777624c6d4..c6132587984 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -417,7 +417,7 @@ static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, B const_decl_t *decl; for(decl = ctx->const_decls; decl; decl = decl->next) { - if(!wcsicmp(decl->name, name)) + if(!vbs_wcsicmp(decl->name, name)) return decl->value_expr; } @@ -425,7 +425,7 @@ static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, B return NULL; for(decl = ctx->global_consts; decl; decl = decl->next) { - if(!wcsicmp(decl->name, name)) + if(!vbs_wcsicmp(decl->name, name)) return decl->value_expr; } @@ -437,7 +437,7 @@ 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)) + if(!vbs_wcsicmp(ctx->func->args[i].name, name)) return TRUE; } @@ -449,7 +449,7 @@ 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)) + if(!vbs_wcsicmp(dim_decl->name, name)) return TRUE; } @@ -1722,7 +1722,7 @@ static BOOL lookup_funcs_name(compile_ctx_t *ctx, const WCHAR *name) function_t *iter; for(iter = ctx->code->funcs; iter; iter = iter->next) { - if(!wcsicmp(iter->name, name)) + if(!vbs_wcsicmp(iter->name, name)) return TRUE; } @@ -1788,7 +1788,7 @@ static BOOL lookup_class_name(compile_ctx_t *ctx, const WCHAR *name) class_desc_t *iter; for(iter = ctx->code->classes; iter; iter = iter->next) { - if(!wcsicmp(iter->name, name)) + if(!vbs_wcsicmp(iter->name, name)) return TRUE; } @@ -1839,7 +1839,7 @@ static BOOL lookup_class_funcs(class_desc_t *class_desc, const WCHAR *name) unsigned i; for(i=0; i < class_desc->func_cnt; i++) { - if(class_desc->funcs[i].name && !wcsicmp(class_desc->funcs[i].name, name)) + if(class_desc->funcs[i].name && !vbs_wcsicmp(class_desc->funcs[i].name, name)) return TRUE; } @@ -1899,14 +1899,14 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) } } - if(!wcsicmp(L"class_initialize", func_decl->name)) { + if(!vbs_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(L"class_terminate", func_decl->name)) { + }else if(!vbs_wcsicmp(L"class_terminate", func_decl->name)) { if(func_decl->type != FUNC_SUB) { FIXME("class terminator is not sub\n"); return E_FAIL; @@ -1976,17 +1976,17 @@ static BOOL lookup_script_identifier(compile_ctx_t *ctx, script_ctx_t *script, c if(!contexts[c]) continue; for(i = 0; i < contexts[c]->global_vars_cnt; i++) { - if(!wcsicmp(contexts[c]->global_vars[i]->name, identifier)) + if(!vbs_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)) + if(!vbs_wcsicmp(contexts[c]->global_funcs[i]->name, identifier)) return TRUE; } for(class = contexts[c]->classes; class; class = class->next) { - if(!wcsicmp(class->name, identifier)) + if(!vbs_wcsicmp(class->name, identifier)) return TRUE; } } @@ -2000,17 +2000,17 @@ static BOOL lookup_script_identifier(compile_ctx_t *ctx, script_ctx_t *script, c continue; for(i = 0; i < var_cnt; i++) { - if(!wcsicmp(vars[i].name, identifier)) + if(!vbs_wcsicmp(vars[i].name, identifier)) return TRUE; } for(func = code->funcs; func; func = func->next) { - if(!wcsicmp(func->name, identifier)) + if(!vbs_wcsicmp(func->name, identifier)) return TRUE; } for(class = code->classes; class; class = class->next) { - if(!wcsicmp(class->name, identifier)) + if(!vbs_wcsicmp(class->name, identifier)) return TRUE; } } diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index b6a32fdacdb..3578625d154 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -126,7 +126,7 @@ HRESULT get_builtin_id(BuiltinDisp *disp, const WCHAR *name, DISPID *id) while(min <= max) { i = (min + max) / 2; - r = wcsicmp(disp->members[i].name, name); + r = vbs_wcsicmp(disp->members[i].name, name); if(!r) { *id = i; return S_OK; @@ -2465,25 +2465,25 @@ static HRESULT Global_DateAdd(BuiltinDisp *This, VARIANT *args, unsigned args_cn hres = to_system_time(args + 2, &ud.st); if (SUCCEEDED(hres)) { - if (!wcsicmp(interval, L"yyyy")) + if (!vbs_wcsicmp(interval, L"yyyy")) ud.st.wYear += count; - else if (!wcsicmp(interval, L"q")) + else if (!vbs_wcsicmp(interval, L"q")) ud.st.wMonth += 3 * count; - else if (!wcsicmp(interval, L"m")) + else if (!vbs_wcsicmp(interval, L"m")) ud.st.wMonth += count; - else if (!wcsicmp(interval, L"y") - || !wcsicmp(interval, L"d") - || !wcsicmp(interval, L"w")) + else if (!vbs_wcsicmp(interval, L"y") + || !vbs_wcsicmp(interval, L"d") + || !vbs_wcsicmp(interval, L"w")) { ud.st.wDay += count; } - else if (!wcsicmp(interval, L"ww")) + else if (!vbs_wcsicmp(interval, L"ww")) ud.st.wDay += 7 * count; - else if (!wcsicmp(interval, L"h")) + else if (!vbs_wcsicmp(interval, L"h")) ud.st.wHour += count; - else if (!wcsicmp(interval, L"n")) + else if (!vbs_wcsicmp(interval, L"n")) ud.st.wMinute += count; - else if (!wcsicmp(interval, L"s")) + else if (!vbs_wcsicmp(interval, L"s")) ud.st.wSecond += count; else { @@ -3629,7 +3629,7 @@ static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, funcs = item->script_obj->global_funcs; cnt = item->script_obj->global_funcs_cnt; for(i = 0; i < cnt; i++) { - if(!wcsicmp(funcs[i]->name, name)) { + if(!vbs_wcsicmp(funcs[i]->name, name)) { hres = create_func_ref(This->ctx, funcs[i], &disp); if(FAILED(hres)) return hres; @@ -3644,7 +3644,7 @@ static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, funcs = This->ctx->script_obj->global_funcs; cnt = This->ctx->script_obj->global_funcs_cnt; for(i = 0; i < cnt; i++) { - if(!wcsicmp(funcs[i]->name, name)) { + if(!vbs_wcsicmp(funcs[i]->name, name)) { hres = create_func_ref(This->ctx, funcs[i], &disp); if(FAILED(hres)) return hres; diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 66d1b84abf6..79b1a728a52 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -48,7 +48,7 @@ static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, vbdisp_invoke_type_t continue; } - if(This->desc->funcs[i].name && !wcsicmp(This->desc->funcs[i].name, name)) { + if(This->desc->funcs[i].name && !vbs_wcsicmp(This->desc->funcs[i].name, name)) { *id = i; return TRUE; } @@ -68,7 +68,7 @@ HRESULT vbdisp_get_id(vbdisp_t *This, BSTR name, vbdisp_invoke_type_t invoke_typ if(!search_private && !This->desc->props[i].is_public) continue; - if(!wcsicmp(This->desc->props[i].name, name)) { + if(!vbs_wcsicmp(This->desc->props[i].name, name)) { *id = i + This->desc->func_cnt; return S_OK; } @@ -972,14 +972,14 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r { function_t *func = This->funcs[i].func; - if (wcsicmp(name, func->name)) continue; + if (vbs_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)) + if (!vbs_wcsicmp(name, func->args[arg].name)) break; if (arg >= 0) pMemId[j] = arg; @@ -991,7 +991,7 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r for (i = 0; i < This->num_vars; i++) { - if (wcsicmp(name, This->disp->global_vars[i]->name)) continue; + if (vbs_wcsicmp(name, This->disp->global_vars[i]->name)) continue; pMemId[0] = i + 1; return S_OK; } @@ -1279,7 +1279,7 @@ static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULO for (i = 0; i < This->num_funcs; i++) { - if (wcsicmp(szName, This->funcs[i].func->name)) continue; + if (vbs_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); @@ -1293,7 +1293,7 @@ static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULO for (i = 0; i < This->num_vars; i++) { - if (wcsicmp(szName, This->disp->global_vars[i]->name)) continue; + if (vbs_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); @@ -1520,14 +1520,14 @@ static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DW return E_UNEXPECTED; for(i = 0; i < This->global_vars_cnt; i++) { - if(!wcsicmp(This->global_vars[i]->name, bstrName)) { + if(!vbs_wcsicmp(This->global_vars[i]->name, bstrName)) { *pid = i + 1; return S_OK; } } for(i = 0; i < This->global_funcs_cnt; i++) { - if(!wcsicmp(This->global_funcs[i]->name, bstrName)) { + if(!vbs_wcsicmp(This->global_funcs[i]->name, bstrName)) { *pid = i + 1 + DISPID_FUNCTION_MASK; return S_OK; } diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 2e2fa6498da..6fff84e5359 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -145,7 +145,7 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL for (j = 0; j < obj->global_vars_cnt; j++) { - if (!wcsicmp(obj->global_vars[j]->name, code->main_code.vars[i].name)) + if (!vbs_wcsicmp(obj->global_vars[j]->name, code->main_code.vars[i].name)) { found = TRUE; break; @@ -171,7 +171,7 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL { for (i = 0; i < obj->global_funcs_cnt; i++) { - if (!wcsicmp(obj->global_funcs[i]->name, func_iter->name)) + if (!vbs_wcsicmp(obj->global_funcs[i]->name, func_iter->name)) { /* global function already exists, replace it */ obj->global_funcs[i] = func_iter; @@ -245,7 +245,7 @@ named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned f 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->flags & flags) == flags && !vbs_wcsicmp(item->name, name)) { if(!item->script_obj && !(item->flags & SCRIPTITEM_GLOBALMEMBERS)) { hres = create_script_disp(ctx, &item->script_obj); if(FAILED(hres)) return NULL; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
On Sat Apr 4 17:21:05 2026 +0000, Jacek Caban wrote:
Nice findings. The code looks overall correct, but please split it into separate commits for better bisectability. An example of a better split would be: - `is_identifier_char` change and its tests - `skip_spaces` and its tests - remaining lexer changes - interpreter changes ` remaining `vbs_wcsicmp` changes now better?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10544#note_135042
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10544
On Mon Apr 6 11:01:33 2026 +0000, Francis De Brabandere wrote:
now better? Yes, thanks.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10544#note_135112
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)