From: Frédéric Delanoy Subject: [2/2] cmd: Add support for LSS comparison operator in if statements Message-Id: <1320671853-17554-2-git-send-email-frederic.delanoy@gmail.com> Date: Mon, 7 Nov 2011 14:17:33 +0100 --- programs/cmd/builtins.c | 29 +++++++++++++- programs/cmd/tests/test_builtins.cmd | 60 ++++++++++++++++++++++++++++-- programs/cmd/tests/test_builtins.cmd.exp | 44 ++++++++++++++++++++-- 3 files changed, 123 insertions(+), 10 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index aba3692..e76669d 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1500,10 +1500,30 @@ void WCMD_popd (void) { static int evaluate_if_comparison_operation(const WCHAR *leftOperand, const WCHAR *operator, const WCHAR *rightOperand, int caseInsensitive) { + WCHAR *endptr_leftOp, *endptr_rightOp; + long int leftOperand_int, rightOperand_int; + BOOL int_operands; + static const WCHAR lssW[] = {'l','s','s','\0'}; + + /* == is a special case, as it always compares strings */ if (!lstrcmpiW(operator, eqeqW)) return caseInsensitive ? lstrcmpiW(leftOperand, rightOperand) == 0 : lstrcmpW (leftOperand, rightOperand) == 0; + /* Check if we have plain integers (in decimal, octal or hexadecimal notation) */ + leftOperand_int = strtolW(leftOperand, &endptr_leftOp, 0); + rightOperand_int = strtolW(rightOperand, &endptr_rightOp, 0); + int_operands = (!*endptr_leftOp) && (!*endptr_rightOp); + + /* Perform actual (integer or string) comparison */ + if (!lstrcmpiW(operator, lssW)) { + if (int_operands) + return leftOperand_int < rightOperand_int; + else + return caseInsensitive ? lstrcmpiW(leftOperand, rightOperand) < 0 + : lstrcmpW (leftOperand, rightOperand) < 0; + } + return -1; } @@ -1582,10 +1602,15 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) while (*p == ' ' || *p == '\t') p++; - if (!p || *p != '=' || !(p+1) || *(p+1) != '=') + if (!p || !(p+1) || (*p == '=' && *(p+1) != '=')) goto syntax_err; - strcpyW(operator, eqeqW); + if (*p == '=') { + strcpyW(operator, eqeqW); + } else { + if (!get_param_buffered(operator, p, 0, ¶mStart, ¶mEnd)) + goto syntax_err; + } p += strlenW(operator); if (!get_param_buffered(rightOperand, p, 0, ¶mStart, ¶mEnd)) diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 13c9393..f48b3a6 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -552,7 +552,7 @@ if exist foo ( ) cd .. & rd foobar -echo ------------ Testing if/else -------------- +echo ------------ Testing if/else ------------ echo if/else should work with blocks if 0 == 0 ( echo if seems to work @@ -569,19 +569,19 @@ if /c==/c ( ) else ( echo parameter detection seems to be broken ) -echo Testing case sensitivity with and without /i option +echo ... case sensitivity with and without /i option ... if bar==BAR echo if does not default to case sensitivity if not bar==BAR echo if seems to default to case sensitivity if /i foo==FOO echo if /i seems to work if /i not foo==FOO echo if /i seems to be broken if /I foo==FOO echo if /I seems to work if /I not foo==FOO echo if /I seems to be broken -echo Testing string comparisons +echo ... string comparisons ... if abc == abc (echo equal) else echo non equal if abc =="abc" (echo equal) else echo non equal if "abc"== abc (echo equal) else echo non equal if "abc"== "abc" (echo equal) else echo non equal -echo Testing tabs handling +echo ... tabs handling ... if@tab@1==1 echo doom if @tab@1==1 echo doom if 1==1 (echo doom) else@tab@echo quake @@ -590,6 +590,58 @@ if 1==0@tab@(echo doom) else echo quake if 1==0 (echo doom)@tab@else echo quake if 1==0 (echo doom) else@tab@echo quake +echo ... comparison operators ... +rem NT4 misevaluates conditionals in for loops so we have to use subroutines as workarounds +rem Imbricated for loops parameters are currently not expanded correctly; this prevents usage of simpler imbricated for loops in tests +echo ...... for strings ...... +rem NT4 stops processing of the whole batch file as soon as it finds a +rem comparison operator non fully uppercased, such as lss instead of LSS, so we +rem can't test those here. +if LSS LSS LSSfoo (echo LSS string can be used as operand for LSS comparison) +if LSS LSS LSS (echo bar) +if 1.1 LSS 1.10 (echo floats are handled as strings) +if "9" LSS "10" (echo numbers in quotes recognized!) else echo numbers in quotes are handled as strings +if not "-1" LSS "1" (echo negative numbers as well) else echo NT +if /i foo LSS FoOc echo if /i seems to work for LSS +if /I not foo LSS FOOb echo if /I seems to be broken for LSS +set STR_PARMS=A B AB BA AA +for %%i in (%STR_PARMS%) do call :LSStest %%i A +for %%i in (%STR_PARMS%) do call :LSStest %%i B +for %%i in (%STR_PARMS%) do call :LSStest %%i AB +for %%i in (%STR_PARMS%) do call :LSStest %%i BA +for %%i in (%STR_PARMS%) do call :LSStest %%i AA +if b LSS B (echo b LSS B) else echo NT4 +if /I b LSS B echo b LSS B insensitive +if b LSS A echo b LSS A +if /I b LSS A echo b LSS A insensitive +if a LSS B (echo a LSS B) else echo NT4 +if /I a LSS B echo a LSS B insensitive +if A LSS b echo A LSS b +if /I A LSS b echo A LSS b insensitive +echo ...... for numbers ...... +if -1 LSS 1 (echo negative numbers handled) +if not -1 LSS -10 (echo negative numbers handled) +if not 9 LSS 010 (echo octal handled) +if not -010 LSS -8 (echo also in negative form) +if 4 LSS 0x5 (echo hexa handled) +if not -1 LSS -0x1A (echo also in negative form) +if 11 LSS 101 (echo 11 LSS 101) +set INT_PARMS=0 1 10 9 +for %%i in (%INT_PARMS%) do call :LSStest %%i 0 +for %%i in (%INT_PARMS%) do call :LSStest %%i 1 +for %%i in (%INT_PARMS%) do call :LSStest %%i 10 +for %%i in (%INT_PARMS%) do call :LSStest %%i 9 +goto :endIfCompOpsSubroutines + +rem IF subroutines helpers +:LSStest +if %1 LSS %2 echo %1 LSS %2 +goto :eof + +:endIfCompOpsSubroutines +set STR_PARMS= +set INT_PARMS= + echo -----------Testing for ----------- echo ...plain FOR for %%i in (A B C) do echo %%i diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 7a0eec3..186d941 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -378,21 +378,21 @@ bar bar NUL @todo_wine@foo created ------------- Testing if/else -------------- +------------ Testing if/else ------------ if/else should work with blocks if seems to work else seems to work if seems not to detect /c as parameter -Testing case sensitivity with and without /i option +... case sensitivity with and without /i option ... if seems to default to case sensitivity if /i seems to work if /I seems to work -Testing string comparisons +... string comparisons ... equal non equal non equal equal -Testing tabs handling +... tabs handling ... doom doom doom @@ -400,6 +400,42 @@ lol quake quake quake +... comparison operators ... +...... for strings ...... +LSS string can be used as operand for LSS comparison +floats are handled as strings +numbers in quotes are handled as strings +negative numbers as well@or_broken@NT +if /i seems to work for LSS +A LSS B +AB LSS B +AA LSS B +A LSS AB +AA LSS AB +A LSS BA +B LSS BA +AB LSS BA +AA LSS BA +A LSS AA +b LSS B@or_broken@NT4 +a LSS B@or_broken@NT4 +a LSS B insensitive +A LSS b +A LSS b insensitive +...... for numbers ...... +negative numbers handled +negative numbers handled +octal handled +also in negative form +hexa handled +also in negative form +11 LSS 101 +0 LSS 1 +0 LSS 10 +1 LSS 10 +9 LSS 10 +0 LSS 9 +1 LSS 9 -----------Testing for ----------- ...plain FOR A -- 1.7.7.1