cmd: Add helper for 'if' comparison operations evaluation
Frédéric Delanoy
frederic.delanoy at gmail.com
Mon Oct 31 05:05:51 CDT 2011
Note: the only comparison operator currently implemented is '=='
Subsequent comparison operators (LSS, ..., GTR) will also use this.
---
programs/cmd/builtins.c | 107 ++++++++++++++++++++++++++++++++++++-----------
1 files changed, 82 insertions(+), 25 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 22e0342..b215887 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -1480,6 +1480,49 @@ void WCMD_popd (void) {
LocalFree (temp);
}
+/*******************************************************************
+ * evaluate_if_comparison_operation
+ *
+ * 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_operation(const WCHAR *leftOperand, const WCHAR *operator,
+ const WCHAR *rightOperand, int caseInsensitive)
+{
+ static const WCHAR eqeqW[] = {'=','=','\0'};
+
+ if (!lstrcmpiW(operator, eqeqW)) {
+ return caseInsensitive ? lstrcmpiW(leftOperand, rightOperand) == 0
+ : lstrcmpW (leftOperand, rightOperand) == 0;
+ }
+
+ return -1;
+}
+
+/* Store potentially double-quoted parameter into a preallocated buffer.
+ * Uses same parameters as WCMD_parameter in addition to buff, except start and end may not be NULL
+ * buff must be wide enough to contain a max-sized WCMD_parameter result
+ * Returns FALSE if no parameter could be found, else TRUE
+ */
+static BOOL get_quoted_param(WCHAR *buff, WCHAR *s, int n, WCHAR **start, WCHAR **end)
+{
+ WCMD_parameter(s, n, start, end);
+ if (!*start) return FALSE;
+ memcpy(buff, *start, (*end - *start + 1)*sizeof(WCHAR));
+ buff[*end - *start + 1] = '\0';
+ return TRUE;
+}
+
/****************************************************************************
* WCMD_if
*
@@ -1495,16 +1538,17 @@ void WCMD_popd (void) {
* FIXME: Much more syntax checking needed!
*/
-void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
-
+void WCMD_if (WCHAR *p, CMD_LIST **cmdList)
+{
int negate; /* Negate condition */
int test; /* Condition evaluation result */
- WCHAR condition[MAX_PATH], *command, *s;
+ WCHAR condition[MAX_PATH], *command;
+ WCHAR leftOperand[MAXSTRING], rightOperand[MAXSTRING], operator[MAXSTRING];
+ WCHAR *paramStart, *paramEnd;
static const WCHAR notW[] = {'n','o','t','\0'};
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);
@@ -1516,10 +1560,7 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
WCHAR *param = WCMD_parameter(p, 1+negate, NULL, NULL);
WCHAR *endptr;
long int param_int = strtolW(param, &endptr, 10);
- if (*endptr) {
- WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
- return;
- }
+ if (*endptr) goto syntax_err;
test = ((long int)errorlevel >= param_int);
WCMD_parameter(p, 2+negate, &command, NULL);
}
@@ -1531,29 +1572,45 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
test = (GetEnvironmentVariableW(WCMD_parameter(p, 1+negate, NULL, NULL), NULL, 0) > 0);
WCMD_parameter(p, 2+negate, &command, NULL);
}
- else if ((s = strstrW (p, eqeqW))) {
- /* We need to get potential surrounding double quotes, so param1/2 can't be used */
- WCHAR *leftPart, *leftPartEnd, *rightPart, *rightPartEnd;
- s += 2;
- WCMD_parameter(p, 0+negate+caseInsensitive, &leftPart, &leftPartEnd);
- WCMD_parameter(p, 1+negate+caseInsensitive, &rightPart, &rightPartEnd);
- test = caseInsensitive
- ? (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
- leftPart, leftPartEnd-leftPart+1,
- rightPart, rightPartEnd-rightPart+1) == CSTR_EQUAL)
- : (CompareStringW(LOCALE_SYSTEM_DEFAULT, 0,
- leftPart, leftPartEnd-leftPart+1,
- rightPart, rightPartEnd-rightPart+1) == CSTR_EQUAL);
- WCMD_parameter(s, 1, &command, NULL);
- }
else {
- WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
- return;
+ /* Need operands and comparison operator with potential surrounding quotes, so return value
+ * of WCMD_parameter can't be used */
+ if (!get_quoted_param(leftOperand, p, negate+caseInsensitive, ¶mStart, ¶mEnd))
+ goto syntax_err;
+
+ /* Note: '==' can't be returned by WCMD_parameter since '=' is a separator */
+ p = paramEnd + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (!p || *p != '=' || !(p+1) || *(p+1) != '=')
+ goto syntax_err;
+ else {
+ operator[0] = '=';
+ operator[1] = '=';
+ operator[2] = '\0';
+ }
+ p += strlenW(operator);
+
+ if (!get_quoted_param(rightOperand, p, 0, ¶mStart, ¶mEnd))
+ goto syntax_err;
+
+ test = evaluate_if_comparison_operation(leftOperand, operator, rightOperand, caseInsensitive);
+ if (test == -1)
+ goto syntax_err;
+
+ p = paramEnd + 1;
+ WCMD_parameter(p, 0, &command, NULL);
}
/* Process rest of IF statement which is on the same line
Note: This may process all or some of the cmdList (eg a GOTO) */
WCMD_part_execute(cmdList, command, NULL, NULL, TRUE, (test != negate));
+ return;
+
+syntax_err:
+ WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
+ return;
}
/****************************************************************************
--
1.7.7.1
More information about the wine-patches
mailing list