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