initially checkin
[gnupg.git] / tools / mpicalc.c
1 /* mpitest.c - test the mpi functions
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This is a RPN calculator; values must be given in hex.
5  * Operaion is like dc(1) except that the input/output radix is
6  * always 16 and you can use a '-' to prefix a negative number.
7  * Addition operators: ++ and --. All operators must be delimeted by a blank
8  *
9  *
10  * This file is part of G10.
11  *
12  * G10 is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * G10 is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
25  */
26
27 #include <config.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31
32 #include "util.h"
33 #include "mpi.h"
34
35 #define STACKSIZE  100
36 static MPI stack[STACKSIZE];
37 static int stackidx;
38
39
40 const char *
41 strusage( int level )
42 {
43     const char *p;
44     switch( level ) {
45       case 10:
46       case 0:   p = "mpicalc - v" VERSION "; "
47                     "Copyright 1997 Werner Koch (dd9jn)" ; break;
48       case 13:  p = "mpicalc"; break;
49       case 14:  p = VERSION; break;
50       case 1:
51       case 11:  p = "Usage: mpicalc (-h for help)";
52                 break;
53       case 2:
54       case 12:  p =
55     "\nSyntax: mpicalc [options] [files]\n"
56     "MPI RPN calculator\n";
57         break;
58       default:  p = default_strusage(level);
59     }
60     return p;
61 }
62
63
64 static void
65 do_add(void)
66 {
67     if( stackidx < 2 ) {
68         fputs("stack underflow\n",stderr);
69         return;
70     }
71     mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
72     stackidx--;
73 }
74
75 static void
76 do_sub(void)
77 {
78     if( stackidx < 2 ) {
79         fputs("stack underflow\n", stderr);
80         return;
81     }
82     mpi_sub( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
83     stackidx--;
84 }
85
86 static void
87 do_inc(void)
88 {
89     if( stackidx < 1 ) {
90         fputs("stack underflow\n", stderr);
91         return;
92     }
93     mpi_add_ui( stack[stackidx-1], stack[stackidx-1], 1 );
94 }
95
96 static void
97 do_dec(void)
98 {
99     if( stackidx < 1 ) {
100         fputs("stack underflow\n", stderr);
101         return;
102     }
103  /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
104 }
105
106 static void
107 do_mul(void)
108 {
109     if( stackidx < 2 ) {
110         fputs("stack underflow\n", stderr);
111         return;
112     }
113     mpi_mul( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
114     stackidx--;
115 }
116
117 static void
118 do_div(void)
119 {
120     if( stackidx < 2 ) {
121         fputs("stack underflow\n", stderr);
122         return;
123     }
124     mpi_fdiv_q( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
125     stackidx--;
126 }
127
128 static void
129 do_rem(void)
130 {
131     if( stackidx < 2 ) {
132         fputs("stack underflow\n", stderr);
133         return;
134     }
135     mpi_fdiv_r( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
136     stackidx--;
137 }
138
139 static void
140 do_powm(void)
141 {
142     MPI a;
143     if( stackidx < 3 ) {
144         fputs("stack underflow\n", stderr);
145         return;
146     }
147     a= mpi_alloc(10);
148     mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] );
149     mpi_free(stack[stackidx-3]);
150     stack[stackidx-3] = a;
151     stackidx -= 2;
152 }
153
154 static void
155 do_inv(void)
156 {
157     MPI a = mpi_alloc(40);
158     if( stackidx < 2 ) {
159         fputs("stack underflow\n", stderr);
160         return;
161     }
162     mpi_inv_mod( a, stack[stackidx-2], stack[stackidx-1] );
163     mpi_set(stack[stackidx-2],a);
164     mpi_free(a);
165     stackidx--;
166 }
167
168 static void
169 do_gcd(void)
170 {
171     MPI a = mpi_alloc(40);
172     if( stackidx < 2 ) {
173         fputs("stack underflow\n", stderr);
174         return;
175     }
176     mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] );
177     mpi_set(stack[stackidx-2],a);
178     mpi_free(a);
179     stackidx--;
180 }
181
182
183 int
184 main(int argc, char **argv)
185 {
186     static ARGPARSE_OPTS opts[] = {
187     {0} };
188     ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
189     int i, c;
190     int state = 0;
191     char strbuf[1000];
192     int stridx=0;
193
194     while( arg_parse( &pargs, opts) ) {
195         switch( pargs.r_opt ) {
196           default : pargs.err = 2; break;
197         }
198     }
199     if( argc )
200         usage(1);
201
202
203     for(i=0; i < STACKSIZE; i++ )
204         stack[i] = NULL;
205     stackidx =0;
206
207     while( (c=getc(stdin)) != EOF ) {
208         if( !state ) {  /* waiting */
209             if( isdigit(c) || (c >='A' && c <= 'F') ) {
210                 state = 1;
211                 ungetc(c, stdin);
212                 strbuf[0] = '0';
213                 strbuf[1] = 'x';
214                 stridx=2;
215             }
216             else if( isspace(c) )
217                 ;
218             else {
219                 switch(c) {
220                   case '+':
221                     if( (c=getc(stdin)) == '+' )
222                         do_inc();
223                     else {
224                         ungetc(c, stdin);
225                         do_add();
226                     }
227                     break;
228                   case '-':
229                     if( (c=getc(stdin)) == '-' )
230                         do_dec();
231                     else if( isdigit(c) || (c >='A' && c <= 'F') ) {
232                         state = 1;
233                         ungetc(c, stdin);
234                         strbuf[0] = '-';
235                         strbuf[1] = '0';
236                         strbuf[2] = 'x';
237                         stridx=3;
238                     }
239                     else {
240                         ungetc(c, stdin);
241                         do_sub();
242                     }
243                     break;
244                   case '*':
245                     do_mul();
246                     break;
247                   case '/':
248                     do_div();
249                     break;
250                   case '%':
251                     do_rem();
252                     break;
253                   case '^':
254                     do_powm();
255                     break;
256                   case 'I':
257                     do_inv();
258                     break;
259                   case 'G':
260                     do_gcd();
261                     break;
262                   case 'i': /* dummy */
263                     if( !stackidx )
264                         fputs("stack underflow\n", stderr);
265                     else {
266                         mpi_free(stack[stackidx-1]);
267                         stackidx--;
268                     }
269                     break;
270                   case 'd': /* duplicate the tos */
271                     if( !stackidx )
272                         fputs("stack underflow\n", stderr);
273                     else if( stackidx < STACKSIZE ) {
274                         mpi_free(stack[stackidx]);
275                         stack[stackidx] = mpi_copy( stack[stackidx-1] );
276                         stackidx++;
277                     }
278                     else
279                         fputs("stack overflow\n", stderr);
280                     break;
281                   case 'c':
282                     for(i=0; i < stackidx; i++ )
283                         mpi_free(stack[i]), stack[i] = NULL;
284                     stackidx = 0;
285                     break;
286                   case 'p': /* print the tos */
287                     if( !stackidx )
288                         puts("stack is empty");
289                     else {
290                         mpi_print(stdout, stack[stackidx-1], 1 );
291                         putchar('\n');
292                     }
293                     break;
294                   case 'f': /* print the stack */
295                     for( i = stackidx-1 ; i >= 0; i-- ) {
296                         printf("[%2d]: ", i );
297                         mpi_print(stdout, stack[i], 1 );
298                         putchar('\n');
299                     }
300                     break;
301                   default:
302                     fputs("invalid operator\n", stderr);
303                 }
304             }
305         }
306         else if( state == 1 ) { /* in a number */
307             if( !(isdigit(c) || (c >='A' && c <= 'F')) ) { /* store the number */
308                 state = 0;
309                 ungetc(c, stdin);
310                 if( stridx < 1000 )
311                     strbuf[stridx] = 0;
312
313                 if( stackidx < STACKSIZE ) {
314                     if( !stack[stackidx] )
315                         stack[stackidx] = mpi_alloc(10);
316                     if( mpi_fromstr(stack[stackidx], strbuf) )
317                         fputs("invalid number\n", stderr);
318                     else
319                         stackidx++;
320                 }
321                 else
322                     fputs("stack overflow\n", stderr);
323             }
324             else { /* store digit */
325                 if( stridx < 999 )
326                     strbuf[stridx++] = c;
327                 else if( stridx == 999 ) {
328                     strbuf[stridx] = 0;
329                     fputs("string too large - truncated\n", stderr);
330                     stridx++;
331                 }
332             }
333         }
334
335     }
336     for(i=0; i < stackidx; i++ )
337         mpi_free(stack[i]);
338     return 0;
339 }
340
341