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