1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
Fix dc inconsistency, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=538685
From upstream: http://busybox.net/downloads/fixes-1.23.1/busybox-1.23.1-dc.patch
Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
--- busybox-1.23.1/miscutils/dc.c
+++ busybox-1.23.1-dc/miscutils/dc.c
@@ -196,14 +196,6 @@ struct op {
};
static const struct op operators[] = {
- {"+", add},
- {"add", add},
- {"-", sub},
- {"sub", sub},
- {"*", mul},
- {"mul", mul},
- {"/", divide},
- {"div", divide},
#if ENABLE_FEATURE_DC_LIBM
{"**", power},
{"exp", power},
@@ -216,28 +208,47 @@ static const struct op operators[] = {
{"not", not},
{"eor", eor},
{"xor", eor},
+ {"+", add},
+ {"add", add},
+ {"-", sub},
+ {"sub", sub},
+ {"*", mul},
+ {"mul", mul},
+ {"/", divide},
+ {"div", divide},
{"p", print_no_pop},
{"f", print_stack_no_pop},
{"o", set_output_base},
};
+/* Feed the stack machine */
static void stack_machine(const char *argument)
{
char *end;
- double d;
+ double number;
const struct op *o;
- d = strtod(argument, &end);
- if (end != argument && *end == '\0') {
- push(d);
- return;
+ next:
+ number = strtod(argument, &end);
+ if (end != argument) {
+ argument = end;
+ push(number);
+ goto next;
}
+ /* We might have matched a digit, eventually advance the argument */
+ argument = skip_whitespace(argument);
+
+ if (*argument == '\0')
+ return;
+
o = operators;
do {
- if (strcmp(o->name, argument) == 0) {
+ const size_t name_len = strlen(o->name);
+ if (strncmp(o->name, argument, name_len) == 0) {
+ argument += name_len;
o->function();
- return;
+ goto next;
}
o++;
} while (o != operators + ARRAY_SIZE(operators));
@@ -254,25 +265,11 @@ int dc_main(int argc UNUSED_PARAM, char
if (!argv[0]) {
/* take stuff from stdin if no args are given */
char *line;
- char *cursor;
- char *token;
while ((line = xmalloc_fgetline(stdin)) != NULL) {
- cursor = line;
- while (1) {
- token = skip_whitespace(cursor);
- if (*token == '\0')
- break;
- cursor = skip_non_whitespace(token);
- if (*cursor != '\0')
- *cursor++ = '\0';
- stack_machine(token);
- }
+ stack_machine(line);
free(line);
}
} else {
- // why? it breaks "dc -2 2 + p"
- //if (argv[0][0] == '-')
- // bb_show_usage();
do {
stack_machine(*argv);
} while (*++argv);
--- busybox-1.23.1/testsuite/dc.tests
+++ busybox-1.23.1-dc/testsuite/dc.tests
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Copyright 2015 by Bernhard Reutner-Fischer
+# Licensed under GPLv2 or later, see file LICENSE in this source tree.
+
+. ./testing.sh
+
+# testing "test name" "command" "expected result" "file input" "stdin"
+
+testing "dc basic syntax (stdin, multiple args)" \
+ "dc" \
+ "30\n" \
+ "" "10 20+p"
+
+testing "dc basic syntax (argv, single arg)" \
+ "dc '10 20+p'" \
+ "30\n" \
+ "" ""
+
+testing "dc basic syntax (argv, multiple args)" \
+ "dc 10 20+p" \
+ "30\n" \
+ "" ""
+
+testing "dc complex with spaces (single arg)" \
+ "dc '8 8 * 2 2 + / p'" \
+ "16\n" \
+ "" ""
+
+testing "dc complex without spaces (single arg)" \
+ "dc '8 8*2 2+/p'" \
+ "16\n" \
+ "" ""
+
+testing "dc complex with spaces (multiple args)" \
+ "dc 8 8 \* 2 2 + / p" \
+ "16\n" \
+ "" ""
+
+testing "dc complex without spaces (multiple args)" \
+ "dc 8 8\*2 2+/p" \
+ "16\n" \
+ "" ""
+
+exit $FAILCOUNT
+
+# we do not support arguments
+testing "dc -e <exprs>" \
+ "dc -e '10 2+f'" \
+ "12\n" \
+ "" ""
+
+testing "dc -f <exprs-from-given-file>" \
+ "dc -f input" \
+ "12\n" \
+ "10 2+f" ""
+
|