[PATCH] cmd: Added set /a (try 3, fixed tests and patch formatting) Some tests were written by Jack Kutilek

joel at teichroeb.net joel at teichroeb.net
Tue Apr 5 01:02:13 CDT 2011


From: Joel Teichroeb <joel at teichroeb.net>

---
 programs/cmd/builtins.c                        |  342 +++++++++++++++++++--
 programs/cmd/cmd.rc                            |    5 +
 programs/cmd/tests/rsrc.rc                     |    6 +
 programs/cmd/tests/test_builtins.cmd           |  119 +++++++
 programs/cmd/tests/test_builtins.cmd.exp       |   78 +++++
 programs/cmd/tests/test_set_operations.cmd     |  401 ++++++++++++++++++++++++
 programs/cmd/tests/test_set_operations.cmd.exp |  200 ++++++++++++
 programs/cmd/wcmd.h                            |    6 +
 programs/cmd/wcmdmain.c                        |    2 +-
 9 files changed, 1137 insertions(+), 22 deletions(-)
 create mode 100644 programs/cmd/tests/test_set_operations.cmd
 create mode 100644 programs/cmd/tests/test_set_operations.cmd.exp

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 944a997..56c3938 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -2252,6 +2252,240 @@ static int WCMD_setshow_sortenv(const WCHAR *s, const WCHAR *stub)
   return displayedcount;
 }
 
