stty: fix option parsing bug (spotted by Sascha Hauer <s.hauer@pengutronix.de>)
[oweals/busybox.git] / miscutils / dc.c
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 "busybox.h"
7 #include <math.h>
8
9 /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
10
11 enum { STACK_SIZE = sizeof(bb_common_bufsiz1) / sizeof(double) };
12
13 #define stack ((double*)&bb_common_bufsiz1)
14 static unsigned int pointer;
15 static unsigned char base;
16
17 static void push(double a)
18 {
19         if (pointer >= STACK_SIZE)
20                 bb_error_msg_and_die("stack overflow");
21         stack[pointer++] = a;
22 }
23
24 static double pop(void)
25 {
26         if (pointer == 0)
27                 bb_error_msg_and_die("stack underflow");
28         return stack[--pointer];
29 }
30
31 static void add(void)
32 {
33         push(pop() + pop());
34 }
35
36 static void sub(void)
37 {
38         double subtrahend = pop();
39
40         push(pop() - subtrahend);
41 }
42
43 static void mul(void)
44 {
45         push(pop() * pop());
46 }
47
48 static void power(void)
49 {
50         double topower = pop();
51
52         push(pow(pop(), topower));
53 }
54
55 static void divide(void)
56 {
57         double divisor = pop();
58
59         push(pop() / divisor);
60 }
61
62 static void mod(void)
63 {
64         unsigned int d = pop();
65
66         push((unsigned int) pop() % d);
67 }
68
69 static void and(void)
70 {
71         push((unsigned int) pop() & (unsigned int) pop());
72 }
73
74 static void or(void)
75 {
76         push((unsigned int) pop() | (unsigned int) pop());
77 }
78
79 static void eor(void)
80 {
81         push((unsigned int) pop() ^ (unsigned int) pop());
82 }
83
84 static void not(void)
85 {
86         push(~(unsigned int) pop());
87 }
88
89 static 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
98 static 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
106 static void print_stack_no_pop(void)
107 {
108         unsigned int i = pointer;
109         while (i)
110                 print_base(stack[--i]);
111 }
112
113 static void print_no_pop(void)
114 {
115         print_base(stack[pointer-1]);
116 }
117
118 struct op {
119         const char name[4];
120         void (*function) (void);
121 };
122
123 static 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
148 static 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  */
177 static 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 */
192 static 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
200 int dc_main(int argc, char **argv);
201 int 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 }