1/* vi: set sw=4 ts=4: */
2#include <ctype.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <math.h>
8#include "busybox.h"
9
10/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
11
12static double stack[100];
13static unsigned int pointer;
14
15static void push(double a)
16{
17	if (pointer >= (sizeof(stack) / sizeof(*stack)))
18		error_msg_and_die("stack overflow");
19	stack[pointer++] = a;
20}
21
22static double pop()
23{
24	if (pointer == 0)
25		error_msg_and_die("stack underflow");
26	return stack[--pointer];
27}
28
29static void add()
30{
31	push(pop() + pop());
32}
33
34static void sub()
35{
36	double subtrahend = pop();
37
38	push(pop() - subtrahend);
39}
40
41static void mul()
42{
43	push(pop() * pop());
44}
45
46static void divide()
47{
48	double divisor = pop();
49
50	push(pop() / divisor);
51}
52
53static void and()
54{
55	push((unsigned int) pop() & (unsigned int) pop());
56}
57
58static void or()
59{
60	push((unsigned int) pop() | (unsigned int) pop());
61}
62
63static void eor()
64{
65	push((unsigned int) pop() ^ (unsigned int) pop());
66}
67
68static void not()
69{
70	push(~(unsigned int) pop());
71}
72
73static void print()
74{
75	printf("%g\n", pop());
76}
77
78struct op {
79	const char *name;
80	void (*function) ();
81};
82
83static const struct op operators[] = {
84	{"+",   add},
85	{"add", add},
86	{"-",   sub},
87	{"sub", sub},
88	{"*",   mul},
89	{"mul", mul},
90	{"/",   divide},
91	{"div", divide},
92	{"and", and},
93	{"or",  or},
94	{"not", not},
95	{"eor", eor},
96	{0,     0}
97};
98
99static void stack_machine(const char *argument)
100{
101	char *endPointer = 0;
102	double d;
103	const struct op *o = operators;
104
105	if (argument == 0) {
106		print();
107		return;
108	}
109
110	d = strtod(argument, &endPointer);
111
112	if (endPointer != argument) {
113		push(d);
114		return;
115	}
116
117	while (o->name != 0) {
118		if (strcmp(o->name, argument) == 0) {
119			(*(o->function)) ();
120			return;
121		}
122		o++;
123	}
124	error_msg_and_die("%s: syntax error.", argument);
125}
126
127/* 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
153int dc_main(int argc, char **argv)
154{
155	/* 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;
161		while ((line = get_line_from_file(stdin))) {
162			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]=='-')
173			show_usage();
174		while (argc >= 2) {
175			stack_machine(argv[1]);
176			argv++;
177			argc--;
178		}
179	}
180	stack_machine(0);
181	return EXIT_SUCCESS;
182}
183