blob: 5e367fe6889a3ebbb0f8b67b632b77226833a6b3 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
John Beppu5db60a72000-06-12 22:59:12 +00002#include <ctype.h>
Eric Andersencc8ed391999-10-05 16:24:54 +00003#include <stdio.h>
4#include <stdlib.h>
Eric Anderseneba8ed72001-03-09 14:36:42 +00005#include <string.h>
Eric Andersencc8ed391999-10-05 16:24:54 +00006#include <unistd.h>
7#include <math.h>
Eric Andersencbe31da2001-02-20 06:14:08 +00008#include "busybox.h"
Eric Andersencc8ed391999-10-05 16:24:54 +00009
10/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
11
Erik Andersene49d5ec2000-02-08 19:58:47 +000012static double stack[100];
13static unsigned int pointer;
Glenn L McGrath6d074322002-12-12 10:31:53 +000014static unsigned char base;
Eric Andersencc8ed391999-10-05 16:24:54 +000015
Erik Andersene49d5ec2000-02-08 19:58:47 +000016static void push(double a)
Eric Andersencc8ed391999-10-05 16:24:54 +000017{
Matt Kraai3e856ce2000-12-01 02:55:13 +000018 if (pointer >= (sizeof(stack) / sizeof(*stack)))
Manuel Novoa III cad53642003-03-19 09:13:01 +000019 bb_error_msg_and_die("stack overflow");
Matt Kraai3e856ce2000-12-01 02:55:13 +000020 stack[pointer++] = a;
Eric Andersencc8ed391999-10-05 16:24:54 +000021}
22
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000023static double pop(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000024{
Matt Kraai3e856ce2000-12-01 02:55:13 +000025 if (pointer == 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +000026 bb_error_msg_and_die("stack underflow");
Eric Andersencc8ed391999-10-05 16:24:54 +000027 return stack[--pointer];
28}
29
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000030static void add(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000031{
32 push(pop() + pop());
33}
34
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000035static void sub(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000036{
Erik Andersene49d5ec2000-02-08 19:58:47 +000037 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000038
39 push(pop() - subtrahend);
40}
41
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000042static void mul(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000043{
44 push(pop() * pop());
45}
46
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000047static void divide(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000048{
Erik Andersene49d5ec2000-02-08 19:58:47 +000049 double divisor = pop();
50
Eric Andersencc8ed391999-10-05 16:24:54 +000051 push(pop() / divisor);
52}
53
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000054static void and(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000055{
Erik Andersene49d5ec2000-02-08 19:58:47 +000056 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000057}
58
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000059static void or(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000060{
Erik Andersene49d5ec2000-02-08 19:58:47 +000061 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000062}
63
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000064static void eor(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000065{
Erik Andersene49d5ec2000-02-08 19:58:47 +000066 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000067}
68
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +000069static void not(void)
Eric Andersencc8ed391999-10-05 16:24:54 +000070{
Erik Andersene49d5ec2000-02-08 19:58:47 +000071 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000072}
73
Glenn L McGrath6d074322002-12-12 10:31:53 +000074static void set_output_base(void)
75{
76 base=(unsigned char)pop();
77 if ((base != 10) && (base != 16)) {
78 fprintf(stderr, "Error: base = %d is not supported.\n", base);
79 base=10;
80 }
81}
82
83static void print_base(double print)
84{
85 if (base == 16)
86 printf("%x\n", (unsigned int)print);
87 else
88 printf("%g\n", print);
89}
90
91static void print_stack_no_pop(void)
92{
93 unsigned int i=pointer;
94 while (i)
95 print_base(stack[--i]);
96}
97
98static void print_no_pop(void)
99{
100 print_base(stack[pointer-1]);
101}
102
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +0000103static void print(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000104{
Glenn L McGrath6d074322002-12-12 10:31:53 +0000105 print_base(pop());
Eric Andersencc8ed391999-10-05 16:24:54 +0000106}
107
108struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000109 const char *name;
Aaron Lehmann2dd2d7a2001-12-06 03:29:37 +0000110 void (*function) (void);
Eric Andersencc8ed391999-10-05 16:24:54 +0000111};
112
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113static const struct op operators[] = {
John Beppuc0352542000-06-21 18:00:46 +0000114 {"+", add},
115 {"add", add},
116 {"-", sub},
117 {"sub", sub},
118 {"*", mul},
119 {"mul", mul},
120 {"/", divide},
121 {"div", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122 {"and", and},
John Beppuc0352542000-06-21 18:00:46 +0000123 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +0000124 {"not", not},
125 {"eor", eor},
Glenn L McGrath6d074322002-12-12 10:31:53 +0000126 {"p", print_no_pop},
127 {"f", print_stack_no_pop},
128 {"o", set_output_base},
John Beppuc0352542000-06-21 18:00:46 +0000129 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +0000130};
131
Erik Andersene49d5ec2000-02-08 19:58:47 +0000132static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +0000133{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134 char *endPointer = 0;
135 double d;
136 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000137
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000139 print();
140 return;
141 }
142
143 d = strtod(argument, &endPointer);
144
Erik Andersene49d5ec2000-02-08 19:58:47 +0000145 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000146 push(d);
147 return;
148 }
149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150 while (o->name != 0) {
151 if (strcmp(o->name, argument) == 0) {
152 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000153 return;
154 }
155 o++;
156 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000157 bb_error_msg_and_die("%s: syntax error.", argument);
Eric Andersencc8ed391999-10-05 16:24:54 +0000158}
159
John Beppu5db60a72000-06-12 22:59:12 +0000160/* return pointer to next token in buffer and set *buffer to one char
161 * past the end of the above mentioned token
162 */
163static char *get_token(char **buffer)
164{
165 char *start = NULL;
166 char *current = *buffer;
167
168 while (isspace(*current)) { current++; }
169 if (*current != 0) {
170 start = current;
171 while (!isspace(*current) && current != 0) { current++; }
172 *buffer = current;
173 }
174 return start;
175}
176
177/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
178static int number_of_tokens(char *buffer)
179{
180 int i = 0;
181 char *b = buffer;
182 while (get_token(&b)) { i++; }
183 return i;
184}
185
John Beppu00216792000-06-21 19:06:16 +0000186int dc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000187{
John Beppu5db60a72000-06-12 22:59:12 +0000188 /* take stuff from stdin if no args are given */
189 if (argc <= 1) {
190 int i, len;
191 char *line = NULL;
192 char *cursor = NULL;
193 char *token = NULL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000194 while ((line = bb_get_chomped_line_from_file(stdin))) {
John Beppu5db60a72000-06-12 22:59:12 +0000195 cursor = line;
196 len = number_of_tokens(line);
197 for (i = 0; i < len; i++) {
198 token = get_token(&cursor);
199 *cursor++ = 0;
200 stack_machine(token);
201 }
202 free(line);
203 }
204 } else {
205 if (*argv[1]=='-')
Manuel Novoa III cad53642003-03-19 09:13:01 +0000206 bb_show_usage();
John Beppu5db60a72000-06-12 22:59:12 +0000207 while (argc >= 2) {
208 stack_machine(argv[1]);
209 argv++;
210 argc--;
211 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000212 }
213 stack_machine(0);
Matt Kraai3e856ce2000-12-01 02:55:13 +0000214 return EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +0000215}