blob: 48aa830d6117ffb676c00be3910ae79f05afd5ca [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{
Erik Andersene49d5ec2000-02-08 19:58:47 +000016 if (pointer >= (sizeof(stack) / sizeof(*stack))) {
Matt Kraaid537a952000-07-14 01:51:25 +000017 errorMsg("stack overflow\n");
Eric Andersencc8ed391999-10-05 16:24:54 +000018 exit(-1);
Erik Andersene49d5ec2000-02-08 19:58:47 +000019 } else
Eric Andersencc8ed391999-10-05 16:24:54 +000020 stack[pointer++] = a;
21}
22
Erik Andersene49d5ec2000-02-08 19:58:47 +000023static double pop()
Eric Andersencc8ed391999-10-05 16:24:54 +000024{
Erik Andersene49d5ec2000-02-08 19:58:47 +000025 if (pointer == 0) {
Matt Kraaid537a952000-07-14 01:51:25 +000026 errorMsg("stack underflow\n");
Eric Andersencc8ed391999-10-05 16:24:54 +000027 exit(-1);
28 }
29 return stack[--pointer];
30}
31
Erik Andersene49d5ec2000-02-08 19:58:47 +000032static void add()
Eric Andersencc8ed391999-10-05 16:24:54 +000033{
34 push(pop() + pop());
35}
36
Erik Andersene49d5ec2000-02-08 19:58:47 +000037static void sub()
Eric Andersencc8ed391999-10-05 16:24:54 +000038{
Erik Andersene49d5ec2000-02-08 19:58:47 +000039 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000040
41 push(pop() - subtrahend);
42}
43
Erik Andersene49d5ec2000-02-08 19:58:47 +000044static void mul()
Eric Andersencc8ed391999-10-05 16:24:54 +000045{
46 push(pop() * pop());
47}
48
Erik Andersene49d5ec2000-02-08 19:58:47 +000049static void divide()
Eric Andersencc8ed391999-10-05 16:24:54 +000050{
Erik Andersene49d5ec2000-02-08 19:58:47 +000051 double divisor = pop();
52
Eric Andersencc8ed391999-10-05 16:24:54 +000053 push(pop() / divisor);
54}
55
Erik Andersene49d5ec2000-02-08 19:58:47 +000056static void and()
Eric Andersencc8ed391999-10-05 16:24:54 +000057{
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000059}
60
Erik Andersene49d5ec2000-02-08 19:58:47 +000061static void or()
Eric Andersencc8ed391999-10-05 16:24:54 +000062{
Erik Andersene49d5ec2000-02-08 19:58:47 +000063 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000064}
65
Erik Andersene49d5ec2000-02-08 19:58:47 +000066static void eor()
Eric Andersencc8ed391999-10-05 16:24:54 +000067{
Erik Andersene49d5ec2000-02-08 19:58:47 +000068 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000069}
70
Erik Andersene49d5ec2000-02-08 19:58:47 +000071static void not()
Eric Andersencc8ed391999-10-05 16:24:54 +000072{
Erik Andersene49d5ec2000-02-08 19:58:47 +000073 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000074}
75
Erik Andersene49d5ec2000-02-08 19:58:47 +000076static void print()
Eric Andersencc8ed391999-10-05 16:24:54 +000077{
78 printf("%g\n", pop());
79}
80
81struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +000082 const char *name;
83 void (*function) ();
Eric Andersencc8ed391999-10-05 16:24:54 +000084};
85
Erik Andersene49d5ec2000-02-08 19:58:47 +000086static const struct op operators[] = {
John Beppuc0352542000-06-21 18:00:46 +000087 {"+", add},
88 {"add", add},
89 {"-", sub},
90 {"sub", sub},
91 {"*", mul},
92 {"mul", mul},
93 {"/", divide},
94 {"div", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +000095 {"and", and},
John Beppuc0352542000-06-21 18:00:46 +000096 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +000097 {"not", not},
98 {"eor", eor},
John Beppuc0352542000-06-21 18:00:46 +000099 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +0000100};
101
Erik Andersene49d5ec2000-02-08 19:58:47 +0000102static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +0000103{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000104 char *endPointer = 0;
105 double d;
106 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000107
Erik Andersene49d5ec2000-02-08 19:58:47 +0000108 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000109 print();
110 return;
111 }
112
113 d = strtod(argument, &endPointer);
114
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000116 push(d);
117 return;
118 }
119
Erik Andersene49d5ec2000-02-08 19:58:47 +0000120 while (o->name != 0) {
121 if (strcmp(o->name, argument) == 0) {
122 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000123 return;
124 }
125 o++;
126 }
Matt Kraaid537a952000-07-14 01:51:25 +0000127 errorMsg("%s: syntax error.\n", argument);
Eric Andersencc8ed391999-10-05 16:24:54 +0000128 exit(-1);
129}
130
John Beppu5db60a72000-06-12 22:59:12 +0000131/* return pointer to next token in buffer and set *buffer to one char
132 * past the end of the above mentioned token
133 */
134static char *get_token(char **buffer)
135{
136 char *start = NULL;
137 char *current = *buffer;
138
139 while (isspace(*current)) { current++; }
140 if (*current != 0) {
141 start = current;
142 while (!isspace(*current) && current != 0) { current++; }
143 *buffer = current;
144 }
145 return start;
146}
147
148/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
149static int number_of_tokens(char *buffer)
150{
151 int i = 0;
152 char *b = buffer;
153 while (get_token(&b)) { i++; }
154 return i;
155}
156
John Beppu00216792000-06-21 19:06:16 +0000157int dc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000158{
John Beppu5db60a72000-06-12 22:59:12 +0000159 /* take stuff from stdin if no args are given */
160 if (argc <= 1) {
161 int i, len;
162 char *line = NULL;
163 char *cursor = NULL;
164 char *token = NULL;
Mark Whitley1ca41772000-06-28 22:15:26 +0000165 while ((line = get_line_from_file(stdin))) {
John Beppu5db60a72000-06-12 22:59:12 +0000166 cursor = line;
167 len = number_of_tokens(line);
168 for (i = 0; i < len; i++) {
169 token = get_token(&cursor);
170 *cursor++ = 0;
171 stack_machine(token);
172 }
173 free(line);
174 }
175 } else {
176 if (*argv[1]=='-')
John Beppu00216792000-06-21 19:06:16 +0000177 usage(dc_usage);
John Beppu5db60a72000-06-12 22:59:12 +0000178 while (argc >= 2) {
179 stack_machine(argv[1]);
180 argv++;
181 argc--;
182 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000183 }
184 stack_machine(0);
Eric Andersenb6106152000-06-19 17:25:40 +0000185 return( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000186}