[PATCH v17 0/2] MR10579: vbscript: Identifier improvements
Windows limits VBScript identifiers to 255 characters, returning error 1030 (Identifier too long) for longer names. Wine previously accepted identifiers of any length. VBScript allows square brackets to quote identifiers containing spaces, special characters, or reserved words. -- v17: vbscript: Support bracketed identifiers like [my var]. https://gitlab.winehq.org/wine/wine/-/merge_requests/10579
From: Francis De Brabandere <francisdb@gmail.com> Windows limits VBScript identifiers to 255 characters, returning error 1030 (Identifier too long) for longer names. Wine previously accepted identifiers of any length. --- dlls/vbscript/lex.c | 5 +++++ dlls/vbscript/tests/lang.vbs | 5 +++++ dlls/vbscript/tests/run.c | 6 ++++++ dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 5 files changed, 18 insertions(+) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 076320e8917..5f177529460 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -28,6 +28,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); +#define MAX_IDENTIFIER_LENGTH 255 + static int lex_error(parser_ctx_t *ctx, HRESULT hres) { ctx->hres = hres; @@ -167,6 +169,9 @@ static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret) ctx->ptr++; len = ctx->ptr-ptr; + if(len > MAX_IDENTIFIER_LENGTH) + return lex_error(ctx, MAKE_VBSERROR(VBSE_IDENTIFIER_TOO_LONG)); + str = parser_alloc(ctx, (len+1)*sizeof(WCHAR)); if(!str) return 0; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 777d7bfc5a9..613d6cb42fa 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -273,6 +273,11 @@ x _ x = 3 +' Maximum identifier length (255 chars) +Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42 +Call ok(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42, "255-char identifier should work") + Class ChainedCallTarget Public Function Ret() Set Ret = Me diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 37c8883fcd9..ccd65490f64 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3206,6 +3206,12 @@ static void test_parse_errors(void) "End Class\n", 2, 11, NULL, S_OK, 1037 + }, + { + /* Identifier too long (256 chars) */ + L"Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", + 0, 260, + NULL, S_OK, 1030 } }; HRESULT hres; diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index f80635bd665..98a8d0af1c5 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -82,6 +82,7 @@ STRINGTABLE VBSE_EXPECTED_END_OF_STATEMENT "Expected end of statement" VBSE_EXPECTED_INTEGER_CONSTANT "Expected integer constant" VBSE_EXPECTED_WHILE_UNTIL_EOS "Expected 'While', 'Until' or end of statement" + VBSE_IDENTIFIER_TOO_LONG "Identifier too long" VBSE_EXPECTED_WITH "Expected 'With'" VBSE_INVALID_NUMBER "Invalid number" VBSE_INVALID_CHAR "Invalid character" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 9cf9cce7ad9..3edcc79dbb1 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -294,6 +294,7 @@ #define VBSE_EXPECTED_INTEGER_CONSTANT 1026 #define VBSE_EXPECTED_WHILE_UNTIL_EOS 1028 #define VBSE_EXPECTED_WITH 1029 +#define VBSE_IDENTIFIER_TOO_LONG 1030 #define VBSE_INVALID_NUMBER 1031 #define VBSE_INVALID_CHAR 1032 #define VBSE_UNTERMINATED_STRING 1033 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10579
From: Francis De Brabandere <francisdb@gmail.com> VBScript allows square brackets to quote identifiers containing spaces, special characters, or reserved words. --- dlls/vbscript/lex.c | 30 +++++++++++++++++++++++++ dlls/vbscript/tests/lang.vbs | 41 +++++++++++++++++++++++++++++++++++ dlls/vbscript/tests/run.c | 12 ++++++++++ dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 5 files changed, 85 insertions(+) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 5f177529460..81cc67e037b 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -410,6 +410,34 @@ static int comment_line(parser_ctx_t *ctx) return tNL; } +static int parse_bracket_identifier(parser_ctx_t *ctx, const WCHAR **ret) +{ + const WCHAR *start = ++ctx->ptr; + WCHAR *str; + int len; + + while(ctx->ptr < ctx->end && *ctx->ptr != ']' && *ctx->ptr != '\n' && *ctx->ptr != '\r') + ctx->ptr++; + + if(ctx->ptr >= ctx->end || *ctx->ptr != ']') + return lex_error(ctx, MAKE_VBSERROR(VBSE_EXPECTED_RBRACKET)); + + len = ctx->ptr - start; + ctx->ptr++; /* skip ']' */ + + if(len > MAX_IDENTIFIER_LENGTH) + return lex_error(ctx, MAKE_VBSERROR(VBSE_IDENTIFIER_TOO_LONG)); + + str = parser_alloc(ctx, (len+1)*sizeof(WCHAR)); + if(!str) + return 0; + + memcpy(str, start, len*sizeof(WCHAR)); + str[len] = 0; + *ret = str; + return tIdentifier; +} + static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) { WCHAR c; @@ -500,6 +528,8 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) || ctx->last_token == tEMPTYBRACKETS) return '('; return tEXPRLBRACKET; + case '[': + return parse_bracket_identifier(ctx, lval); case '"': return parse_string_literal(ctx, lval); case '#': diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 613d6cb42fa..f74979cb109 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -278,6 +278,47 @@ Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42 Call ok(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42, "255-char identifier should work") +' Bracketed identifiers +Dim [my var] +[my var] = 42 +Call ok([my var] = 42, "[my var] = " & [my var]) + +Dim [hello world!] +[hello world!] = "works" +Call ok([hello world!] = "works", "[hello world!] = " & [hello world!]) + +Dim [] +[] = "empty" +Call ok([] = "empty", "[] = " & []) + +Dim [ ] +[ ] = "spaces" +Call ok([ ] = "spaces", "[ ] = " & [ ]) + +Dim [dim] +[dim] = 99 +Call ok([dim] = 99, "[dim] = " & [dim]) + +Class BracketTestObj + Public [my property] + Public Sub Class_Initialize + [my property] = "init" + End Sub +End Class + +Dim bracketObj +Set bracketObj = New BracketTestObj +bracketObj.[my property] = "updated" +Call ok(bracketObj.[my property] = "updated", "bracketObj.[my property] = " & bracketObj.[my property]) + +Dim [loop var] +Dim bracketTotal : bracketTotal = 0 +For [loop var] = 1 To 3 + bracketTotal = bracketTotal + [loop var] +Next +Call ok(bracketTotal = 6, "For [loop var] total = " & bracketTotal) + +' Chained call syntax Class ChainedCallTarget Public Function Ret() Set Ret = Me diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index ccd65490f64..337481ff51c 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3212,6 +3212,18 @@ static void test_parse_errors(void) L"Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", 0, 260, NULL, S_OK, 1030 + }, + { + /* Nested square brackets */ + L"Dim [[nested]]\n", + 0, 13, + NULL, S_OK, 1032 + }, + { + /* Unclosed square bracket */ + L"Dim [unclosed\n", + 0, 13, + NULL, S_OK, 1007 } }; HRESULT hres; diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index 98a8d0af1c5..bdb71c86cbd 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -64,6 +64,7 @@ STRINGTABLE VBSE_UNQUALIFIED_REFERENCE "Invalid or unqualified reference" VBSE_SYNTAX_ERROR "Syntax error" VBSE_EXPECTED_LPAREN "Expected '('" + VBSE_EXPECTED_RBRACKET "Expected ']'" VBSE_EXPECTED_RPAREN "Expected ')'" VBSE_EXPECTED_IDENTIFIER "Expected identifier" VBSE_EXPECTED_ASSIGN "Expected '='" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 3edcc79dbb1..1bcc1d8da67 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -276,6 +276,7 @@ #define VBSE_SYNTAX_ERROR 1002 #define VBSE_EXPECTED_LPAREN 1005 #define VBSE_EXPECTED_RPAREN 1006 +#define VBSE_EXPECTED_RBRACKET 1007 #define VBSE_EXPECTED_IDENTIFIER 1010 #define VBSE_EXPECTED_ASSIGN 1011 #define VBSE_EXPECTED_IF 1012 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10579
On Sat Apr 11 07:42:53 2026 +0000, Francis De Brabandere wrote:
changed this line in [version 15 of the diff](/wine/wine/-/merge_requests/10579/diffs?diff_id=259778&start_sha=82352f1eb22c0cdfcc195d3db5a650538d1ca208#b4267e979d2234221210ef007bea3a4eb1b1b55b_279_279) Added and renamed to match the other EXPECTED defs
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10579#note_135856
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10579
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)