Extract usage information into a separate file.
[oweals/busybox.git] / miscutils / dc.c
1 /* vi: set sw=4 ts=4: */
2 #include "internal.h"
3 #include <ctype.h>
4 #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
11 static double stack[100];
12 static unsigned int pointer;
13
14 static void push(double a)
15 {
16         if (pointer >= (sizeof(stack) / sizeof(*stack))) {
17                 errorMsg("stack overflow\n");
18                 exit(-1);
19         } else
20                 stack[pointer++] = a;
21 }
22
23 static double pop()
24 {
25         if (pointer == 0) {
26                 errorMsg("stack underflow\n");
27                 exit(-1);
28         }
29         return stack[--pointer];
30 }
31
32 static void add()
33 {
34         push(pop() + pop());
35 }
36
37 static void sub()
38 {
39         double subtrahend = pop();
40
41         push(pop() - subtrahend);
42 }
43
44 static void mul()
45 {
46         push(pop() * pop());
47 }
48
49 static void divide()
50 {
51         double divisor = pop();
52
53         push(pop() / divisor);
54 }
55
56 static void and()
57 {
58         push((unsigned int) pop() & (unsigned int) pop());
59 }
60
61 static void or()
62 {
63         push((unsigned int) pop() | (unsigned int) pop());
64 }
65
66 static void eor()
67 {
68         push((unsigned int) pop() ^ (unsigned int) pop());
69 }
70
71 static void not()
72 {
73         push(~(unsigned int) pop());
74 }
75
76 static void print()
77 {
78         printf("%g\n", pop());
79 }
80
81 struct op {
82         const char *name;
83         void (*function) ();
84 };
85
86 static const struct op operators[] = {
87         {"+",   add},
88         {"add", add},
89         {"-",   sub},
90         {"sub", sub},
91         {"*",   mul},
92         {"mul", mul},
93         {"/",   divide},
94         {"div", divide},
95         {"and", and},
96         {"or",  or},
97         {"not", not},
98         {"eor", eor},
99         {0,     0}
100 };
101
102 static void stack_machine(const char *argument)
103 {
104         char *endPointer = 0;
105         double d;
106         const struct op *o = operators;
107
108         if (argument == 0) {
109                 print();
110                 return;
111         }
112
113         d = strtod(argument, &endPointer);
114
115         if (endPointer != argument) {
116                 push(d);
117                 return;
118         }
119
120         while (o->name != 0) {
121                 if (strcmp(o->name, argument) == 0) {
122                         (*(o->function)) ();
123                         return;
124                 }
125                 o++;
126         }
127         errorMsg("%s: syntax error.\n", argument);
128         exit(-1);
129 }
130
131 /* return pointer to next token in buffer and set *buffer to one char
132  * past the end of the above mentioned token 
133  */
134 static 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 */
149 static 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
157 int dc_main(int argc, char **argv)
158 {
159         /* 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;
165                 while ((line = get_line_from_file(stdin))) {
166                         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]=='-')
177                         usage(dc_usage);
178                 while (argc >= 2) {
179                         stack_machine(argv[1]);
180                         argv++;
181                         argc--;
182                 }
183         }
184         stack_machine(0);
185         return( TRUE);
186 }