blob: 122673a95a59d389edaf30d1438f7a020ff2d08f [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen3570a342000-09-25 21:45:58 +00002#include "busybox.h"
John Beppu5db60a72000-06-12 22:59:12 +00003#include <ctype.h>
Eric Andersencc8ed391999-10-05 16:24:54 +00004#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <math.h>
8
9/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
10
Erik Andersene49d5ec2000-02-08 19:58:47 +000011static double stack[100];
12static unsigned int pointer;
Eric Andersencc8ed391999-10-05 16:24:54 +000013
Erik Andersene49d5ec2000-02-08 19:58:47 +000014static void push(double a)
Eric Andersencc8ed391999-10-05 16:24:54 +000015{
Matt Kraai3e856ce2000-12-01 02:55:13 +000016 if (pointer >= (sizeof(stack) / sizeof(*stack)))
Matt Kraaidd19c692001-01-31 19:00:21 +000017 error_msg_and_die("stack overflow");
Matt Kraai3e856ce2000-12-01 02:55:13 +000018 stack[pointer++] = a;
Eric Andersencc8ed391999-10-05 16:24:54 +000019}
20
Erik Andersene49d5ec2000-02-08 19:58:47 +000021static double pop()
Eric Andersencc8ed391999-10-05 16:24:54 +000022{
Matt Kraai3e856ce2000-12-01 02:55:13 +000023 if (pointer == 0)
Matt Kraaidd19c692001-01-31 19:00:21 +000024 error_msg_and_die("stack underflow");
Eric Andersencc8ed391999-10-05 16:24:54 +000025 return stack[--pointer];
26}
27
Erik Andersene49d5ec2000-02-08 19:58:47 +000028static void add()
Eric Andersencc8ed391999-10-05 16:24:54 +000029{
30 push(pop() + pop());
31}
32
Erik Andersene49d5ec2000-02-08 19:58:47 +000033static void sub()
Eric Andersencc8ed391999-10-05 16:24:54 +000034{
Erik Andersene49d5ec2000-02-08 19:58:47 +000035 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000036
37 push(pop() - subtrahend);
38}
39
Erik Andersene49d5ec2000-02-08 19:58:47 +000040static void mul()
Eric Andersencc8ed391999-10-05 16:24:54 +000041{
42 push(pop() * pop());
43}
44
Erik Andersene49d5ec2000-02-08 19:58:47 +000045static void divide()
Eric Andersencc8ed391999-10-05 16:24:54 +000046{
Erik Andersene49d5ec2000-02-08 19:58:47 +000047 double divisor = pop();
48
Eric Andersencc8ed391999-10-05 16:24:54 +000049 push(pop() / divisor);
50}
51
Erik Andersene49d5ec2000-02-08 19:58:47 +000052static void and()
Eric Andersencc8ed391999-10-05 16:24:54 +000053{
Erik Andersene49d5ec2000-02-08 19:58:47 +000054 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000055}
56
Erik Andersene49d5ec2000-02-08 19:58:47 +000057static void or()
Eric Andersencc8ed391999-10-05 16:24:54 +000058{
Erik Andersene49d5ec2000-02-08 19:58:47 +000059 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000060}
61
Erik Andersene49d5ec2000-02-08 19:58:47 +000062static void eor()
Eric Andersencc8ed391999-10-05 16:24:54 +000063{
Erik Andersene49d5ec2000-02-08 19:58:47 +000064 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000065}
66
Erik Andersene49d5ec2000-02-08 19:58:47 +000067static void not()
Eric Andersencc8ed391999-10-05 16:24:54 +000068{
Erik Andersene49d5ec2000-02-08 19:58:47 +000069 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000070}
71
Erik Andersene49d5ec2000-02-08 19:58:47 +000072static void print()
Eric Andersencc8ed391999-10-05 16:24:54 +000073{
74 printf("%g\n", pop());
75}
76
77struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +000078 const char *name;
79 void (*function) ();
Eric Andersencc8ed391999-10-05 16:24:54 +000080};
81
Erik Andersene49d5ec2000-02-08 19:58:47 +000082static const struct op operators[] = {
John Beppuc0352542000-06-21 18:00:46 +000083 {"+", add},
84 {"add", add},
85 {"-", sub},
86 {"sub", sub},
87 {"*", mul},
88 {"mul", mul},
89 {"/", divide},
90 {"div", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +000091 {"and", and},
John Beppuc0352542000-06-21 18:00:46 +000092 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +000093 {"not", not},
94 {"eor", eor},
John Beppuc0352542000-06-21 18:00:46 +000095 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +000096};
97
Erik Andersene49d5ec2000-02-08 19:58:47 +000098static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +000099{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000100 char *endPointer = 0;
101 double d;
102 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000103
Erik Andersene49d5ec2000-02-08 19:58:47 +0000104 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000105 print();
106 return;
107 }
108
109 d = strtod(argument, &endPointer);
110
Erik Andersene49d5ec2000-02-08 19:58:47 +0000111 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000112 push(d);
113 return;
114 }
115
Erik Andersene49d5ec2000-02-08 19:58:47 +0000116 while (o->name != 0) {
117 if (strcmp(o->name, argument) == 0) {
118 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000119 return;
120 }
121 o++;
122 }
Matt Kraaidd19c692001-01-31 19:00:21 +0000123 error_msg_and_die("%s: syntax error.", argument);
Eric Andersencc8ed391999-10-05 16:24:54 +0000124}
125
John Beppu5db60a72000-06-12 22:59:12 +0000126/* return pointer to next token in buffer and set *buffer to one char
127 * past the end of the above mentioned token
128 */
129static char *get_token(char **buffer)
130{
131 char *start = NULL;
132 char *current = *buffer;
133
134 while (isspace(*current)) { current++; }
135 if (*current != 0) {
136 start = current;
137 while (!isspace(*current) && current != 0) { current++; }
138 *buffer = current;
139 }
140 return start;
141}
142
143/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
144static int number_of_tokens(char *buffer)
145{
146 int i = 0;
147 char *b = buffer;
148 while (get_token(&b)) { i++; }
149 return i;
150}
151
John Beppu00216792000-06-21 19:06:16 +0000152int dc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000153{
John Beppu5db60a72000-06-12 22:59:12 +0000154 /* take stuff from stdin if no args are given */
155 if (argc <= 1) {
156 int i, len;
157 char *line = NULL;
158 char *cursor = NULL;
159 char *token = NULL;
Mark Whitley1ca41772000-06-28 22:15:26 +0000160 while ((line = get_line_from_file(stdin))) {
John Beppu5db60a72000-06-12 22:59:12 +0000161 cursor = line;
162 len = number_of_tokens(line);
163 for (i = 0; i < len; i++) {
164 token = get_token(&cursor);
165 *cursor++ = 0;
166 stack_machine(token);
167 }
168 free(line);
169 }
170 } else {
171 if (*argv[1]=='-')
John Beppu00216792000-06-21 19:06:16 +0000172 usage(dc_usage);
John Beppu5db60a72000-06-12 22:59:12 +0000173 while (argc >= 2) {
174 stack_machine(argv[1]);
175 argv++;
176 argc--;
177 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000178 }
179 stack_machine(0);
Matt Kraai3e856ce2000-12-01 02:55:13 +0000180 return EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +0000181}