assuan/
[gnupg.git] / tools / mpicalc.c
blobaedb27ecf65a3389da55f269f87d3bf9fa689414
1 /* mpitest.c - test the mpi functions
2 * Copyright (C) 1998 Free Software Foundation, Inc.
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
10 * This file is part of GnuPG.
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.
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.
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
27 #include <config.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <gcrypt.h>
33 #include "util.h"
34 #include "i18n.h"
36 #define STACKSIZE 100
37 static MPI stack[STACKSIZE];
38 static int stackidx;
41 static const char *
42 my_strusage( int level )
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 = NULL;
61 return p;
65 static void
66 i18n_init(void)
68 #ifdef ENABLE_NLS
69 #ifdef HAVE_LC_MESSAGES
70 setlocale( LC_MESSAGES, "" );
71 #else
72 setlocale( LC_ALL, "" );
73 #endif
74 bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
75 textdomain( PACKAGE );
76 #endif
79 int
80 mpi_print( FILE *fp, MPI a, int mode )
82 int n=0;
84 if( !a )
85 return fprintf(fp, "[MPI_NULL]");
86 if( !mode ) {
87 unsigned int n1;
88 n1 = gcry_mpi_get_nbits(a);
89 n += fprintf(fp, "[%u bits]", n1);
91 else {
92 int rc;
93 char *buffer;
95 rc = gcry_mpi_aprint( GCRYMPI_FMT_HEX, (void **)&buffer, NULL, a );
96 fputs( buffer, fp );
97 n += strlen(buffer);
98 gcry_free( buffer );
100 return n;
104 static void
105 do_add(void)
107 if( stackidx < 2 ) {
108 fputs("stack underflow\n",stderr);
109 return;
111 mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
112 stackidx--;
115 static void
116 do_sub(void)
118 if( stackidx < 2 ) {
119 fputs("stack underflow\n", stderr);
120 return;
122 mpi_sub( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
123 stackidx--;
126 static void
127 do_inc(void)
129 if( stackidx < 1 ) {
130 fputs("stack underflow\n", stderr);
131 return;
133 mpi_add_ui( stack[stackidx-1], stack[stackidx-1], 1 );
136 static void
137 do_dec(void)
139 if( stackidx < 1 ) {
140 fputs("stack underflow\n", stderr);
141 return;
143 /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
146 static void
147 do_mul(void)
149 if( stackidx < 2 ) {
150 fputs("stack underflow\n", stderr);
151 return;
153 mpi_mul( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
154 stackidx--;
157 static void
158 do_mulm(void)
160 if( stackidx < 3 ) {
161 fputs("stack underflow\n", stderr);
162 return;
164 mpi_mulm( stack[stackidx-3], stack[stackidx-3],
165 stack[stackidx-2], stack[stackidx-1] );
166 stackidx -= 2;
169 static void
170 do_div(void)
172 if( stackidx < 2 ) {
173 fputs("stack underflow\n", stderr);
174 return;
176 mpi_fdiv_q( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
177 stackidx--;
180 static void
181 do_rem(void)
183 if( stackidx < 2 ) {
184 fputs("stack underflow\n", stderr);
185 return;
187 mpi_fdiv_r( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
188 stackidx--;
191 static void
192 do_powm(void)
194 MPI a;
195 if( stackidx < 3 ) {
196 fputs("stack underflow\n", stderr);
197 return;
199 a= mpi_alloc(10);
200 mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] );
201 mpi_free(stack[stackidx-3]);
202 stack[stackidx-3] = a;
203 stackidx -= 2;
206 static void
207 do_inv(void)
209 MPI a = mpi_alloc(40);
210 if( stackidx < 2 ) {
211 fputs("stack underflow\n", stderr);
212 return;
214 mpi_invm( a, stack[stackidx-2], stack[stackidx-1] );
215 mpi_set(stack[stackidx-2],a);
216 mpi_free(a);
217 stackidx--;
220 static void
221 do_gcd(void)
223 MPI a = mpi_alloc(40);
224 if( stackidx < 2 ) {
225 fputs("stack underflow\n", stderr);
226 return;
228 mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] );
229 mpi_set(stack[stackidx-2],a);
230 mpi_free(a);
231 stackidx--;
234 static void
235 do_rshift(void)
237 if( stackidx < 1 ) {
238 fputs("stack underflow\n", stderr);
239 return;
241 mpi_rshift( stack[stackidx-1],stack[stackidx-1], 1 );
246 main(int argc, char **argv)
248 static ARGPARSE_OPTS opts[] = {
249 {0} };
250 ARGPARSE_ARGS pargs;
251 int i, c;
252 int state = 0;
253 char strbuf[1000];
254 int stridx=0;
256 pargs.argc = &argc;
257 pargs.argv = &argv;
258 pargs.flags = 0;
260 set_strusage( my_strusage );
261 i18n_init();
262 while( arg_parse( &pargs, opts) ) {
263 switch( pargs.r_opt ) {
264 default : pargs.err = 2; break;
267 if( argc )
268 usage(1);
271 for(i=0; i < STACKSIZE; i++ )
272 stack[i] = NULL;
273 stackidx =0;
275 while( (c=getc(stdin)) != EOF ) {
276 if( !state ) { /* waiting */
277 if( isdigit(c) ) {
278 state = 1;
279 ungetc(c, stdin);
280 strbuf[0] = '0';
281 strbuf[1] = 'x';
282 stridx=2;
284 else if( isspace(c) )
286 else {
287 switch(c) {
288 case '+':
289 if( (c=getc(stdin)) == '+' )
290 do_inc();
291 else {
292 ungetc(c, stdin);
293 do_add();
295 break;
296 case '-':
297 if( (c=getc(stdin)) == '-' )
298 do_dec();
299 else if( isdigit(c) || (c >='A' && c <= 'F') ) {
300 state = 1;
301 ungetc(c, stdin);
302 strbuf[0] = '-';
303 strbuf[1] = '0';
304 strbuf[2] = 'x';
305 stridx=3;
307 else {
308 ungetc(c, stdin);
309 do_sub();
311 break;
312 case '*':
313 do_mul();
314 break;
315 case 'm':
316 do_mulm();
317 break;
318 case '/':
319 do_div();
320 break;
321 case '%':
322 do_rem();
323 break;
324 case '^':
325 do_powm();
326 break;
327 case 'I':
328 do_inv();
329 break;
330 case 'G':
331 do_gcd();
332 break;
333 case '>':
334 do_rshift();
335 break;
336 case 'i': /* dummy */
337 if( !stackidx )
338 fputs("stack underflow\n", stderr);
339 else {
340 mpi_free(stack[stackidx-1]);
341 stackidx--;
343 break;
344 case 'd': /* duplicate the tos */
345 if( !stackidx )
346 fputs("stack underflow\n", stderr);
347 else if( stackidx < STACKSIZE ) {
348 mpi_free(stack[stackidx]);
349 stack[stackidx] = mpi_copy( stack[stackidx-1] );
350 stackidx++;
352 else
353 fputs("stack overflow\n", stderr);
354 break;
355 case 'c':
356 for(i=0; i < stackidx; i++ )
357 mpi_free(stack[i]), stack[i] = NULL;
358 stackidx = 0;
359 break;
360 case 'p': /* print the tos */
361 if( !stackidx )
362 puts("stack is empty");
363 else {
364 mpi_print(stdout, stack[stackidx-1], 1 );
365 putchar('\n');
367 break;
368 case 'f': /* print the stack */
369 for( i = stackidx-1 ; i >= 0; i-- ) {
370 printf("[%2d]: ", i );
371 mpi_print(stdout, stack[i], 1 );
372 putchar('\n');
374 break;
375 default:
376 fputs("invalid operator\n", stderr);
380 else if( state == 1 ) { /* in a number */
381 if( !isxdigit(c) ) { /* store the number */
382 state = 0;
383 ungetc(c, stdin);
384 if( stridx < 1000 )
385 strbuf[stridx] = 0;
387 if( stackidx < STACKSIZE ) {
388 if( !stack[stackidx] )
389 stack[stackidx] = mpi_alloc(10);
390 if( mpi_fromstr(stack[stackidx], strbuf) )
391 fputs("invalid number\n", stderr);
392 else
393 stackidx++;
395 else
396 fputs("stack overflow\n", stderr);
398 else { /* store digit */
399 if( stridx < 999 )
400 strbuf[stridx++] = c;
401 else if( stridx == 999 ) {
402 strbuf[stridx] = 0;
403 fputs("string too large - truncated\n", stderr);
404 stridx++;
410 for(i=0; i < stackidx; i++ )
411 mpi_free(stack[i]);
412 return 0;