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, 13 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.