See ChangeLog: Mon May 31 19:41:10 CEST 1999 Werner Koch
[gnupg.git] / tools / mpicalc.c
1 /* mpitest.c - test the mpi functions
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This is an RPN calculator; values must be given in hex.
5  * Operation 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 delimited 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;
215     int i, c;
216     int state = 0;
217     char strbuf[1000];
218     int stridx=0;
219
220     pargs.argc = &argc;
221     pargs.argv = &argv;
222     pargs.flags = 0;
223
224     i18n_init();
225     while( arg_parse( &pargs, opts) ) {
226         switch( pargs.r_opt ) {
227           default : pargs.err = 2; break;
228         }
229     }
230     if( argc )
231         usage(1);
232
233
234     for(i=0; i < STACKSIZE; i++ )
235         stack[i] = NULL;
236     stackidx =0;
237
238     while( (c=getc(stdin)) != EOF ) {
239         if( !state ) {  /* waiting */
240             if( isdigit(c) || (c >='A' && c <= 'F') ) {
241                 state = 1;
242                 ungetc(c, stdin);
243                 strbuf[0] = '0';
244                 strbuf[1] = 'x';
245                 stridx=2;
246             }
247             else if( isspace(c) )
248                 ;
249             else {
250                 switch(c) {
251                   case '+':
252                     if( (c=getc(stdin)) == '+' )
253                         do_inc();
254                     else {
255                         ungetc(c, stdin);
256                         do_add();
257                     }
258                     break;
259                   case '-':
260                     if( (c=getc(stdin)) == '-' )
261                         do_dec();
262                     else if( isdigit(c) || (c >='A' && c <= 'F') ) {
263                         state = 1;
264                         ungetc(c, stdin);
265                         strbuf[0] = '-';
266                         strbuf[1] = '0';
267                         strbuf[2] = 'x';
268                         stridx=3;
269                     }
270                     else {
271                         ungetc(c, stdin);
272                         do_sub();
273                     }
274                     break;
275                   case '*':
276                     do_mul();
277                     break;
278                   case '/':
279                     do_div();
280                     break;
281                   case '%':
282                     do_rem();
283                     break;
284                   case '^':
285                     do_powm();
286                     break;
287                   case 'I':
288                     do_inv();
289                     break;
290                   case 'G':
291                     do_gcd();
292                     break;
293                   case '>':
294                     do_rshift();
295                     break;
296                   case 'i': /* dummy */
297                     if( !stackidx )
298                         fputs("stack underflow\n", stderr);
299                     else {
300                         mpi_free(stack[stackidx-1]);
301                         stackidx--;
302                     }
303                     break;
304                   case 'd': /* duplicate the tos */
305                     if( !stackidx )
306                         fputs("stack underflow\n", stderr);
307                     else if( stackidx < STACKSIZE ) {
308                         mpi_free(stack[stackidx]);
309                         stack[stackidx] = mpi_copy( stack[stackidx-1] );
310                         stackidx++;
311                     }
312                     else
313                         fputs("stack overflow\n", stderr);
314                     break;
315                   case 'c':
316                     for(i=0; i < stackidx; i++ )
317                         mpi_free(stack[i]), stack[i] = NULL;
318                     stackidx = 0;
319                     break;
320                   case 'p': /* print the tos */
321                     if( !stackidx )
322                         puts("stack is empty");
323                     else {
324                         mpi_print(stdout, stack[stackidx-1], 1 );
325                         putchar('\n');
326                     }
327                     break;
328                   case 'f': /* print the stack */
329                     for( i = stackidx-1 ; i >= 0; i-- ) {
330                         printf("[%2d]: ", i );
331                         mpi_print(stdout, stack[i], 1 );
332                         putchar('\n');
333                     }
334                     break;
335                   default:
336                     fputs("invalid operator\n", stderr);
337                 }
338             }
339         }
340         else if( state == 1 ) { /* in a number */
341             if( !(isdigit(c) || (c >='A' && c <= 'F')) ) { /* store the number */
342                 state = 0;
343                 ungetc(c, stdin);
344                 if( stridx < 1000 )
345                     strbuf[stridx] = 0;
346
347                 if( stackidx < STACKSIZE ) {
348                     if( !stack[stackidx] )
349                         stack[stackidx] = mpi_alloc(10);
350                     if( mpi_fromstr(stack[stackidx], strbuf) )
351                         fputs("invalid number\n", stderr);
352                     else
353                         stackidx++;
354                 }
355                 else
356                     fputs("stack overflow\n", stderr);
357             }
358             else { /* store digit */
359                 if( stridx < 999 )
360                     strbuf[stridx++] = c;
361                 else if( stridx == 999 ) {
362                     strbuf[stridx] = 0;
363                     fputs("string too large - truncated\n", stderr);
364                     stridx++;
365                 }
366             }
367         }
368
369     }
370     for(i=0; i < stackidx; i++ )
371         mpi_free(stack[i]);
372     return 0;
373 }
374
375