3 |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 |
*/ |
*/ |
5 |
|
|
6 |
#include "busybox.h" |
#include "libbb.h" |
|
#include <ctype.h> |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
7 |
#include <math.h> |
#include <math.h> |
8 |
|
|
9 |
/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ |
/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ |
10 |
|
|
11 |
static double stack[100]; |
|
12 |
static unsigned int pointer; |
struct globals { |
13 |
static unsigned char base; |
unsigned pointer; |
14 |
|
unsigned base; |
15 |
|
double stack[1]; |
16 |
|
}; |
17 |
|
enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) }; |
18 |
|
#define G (*(struct globals*)&bb_common_bufsiz1) |
19 |
|
#define pointer (G.pointer ) |
20 |
|
#define base (G.base ) |
21 |
|
#define stack (G.stack ) |
22 |
|
#define INIT_G() do { \ |
23 |
|
base = 10; \ |
24 |
|
} while (0) |
25 |
|
|
26 |
|
|
27 |
static void push(double a) |
static void push(double a) |
28 |
{ |
{ |
29 |
if (pointer >= (sizeof(stack) / sizeof(*stack))) |
if (pointer >= STACK_SIZE) |
30 |
bb_error_msg_and_die("stack overflow"); |
bb_error_msg_and_die("stack overflow"); |
31 |
stack[pointer++] = a; |
stack[pointer++] = a; |
32 |
} |
} |
55 |
push(pop() * pop()); |
push(pop() * pop()); |
56 |
} |
} |
57 |
|
|
58 |
|
#if ENABLE_FEATURE_DC_LIBM |
59 |
static void power(void) |
static void power(void) |
60 |
{ |
{ |
61 |
double topower = pop(); |
double topower = pop(); |
62 |
|
|
63 |
push(pow(pop(), topower)); |
push(pow(pop(), topower)); |
64 |
} |
} |
65 |
|
#endif |
66 |
|
|
67 |
static void divide(void) |
static void divide(void) |
68 |
{ |
{ |
73 |
|
|
74 |
static void mod(void) |
static void mod(void) |
75 |
{ |
{ |
76 |
unsigned int d = pop(); |
unsigned d = pop(); |
77 |
|
|
78 |
push((unsigned int) pop() % d); |
push((unsigned) pop() % d); |
79 |
} |
} |
80 |
|
|
81 |
static void and(void) |
static void and(void) |
82 |
{ |
{ |
83 |
push((unsigned int) pop() & (unsigned int) pop()); |
push((unsigned) pop() & (unsigned) pop()); |
84 |
} |
} |
85 |
|
|
86 |
static void or(void) |
static void or(void) |
87 |
{ |
{ |
88 |
push((unsigned int) pop() | (unsigned int) pop()); |
push((unsigned) pop() | (unsigned) pop()); |
89 |
} |
} |
90 |
|
|
91 |
static void eor(void) |
static void eor(void) |
92 |
{ |
{ |
93 |
push((unsigned int) pop() ^ (unsigned int) pop()); |
push((unsigned) pop() ^ (unsigned) pop()); |
94 |
} |
} |
95 |
|
|
96 |
static void not(void) |
static void not(void) |
97 |
{ |
{ |
98 |
push(~(unsigned int) pop()); |
push(~(unsigned) pop()); |
99 |
} |
} |
100 |
|
|
101 |
static void set_output_base(void) |
static void set_output_base(void) |
102 |
{ |
{ |
103 |
base=(unsigned char)pop(); |
static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 }; |
104 |
if ((base != 10) && (base != 16)) { |
unsigned b = (unsigned)pop(); |
105 |
fprintf(stderr, "Error: base = %d is not supported.\n", base); |
|
106 |
base=10; |
base = *strchrnul(bases, b); |
107 |
|
if (base == 0) { |
108 |
|
bb_error_msg("error, base %u is not supported", b); |
109 |
|
base = 10; |
110 |
} |
} |
111 |
} |
} |
112 |
|
|
113 |
static void print_base(double print) |
static void print_base(double print) |
114 |
{ |
{ |
115 |
if (base == 16) |
unsigned x, i; |
116 |
printf("%x\n", (unsigned int)print); |
|
117 |
else |
if (base == 10) { |
118 |
printf("%g\n", print); |
printf("%g\n", print); |
119 |
|
return; |
120 |
|
} |
121 |
|
|
122 |
|
x = (unsigned)print; |
123 |
|
switch (base) { |
124 |
|
case 16: |
125 |
|
printf("%x\n", x); |
126 |
|
break; |
127 |
|
case 8: |
128 |
|
printf("%o\n", x); |
129 |
|
break; |
130 |
|
default: /* base 2 */ |
131 |
|
i = (unsigned)INT_MAX + 1; |
132 |
|
do { |
133 |
|
if (x & i) break; |
134 |
|
i >>= 1; |
135 |
|
} while (i > 1); |
136 |
|
do { |
137 |
|
bb_putchar('1' - !(x & i)); |
138 |
|
i >>= 1; |
139 |
|
} while (i); |
140 |
|
bb_putchar('\n'); |
141 |
|
} |
142 |
} |
} |
143 |
|
|
144 |
static void print_stack_no_pop(void) |
static void print_stack_no_pop(void) |
145 |
{ |
{ |
146 |
unsigned int i=pointer; |
unsigned i = pointer; |
147 |
while (i) |
while (i) |
148 |
print_base(stack[--i]); |
print_base(stack[--i]); |
149 |
} |
} |
154 |
} |
} |
155 |
|
|
156 |
struct op { |
struct op { |
157 |
const char *name; |
const char name[4]; |
158 |
void (*function) (void); |
void (*function) (void); |
159 |
}; |
}; |
160 |
|
|
167 |
{"mul", mul}, |
{"mul", mul}, |
168 |
{"/", divide}, |
{"/", divide}, |
169 |
{"div", divide}, |
{"div", divide}, |
170 |
|
#if ENABLE_FEATURE_DC_LIBM |
171 |
{"**", power}, |
{"**", power}, |
172 |
{"exp", power}, |
{"exp", power}, |
173 |
{"pow", power}, |
{"pow", power}, |
174 |
|
#endif |
175 |
{"%", mod}, |
{"%", mod}, |
176 |
{"mod", mod}, |
{"mod", mod}, |
177 |
{"and", and}, |
{"and", and}, |
182 |
{"p", print_no_pop}, |
{"p", print_no_pop}, |
183 |
{"f", print_stack_no_pop}, |
{"f", print_stack_no_pop}, |
184 |
{"o", set_output_base}, |
{"o", set_output_base}, |
185 |
{0, 0} |
{ /* zero filled */ } |
186 |
}; |
}; |
187 |
|
|
188 |
static void stack_machine(const char *argument) |
static void stack_machine(const char *argument) |
189 |
{ |
{ |
190 |
char *endPointer = 0; |
char *endPointer; |
191 |
double d; |
double d; |
192 |
const struct op *o = operators; |
const struct op *o = operators; |
193 |
|
|
201 |
return; |
return; |
202 |
} |
} |
203 |
|
|
204 |
while (o->name != 0) { |
while (o->name[0]) { |
205 |
if (strcmp(o->name, argument) == 0) { |
if (strcmp(o->name, argument) == 0) { |
206 |
(*(o->function)) (); |
o->function(); |
207 |
return; |
return; |
208 |
} |
} |
209 |
o++; |
o++; |
216 |
*/ |
*/ |
217 |
static char *get_token(char **buffer) |
static char *get_token(char **buffer) |
218 |
{ |
{ |
219 |
char *start = NULL; |
char *current = skip_whitespace(*buffer); |
220 |
char *current; |
if (*current != '\0') { |
221 |
|
*buffer = skip_non_whitespace(current); |
222 |
current = skip_whitespace(*buffer); |
return current; |
|
if (*current != 0) { |
|
|
start = current; |
|
|
while (!isspace(*current) && *current != 0) { current++; } |
|
|
*buffer = current; |
|
223 |
} |
} |
224 |
return start; |
return NULL; |
225 |
} |
} |
226 |
|
|
227 |
/* In Perl one might say, scalar m|\s*(\S+)\s*|g */ |
int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
228 |
static int number_of_tokens(char *buffer) |
int dc_main(int argc UNUSED_PARAM, char **argv) |
229 |
{ |
{ |
230 |
int i = 0; |
INIT_G(); |
|
char *b = buffer; |
|
|
while (get_token(&b)) { i++; } |
|
|
return i; |
|
|
} |
|
231 |
|
|
232 |
int dc_main(int argc, char **argv) |
argv++; |
233 |
{ |
if (!argv[0]) { |
234 |
/* take stuff from stdin if no args are given */ |
/* take stuff from stdin if no args are given */ |
235 |
if (argc <= 1) { |
char *line; |
236 |
int i, len; |
char *cursor; |
237 |
char *line = NULL; |
char *token; |
238 |
char *cursor = NULL; |
while ((line = xmalloc_fgetline(stdin)) != NULL) { |
|
char *token = NULL; |
|
|
while ((line = xmalloc_getline(stdin))) { |
|
239 |
cursor = line; |
cursor = line; |
240 |
len = number_of_tokens(line); |
while (1) { |
|
for (i = 0; i < len; i++) { |
|
241 |
token = get_token(&cursor); |
token = get_token(&cursor); |
242 |
*cursor++ = 0; |
if (!token) break; |
243 |
|
*cursor++ = '\0'; |
244 |
stack_machine(token); |
stack_machine(token); |
245 |
} |
} |
246 |
free(line); |
free(line); |
247 |
} |
} |
248 |
} else { |
} else { |
249 |
if (*argv[1]=='-') |
if (argv[0][0] == '-') |
250 |
bb_show_usage(); |
bb_show_usage(); |
251 |
while (argc >= 2) { |
do { |
252 |
stack_machine(argv[1]); |
stack_machine(*argv); |
253 |
argv++; |
} while (*++argv); |
|
argc--; |
|
|
} |
|
254 |
} |
} |
255 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
256 |
} |
} |