Contents of /tags/mkinitrd-6_3_0/busybox/miscutils/dc.c
Parent Directory | Revision Log
Revision 1139 -
(show annotations)
(download)
Thu Aug 19 10:14:02 2010 UTC (14 years, 1 month ago) by niro
File MIME type: text/plain
File size: 4267 byte(s)
Thu Aug 19 10:14:02 2010 UTC (14 years, 1 month ago) by niro
File MIME type: text/plain
File size: 4267 byte(s)
tagged 'mkinitrd-6_3_0'
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 | */ |
5 | |
6 | #include "libbb.h" |
7 | #include <math.h> |
8 | |
9 | /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ |
10 | |
11 | |
12 | struct globals { |
13 | unsigned pointer; |
14 | unsigned base; |
15 | double stack[1]; |
16 | } FIX_ALIASING; |
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) |
28 | { |
29 | if (pointer >= STACK_SIZE) |
30 | bb_error_msg_and_die("stack overflow"); |
31 | stack[pointer++] = a; |
32 | } |
33 | |
34 | static double pop(void) |
35 | { |
36 | if (pointer == 0) |
37 | bb_error_msg_and_die("stack underflow"); |
38 | return stack[--pointer]; |
39 | } |
40 | |
41 | static void add(void) |
42 | { |
43 | push(pop() + pop()); |
44 | } |
45 | |
46 | static void sub(void) |
47 | { |
48 | double subtrahend = pop(); |
49 | |
50 | push(pop() - subtrahend); |
51 | } |
52 | |
53 | static void mul(void) |
54 | { |
55 | push(pop() * pop()); |
56 | } |
57 | |
58 | #if ENABLE_FEATURE_DC_LIBM |
59 | static void power(void) |
60 | { |
61 | double topower = pop(); |
62 | |
63 | push(pow(pop(), topower)); |
64 | } |
65 | #endif |
66 | |
67 | static void divide(void) |
68 | { |
69 | double divisor = pop(); |
70 | |
71 | push(pop() / divisor); |
72 | } |
73 | |
74 | static void mod(void) |
75 | { |
76 | unsigned d = pop(); |
77 | |
78 | push((unsigned) pop() % d); |
79 | } |
80 | |
81 | static void and(void) |
82 | { |
83 | push((unsigned) pop() & (unsigned) pop()); |
84 | } |
85 | |
86 | static void or(void) |
87 | { |
88 | push((unsigned) pop() | (unsigned) pop()); |
89 | } |
90 | |
91 | static void eor(void) |
92 | { |
93 | push((unsigned) pop() ^ (unsigned) pop()); |
94 | } |
95 | |
96 | static void not(void) |
97 | { |
98 | push(~(unsigned) pop()); |
99 | } |
100 | |
101 | static void set_output_base(void) |
102 | { |
103 | static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 }; |
104 | unsigned b = (unsigned)pop(); |
105 | |
106 | 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) |
114 | { |
115 | unsigned x, i; |
116 | |
117 | if (base == 10) { |
118 | 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) |
145 | { |
146 | unsigned i = pointer; |
147 | while (i) |
148 | print_base(stack[--i]); |
149 | } |
150 | |
151 | static void print_no_pop(void) |
152 | { |
153 | print_base(stack[pointer-1]); |
154 | } |
155 | |
156 | struct op { |
157 | const char name[4]; |
158 | void (*function) (void); |
159 | }; |
160 | |
161 | static const struct op operators[] = { |
162 | {"+", add}, |
163 | {"add", add}, |
164 | {"-", sub}, |
165 | {"sub", sub}, |
166 | {"*", mul}, |
167 | {"mul", mul}, |
168 | {"/", divide}, |
169 | {"div", divide}, |
170 | #if ENABLE_FEATURE_DC_LIBM |
171 | {"**", power}, |
172 | {"exp", power}, |
173 | {"pow", power}, |
174 | #endif |
175 | {"%", mod}, |
176 | {"mod", mod}, |
177 | {"and", and}, |
178 | {"or", or}, |
179 | {"not", not}, |
180 | {"eor", eor}, |
181 | {"xor", eor}, |
182 | {"p", print_no_pop}, |
183 | {"f", print_stack_no_pop}, |
184 | {"o", set_output_base}, |
185 | { "", NULL } |
186 | }; |
187 | |
188 | static void stack_machine(const char *argument) |
189 | { |
190 | char *endPointer; |
191 | double d; |
192 | const struct op *o = operators; |
193 | |
194 | d = strtod(argument, &endPointer); |
195 | |
196 | if (endPointer != argument && *endPointer == '\0') { |
197 | push(d); |
198 | return; |
199 | } |
200 | |
201 | while (o->function) { |
202 | if (strcmp(o->name, argument) == 0) { |
203 | o->function(); |
204 | return; |
205 | } |
206 | o++; |
207 | } |
208 | bb_error_msg_and_die("syntax error at '%s'", argument); |
209 | } |
210 | |
211 | /* return pointer to next token in buffer and set *buffer to one char |
212 | * past the end of the above mentioned token |
213 | */ |
214 | static char *get_token(char **buffer) |
215 | { |
216 | char *current = skip_whitespace(*buffer); |
217 | if (*current != '\0') { |
218 | *buffer = skip_non_whitespace(current); |
219 | return current; |
220 | } |
221 | return NULL; |
222 | } |
223 | |
224 | int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
225 | int dc_main(int argc UNUSED_PARAM, char **argv) |
226 | { |
227 | INIT_G(); |
228 | |
229 | argv++; |
230 | if (!argv[0]) { |
231 | /* take stuff from stdin if no args are given */ |
232 | char *line; |
233 | char *cursor; |
234 | char *token; |
235 | while ((line = xmalloc_fgetline(stdin)) != NULL) { |
236 | cursor = line; |
237 | while (1) { |
238 | token = get_token(&cursor); |
239 | if (!token) |
240 | break; |
241 | *cursor++ = '\0'; |
242 | stack_machine(token); |
243 | } |
244 | free(line); |
245 | } |
246 | } else { |
247 | // why? it breaks "dc -2 2 * p" |
248 | //if (argv[0][0] == '-') |
249 | // bb_show_usage(); |
250 | do { |
251 | stack_machine(*argv); |
252 | } while (*++argv); |
253 | } |
254 | return EXIT_SUCCESS; |
255 | } |