[1/2] cmd: Add helper for 'if' comparison operations evaluation (try 2) (resend)

Frédéric Delanoy frederic.delanoy at gmail.com
Mon Nov 7 07:17:32 CST 2011


Note: the only comparison operator currently implemented is '=='
'==' is handled as a special case since '=' is a separator and hence can't be returned by WCMD_parameter.

Subsequent comparison operators (LSS, ..., GTR) will also be handled by the evaluation function.
---
 programs/cmd/builtins.c |  103 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 78 insertions(+), 25 deletions(-)

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 22e0342..aba3692 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -63,6 +63,7 @@ static const WCHAR dotdotW[] = {'.','.','\0'};
 static const WCHAR slashW[]  = {'\\','\0'};
 static const WCHAR starW[]   = {'*','\0'};
 static const WCHAR equalW[]  = {'=','\0'};
+static const WCHAR eqeqW[]   = {'=','=','\0'};
 static const WCHAR fslashW[] = {'/','\0'};
 static const WCHAR onW[]  = {'O','N','\0'};
 static const WCHAR offW[] = {'O','F','F','\0'};
@@ -1480,6 +1481,46 @@ 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)
+{
+    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_param_buffered(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 +1536,15 @@ 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;
   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 +1556,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 +1568,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;
+    WCHAR leftOperand[MAXSTRING], rightOperand[MAXSTRING], operator[MAXSTRING];
+    WCHAR *paramStart, *paramEnd;
+
+    /* Need operands and comparison operator with potential surrounding quotes, so return value
+     * of WCMD_parameter can't be used */
+    if (!get_param_buffered(leftOperand, p, negate+caseInsensitive, &paramStart, &paramEnd))
+      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;
+
+    strcpyW(operator, eqeqW);
+    p += strlenW(operator);
+
+    if (!get_param_buffered(rightOperand, p, 0, &paramStart, &paramEnd))
+      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