source: MondoRescue/branches/2.2.5/mindi-busybox/miscutils/dc.c@ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 16 years ago

Update to busybox 1.7.2

File size: 3.8 KB
Line 
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
11enum { STACK_SIZE = COMMON_BUFSIZE / sizeof(double) };
12
13#define stack ((double*)&bb_common_bufsiz1)
14static unsigned int pointer;
15static unsigned char base;
16
17static void push(double a)
18{
19 if (pointer >= STACK_SIZE)
20 bb_error_msg_and_die("stack overflow");
21 stack[pointer++] = a;
22}
23
24static double pop(void)
25{
26 if (pointer == 0)
27 bb_error_msg_and_die("stack underflow");
28 return stack[--pointer];
29}
30
31static void add(void)
32{
33 push(pop() + pop());
34}
35
36static void sub(void)
37{
38 double subtrahend = pop();
39
40 push(pop() - subtrahend);
41}
42
43static void mul(void)
44{
45 push(pop() * pop());
46}
47
48static void power(void)
49{
50 double topower = pop();
51
52 push(pow(pop(), topower));
53}
54
55static void divide(void)
56{
57 double divisor = pop();
58
59 push(pop() / divisor);
60}
61
62static void mod(void)
63{
64 unsigned int d = pop();
65
66 push((unsigned int) pop() % d);
67}
68
69static void and(void)
70{
71 push((unsigned int) pop() & (unsigned int) pop());
72}
73
74static void or(void)
75{
76 push((unsigned int) pop() | (unsigned int) pop());
77}
78
79static void eor(void)
80{
81 push((unsigned int) pop() ^ (unsigned int) pop());
82}
83
84static void not(void)
85{
86 push(~(unsigned int) pop());
87}
88
89static void set_output_base(void)
90{
91 base = (unsigned char)pop();
92 if ((base != 10) && (base != 16)) {
93 bb_error_msg("error, base %d is not supported", base);
94 base = 10;
95 }
96}
97
98static void print_base(double print)
99{
100 if (base == 16)
101 printf("%x\n", (unsigned int)print);
102 else
103 printf("%g\n", print);
104}
105
106static void print_stack_no_pop(void)
107{
108 unsigned int i = pointer;
109 while (i)
110 print_base(stack[--i]);
111}
112
113static void print_no_pop(void)
114{
115 print_base(stack[pointer-1]);
116}
117
118struct op {
119 const char name[4];
120 void (*function) (void);
121};
122
123static const struct op operators[] = {
124 {"+", add},
125 {"add", add},
126 {"-", sub},
127 {"sub", sub},
128 {"*", mul},
129 {"mul", mul},
130 {"/", divide},
131 {"div", divide},
132 {"**", power},
133 {"exp", power},
134 {"pow", power},
135 {"%", mod},
136 {"mod", mod},
137 {"and", and},
138 {"or", or},
139 {"not", not},
140 {"eor", eor},
141 {"xor", eor},
142 {"p", print_no_pop},
143 {"f", print_stack_no_pop},
144 {"o", set_output_base},
145 {"", 0}
146};
147
148static void stack_machine(const char *argument)
149{
150 char *endPointer = 0;
151 double d;
152 const struct op *o = operators;
153
154 if (argument == 0)
155 return;
156
157 d = strtod(argument, &endPointer);
158
159 if (endPointer != argument) {
160 push(d);
161 return;
162 }
163
164 while (o->name[0]) {
165 if (strcmp(o->name, argument) == 0) {
166 o->function();
167 return;
168 }
169 o++;
170 }
171 bb_error_msg_and_die("%s: syntax error", argument);
172}
173
174/* return pointer to next token in buffer and set *buffer to one char
175 * past the end of the above mentioned token
176 */
177static char *get_token(char **buffer)
178{
179 char *start = NULL;
180 char *current;
181
182 current = skip_whitespace(*buffer);
183 if (*current != 0) {
184 start = current;
185 current = skip_non_whitespace(current);
186 *buffer = current;
187 }
188 return start;
189}
190
191/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
192static int number_of_tokens(char *buffer)
193{
194 int i = 0;
195 char *b = buffer;
196 while (get_token(&b)) { i++; }
197 return i;
198}
199
200int dc_main(int argc, char **argv);
201int dc_main(int argc, char **argv)
202{
203 /* take stuff from stdin if no args are given */
204 if (argc <= 1) {
205 int i, len;
206 char *line = NULL;
207 char *cursor = NULL;
208 char *token = NULL;
209 while ((line = xmalloc_getline(stdin))) {
210 cursor = line;
211 len = number_of_tokens(line);
212 for (i = 0; i < len; i++) {
213 token = get_token(&cursor);
214 *cursor++ = 0;
215 stack_machine(token);
216 }
217 free(line);
218 }
219 } else {
220 if (*argv[1] == '-')
221 bb_show_usage();
222 while (argc >= 2) {
223 stack_machine(argv[1]);
224 argv++;
225 argc--;
226 }
227 }
228 return EXIT_SUCCESS;
229}
Note: See TracBrowser for help on using the repository browser.