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

Last change on this file since 3621 was 3621, checked in by Bruno Cornec, 7 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.