+typedef struct STACK {
+  int data;
+  struct STACK *next;
+} stack;
+typedef struct STACKPAIR {
+  stack *output, *op;
+} stackpair;
+void push(stack **head, int value)
+{
+  stack *node = HeapAlloc(GetProcessHeap(),0,sizeof(stack));
+  node->data = value;
+  node->next = *head;
+  *head = node;
+
+}
+int pop(stack **head)
+{
+  stack *top = *head;
+  int value = top->data;
+  *head = top->next;
+  HeapFree(GetProcessHeap(), 0, top);
+  return value;
+
+}
+
+int priority(const WCHAR op)
+{
+  switch(op)
+  {
+    case '/':
+    case '*':
+    case '%':
+      return 6;
+    case '+':
+    case '-':
+      return 5;
+    case '<':
+    case '>':
+      return 4;
+    case '&':
+      return 3;
+    case '^':
+      return 2;
+    case '|':
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+int evaluate(stackpair *pair)
+{
+  int r = 0, a, b, op;
+
+  op = pop(&(pair->op));
+  if (op == '(') {
+    SetLastError(WCMD_UNBALPARENS);
+    return 1;
+  }
+  if (!pair->output || !pair->output->next) {
+    SetLastError(WCMD_MISSINGOPERAND);
+    return 1;
+  }
+  b = pop(&(pair->output));
+  a = pop(&(pair->output));
+
+  switch (op)
+  {
+    case '+':
+      r=a+b;
+      break;
+    case '-':
+      r= a-b;
+      break;
+    case '*':
+      r= a*b;
+      break;
+    case '/':
+      if (b == 0) {
+        SetLastError(WCMD_DIVIDEBYZERO);
+        return 1;
+      }
+      r= a/b;
+      break;
+    case '%':
+      if (b == 0) {
+        SetLastError(WCMD_DIVIDEBYZERO);
+        return 1;
+      }
+      r= a%b;
+      break;
+    case '&':
+      r= a&b;
+      break;
+    case '|':
+      r= a|b;
+      break;
+    case '^':
+      r= a^b;
+      break;
+    case '<':
+      if (b < 0)
+        r = 0;
+      else
+        r= a<<b;
+      break;
+    case '>':
+      if (b < 0)
+        r = 0;
+      else
+        r= a>>b;
+      break;
+  }
+  push(&(pair->output), r);
+  return 0;
+}
+
+static inline int find_nondigit(const WCHAR *s, int base)
+{
+  int i = 0;
+  switch (base) {
+    case 8:  while (s[i]) { if (s[i] < '0' || s[i] > '7') return i;  i++; } break;
+    case 10: while (s[i]) { if (!isdigit(s[i])) return i;  i++; } break;
+    case 16: while (s[i]) { if (!isxdigit(s[i])) return i;  i++; } break;
+  }
+  return i;
+}
+
+int WCMD_parse_bracketed_infix(const WCHAR *s, WCHAR *o)
+{
+  static WCHAR format[] = {'%','d','\0'};
+  stackpair pair;
+  int i = 0;
+  int opnext = 0;
+  WCHAR *end = 0;
+  pair.output = 0;
+  pair.op = 0;
+  while (s[i] != 0)
+  {
+    int pri = priority(s[i]);
+    while (s[i] == ' ')
+      ++i;
+    if (!opnext) {
+      if ((s[i] <= '9' && s[i] >= '0') || ((s[i] == '-' || s[i] == '+'))){
+        int base = 10;
+        int val;
+        int j = i;
+        if (s[i] == '0') {
+          if (tolower(s[i+1]) == 'x') {
+            base = 16;
+            j += 2;
+          } else {
+            base = 8;
+            j += 1;
+          }
+        }
+        j += find_nondigit(&(s[j]), base);
+        if (s[j] != 0 && !(priority(s[j]) != 0 || s[j] == ' ' || s[j] == ')')) {
+          SetLastError(WCMD_INVALIDNUMBER);
+          return 1;
+        }
+        val = strtolW(&(s[i]), &end, base);
+        push(&(pair.output), val);
+        i += end - &(s[i]) -1;
+        opnext = 1;
+      } else if (isalpha(s[i])) {
+        int j = i;
+        /* this is only 16 because the max int will fit in there. */
+        WCHAR contents[16], *varname;
+        for (;isalpha(s[j]); ++j);
+        /* is there a way to do this without allocating memory? */
+        varname = HeapAlloc(GetProcessHeap(),0,(j-i+1)*sizeof(WCHAR));
+
+        memcpy(varname, &(s[i]), (j-i)*sizeof(WCHAR));
+        varname[j-i] = 0;
+        GetEnvironmentVariableW(varname, contents, 16);
+
+        push(&(pair.output), strtolW(contents, &end, 10));
+        HeapFree(GetProcessHeap(), 0, varname);
+        i = j-1;
+        opnext = 1;
+      } else if (s[i] == '(') {
+        push(&(pair.op), '(');
+      } else {
+        SetLastError(WCMD_MISSINGOPERAND);
+        return 1;
+      }
+    } else if (pri && opnext) {
+      if (pair.op == 0 || pair.op->data == '(' || priority(pair.op->data) < pri) {
+        if ((s[i] == '<' && s[i+1] == '<') || (s[i] == '>' && s[i+1] == '>'))
+         ++i;
+        else if ((s[i] == '<' && s[i+1] != '<') || (s[i] == '>' && s[i+1] != '>')) {
+          SetLastError(WCMD_MISSINGOPERATOR);
+          return 1;
+        }
+        push(&(pair.op), s[i]);
+        opnext = 0;
+      } else {
+        if (evaluate(&pair))
+          return 1;
+        --i;
+      }
+
+    } else if (s[i] == ')') {
+
+      while (pair.op && pair.op->data != '(') {
+        if (evaluate(&pair))
+          return 1;
+
+      }
+      if (!pair.op) {
+        SetLastError(WCMD_MISSINGOPERATOR);
+        return 1;
+      }
+      pop(&(pair.op));
+    } else {
+      SetLastError(WCMD_MISSINGOPERAND);
+      return 1;
+    }
+    ++i;
+  }
+  while (pair.op) {
+    if (evaluate(&pair))
+      return 1;
+  }
+  if (!pair.output) {
+    SetLastError(WCMD_MISSINGOPERAND);
+    return 1;
+  }
+  sprintfW(o, format, pop(&(pair.output)));
+  return 0;
+}
+
+
 /****************************************************************************
  * WCMD_setshow_env
  *
@@ -2261,9 +2495,10 @@ static int WCMD_setshow_sortenv(const WCHAR *s, const WCHAR *stub)
 void WCMD_setshow_env (WCHAR *s) {
 
   LPVOID env;
-  WCHAR *p;
+  WCHAR *p, *c;
   int status;
-  static const WCHAR parmP[] = {'/','P','\0'};
+  int opt_p = 0, opt_a = 0;
+  int q = 0;
 
   if (param1[0] == 0x00 && quals[0] == 0x00) {
     env = GetEnvironmentStringsW();
@@ -2271,10 +2506,25 @@ void WCMD_setshow_env (WCHAR *s) {
     return;
   }
 
+  while (quals[q] != 0) {
+    ++q;
+    if (quals[q] == 'P')
+      opt_p = 1;
+    else if (quals[q] == 'A')
+      opt_a = 1;
+    ++q;
+  }
+
+  /* skip past the options, this could probably be done better */
+  while (s[0] == '/') {
+    s += 2;
+    while (s[0] == ' ')
+      ++s;
+  }
+
+
   /* See if /P supplied, and if so echo the prompt, and read in a reply */
-  if (CompareStringW(LOCALE_USER_DEFAULT,
-                     NORM_IGNORECASE | SORT_STRINGSORT,
-                     s, 2, parmP, -1) == 2) {
+  if (opt_p) {
     WCHAR string[MAXSTRING];
     DWORD count;
 
@@ -2306,27 +2556,77 @@ void WCMD_setshow_env (WCHAR *s) {
 
   } else {
     DWORD gle;
+    do {
+      c = opt_a ? strchrW (s, ',') : 0;
+      if (c)
+        *c++ = '\0';
 
-    if (*s=='\"')
+      if (*s=='\"')
         WCMD_opt_s_strip_quotes(s);
-    p = strchrW (s, '=');
-    if (p == NULL) {
-      env = GetEnvironmentStringsW();
-      if (WCMD_setshow_sortenv( env, s ) == 0) {
-        WCMD_output (WCMD_LoadMessage(WCMD_MISSINGENV), s);
-        errorlevel = 1;
+      p = strchrW (s, '=');
+
+      if (p == NULL) {
+        if (opt_a) {
+          WCHAR out[16];
+          WCHAR out2[16];
+          static WCHAR format[] = {'%','s','\n','\0'};
+          if (WCMD_parse_bracketed_infix(s, out)) {
+            WCMD_output(WCMD_LoadMessage(GetLastError()));
+            return;
+          }
+          sprintfW(out2, format, out);
+          WCMD_output(out2);
+        } else {
+          env = GetEnvironmentStringsW();
+          if (WCMD_setshow_sortenv( env, s ) == 0) {
+            WCMD_output (WCMD_LoadMessage(WCMD_MISSINGENV), s);
+            errorlevel = 1;
+          }
+        }
+        return;
       }
-      return;
-    }
-    *p++ = '\0';
 
-    if (strlenW(p) == 0) p = NULL;
-    status = SetEnvironmentVariableW(s, p);
-    gle = GetLastError();
-    if ((!status) & (gle == ERROR_ENVVAR_NOT_FOUND)) {
-      errorlevel = 1;
-    } else if ((!status)) WCMD_print_error();
+      *p++ = '\0';
+
+      if (*p=='\"')
+        WCMD_opt_s_strip_quotes(p);
+
+      if (strlenW(p) == 0)
+        p = NULL;
+      if (opt_a) {
+        int inplace = 0;
+        WCHAR out[16];
+        WCHAR *in = 0;
+
+        if (priority(*(p-2))) {
+          inplace = 1;
+          *(p-1) = ' ';
+        }
+
+        in = inplace ? s : p;
+        if (WCMD_parse_bracketed_infix(in, out)) {
+          WCHAR *error = WCMD_LoadMessage(GetLastError());
+          WCMD_output_asis_len(error, lstrlenW(error), GetStdHandle(STD_ERROR_HANDLE));
+          return;
+        }
+        if (inplace) {
+          if (*(p-2) == '<' || *(p-2) == '>')
+            *(p-3) = '\0';
+          else
+            *(p-2) = '\0';
+        }
+        p = out;
+
+      }
+      status = SetEnvironmentVariableW(s, p);
+      gle = GetLastError();
+      if ((!status) & (gle == ERROR_ENVVAR_NOT_FOUND)) {
+        errorlevel = 1;
+      } else if ((!status)) WCMD_print_error();
+      s = c;
+    } while (c);
   }
+
 }
 
 /****************************************************************************
diff --git a/programs/cmd/cmd.rc b/programs/cmd/cmd.rc
index f5f8ae6..614454c 100644
--- a/programs/cmd/cmd.rc
+++ b/programs/cmd/cmd.rc
@@ -287,4 +287,9 @@ Enter HELP <command> for further information on any of the above commands\n"
   WCMD_VERSION,"CMD Version %s\n\n"
   WCMD_MOREPROMPT, "More? "
   WCMD_LINETOOLONG, "The input line is too long.\n"
+  WCMD_DIVIDEBYZERO, "Divide by zero error.\n"
+  WCMD_MISSINGOPERAND, "Missing operand.\n"
+  WCMD_MISSINGOPERATOR, "Missing operator.\n"
+  WCMD_UNBALPARENS, "Unbalanced parenthesis.\n"
+  WCMD_INVALIDNUMBER, "Invalid number.  Numeric constants are either decimal (17),\nhexadecimal (0x11), or octal (021).\n"
 }
diff --git a/programs/cmd/tests/rsrc.rc b/programs/cmd/tests/rsrc.rc
index bcb738d..3fc4aa5 100644
--- a/programs/cmd/tests/rsrc.rc
+++ b/programs/cmd/tests/rsrc.rc
@@ -21,3 +21,9 @@ test_builtins.cmd TESTCMD "test_builtins.cmd"
 
 /* @makedep: test_builtins.cmd.exp */
 test_builtins.cmd.exp TESTOUT "test_builtins.cmd.exp"
+
+/* @makedep: test_set_operations.cmd */
+test_set_operations.cmd TESTCMD "test_set_operations.cmd"
+
+/* @makedep: test_set_operations.cmd.exp */
+test_set_operations.cmd.exp TESTOUT "test_set_operations.cmd.exp"
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 2b117e4..ceaf139 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -32,6 +32,125 @@ echo ------------ Testing 'set' --------------
 echo set "FOO=bar" should not include the quotes in the variable value
 set "FOO=bar"
 echo %FOO%
+echo -------------- Testing 'set /a' ---------------------
+echo "+"
+set /a name=4+7
+echo %name%
+echo "-"
+set /a name=7-3
+echo %name%
+echo "*"
+set /a name=2*5
+echo %name%
+echo "/"
+set /a name=15/3
+echo %name%
+echo "%"
+set /a name="5%%2"
+echo %name%
+echo "&"
+set /a name="10&6"
+echo %name%
+echo "|"
+set /a name="10|6"
+echo %name%
+echo "^"
+set /a name="10^6"
+echo %name%
+echo "<<"
+set /a name="8<<2"
+echo %name%
+echo ">>"
+set /a name="8>>2"
+echo %name%
+echo "*="
+set /a name*=2
+echo %name%
+echo "/="
+set /a name/=4
+echo %name%
+echo "+="
+set /a name+= 4
+echo %name%
+echo "-="
+set /a name-=2
+echo %name%
+echo "&="
+set /a "name&=5"
+echo %name%
+echo "|="
+set /a "name|=6"
+echo %name%
+echo "^="
+set /a "name^=13"
+echo %name%
+echo "<<="
+set /a "name<<=1"
+echo %name%
+echo ">>="
+set /a "name>>=1"
+echo %name%
+echo "_>= || _<="
+set /a "name>=1"
+echo %name%
+echo "_+"
+set /a name=3+
+echo %name%
+echo "integer rounding"
+set /a name="10/4"
+echo %name%
+echo "octal notation"
+set /a name=022
+echo %name%
+set /a name=093
+echo %name%
+echo "hex notation"
+set /a name=0xDAD
+echo %name%
+set /a name=0xWRONG
+echo %name%
+echo ", expression separation"
+set /a name1=3+10,name2=4*6
+echo %name1%
+echo %name2%
+echo "divide by zero"
+set /a name=5/0
+echo %name%
+echo "undefined variables = 0"
+set name=test
+set /a name+=4
+echo %name%
+set /a name=aaaaah
+echo %name%
+echo "variables in expression"
+set /a name=4
+echo %name%
+set /a name1=9+name
+echo %name1%
+set /a name1=5-%name%
+echo %name1%
+echo parenthesis don't seem to be supported on NT4 and below
+echo "(_)_"
+set /a name="15/(2+3)"
+echo %name%
+echo "(_(_))_"
+set /a name=(4*(10-5)/2)+1
+echo %name%
+echo "((_))"
+set /a name=((2+2))
+echo %name%
+echo "()"
+set /a name=()
+echo %name%
+echo "(_+_"
+set /a name=(2+2
+echo %name%
+echo "_+_)"
+set /a name=2+2)
+echo %name%
+echo "(_+"
+set /a name=(2+
+echo %name%
 
 echo ------------ Testing variable expansion --------------
 echo ~dp0 should be directory containing batch file
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index e4644d3..cb87b7b 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -50,6 +50,84 @@ word at space@@space@
 ------------ Testing 'set' --------------
 set "FOO=bar" should not include the quotes in the variable value
 bar
+-------------- Testing 'set /a' ---------------------
+"+"
+11
+"-"
+4
+"*"
+10
+"/"
+5
+""
+1
+"&"
+2
+"|"
+14
+"^"
+12
+"<<"
+32
+">>"
+2
+"*="
+4
+"/="
+1
+"+="
+5
+"-="
+3
+"&="
+1
+"|="
+7
+"^="
+10
+"<<="
+20
+">>="
+10
+"_>= || _<="
+10
+"_+"
+10
+"integer rounding"
+2
+"octal notation"
+18
+18
+"hex notation"
+3501
+3501
+", expression separation"
+13
+24
+"divide by zero"
+3501
+"undefined variables = 0"
+4
+0
+"variables in expression"
+4
+13
+1
+parenthesis don't seem to be supported on NT4 and below
+"(_)_"
+3 at or_broken@4
+"(_(_))_"
+11 at or_broken@4
+"((_))"
+4
+"()"
+4
+"(_+_"
+4
+"_+_)"
+4
+"(_+"
+4
 ------------ Testing variable expansion --------------
 ~dp0 should be directory containing batch file
 @pwd@\
diff --git a/programs/cmd/tests/test_set_operations.cmd b/programs/cmd/tests/test_set_operations.cmd
new file mode 100644
index 0000000..f1110b0
--- /dev/null
+++ b/programs/cmd/tests/test_set_operations.cmd
@@ -0,0 +1,401 @@
+ at echo off
+set /a name="3+4+5"
+echo %name%
+set /a name="3+4-5"
+echo %name%
+set /a name="3+4*5"
+echo %name%
+set /a name="3+4/5"
+echo %name%
+set /a name="3+4<<5"
+echo %name%
+set /a name="3+4>>5"
+echo %name%
+set /a name="3+4|5"
+echo %name%
+set /a name="3+4&5"
+echo %name%
+set /a name="3+4^5"
+echo %name%
+set /a name="3+4%%5"
+echo %name%
+set /a name="3-4+5"
+echo %name%
+set /a name="3-4-5"
+echo %name%
+set /a name="3-4*5"
+echo %name%
+set /a name="3-4/5"
+echo %name%
+set /a name="3-4<<5"
+echo %name%
+set /a name="3-4>>5"
+echo %name%
+set /a name="3-4|5"
+echo %name%
+set /a name="3-4&5"
+echo %name%
+set /a name="3-4^5"
+echo %name%
+set /a name="3-4%%5"
+echo %name%
+set /a name="3*4+5"
+echo %name%
+set /a name="3*4-5"
+echo %name%
+set /a name="3*4*5"
+echo %name%
+set /a name="3*4/5"
+echo %name%
+set /a name="3*4<<5"
+echo %name%
+set /a name="3*4>>5"
+echo %name%
+set /a name="3*4|5"
+echo %name%
+set /a name="3*4&5"
+echo %name%
+set /a name="3*4^5"
+echo %name%
+set /a name="3*4%%5"
+echo %name%
+set /a name="3/4+5"
+echo %name%
+set /a name="3/4-5"
+echo %name%
+set /a name="3/4*5"
+echo %name%
+set /a name="3/4/5"
+echo %name%
+set /a name="3/4<<5"
+echo %name%
+set /a name="3/4>>5"
+echo %name%
+set /a name="3/4|5"
+echo %name%
+set /a name="3/4&5"
+echo %name%
+set /a name="3/4^5"
+echo %name%
+set /a name="3/4%%5"
+echo %name%
+set /a name="3<<4+5"
+echo %name%
+set /a name="3<<4-5"
+echo %name%
+set /a name="3<<4*5"
+echo %name%
+set /a name="3<<4/5"
+echo %name%
+set /a name="3<<4<<5"
+echo %name%
+set /a name="3<<4>>5"
+echo %name%
+set /a name="3<<4|5"
+echo %name%
+set /a name="3<<4&5"
+echo %name%
+set /a name="3<<4^5"
+echo %name%
+set /a name="3<<4%%5"
+echo %name%
+set /a name="3>>4+5"
+echo %name%
+set /a name="3>>4-5"
+echo %name%
+set /a name="3>>4*5"
+echo %name%
+set /a name="3>>4/5"
+echo %name%
+set /a name="3>>4<<5"
+echo %name%
+set /a name="3>>4>>5"
+echo %name%
+set /a name="3>>4|5"
+echo %name%
+set /a name="3>>4&5"
+echo %name%
+set /a name="3>>4^5"
+echo %name%
+set /a name="3>>4%%5"
+echo %name%
+set /a name="3|4+5"
+echo %name%
+set /a name="3|4-5"
+echo %name%
+set /a name="3|4*5"
+echo %name%
+set /a name="3|4/5"
+echo %name%
+set /a name="3|4<<5"
+echo %name%
+set /a name="3|4>>5"
+echo %name%
+set /a name="3|4|5"
+echo %name%
+set /a name="3|4&5"
+echo %name%
+set /a name="3|4^5"
+echo %name%
+set /a name="3|4%%5"
+echo %name%
+set /a name="3&4+5"
+echo %name%
+set /a name="3&4-5"
+echo %name%
+set /a name="3&4*5"
+echo %name%
+set /a name="3&4/5"
+echo %name%
+set /a name="3&4<<5"
+echo %name%
+set /a name="3&4>>5"
+echo %name%
+set /a name="3&4|5"
+echo %name%
+set /a name="3&4&5"
+echo %name%
+set /a name="3&4^5"
+echo %name%
+set /a name="3&4%%5"
+echo %name%
+set /a name="3^4+5"
+echo %name%
+set /a name="3^4-5"
+echo %name%
+set /a name="3^4*5"
+echo %name%
+set /a name="3^4/5"
+echo %name%
+set /a name="3^4<<5"
+echo %name%
+set /a name="3^4>>5"
+echo %name%
+set /a name="3^4|5"
+echo %name%
+set /a name="3^4&5"
+echo %name%
+set /a name="3^4^5"
+echo %name%
+set /a name="3^4%%5"
+echo %name%
+set /a name="3%%4+5"
+echo %name%
+set /a name="3%%4-5"
+echo %name%
+set /a name="3%%4*5"
+echo %name%
+set /a name="3%%4/5"
+echo %name%
+set /a name="3%%4<<5"
+echo %name%
+set /a name="3%%4>>5"
+echo %name%
+set /a name="3%%4|5"
+echo %name%
+set /a name="3%%4&5"
+echo %name%
+set /a name="3%%4^5"
+echo %name%
+set /a name="3%%4%%5"
+echo %name%
+set /a name="5+4+3"
+echo %name%
+set /a name="5+4-3"
+echo %name%
+set /a name="5+4*3"
+echo %name%
+set /a name="5+4/3"
+echo %name%
+set /a name="5+4<<3"
+echo %name%
+set /a name="5+4>>3"
+echo %name%
+set /a name="5+4|3"
+echo %name%
+set /a name="5+4&3"
+echo %name%
+set /a name="5+4^3"
+echo %name%
+set /a name="5+4%%3"
+echo %name%
+set /a name="5-4+3"
+echo %name%
+set /a name="5-4-3"
+echo %name%
+set /a name="5-4*3"
+echo %name%
+set /a name="5-4/3"
+echo %name%
+set /a name="5-4<<3"
+echo %name%
+set /a name="5-4>>3"
+echo %name%
+set /a name="5-4|3"
+echo %name%
+set /a name="5-4&3"
+echo %name%
+set /a name="5-4^3"
+echo %name%
+set /a name="5-4%%3"
+echo %name%
+set /a name="5*4+3"
+echo %name%
+set /a name="5*4-3"
+echo %name%
+set /a name="5*4*3"
+echo %name%
+set /a name="5*4/3"
+echo %name%
+set /a name="5*4<<3"
+echo %name%
+set /a name="5*4>>3"
+echo %name%
+set /a name="5*4|3"
+echo %name%
+set /a name="5*4&3"
+echo %name%
+set /a name="5*4^3"
+echo %name%
+set /a name="5*4%%3"
+echo %name%
+set /a name="5/4+3"
+echo %name%
+set /a name="5/4-3"
+echo %name%
+set /a name="5/4*3"
+echo %name%
+set /a name="5/4/3"
+echo %name%
+set /a name="5/4<<3"
+echo %name%
+set /a name="5/4>>3"
+echo %name%
+set /a name="5/4|3"
+echo %name%
+set /a name="5/4&3"
+echo %name%
+set /a name="5/4^3"
+echo %name%
+set /a name="5/4%%3"
+echo %name%
+set /a name="5<<4+3"
+echo %name%
+set /a name="5<<4-3"
+echo %name%
+set /a name="5<<4*3"
+echo %name%
+set /a name="5<<4/3"
+echo %name%
+set /a name="5<<4<<3"
+echo %name%
+set /a name="5<<4>>3"
+echo %name%
+set /a name="5<<4|3"
+echo %name%
+set /a name="5<<4&3"
+echo %name%
+set /a name="5<<4^3"
+echo %name%
+set /a name="5<<4%%3"
+echo %name%
+set /a name="5>>4+3"
+echo %name%
+set /a name="5>>4-3"
+echo %name%
+set /a name="5>>4*3"
+echo %name%
+set /a name="5>>4/3"
+echo %name%
+set /a name="5>>4<<3"
+echo %name%
+set /a name="5>>4>>3"
+echo %name%
+set /a name="5>>4|3"
+echo %name%
+set /a name="5>>4&3"
+echo %name%
+set /a name="5>>4^3"
+echo %name%
+set /a name="5>>4%%3"
+echo %name%
+set /a name="5|4+3"
+echo %name%
+set /a name="5|4-3"
+echo %name%
+set /a name="5|4*3"
+echo %name%
+set /a name="5|4/3"
+echo %name%
+set /a name="5|4<<3"
+echo %name%
+set /a name="5|4>>3"
+echo %name%
+set /a name="5|4|3"
+echo %name%
+set /a name="5|4&3"
+echo %name%
+set /a name="5|4^3"
+echo %name%
+set /a name="5|4%%3"
+echo %name%
+set /a name="5&4+3"
+echo %name%
+set /a name="5&4-3"
+echo %name%
+set /a name="5&4*3"
+echo %name%
+set /a name="5&4/3"
+echo %name%
+set /a name="5&4<<3"
+echo %name%
+set /a name="5&4>>3"
+echo %name%
+set /a name="5&4|3"
+echo %name%
+set /a name="5&4&3"
+echo %name%
+set /a name="5&4^3"
+echo %name%
+set /a name="5&4%%3"
+echo %name%
+set /a name="5^4+3"
+echo %name%
+set /a name="5^4-3"
+echo %name%
+set /a name="5^4*3"
+echo %name%
+set /a name="5^4/3"
+echo %name%
+set /a name="5^4<<3"
+echo %name%
+set /a name="5^4>>3"
+echo %name%
+set /a name="5^4|3"
+echo %name%
+set /a name="5^4&3"
+echo %name%
+set /a name="5^4^3"
+echo %name%
+set /a name="5^4%%3"
+echo %name%
+set /a name="5%%4+3"
+echo %name%
+set /a name="5%%4-3"
+echo %name%
+set /a name="5%%4*3"
+echo %name%
+set /a name="5%%4/3"
+echo %name%
+set /a name="5%%4<<3"
+echo %name%
+set /a name="5%%4>>3"
+echo %name%
+set /a name="5%%4|3"
+echo %name%
+set /a name="5%%4&3"
+echo %name%
+set /a name="5%%4^3"
+echo %name%
+set /a name="5%%4%%3"
+echo %name%
diff --git a/programs/cmd/tests/test_set_operations.cmd.exp b/programs/cmd/tests/test_set_operations.cmd.exp
new file mode 100644
index 0000000..38ae86c
--- /dev/null
+++ b/programs/cmd/tests/test_set_operations.cmd.exp
@@ -0,0 +1,200 @@
+12
+2
+23
+3
+224
+0
+7
+5
+2
+7
+4
+-6
+-17
+3
+-32
+-1
+-1
+5
+-6
+-1
+17
+7
+60
+2 at or_broken@0
+384
+0
+13
+4
+9
+2 at or_broken@12
+5
+-5
+0
+0
+0
+0
+5
+0
+5
+0
+1536
+0 at or_broken@-2147483648
+3145728
+3
+1536
+1 at or_broken@3
+53
+0
+53
+48
+0
+0
+0
+3
+0
+0
+5
+0
+5
+0
+11
+-1
+23
+3
+131
+3
+7
+7
+3
+7
+1
+3
+0
+0
+0
+0
+5
+0
+5
+0
+10
+-4
+23
+3
+131
+3
+7
+7
+2
+7
+8
+-2
+15
+0
+96
+0
+7
+1
+6
+3
+12
+6
+17
+6
+72
+1
+11
+1
+10
+6
+4
+-2
+-7
+4
+8
+0
+3
+1
+2
+4
+23
+17
+60
+6 at or_broken@5
+160
+2
+23
+0
+23
+2 at or_broken@5
+4
+-2
+3
+0
+8
+0
+3
+1
+2
+1 at or_broken@5
+640
+10
+20480
+10
+640
+10 at or_broken@5
+83
+0
+83
+10
+0
+2
+0
+2
+0
+0
+3
+0
+3
+2
+7
+5
+13
+5
+37
+5
+7
+5
+7
+5
+5
+1
+4
+1
+0
+0
+7
+0
+7
+1
+2
+4
+9
+4
+37
+5
+3
+5
+2
+4
+4
+-2
+3
+0
+8
+0
+3
+1
+2
+1
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index ce4c2da..778bbdb 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -72,6 +72,7 @@ void WCMD_more (WCHAR *);
 void WCMD_move (void);
 void WCMD_output (const WCHAR *format, ...);
 void WCMD_output_asis (const WCHAR *message);
+void WCMD_output_asis_len(const WCHAR *message, int len, HANDLE device);
 void WCMD_pause (void);
 void WCMD_popd (void);
 void WCMD_print_error (void);
@@ -250,6 +251,11 @@ extern WCHAR version_string[];
 #define WCMD_VERSION          1033
 #define WCMD_MOREPROMPT       1034
 #define WCMD_LINETOOLONG      1035
+#define WCMD_DIVIDEBYZERO     1036
+#define WCMD_MISSINGOPERAND   1037
+#define WCMD_MISSINGOPERATOR  1038
+#define WCMD_UNBALPARENS      1039
+#define WCMD_INVALIDNUMBER    1040
 
 /* msdn specified max for Win XP */
 #define MAXSTRING 8192
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 7b7ce8f..7d26a78 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -105,7 +105,7 @@ BOOL unicodePipes = FALSE;
  *  and hence required WriteConsoleW to output it, however if file i/o is
  *  redirected, it needs to be WriteFile'd using OEM (not ANSI) format
  */
-static void WCMD_output_asis_len(const WCHAR *message, int len, HANDLE device) {
+void WCMD_output_asis_len(const WCHAR *message, int len, HANDLE device) {
 
     DWORD   nOut= 0;
     DWORD   res = 0;
-- 
1.7.4.3




More information about the wine-patches mailing list