cast5 does now work
[gnupg.git] / tools / mpicalc.c
1 /* mpitest.c - test the mpi functions
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
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 GNUPG.
11  *
12  * GNUPG 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  * GNUPG 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 #include "i18n.h"
35
36 #define STACKSIZE  100
37 static MPI stack[STACKSIZE];
38 static int stackidx;
39
40
41 const char *
42 strusage( int level )
43 {
44     const char *p;
45     switch( level ) {
46       case 10:
47       case 0:   p = "mpicalc - v" VERSION "; "
48                     "Copyright 1997 Werner Koch (dd9jn)" ; break;
49       case 13:  p = "mpicalc"; break;
50       case 14:  p = VERSION; break;
51       case 1:
52       case 11:  p = "Usage: mpicalc (-h for help)";
53                 break;
54       case 2:
55       case 12:  p =
56     "\nSyntax: mpicalc [options] [files]\n"
57     "MPI RPN calculator\n";
58         break;
59       default:  p = default_strusage(level);
60     }
61     return p;
62 }
63
64
65 static void
66 i18n_init(void)
67 {
68   #ifdef ENABLE_NLS
69     #ifdef HAVE_LC_MESSAGES
70        setlocale( LC_MESSAGES, "" );
71     #else
72        setlocale( LC_ALL, "" );
73     #endif
74     bindtextdomain( PACKAGE, G10_LOCALEDIR );
75     textdomain( PACKAGE );
76   #endif
77 }
78
79
80 static void
81 do_add(void)
82 {
83     if( stackidx < 2 ) {
84         fputs("stack underflow\n",stderr);
85         return;
86     }
87     mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
88     stackidx--;
89 }
90
91 static void
92 do_sub(void)
93 {
94     if( stackidx < 2 ) {
95         fputs("stack underflow\n", stderr);
96         return;
97     }
98     mpi_sub( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
99     stackidx--;
100 }
101
102 static void
103 do_inc(void)
104 {
105     if( stackidx < 1 ) {
106         fputs("stack underflow\n", stderr);
107         return;
108     }
109     mpi_add_ui( stack[stackidx-1], stack[stackidx-1], 1 );
110 }
111
112 static void
113 do_dec(void)
114 {
115     if( stackidx < 1 ) {
116         fputs("stack underflow\n", stderr);
117         return;
118     }
119  /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
120 }
121
122 static void
123 do_mul(void)
124 {
125     if( stackidx < 2 ) {
126         fputs("stack underflow\n", stderr);
127         return;
128     }
129     mpi_mul( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
130     stackidx--;
131 }
132
133 static void
134 do_div(void)
135 {
136     if( stackidx < 2 ) {
137         fputs("stack underflow\n", stderr);
138         return;
139     }
140     mpi_fdiv_q( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
141     stackidx--;
142 }
143
144 static void
145 do_rem(void)
146 {
147     if( stackidx < 2 ) {
148         fputs("stack underflow\n", stderr);
149         return;
150     }
151     mpi_fdiv_r( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
152     stackidx--;
153 }
154
155 static void
156 do_powm(void)
157 {
158     MPI a;
159     if( stackidx < 3 ) {
160         fputs("stack underflow\n", stderr);
161         return;
162     }
163     a= mpi_alloc(10);
164     mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] );
165     mpi_free(stack[stackidx-3]);
166     stack[stackidx-3] = a;
167     stackidx -= 2;
168 }
169
170 static void
171 do_inv(void)
172 {
173     MPI a = mpi_alloc(40);
174     if( stackidx < 2 ) {
175         fputs("stack underflow\n", stderr);
176         return;
177     }
178     mpi_invm( a, stack[stackidx-2], stack[stackidx-1] );
179     mpi_set(stack[stackidx-2],a);
180     mpi_free(a);
181     stackidx--;
182 }
183
184 static void
185 do_gcd(void)
186 {
187     MPI a = mpi_alloc(40);
188     if( stackidx < 2 ) {
189         fputs("stack underflow\n", stderr);
190         return;
191     }
192     mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] );
193     mpi_set(stack[stackidx-2],a);
194     mpi_free(a);
195     stackidx--;
196 }
197
198 static void
199 do_rshift(void)
200 {
201     if( stackidx < 1 ) {
202         fputs("stack underflow\n", stderr);
203         return;
204     }
205     mpi_rshift( stack[stackidx-1],stack[stackidx-1], 1 );
206 }
207
208
209 int
210 main(int argc, char **argv)
211 {
212     static ARGPARSE_OPTS opts[] = {
213     {0} };
214     ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
215     int i, c;
216     int state = 0;
217     char strbuf[1000];
218     int stridx=0;
219
220     i18n_init();
221     while( arg_parse( &pargs, opts) ) {
222         switch( pargs.r_opt ) {
223           default : pargs.err = 2; break;
224         }
225     }
226     if( argc )
227         usage(1);
228
229
230     for(i=0; i < STACKSIZE; i++ )
231         stack[i] = NULL;
232     stackidx =0;
233
234     while( (c=getc(stdin)) != EOF ) {
235         if( !state ) {  /* waiting */
236             if( isdigit(c) || (c >='A' && c <= 'F') ) {
237                 state = 1;
238                 ungetc(c, stdin);
239                 strbuf[0] = '0';
240                 strbuf[1] = 'x';
241                 stridx=2;
242             }
243             else if( isspace(c) )
244                 ;
245             else {
246                 switch(c) {
247                   case '+':
248                     if( (c=getc(stdin)) == '+' )
249                         do_inc();
250                     else {
251                         ungetc(c, stdin);
252                         do_add();
253                     }
254                     break;
255                   case '-':
256                     if( (c=getc(stdin)) == '-' )
257                         do_dec();
258                     else if( isdigit(c) || (c >='A' && c <= 'F') ) {
259                         state = 1;
260                         ungetc(c, stdin);
261                         strbuf[0] = '-';
262                         strbuf[1] = '0';
263                         strbuf[2] = 'x';
264                         stridx=3;
265                     }
266                     else {
267                         ungetc(c, stdin);
268                         do_sub();
269                     }
270                     break;
271                   case '*':
272                     do_mul();
273                     break;
274                   case '/':
275                     do_div();
276                     break;
277                   case '%':
278                     do_rem();
279                     break;
280                   case '^':
281                     do_powm();
282                     break;
283                   case 'I':
284                     do_inv();
285                     break;
286                   case 'G':
287                     do_gcd();
288                     break;
289                   case '>':
290                     do_rshift();
291                     break;
292                   case 'i': /* dummy */
293                     if( !stackidx )
294                         fputs("stack underflow\n", stderr);
295                     else {
296                         mpi_free(stack[stackidx-1]);
297                         stackidx--;
298                     }
299                     break;
300                   case 'd': /* duplicate the tos */
301                     if( !stackidx )
302                         fputs("stack underflow\n", stderr);
303                     else if( stackidx < STACKSIZE ) {
304                         mpi_free(stack[stackidx]);
305                         stack[stackidx] = mpi_copy( stack[stackidx-1] );
306                         stackidx++;
307                     }
308                     else
309                         fputs("stack overflow\n", stderr);
310                     break;
311                   case 'c':
312                     for(i=0; i < stackidx; i++ )
313                         mpi_free(stack[i]), stack[i] = NULL;
314                     stackidx = 0;
315                     break;
316                   case 'p': /* print the tos */
317                     if( !stackidx )
318                         puts("stack is empty");
319                     else {
320                         mpi_print(stdout, stack[stackidx-1], 1 );
321                         putchar('\n');
322                     }
323                     break;
324                   case 'f': /* print the stack */
325                     for( i = stackidx-1 ; i >= 0; i-- ) {
326                         printf("[%2d]: ", i );
327                         mpi_print(stdout, stack[i], 1 );
328                         putchar('\n');
329                     }
330                     break;
331                   default:
332                     fputs("invalid operator\n", stderr);
333                 }
334             }
335         }
336         else if( state == 1 ) { /* in a number */
337             if( !(isdigit(c) || (c >='A' && c <= 'F')) ) { /* store the number */
338                 state = 0;
339                 ungetc(c, stdin);
340                 if( stridx < 1000 )
341                     strbuf[stridx] = 0;
342
343                 if( stackidx < STACKSIZE ) {
344                     if( !stack[stackidx] )
345                         stack[stackidx] = mpi_alloc(10);
346                     if( mpi_fromstr(stack[stackidx], strbuf) )
347                         fputs("invalid number\n", stderr);
348                     else
349                         stackidx++;
350                 }
351                 else
352                     fputs("stack overflow\n", stderr);
353             }
354             else { /* store digit */
355                 if( stridx < 999 )
356                     strbuf[stridx++] = c;
357                 else if( stridx == 999 ) {
358                     strbuf[stridx] = 0;
359                     fputs("string too large - truncated\n", stderr);
360                     stridx++;
361                 }
362             }
363         }
364
365     }
366     for(i=0; i < stackidx; i++ )
367         mpi_free(stack[i]);
368     return 0;
369 }
370
371