Simplified version checking.
[oweals/busybox.git] / dc.c
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
12 static double stack[100];
13 static unsigned int pointer;
14
15 static 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
22 static double pop()
23 {
24         if (pointer == 0)
25                 error_msg_and_die("stack underflow");
26         return stack[--pointer];
27 }
28
29 static void add()
30 {
31         push(pop() + pop());
32 }
33
34 static void sub()
35 {
36         double subtrahend = pop();
37
38         push(pop() - subtrahend);
39 }
40
41 static void mul()
42 {
43         push(pop() * pop());
44 }
45
46 static void divide()
47 {
48         double divisor = pop();
49
50         push(pop() / divisor);
51 }
52
53 static void and()
54 {
55         push((unsigned int) pop() & (unsigned int) pop());
56 }
57
58 static void or()
59 {
60         push((unsigned int) pop() | (unsigned int) pop());
61 }
62
63 static void eor()
64 {
65         push((unsigned int) pop() ^ (unsigned int) pop());
66 }
67
68 static void not()
69 {
70         push(~(unsigned int) pop());
71 }
72
73 static void print()
74 {
75         printf("%g\n", pop());
76 }
77
78 struct op {
79         const char *name;
80         void (*function) ();
81 };
82
83 static 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
99 static 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  */
130 static 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 */
145 static 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
153 int 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 }