From 154710a0932e915426b3f08356794aeb7141aa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delanoy?= Date: Thu, 25 Oct 2012 23:48:02 +0200 Subject: [PATCH] cmd: Add support for LSS comparison operator in if statements. --- programs/cmd/builtins.c | 63 +++++++++++++++++++++--- programs/cmd/tests/test_builtins.cmd.exp | 50 +++++++++---------- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index af669d371c8..95419a1de29 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -104,6 +104,7 @@ static const WCHAR onW[] = {'O','N','\0'}; static const WCHAR offW[] = {'O','F','F','\0'}; static const WCHAR parmY[] = {'/','Y','\0'}; static const WCHAR parmNoY[] = {'/','-','Y','\0'}; +static const WCHAR eqeqW[] = {'=','=','\0'}; static HINSTANCE hinst; struct env_stack *saved_environment; @@ -2332,6 +2333,52 @@ void WCMD_popd (void) { LocalFree (temp); } +/******************************************************************* + * evaluate_if_comparison + * + * Evaluates an "if" comparison operation + * + * PARAMS + * leftOperand [I] left operand, non NULL + * operator [I] "if" binary comparison operator, non NULL + * rightOperand [I] right operand, non NULL + * caseInsensitive [I] 0 for case sensitive comparison, anything else for insensitive + * + * RETURNS + * Success: 1 if operator applied to the operands evaluates to TRUE + * 0 if operator applied to the operands evaluates to FALSE + * Failure: -1 if operator is not recognized + */ +static int evaluate_if_comparison(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; +} + /**************************************************************************** * WCMD_if * @@ -2355,7 +2402,6 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) static const WCHAR errlvlW[] = {'e','r','r','o','r','l','e','v','e','l','\0'}; static const WCHAR existW[] = {'e','x','i','s','t','\0'}; static const WCHAR defdW[] = {'d','e','f','i','n','e','d','\0'}; - static const WCHAR eqeqW[] = {'=','=','\0'}; static const WCHAR parmI[] = {'/','I','\0'}; int caseInsensitive = (strstrW(quals, parmI) != NULL); @@ -2394,18 +2440,21 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) while (*p == ' ' || *p == '\t') p++; - if (strncmpW(p, eqeqW, strlenW(eqeqW))) - goto syntax_err; - - strcpyW(operator, eqeqW); + if (!strncmpW(p, eqeqW, strlenW(eqeqW))) + strcpyW(operator, eqeqW); + else { + strcpyW(operator, WCMD_parameter(p, 0, ¶mStart, FALSE, FALSE)); + if (!*operator) goto syntax_err; + } p += strlenW(operator); strcpyW(rightOperand, WCMD_parameter(p, 0, ¶mStart, TRUE, FALSE)); if (!*rightOperand) goto syntax_err; - test = caseInsensitive ? lstrcmpiW(leftOperand, rightOperand) == 0 - : lstrcmpW (leftOperand, rightOperand) == 0; + test = evaluate_if_comparison(leftOperand, operator, rightOperand, caseInsensitive); + if (test == -1) + goto syntax_err; p = paramStart + strlenW(rightOperand); WCMD_parameter(p, 0, &command, FALSE, FALSE); diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 9b5eb3bc64b..b25eb9e8871 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -441,25 +441,25 @@ quake --- comparison operators ------ for strings LSS string can be used as operand for LSS comparison -@todo_wine@floats are handled as strings -@todo_wine@numbers in quotes are handled as strings -@todo_wine@negative numbers as well@or_broken@NT4 -@todo_wine@if /i seems to work for LSS -@todo_wine@A LSS B -@todo_wine@AB LSS B -@todo_wine@AA LSS B -@todo_wine@A LSS AB -@todo_wine@AA LSS AB -@todo_wine@A LSS BA -@todo_wine@B LSS BA -@todo_wine@AB LSS BA -@todo_wine@AA LSS BA -@todo_wine@A LSS AA -@todo_wine@b LSS B@or_broken@NT4 -@todo_wine@a LSS B@or_broken@NT4 -@todo_wine@a LSS B insensitive -@todo_wine@A LSS b -@todo_wine@A LSS b insensitive +floats are handled as strings +numbers in quotes are handled as strings +negative numbers as well@or_broken@NT4 +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 @todo_wine@A LEQ A @todo_wine@A LEQ B @todo_wine@B LEQ B @@ -540,12 +540,12 @@ also in negative form hexa handled also in negative form 11 LSS 101 -@todo_wine@0 LSS 1 -@todo_wine@0 LSS 10 -@todo_wine@1 LSS 10 -@todo_wine@9 LSS 10 -@todo_wine@0 LSS 9 -@todo_wine@1 LSS 9 +0 LSS 1 +0 LSS 10 +1 LSS 10 +9 LSS 10 +0 LSS 9 +1 LSS 9 @todo_wine@0 LEQ 0 @todo_wine@0 LEQ 1 @todo_wine@1 LEQ 1