random: Remove the new API introduced by the new DRBG.
[libgcrypt.git] / src / mpicalc.c
1 /* mpicalc.c - Simple RPN calculator using gcry_mpi functions
2  * Copyright (C) 1997, 1998, 1999, 2004, 2006, 2013  Werner Koch
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2.1 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19    This program is a simple RPN calculator which was originally used
20    to develop the mpi functions of GnuPG.  Values must be given in
21    hex.  Operation is like dc(1) except that the input/output radix is
22    always 16 and you can use a '-' to prefix a negative number.
23    Addition operators: ++ and --.  All operators must be delimited by
24    a blank.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33
34 #ifdef _GCRYPT_IN_LIBGCRYPT
35 # undef _GCRYPT_IN_LIBGCRYPT
36 # include "gcrypt.h"
37 #else
38 # include <gcrypt.h>
39 #endif
40
41
42 #define MPICALC_VERSION "2.0"
43 #define NEED_LIBGCRYPT_VERSION "1.6.0"
44
45 #define STACKSIZE  500
46 static gcry_mpi_t stack[STACKSIZE];
47 static int stackidx;
48
49
50 static int
51 scan_mpi (gcry_mpi_t retval, const char *string)
52 {
53   gpg_error_t err;
54   gcry_mpi_t val;
55
56   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
57   if (err)
58     {
59       fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err));
60       return -1;
61     }
62   mpi_set (retval, val);
63   mpi_release (val);
64   return 0;
65 }
66
67
68 static void
69 print_mpi (gcry_mpi_t a)
70 {
71   gpg_error_t err;
72   char *buf;
73   void *bufaddr = &buf;
74
75   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
76   if (err)
77     fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (err));
78   else
79     {
80       fputs (buf, stdout);
81       gcry_free (buf);
82     }
83 }
84
85
86
87 static void
88 do_add (void)
89 {
90   if (stackidx < 2)
91     {
92       fputs ("stack underflow\n", stderr);
93       return;
94     }
95   mpi_add (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
96   stackidx--;
97 }
98
99 static void
100 do_sub (void)
101 {
102   if (stackidx < 2)
103     {
104       fputs ("stack underflow\n", stderr);
105       return;
106     }
107   mpi_sub (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
108   stackidx--;
109 }
110
111 static void
112 do_inc (void)
113 {
114   if (stackidx < 1)
115     {
116       fputs ("stack underflow\n", stderr);
117       return;
118     }
119   mpi_add_ui (stack[stackidx - 1], stack[stackidx - 1], 1);
120 }
121
122 static void
123 do_dec (void)
124 {
125   if (stackidx < 1)
126     {
127       fputs ("stack underflow\n", stderr);
128       return;
129     }
130   /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
131 }
132
133 static void
134 do_mul (void)
135 {
136   if (stackidx < 2)
137     {
138       fputs ("stack underflow\n", stderr);
139       return;
140     }
141   mpi_mul (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
142   stackidx--;
143 }
144
145 static void
146 do_mulm (void)
147 {
148   if (stackidx < 3)
149     {
150       fputs ("stack underflow\n", stderr);
151       return;
152     }
153   mpi_mulm (stack[stackidx - 3], stack[stackidx - 3],
154             stack[stackidx - 2], stack[stackidx - 1]);
155   stackidx -= 2;
156 }
157
158 static void
159 do_div (void)
160 {
161   if (stackidx < 2)
162     {
163       fputs ("stack underflow\n", stderr);
164       return;
165     }
166   mpi_fdiv (stack[stackidx - 2], NULL,
167             stack[stackidx - 2], stack[stackidx - 1]);
168   stackidx--;
169 }
170
171 static void
172 do_rem (void)
173 {
174   if (stackidx < 2)
175     {
176       fputs ("stack underflow\n", stderr);
177       return;
178     }
179   mpi_mod (stack[stackidx - 2],
180            stack[stackidx - 2], stack[stackidx - 1]);
181   stackidx--;
182 }
183
184 static void
185 do_powm (void)
186 {
187   gcry_mpi_t a;
188   if (stackidx < 3)
189     {
190       fputs ("stack underflow\n", stderr);
191       return;
192     }
193   a = mpi_new (0);
194   mpi_powm (a, stack[stackidx - 3], stack[stackidx - 2], stack[stackidx - 1]);
195   mpi_release (stack[stackidx - 3]);
196   stack[stackidx - 3] = a;
197   stackidx -= 2;
198 }
199
200 static void
201 do_inv (void)
202 {
203   gcry_mpi_t a;
204
205   if (stackidx < 2)
206     {
207       fputs ("stack underflow\n", stderr);
208       return;
209     }
210   a = mpi_new (0);
211   mpi_invm (a, stack[stackidx - 2], stack[stackidx - 1]);
212   mpi_set (stack[stackidx - 2], a);
213   mpi_release (a);
214   stackidx--;
215 }
216
217 static void
218 do_gcd (void)
219 {
220   gcry_mpi_t a;
221
222   if (stackidx < 2)
223     {
224       fputs ("stack underflow\n", stderr);
225       return;
226     }
227   a = mpi_new (0);
228   mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]);
229   mpi_set (stack[stackidx - 2], a);
230   mpi_release (a);
231   stackidx--;
232 }
233
234 static void
235 do_rshift (void)
236 {
237   if (stackidx < 1)
238     {
239       fputs ("stack underflow\n", stderr);
240       return;
241     }
242   mpi_rshift (stack[stackidx - 1], stack[stackidx - 1], 1);
243 }
244
245
246 static void
247 do_nbits (void)
248 {
249   unsigned int n;
250
251   if (stackidx < 1)
252     {
253       fputs ("stack underflow\n", stderr);
254       return;
255     }
256   n = mpi_get_nbits (stack[stackidx - 1]);
257   mpi_set_ui (stack[stackidx - 1], n);
258 }
259
260
261 static void
262 do_primecheck (void)
263 {
264   gpg_error_t err;
265
266   if (stackidx < 1)
267     {
268       fputs ("stack underflow\n", stderr);
269       return;
270     }
271   err = gcry_prime_check (stack[stackidx - 1], 0);
272   mpi_set_ui (stack[stackidx - 1], !err);
273   if (err && gpg_err_code (err) != GPG_ERR_NO_PRIME)
274     fprintf (stderr, "checking prime failed: %s\n", gpg_strerror (err));
275 }
276
277
278 static int
279 my_getc (void)
280 {
281   static int shown;
282   int c;
283
284   for (;;)
285     {
286       if ((c = getc (stdin)) == EOF)
287         return EOF;
288       if (!(c & 0x80))
289         return c;
290
291       if (!shown)
292         {
293           shown = 1;
294           fputs ("note: Non ASCII characters are ignored\n", stderr);
295         }
296     }
297 }
298
299
300 static void
301 print_help (void)
302 {
303   fputs ("+   add           [0] := [1] + [0]          {-1}\n"
304          "-   subtract      [0] := [1] - [0]          {-1}\n"
305          "*   multiply      [0] := [1] * [0]          {-1}\n"
306          "/   divide        [0] := [1] - [0]          {-1}\n"
307          "%   modulo        [0] := [1] % [0]          {-1}\n"
308          ">   right shift   [0] := [0] >> 1           {0}\n"
309          "++  increment     [0] := [0]++              {0}\n"
310          "--  decrement     [0] := [0]--              {0}\n"
311          "m   multiply mod  [0] := [2] * [1] mod [0]  {-2}\n"
312          "^   power mod     [0] := [2] ^ [1] mod [0]  {-2}\n"
313          "I   inverse mod   [0] := [1]^-1 mod [0]     {-1}\n"
314          "G   gcd           [0] := gcd([1],[0])       {-1}\n"
315          "i   remove item   [0] := [1]                {-1}\n"
316          "d   dup item      [-1] := [0]               {+1}\n"
317          "r   reverse       [0] := [1], [1] := [0]    {0}\n"
318          "b   # of bits     [0] := nbits([0])         {0}\n"
319          "P   prime check   [0] := is_prime([0])?1:0  {0}\n"
320          "c   clear stack\n"
321          "p   print top item\n"
322          "f   print the stack\n"
323          "#   ignore until end of line\n"
324          "?   print this help\n"
325          , stdout);
326 }
327
328
329
330 int
331 main (int argc, char **argv)
332 {
333   const char *pgm;
334   int last_argc = -1;
335   int print_config = 0;
336   int i, c;
337   int state = 0;
338   char strbuf[4096];
339   int stridx = 0;
340
341   if (argc)
342     {
343       pgm = strrchr (*argv, '/');
344       if (pgm)
345         pgm++;
346       else
347         pgm = *argv;
348       argc--; argv++;
349     }
350   else
351     pgm = "?";
352
353   while (argc && last_argc != argc )
354     {
355       last_argc = argc;
356       if (!strcmp (*argv, "--"))
357         {
358           argc--; argv++;
359           break;
360         }
361       else if (!strcmp (*argv, "--version")
362                || !strcmp (*argv, "--help"))
363         {
364           printf ("%s " MPICALC_VERSION "\n"
365                   "libgcrypt %s\n"
366                   "Copyright (C) 1997, 2013  Werner Koch\n"
367                   "License LGPLv2.1+: GNU LGPL version 2.1 or later "
368                   "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n"
369                   "This is free software: you are free to change and "
370                   "redistribute it.\n"
371                   "There is NO WARRANTY, to the extent permitted by law.\n"
372                   "\n"
373                   "Syntax: mpicalc [options]\n"
374                   "Simple interactive big integer RPN calculator\n"
375                   "\n"
376                   "Options:\n"
377                   "  --version           print version information\n"
378                   "  --print-config      print the Libgcrypt config\n"
379                   "  --disable-hwf NAME  disable feature NAME\n",
380                   pgm, gcry_check_version (NULL));
381           exit (0);
382         }
383       else if (!strcmp (*argv, "--print-config"))
384         {
385           argc--; argv++;
386           print_config = 1;
387         }
388       else if (!strcmp (*argv, "--disable-hwf"))
389         {
390           argc--; argv++;
391           if (argc)
392             {
393               if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
394                 fprintf (stderr, "%s: unknown hardware feature `%s'"
395                          " - option ignored\n", pgm, *argv);
396               argc--; argv++;
397             }
398         }
399     }
400
401   if (argc)
402     {
403       fprintf (stderr, "usage: %s [options]  (--help for help)\n", pgm);
404       exit (1);
405     }
406
407   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
408     {
409       fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
410                pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
411       exit (1);
412     }
413   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
414   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
415   if (print_config)
416     {
417       gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
418       exit (0);
419     }
420
421   for (i = 0; i < STACKSIZE; i++)
422     stack[i] = NULL;
423   stackidx = 0;
424
425   while ((c = my_getc ()) != EOF)
426     {
427       if (!state) /* waiting */
428         {
429           if (isdigit (c))
430             {
431               state = 1;
432               ungetc (c, stdin);
433               strbuf[0] = '0';
434               strbuf[1] = 'x';
435               stridx = 2;
436             }
437           else if (isspace (c))
438             ;
439           else
440             {
441               switch (c)
442                 {
443                 case '#':
444                   state = 2;
445                   break;
446                 case '+':
447                   if ((c = my_getc ()) == '+')
448                     do_inc ();
449                   else
450                     {
451                       ungetc (c, stdin);
452                       do_add ();
453                     }
454                   break;
455                 case '-':
456                   if ((c = my_getc ()) == '-')
457                     do_dec ();
458                   else if (isdigit (c)
459                            || (c >= 'A' && c <= 'F')
460                            || (c >= 'a' && c <= 'f'))
461                     {
462                       state = 1;
463                       ungetc (c, stdin);
464                       strbuf[0] = '-';
465                       strbuf[1] = '0';
466                       strbuf[2] = 'x';
467                       stridx = 3;
468                     }
469                   else
470                     {
471                       ungetc (c, stdin);
472                       do_sub ();
473                     }
474                   break;
475                 case '*':
476                   do_mul ();
477                   break;
478                 case 'm':
479                   do_mulm ();
480                   break;
481                 case '/':
482                   do_div ();
483                   break;
484                 case '%':
485                   do_rem ();
486                   break;
487                 case '^':
488                   do_powm ();
489                   break;
490                 case '>':
491                   do_rshift ();
492                   break;
493                 case 'I':
494                   do_inv ();
495                   break;
496                 case 'G':
497                   do_gcd ();
498                   break;
499                 case 'i':       /* dummy */
500                   if (!stackidx)
501                     fputs ("stack underflow\n", stderr);
502                   else
503                     {
504                       mpi_release (stack[stackidx - 1]);
505                       stackidx--;
506                     }
507                   break;
508                 case 'd':       /* duplicate the tos */
509                   if (!stackidx)
510                     fputs ("stack underflow\n", stderr);
511                   else if (stackidx < STACKSIZE)
512                     {
513                       mpi_release (stack[stackidx]);
514                       stack[stackidx] = mpi_copy (stack[stackidx - 1]);
515                       stackidx++;
516                     }
517                   else
518                     fputs ("stack overflow\n", stderr);
519                   break;
520                 case 'r':       /* swap top elements */
521                   if (stackidx < 2)
522                     fputs ("stack underflow\n", stderr);
523                   else if (stackidx < STACKSIZE)
524                     {
525                       gcry_mpi_t tmp = stack[stackidx-1];
526                       stack[stackidx-1] = stack[stackidx - 2];
527                       stack[stackidx-2] = tmp;
528                     }
529                   break;
530                 case 'b':
531                   do_nbits ();
532                   break;
533                 case 'P':
534                   do_primecheck ();
535                   break;
536                 case 'c':
537                   for (i = 0; i < stackidx; i++)
538                     {
539                       mpi_release (stack[i]); stack[i] = NULL;
540                     }
541                   stackidx = 0;
542                   break;
543                 case 'p':       /* print the tos */
544                   if (!stackidx)
545                     puts ("stack is empty");
546                   else
547                     {
548                       print_mpi (stack[stackidx - 1]);
549                       putchar ('\n');
550                     }
551                   break;
552                 case 'f':       /* print the stack */
553                   for (i = stackidx - 1; i >= 0; i--)
554                     {
555                       printf ("[%2d]: ", i);
556                       print_mpi (stack[i]);
557                       putchar ('\n');
558                     }
559                   break;
560                 case '?':
561                   print_help ();
562                   break;
563                 default:
564                   fputs ("invalid operator\n", stderr);
565                 }
566             }
567         }
568       else if (state == 1) /* In a number. */
569         {
570           if (!isxdigit (c))
571             {
572               /* Store the number */
573               state = 0;
574               ungetc (c, stdin);
575               if (stridx < sizeof strbuf)
576                 strbuf[stridx] = 0;
577
578               if (stackidx < STACKSIZE)
579                 {
580                   if (!stack[stackidx])
581                     stack[stackidx] = mpi_new (0);
582                   if (scan_mpi (stack[stackidx], strbuf))
583                     fputs ("invalid number\n", stderr);
584                   else
585                     stackidx++;
586                 }
587               else
588                 fputs ("stack overflow\n", stderr);
589             }
590           else
591             { /* Store a digit.  */
592               if (stridx < sizeof strbuf - 1)
593                 strbuf[stridx++] = c;
594               else if (stridx == sizeof strbuf - 1)
595                 {
596                   strbuf[stridx] = 0;
597                   fputs ("input too large - truncated\n", stderr);
598                   stridx++;
599                 }
600             }
601         }
602       else if (state == 2) /* In a comment. */
603         {
604           if (c == '\n')
605             state = 0;
606         }
607
608     }
609
610   for (i = 0; i < stackidx; i++)
611     mpi_release (stack[i]);
612   return 0;
613 }