source: MondoRescue/branches/3.3/mindi-busybox/miscutils/dc.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 5.1 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6#include "libbb.h"
7#include "common_bufsiz.h"
8#include <math.h>
9
10//usage:#define dc_trivial_usage
11//usage: "EXPRESSION..."
12//usage:
13//usage:#define dc_full_usage "\n\n"
14//usage: "Tiny RPN calculator. Operations:\n"
15//usage: "+, add, -, sub, *, mul, /, div, %, mod, "IF_FEATURE_DC_LIBM("**, exp, ")"and, or, not, xor,\n"
16//usage: "p - print top of the stack (without popping),\n"
17//usage: "f - print entire stack,\n"
18//usage: "o - pop the value and set output radix (must be 10, 16, 8 or 2).\n"
19//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
20//usage:
21//usage:#define dc_example_usage
22//usage: "$ dc 2 2 + p\n"
23//usage: "4\n"
24//usage: "$ dc 8 8 \\* 2 2 + / p\n"
25//usage: "16\n"
26//usage: "$ dc 0 1 and p\n"
27//usage: "0\n"
28//usage: "$ dc 0 1 or p\n"
29//usage: "1\n"
30//usage: "$ echo 72 9 div 8 mul p | dc\n"
31//usage: "64\n"
32
33#if 0
34typedef unsigned data_t;
35#define DATA_FMT ""
36#elif 0
37typedef unsigned long data_t;
38#define DATA_FMT "l"
39#else
40typedef unsigned long long data_t;
41#define DATA_FMT "ll"
42#endif
43
44
45struct globals {
46 unsigned pointer;
47 unsigned base;
48 double stack[1];
49} FIX_ALIASING;
50enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) };
51#define G (*(struct globals*)bb_common_bufsiz1)
52#define pointer (G.pointer )
53#define base (G.base )
54#define stack (G.stack )
55#define INIT_G() do { \
56 setup_common_bufsiz(); \
57 base = 10; \
58} while (0)
59
60
61static void check_under(void)
62{
63 if (pointer == 0)
64 bb_error_msg_and_die("stack underflow");
65}
66
67static void push(double a)
68{
69 if (pointer >= STACK_SIZE)
70 bb_error_msg_and_die("stack overflow");
71 stack[pointer++] = a;
72}
73
74static double pop(void)
75{
76 check_under();
77 return stack[--pointer];
78}
79
80static void add(void)
81{
82 push(pop() + pop());
83}
84
85static void sub(void)
86{
87 double subtrahend = pop();
88
89 push(pop() - subtrahend);
90}
91
92static void mul(void)
93{
94 push(pop() * pop());
95}
96
97#if ENABLE_FEATURE_DC_LIBM
98static void power(void)
99{
100 double topower = pop();
101
102 push(pow(pop(), topower));
103}
104#endif
105
106static void divide(void)
107{
108 double divisor = pop();
109
110 push(pop() / divisor);
111}
112
113static void mod(void)
114{
115 data_t d = pop();
116
117 push((data_t) pop() % d);
118}
119
120static void and(void)
121{
122 push((data_t) pop() & (data_t) pop());
123}
124
125static void or(void)
126{
127 push((data_t) pop() | (data_t) pop());
128}
129
130static void eor(void)
131{
132 push((data_t) pop() ^ (data_t) pop());
133}
134
135static void not(void)
136{
137 push(~(data_t) pop());
138}
139
140static void set_output_base(void)
141{
142 static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 };
143 unsigned b = (unsigned)pop();
144
145 base = *strchrnul(bases, b);
146 if (base == 0) {
147 bb_error_msg("error, base %u is not supported", b);
148 base = 10;
149 }
150}
151
152static void print_base(double print)
153{
154 data_t x, i;
155
156 x = (data_t) print;
157 if (base == 10) {
158 if (x == print) /* exactly representable as unsigned integer */
159 printf("%"DATA_FMT"u\n", x);
160 else
161 printf("%g\n", print);
162 return;
163 }
164
165 switch (base) {
166 case 16:
167 printf("%"DATA_FMT"x\n", x);
168 break;
169 case 8:
170 printf("%"DATA_FMT"o\n", x);
171 break;
172 default: /* base 2 */
173 i = MAXINT(data_t) - (MAXINT(data_t) >> 1);
174 /* i is 100000...00000 */
175 do {
176 if (x & i)
177 break;
178 i >>= 1;
179 } while (i > 1);
180 do {
181 bb_putchar('1' - !(x & i));
182 i >>= 1;
183 } while (i);
184 bb_putchar('\n');
185 }
186}
187
188static void print_stack_no_pop(void)
189{
190 unsigned i = pointer;
191 while (i)
192 print_base(stack[--i]);
193}
194
195static void print_no_pop(void)
196{
197 check_under();
198 print_base(stack[pointer-1]);
199}
200
201struct op {
202 const char name[4];
203 void (*function) (void);
204};
205
206static const struct op operators[] = {
207#if ENABLE_FEATURE_DC_LIBM
208 {"**", power},
209 {"exp", power},
210 {"pow", power},
211#endif
212 {"%", mod},
213 {"mod", mod},
214 {"and", and},
215 {"or", or},
216 {"not", not},
217 {"eor", eor},
218 {"xor", eor},
219 {"+", add},
220 {"add", add},
221 {"-", sub},
222 {"sub", sub},
223 {"*", mul},
224 {"mul", mul},
225 {"/", divide},
226 {"div", divide},
227 {"p", print_no_pop},
228 {"f", print_stack_no_pop},
229 {"o", set_output_base},
230};
231
232/* Feed the stack machine */
233static void stack_machine(const char *argument)
234{
235 char *end;
236 double number;
237 const struct op *o;
238
239 next:
240 number = strtod(argument, &end);
241 if (end != argument) {
242 argument = end;
243 push(number);
244 goto next;
245 }
246
247 /* We might have matched a digit, eventually advance the argument */
248 argument = skip_whitespace(argument);
249
250 if (*argument == '\0')
251 return;
252
253 o = operators;
254 do {
255 char *after_name = is_prefixed_with(argument, o->name);
256 if (after_name) {
257 argument = after_name;
258 o->function();
259 goto next;
260 }
261 o++;
262 } while (o != operators + ARRAY_SIZE(operators));
263
264 bb_error_msg_and_die("syntax error at '%s'", argument);
265}
266
267int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
268int dc_main(int argc UNUSED_PARAM, char **argv)
269{
270 INIT_G();
271
272 argv++;
273 if (!argv[0]) {
274 /* take stuff from stdin if no args are given */
275 char *line;
276 while ((line = xmalloc_fgetline(stdin)) != NULL) {
277 stack_machine(line);
278 free(line);
279 }
280 } else {
281 do {
282 stack_machine(*argv);
283 } while (*++argv);
284 }
285 return EXIT_SUCCESS;
286}
Note: See TracBrowser for help on using the repository browser.