[PATCH v2 0/2] MR10900: vbscript: Parse octal numeric literals (&O...).
Native cscript accepts &O0, &O17, &O177777, etc. as octal integer literals. Wine was emitting err 1002 (syntax error) for any &O prefix because the lexer only recognised &H. Add an oct_to_int helper and parse_oct_literal mirroring parse_hex_literal, allowing up to 32-bit values; overflow checks use an ULONGLONG accumulator since 11-digit octal can exceed 32 bits. -- v2: vbscript: Parse octal numeric literals (&O...). vbscript/tests: Add tests for octal numeric literals. https://gitlab.winehq.org/wine/wine/-/merge_requests/10900
From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/tests/lang.vbs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 1b6cdf763e4..b2b8a3eab3c 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -72,6 +72,29 @@ Call ok(&H000000031& = 49, "&H000000031& <> 49") Call ok(getVT(&H00000000000000FF) = "VT_I2", "getVT(&H00000000000000FF) is not VT_I2") Call ok(getVT(&H007FFFFFFF) = "VT_I4", "getVT(&H007FFFFFFF) is not VT_I4") Call ok(&h0 = 0, "&h0 <> 0") + +' Octal literals (&O...) +sub testOctalLiterals() + Dim oct + on error resume next + + Err.Clear : oct = Eval("&O0") : todo_wine_ok Err.number = 0 and oct = 0, "&O0 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O17") : todo_wine_ok Err.number = 0 and oct = 15, "&O17 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&o17") : todo_wine_ok Err.number = 0 and oct = 15, "&o17 (lowercase) oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O77") : todo_wine_ok Err.number = 0 and oct = 63, "&O77 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O777") : todo_wine_ok Err.number = 0 and oct = 511, "&O777 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O177777") : todo_wine_ok Err.number = 0 and oct = -1, "&O177777 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O200000") : todo_wine_ok Err.number = 0 and oct = 65536, "&O200000 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O17777777777") : todo_wine_ok Err.number = 0 and oct = 2147483647, "&O17777777777 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O37777777777") : todo_wine_ok Err.number = 0 and oct = -1, "&O37777777777 oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O17&") : todo_wine_ok Err.number = 0 and oct = 15, "&O17& oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O177777&") : todo_wine_ok Err.number = 0 and oct = 65535, "&O177777& oct=" & oct & " err=" & Err.number + Err.Clear : oct = Eval("&O77") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I2*", "getVT(&O77) = " & getVT(oct) + Err.Clear : oct = Eval("&O200000") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I4*", "getVT(&O200000) = " & getVT(oct) + Err.Clear : oct = Eval("&O177777&") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I4*", "getVT(&O177777&) = " & getVT(oct) + Err.Clear : oct = Eval("&O8") : call ok(Err.number = 1002, "&O8 should be syntax error, got err=" & Err.number) +end sub +call testOctalLiterals() Call ok(&h0& = 0, "&h0& <> 0") Call ok(&h00 = 0, "&h00 <> 0") Call ok(&h000000000 = 0, "&h000000000 <> 0") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10900
From: Francis De Brabandere <francisdb@gmail.com> Native cscript accepts &O0, &O17, &O177777, etc. as octal integer literals. Wine was emitting err 1002 (syntax error) for any &O prefix because the lexer only recognised &H. Add an oct_to_int helper and parse_oct_literal mirroring parse_hex_literal, allowing up to 32-bit values; overflow checks use an ULONGLONG accumulator since 11-digit octal can exceed 32 bits. --- dlls/vbscript/lex.c | 35 +++++++++++++++++++++++++++++++++++ dlls/vbscript/tests/lang.vbs | 36 ++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 81cc67e037b..bd6d97bf6d7 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -394,6 +394,39 @@ static int parse_hex_literal(parser_ctx_t *ctx, LONG *ret) return tInt; } +static int oct_to_int(WCHAR c) +{ + if('0' <= c && c <= '7') + return c-'0'; + return -1; +} + +static int parse_oct_literal(parser_ctx_t *ctx, LONG *ret) +{ + ULONGLONG l = 0; + int d; + + /* Skip leading zeros — Windows allows any number of them. */ + while(ctx->ptr[1] == '0') + ctx->ptr++; + + while((d = oct_to_int(*++ctx->ptr)) != -1) { + l = l*8 + d; + if(l > 0xFFFFFFFFULL) { + WARN("overflow in oct literal\n"); + return 0; + } + } + + if(*ctx->ptr == '&') { + ctx->ptr++; + *ret = (LONG)l; + }else { + *ret = l == (UINT16)l ? (INT16)l : (LONG)l; + } + return tInt; +} + static void skip_spaces(parser_ctx_t *ctx) { while(*ctx->ptr == ' ' || *ctx->ptr == '\t' || *ctx->ptr == '\v' || *ctx->ptr == '\f') @@ -537,6 +570,8 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) case '&': if((*++ctx->ptr == 'h' || *ctx->ptr == 'H') && hex_to_int(ctx->ptr[1]) != -1) return parse_hex_literal(ctx, lval); + if((*ctx->ptr == 'o' || *ctx->ptr == 'O') && oct_to_int(ctx->ptr[1]) != -1) + return parse_oct_literal(ctx, lval); return '&'; case '=': switch(*++ctx->ptr) { diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index b2b8a3eab3c..7ab9290bab4 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -74,27 +74,27 @@ Call ok(getVT(&H007FFFFFFF) = "VT_I4", "getVT(&H007FFFFFFF) is not VT_I4") Call ok(&h0 = 0, "&h0 <> 0") ' Octal literals (&O...) -sub testOctalLiterals() +Call ok(&O0 = 0, "&O0 <> 0") +Call ok(&O17 = 15, "&O17 <> 15") +Call ok(&o17 = 15, "&o17 (lowercase) <> 15") +Call ok(&O77 = 63, "&O77 <> 63") +Call ok(&O777 = 511, "&O777 <> 511") +Call ok(&O177777 = -1, "&O177777 <> -1") +Call ok(&O200000 = 65536, "&O200000 <> 65536") +Call ok(&O17777777777 = 2147483647, "&O17777777777 <> 2147483647") +Call ok(&O37777777777 = -1, "&O37777777777 <> -1") +Call ok(&O17& = 15, "&O17& <> 15") +Call ok(&O177777& = 65535, "&O177777& <> 65535") +Call ok(getVT(&O77) = "VT_I2", "getVT(&O77) is not VT_I2") +Call ok(getVT(&O200000) = "VT_I4", "getVT(&O200000) is not VT_I4") +Call ok(getVT(&O177777&) = "VT_I4", "getVT(&O177777&) is not VT_I4") + +sub testOctalLiteralErrors() Dim oct on error resume next - - Err.Clear : oct = Eval("&O0") : todo_wine_ok Err.number = 0 and oct = 0, "&O0 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O17") : todo_wine_ok Err.number = 0 and oct = 15, "&O17 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&o17") : todo_wine_ok Err.number = 0 and oct = 15, "&o17 (lowercase) oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O77") : todo_wine_ok Err.number = 0 and oct = 63, "&O77 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O777") : todo_wine_ok Err.number = 0 and oct = 511, "&O777 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O177777") : todo_wine_ok Err.number = 0 and oct = -1, "&O177777 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O200000") : todo_wine_ok Err.number = 0 and oct = 65536, "&O200000 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O17777777777") : todo_wine_ok Err.number = 0 and oct = 2147483647, "&O17777777777 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O37777777777") : todo_wine_ok Err.number = 0 and oct = -1, "&O37777777777 oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O17&") : todo_wine_ok Err.number = 0 and oct = 15, "&O17& oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O177777&") : todo_wine_ok Err.number = 0 and oct = 65535, "&O177777& oct=" & oct & " err=" & Err.number - Err.Clear : oct = Eval("&O77") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I2*", "getVT(&O77) = " & getVT(oct) - Err.Clear : oct = Eval("&O200000") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I4*", "getVT(&O200000) = " & getVT(oct) - Err.Clear : oct = Eval("&O177777&") : todo_wine_ok Err.number = 0 and getVT(oct) = "VT_I4*", "getVT(&O177777&) = " & getVT(oct) - Err.Clear : oct = Eval("&O8") : call ok(Err.number = 1002, "&O8 should be syntax error, got err=" & Err.number) + Err.Clear : oct = Eval("&O8") : call ok(Err.number = 1002, "&O8 should be syntax error, got err=" & Err.number) end sub -call testOctalLiterals() +call testOctalLiteralErrors() Call ok(&h0& = 0, "&h0& <> 0") Call ok(&h00 = 0, "&h00 <> 0") Call ok(&h000000000 = 0, "&h000000000 <> 0") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10900
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)