[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