blob: 8d7a92a2802f5c871f40a4cb65bafd22667d9abe [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;
Eric Andersencc8ed391999-10-05 16:24:54 +000014
Erik Andersene49d5ec2000-02-08 19:58:47 +000015static void push(double a)
Eric Andersencc8ed391999-10-05 16:24:54 +000016{
Matt Kraai3e856ce2000-12-01 02:55:13 +000017 if (pointer >= (sizeof(stack) / sizeof(*stack)))
Matt Kraaidd19c692001-01-31 19:00:21 +000018 error_msg_and_die("stack overflow");
Matt Kraai3e856ce2000-12-01 02:55:13 +000019 stack[pointer++] = a;
Eric Andersencc8ed391999-10-05 16:24:54 +000020}
21
Erik Andersene49d5ec2000-02-08 19:58:47 +000022static double pop()
Eric Andersencc8ed391999-10-05 16:24:54 +000023{
Matt Kraai3e856ce2000-12-01 02:55:13 +000024 if (pointer == 0)
Matt Kraaidd19c692001-01-31 19:00:21 +000025 error_msg_and_die("stack underflow");
Eric Andersencc8ed391999-10-05 16:24:54 +000026 return stack[--pointer];
27}
28
Erik Andersene49d5ec2000-02-08 19:58:47 +000029static void add()
Eric Andersencc8ed391999-10-05 16:24:54 +000030{
31 push(pop() + pop());
32}
33
Erik Andersene49d5ec2000-02-08 19:58:47 +000034static void sub()
Eric Andersencc8ed391999-10-05 16:24:54 +000035{
Erik Andersene49d5ec2000-02-08 19:58:47 +000036 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000037
38 push(pop() - subtrahend);
39}
40
Erik Andersene49d5ec2000-02-08 19:58:47 +000041static void mul()
Eric Andersencc8ed391999-10-05 16:24:54 +000042{
43 push(pop() * pop());
44}
45
Erik Andersene49d5ec2000-02-08 19:58:47 +000046static void divide()
Eric Andersencc8ed391999-10-05 16:24:54 +000047{
Erik Andersene49d5ec2000-02-08 19:58:47 +000048 double divisor = pop();
49
Eric Andersencc8ed391999-10-05 16:24:54 +000050 push(pop() / divisor);
51}
52
Erik Andersene49d5ec2000-02-08 19:58:47 +000053static void and()
Eric Andersencc8ed391999-10-05 16:24:54 +000054{
Erik Andersene49d5ec2000-02-08 19:58:47 +000055 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000056}
57
Erik Andersene49d5ec2000-02-08 19:58:47 +000058static void or()
Eric Andersencc8ed391999-10-05 16:24:54 +000059{
Erik Andersene49d5ec2000-02-08 19:58:47 +000060 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000061}
62
Erik Andersene49d5ec2000-02-08 19:58:47 +000063static void eor()
Eric Andersencc8ed391999-10-05 16:24:54 +000064{
Erik Andersene49d5ec2000-02-08 19:58:47 +000065 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000066}
67
Erik Andersene49d5ec2000-02-08 19:58:47 +000068static void not()
Eric Andersencc8ed391999-10-05 16:24:54 +000069{
Erik Andersene49d5ec2000-02-08 19:58:47 +000070 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000071}
72
Erik Andersene49d5ec2000-02-08 19:58:47 +000073static void print()
Eric Andersencc8ed391999-10-05 16:24:54 +000074{
75 printf("%g\n", pop());
76}
77
78struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 const char *name;
80 void (*function) ();
Eric Andersencc8ed391999-10-05 16:24:54 +000081};
82
Erik Andersene49d5ec2000-02-08 19:58:47 +000083static const struct op operators[] = {
John Beppuc0352542000-06-21 18:00:46 +000084 {"+", add},
85 {"add", add},
86 {"-", sub},
87 {"sub", sub},
88 {"*", mul},
89 {"mul", mul},
90 {"/", divide},
91 {"div", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +000092 {"and", and},
John Beppuc0352542000-06-21 18:00:46 +000093 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +000094 {"not", not},
95 {"eor", eor},
John Beppuc0352542000-06-21 18:00:46 +000096 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +000097};
98
Erik Andersene49d5ec2000-02-08 19:58:47 +000099static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +0000100{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000101 char *endPointer = 0;
102 double d;
103 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
Erik Andersene49d5ec2000-02-08 19:58:47 +0000105 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000106 print();
107 return;
108 }
109
110 d = strtod(argument, &endPointer);
111
Erik Andersene49d5ec2000-02-08 19:58:47 +0000112 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000113 push(d);
114 return;
115 }
116
Erik Andersene49d5ec2000-02-08 19:58:47 +0000117 while (o->name != 0) {
118 if (strcmp(o->name, argument) == 0) {
119 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000120 return;
121 }
122 o++;
123 }
Matt Kraaidd19c692001-01-31 19:00:21 +0000124 error_msg_and_die("%s: syntax error.", argument);
Eric Andersencc8ed391999-10-05 16:24:54 +0000125}
126
John Beppu5db60a72000-06-12 22:59:12 +0000127/* return pointer to next token in buffer and set *buffer to one char
128 * past the end of the above mentioned token
129 */
130static char *get_token(char **buffer)
131{
132 char *start = NULL;
133 char *current = *buffer;
134
135 while (isspace(*current)) { current++; }
136 if (*current != 0) {
137 start = current;
138 while (!isspace(*current) && current != 0) { current++; }
139 *buffer = current;
140 }
141 return start;
142}
143
144/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
145static int number_of_tokens(char *buffer)
146{
147 int i = 0;
148 char *b = buffer;
149 while (get_token(&b)) { i++; }
150 return i;
151}
152
John Beppu00216792000-06-21 19:06:16 +0000153int dc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000154{
John Beppu5db60a72000-06-12 22:59:12 +0000155 /* take stuff from stdin if no args are given */
156 if (argc <= 1) {
157 int i, len;
158 char *line = NULL;
159 char *cursor = NULL;
160 char *token = NULL;
Mark Whitley1ca41772000-06-28 22:15:26 +0000161 while ((line = get_line_from_file(stdin))) {
John Beppu5db60a72000-06-12 22:59:12 +0000162 cursor = line;
163 len = number_of_tokens(line);
164 for (i = 0; i < len; i++) {
165 token = get_token(&cursor);
166 *cursor++ = 0;
167 stack_machine(token);
168 }
169 free(line);
170 }
171 } else {
172 if (*argv[1]=='-')
Eric Andersen67991cf2001-02-14 21:23:06 +0000173 show_usage();
John Beppu5db60a72000-06-12 22:59:12 +0000174 while (argc >= 2) {
175 stack_machine(argv[1]);
176 argv++;
177 argc--;
178 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000179 }
180 stack_machine(0);
Matt Kraai3e856ce2000-12-01 02:55:13 +0000181 return EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +0000182}