LCOV - code coverage report
Current view: top level - src - mpicalc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 275 0.0 %
Date: 2017-03-02 16:44:37 Functions: 0 19 0.0 %

          Line data    Source code
       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           0 : scan_mpi (gcry_mpi_t retval, const char *string)
      52             : {
      53             :   gpg_error_t err;
      54             :   gcry_mpi_t val;
      55             : 
      56           0 :   err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
      57           0 :   if (err)
      58             :     {
      59           0 :       fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err));
      60           0 :       return -1;
      61             :     }
      62           0 :   mpi_set (retval, val);
      63           0 :   mpi_release (val);
      64           0 :   return 0;
      65             : }
      66             : 
      67             : 
      68             : static void
      69           0 : print_mpi (gcry_mpi_t a)
      70             : {
      71             :   gpg_error_t err;
      72             :   char *buf;
      73           0 :   void *bufaddr = &buf;
      74             : 
      75           0 :   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
      76           0 :   if (err)
      77           0 :     fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (err));
      78             :   else
      79             :     {
      80           0 :       fputs (buf, stdout);
      81           0 :       gcry_free (buf);
      82             :     }
      83           0 : }
      84             : 
      85             : 
      86             : 
      87             : static void
      88           0 : do_add (void)
      89             : {
      90           0 :   if (stackidx < 2)
      91             :     {
      92           0 :       fputs ("stack underflow\n", stderr);
      93           0 :       return;
      94             :     }
      95           0 :   mpi_add (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
      96           0 :   stackidx--;
      97             : }
      98             : 
      99             : static void
     100           0 : do_sub (void)
     101             : {
     102           0 :   if (stackidx < 2)
     103             :     {
     104           0 :       fputs ("stack underflow\n", stderr);
     105           0 :       return;
     106             :     }
     107           0 :   mpi_sub (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
     108           0 :   stackidx--;
     109             : }
     110             : 
     111             : static void
     112           0 : do_inc (void)
     113             : {
     114           0 :   if (stackidx < 1)
     115             :     {
     116           0 :       fputs ("stack underflow\n", stderr);
     117           0 :       return;
     118             :     }
     119           0 :   mpi_add_ui (stack[stackidx - 1], stack[stackidx - 1], 1);
     120             : }
     121             : 
     122             : static void
     123           0 : do_dec (void)
     124             : {
     125           0 :   if (stackidx < 1)
     126             :     {
     127           0 :       fputs ("stack underflow\n", stderr);
     128           0 :       return;
     129             :     }
     130             :   /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
     131             : }
     132             : 
     133             : static void
     134           0 : do_mul (void)
     135             : {
     136           0 :   if (stackidx < 2)
     137             :     {
     138           0 :       fputs ("stack underflow\n", stderr);
     139           0 :       return;
     140             :     }
     141           0 :   mpi_mul (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
     142           0 :   stackidx--;
     143             : }
     144             : 
     145             : static void
     146           0 : do_mulm (void)
     147             : {
     148           0 :   if (stackidx < 3)
     149             :     {
     150           0 :       fputs ("stack underflow\n", stderr);
     151           0 :       return;
     152             :     }
     153           0 :   mpi_mulm (stack[stackidx - 3], stack[stackidx - 3],
     154             :             stack[stackidx - 2], stack[stackidx - 1]);
     155           0 :   stackidx -= 2;
     156             : }
     157             : 
     158             : static void
     159           0 : do_div (void)
     160             : {
     161           0 :   if (stackidx < 2)
     162             :     {
     163           0 :       fputs ("stack underflow\n", stderr);
     164           0 :       return;
     165             :     }
     166           0 :   mpi_fdiv (stack[stackidx - 2], NULL,
     167             :             stack[stackidx - 2], stack[stackidx - 1]);
     168           0 :   stackidx--;
     169             : }
     170             : 
     171             : static void
     172           0 : do_rem (void)
     173             : {
     174           0 :   if (stackidx < 2)
     175             :     {
     176           0 :       fputs ("stack underflow\n", stderr);
     177           0 :       return;
     178             :     }
     179           0 :   mpi_mod (stack[stackidx - 2],
     180             :            stack[stackidx - 2], stack[stackidx - 1]);
     181           0 :   stackidx--;
     182             : }
     183             : 
     184             : static void
     185           0 : do_powm (void)
     186             : {
     187             :   gcry_mpi_t a;
     188           0 :   if (stackidx < 3)
     189             :     {
     190           0 :       fputs ("stack underflow\n", stderr);
     191           0 :       return;
     192             :     }
     193           0 :   a = mpi_new (0);
     194           0 :   mpi_powm (a, stack[stackidx - 3], stack[stackidx - 2], stack[stackidx - 1]);
     195           0 :   mpi_release (stack[stackidx - 3]);
     196           0 :   stack[stackidx - 3] = a;
     197           0 :   stackidx -= 2;
     198             : }
     199             : 
     200             : static void
     201           0 : do_inv (void)
     202             : {
     203             :   gcry_mpi_t a;
     204             : 
     205           0 :   if (stackidx < 2)
     206             :     {
     207           0 :       fputs ("stack underflow\n", stderr);
     208           0 :       return;
     209             :     }
     210           0 :   a = mpi_new (0);
     211           0 :   mpi_invm (a, stack[stackidx - 2], stack[stackidx - 1]);
     212           0 :   mpi_set (stack[stackidx - 2], a);
     213           0 :   mpi_release (a);
     214           0 :   stackidx--;
     215             : }
     216             : 
     217             : static void
     218           0 : do_gcd (void)
     219             : {
     220             :   gcry_mpi_t a;
     221             : 
     222           0 :   if (stackidx < 2)
     223             :     {
     224           0 :       fputs ("stack underflow\n", stderr);
     225           0 :       return;
     226             :     }
     227           0 :   a = mpi_new (0);
     228           0 :   mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]);
     229           0 :   mpi_set (stack[stackidx - 2], a);
     230           0 :   mpi_release (a);
     231           0 :   stackidx--;
     232             : }
     233             : 
     234             : static void
     235           0 : do_rshift (void)
     236             : {
     237           0 :   if (stackidx < 1)
     238             :     {
     239           0 :       fputs ("stack underflow\n", stderr);
     240           0 :       return;
     241             :     }
     242           0 :   mpi_rshift (stack[stackidx - 1], stack[stackidx - 1], 1);
     243             : }
     244             : 
     245             : 
     246             : static void
     247           0 : do_nbits (void)
     248             : {
     249             :   unsigned int n;
     250             : 
     251           0 :   if (stackidx < 1)
     252             :     {
     253           0 :       fputs ("stack underflow\n", stderr);
     254           0 :       return;
     255             :     }
     256           0 :   n = mpi_get_nbits (stack[stackidx - 1]);
     257           0 :   mpi_set_ui (stack[stackidx - 1], n);
     258             : }
     259             : 
     260             : 
     261             : static void
     262           0 : do_primecheck (void)
     263             : {
     264             :   gpg_error_t err;
     265             : 
     266           0 :   if (stackidx < 1)
     267             :     {
     268           0 :       fputs ("stack underflow\n", stderr);
     269           0 :       return;
     270             :     }
     271           0 :   err = gcry_prime_check (stack[stackidx - 1], 0);
     272           0 :   mpi_set_ui (stack[stackidx - 1], !err);
     273           0 :   if (err && gpg_err_code (err) != GPG_ERR_NO_PRIME)
     274           0 :     fprintf (stderr, "checking prime failed: %s\n", gpg_strerror (err));
     275             : }
     276             : 
     277             : 
     278             : static int
     279           0 : my_getc (void)
     280             : {
     281             :   static int shown;
     282             :   int c;
     283             : 
     284             :   for (;;)
     285             :     {
     286           0 :       if ((c = getc (stdin)) == EOF)
     287           0 :         return EOF;
     288           0 :       if (!(c & 0x80))
     289           0 :         return c;
     290             : 
     291           0 :       if (!shown)
     292             :         {
     293           0 :           shown = 1;
     294           0 :           fputs ("note: Non ASCII characters are ignored\n", stderr);
     295             :         }
     296             :     }
     297             : }
     298             : 
     299             : 
     300             : static void
     301           0 : print_help (void)
     302             : {
     303           0 :   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           0 : }
     327             : 
     328             : 
     329             : 
     330             : int
     331           0 : main (int argc, char **argv)
     332             : {
     333             :   const char *pgm;
     334           0 :   int last_argc = -1;
     335           0 :   int print_config = 0;
     336             :   int i, c;
     337           0 :   int state = 0;
     338             :   char strbuf[4096];
     339           0 :   int stridx = 0;
     340             : 
     341           0 :   if (argc)
     342             :     {
     343           0 :       pgm = strrchr (*argv, '/');
     344           0 :       if (pgm)
     345           0 :         pgm++;
     346             :       else
     347           0 :         pgm = *argv;
     348           0 :       argc--; argv++;
     349             :     }
     350             :   else
     351           0 :     pgm = "?";
     352             : 
     353           0 :   while (argc && last_argc != argc )
     354             :     {
     355           0 :       last_argc = argc;
     356           0 :       if (!strcmp (*argv, "--"))
     357             :         {
     358           0 :           argc--; argv++;
     359           0 :           break;
     360             :         }
     361           0 :       else if (!strcmp (*argv, "--version")
     362           0 :                || !strcmp (*argv, "--help"))
     363             :         {
     364           0 :           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           0 :           exit (0);
     382             :         }
     383           0 :       else if (!strcmp (*argv, "--print-config"))
     384             :         {
     385           0 :           argc--; argv++;
     386           0 :           print_config = 1;
     387             :         }
     388           0 :       else if (!strcmp (*argv, "--disable-hwf"))
     389             :         {
     390           0 :           argc--; argv++;
     391           0 :           if (argc)
     392             :             {
     393           0 :               if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
     394           0 :                 fprintf (stderr, "%s: unknown hardware feature `%s'"
     395             :                          " - option ignored\n", pgm, *argv);
     396           0 :               argc--; argv++;
     397             :             }
     398             :         }
     399             :     }
     400             : 
     401           0 :   if (argc)
     402             :     {
     403           0 :       fprintf (stderr, "usage: %s [options]  (--help for help)\n", pgm);
     404           0 :       exit (1);
     405             :     }
     406             : 
     407           0 :   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
     408             :     {
     409           0 :       fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
     410             :                pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     411           0 :       exit (1);
     412             :     }
     413           0 :   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
     414           0 :   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
     415           0 :   if (print_config)
     416             :     {
     417           0 :       gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
     418           0 :       exit (0);
     419             :     }
     420             : 
     421           0 :   for (i = 0; i < STACKSIZE; i++)
     422           0 :     stack[i] = NULL;
     423           0 :   stackidx = 0;
     424             : 
     425           0 :   while ((c = my_getc ()) != EOF)
     426             :     {
     427           0 :       if (!state) /* waiting */
     428             :         {
     429           0 :           if (isdigit (c))
     430             :             {
     431           0 :               state = 1;
     432           0 :               ungetc (c, stdin);
     433           0 :               strbuf[0] = '0';
     434           0 :               strbuf[1] = 'x';
     435           0 :               stridx = 2;
     436             :             }
     437           0 :           else if (isspace (c))
     438             :             ;
     439             :           else
     440             :             {
     441           0 :               switch (c)
     442             :                 {
     443             :                 case '#':
     444           0 :                   state = 2;
     445           0 :                   break;
     446             :                 case '+':
     447           0 :                   if ((c = my_getc ()) == '+')
     448           0 :                     do_inc ();
     449             :                   else
     450             :                     {
     451           0 :                       ungetc (c, stdin);
     452           0 :                       do_add ();
     453             :                     }
     454           0 :                   break;
     455             :                 case '-':
     456           0 :                   if ((c = my_getc ()) == '-')
     457           0 :                     do_dec ();
     458           0 :                   else if (isdigit (c)
     459           0 :                            || (c >= 'A' && c <= 'F')
     460           0 :                            || (c >= 'a' && c <= 'f'))
     461             :                     {
     462           0 :                       state = 1;
     463           0 :                       ungetc (c, stdin);
     464           0 :                       strbuf[0] = '-';
     465           0 :                       strbuf[1] = '0';
     466           0 :                       strbuf[2] = 'x';
     467           0 :                       stridx = 3;
     468             :                     }
     469             :                   else
     470             :                     {
     471           0 :                       ungetc (c, stdin);
     472           0 :                       do_sub ();
     473             :                     }
     474           0 :                   break;
     475             :                 case '*':
     476           0 :                   do_mul ();
     477           0 :                   break;
     478             :                 case 'm':
     479           0 :                   do_mulm ();
     480           0 :                   break;
     481             :                 case '/':
     482           0 :                   do_div ();
     483           0 :                   break;
     484             :                 case '%':
     485           0 :                   do_rem ();
     486           0 :                   break;
     487             :                 case '^':
     488           0 :                   do_powm ();
     489           0 :                   break;
     490             :                 case '>':
     491           0 :                   do_rshift ();
     492           0 :                   break;
     493             :                 case 'I':
     494           0 :                   do_inv ();
     495           0 :                   break;
     496             :                 case 'G':
     497           0 :                   do_gcd ();
     498           0 :                   break;
     499             :                 case 'i':       /* dummy */
     500           0 :                   if (!stackidx)
     501           0 :                     fputs ("stack underflow\n", stderr);
     502             :                   else
     503             :                     {
     504           0 :                       mpi_release (stack[stackidx - 1]);
     505           0 :                       stackidx--;
     506             :                     }
     507           0 :                   break;
     508             :                 case 'd':       /* duplicate the tos */
     509           0 :                   if (!stackidx)
     510           0 :                     fputs ("stack underflow\n", stderr);
     511           0 :                   else if (stackidx < STACKSIZE)
     512             :                     {
     513           0 :                       mpi_release (stack[stackidx]);
     514           0 :                       stack[stackidx] = mpi_copy (stack[stackidx - 1]);
     515           0 :                       stackidx++;
     516             :                     }
     517             :                   else
     518           0 :                     fputs ("stack overflow\n", stderr);
     519           0 :                   break;
     520             :                 case 'r':       /* swap top elements */
     521           0 :                   if (stackidx < 2)
     522           0 :                     fputs ("stack underflow\n", stderr);
     523           0 :                   else if (stackidx < STACKSIZE)
     524             :                     {
     525           0 :                       gcry_mpi_t tmp = stack[stackidx-1];
     526           0 :                       stack[stackidx-1] = stack[stackidx - 2];
     527           0 :                       stack[stackidx-2] = tmp;
     528             :                     }
     529           0 :                   break;
     530             :                 case 'b':
     531           0 :                   do_nbits ();
     532           0 :                   break;
     533             :                 case 'P':
     534           0 :                   do_primecheck ();
     535           0 :                   break;
     536             :                 case 'c':
     537           0 :                   for (i = 0; i < stackidx; i++)
     538             :                     {
     539           0 :                       mpi_release (stack[i]); stack[i] = NULL;
     540             :                     }
     541           0 :                   stackidx = 0;
     542           0 :                   break;
     543             :                 case 'p':       /* print the tos */
     544           0 :                   if (!stackidx)
     545           0 :                     puts ("stack is empty");
     546             :                   else
     547             :                     {
     548           0 :                       print_mpi (stack[stackidx - 1]);
     549           0 :                       putchar ('\n');
     550             :                     }
     551           0 :                   break;
     552             :                 case 'f':       /* print the stack */
     553           0 :                   for (i = stackidx - 1; i >= 0; i--)
     554             :                     {
     555           0 :                       printf ("[%2d]: ", i);
     556           0 :                       print_mpi (stack[i]);
     557           0 :                       putchar ('\n');
     558             :                     }
     559           0 :                   break;
     560             :                 case '?':
     561           0 :                   print_help ();
     562           0 :                   break;
     563             :                 default:
     564           0 :                   fputs ("invalid operator\n", stderr);
     565             :                 }
     566             :             }
     567             :         }
     568           0 :       else if (state == 1) /* In a number. */
     569             :         {
     570           0 :           if (!isxdigit (c))
     571             :             {
     572             :               /* Store the number */
     573           0 :               state = 0;
     574           0 :               ungetc (c, stdin);
     575           0 :               if (stridx < sizeof strbuf)
     576           0 :                 strbuf[stridx] = 0;
     577             : 
     578           0 :               if (stackidx < STACKSIZE)
     579             :                 {
     580           0 :                   if (!stack[stackidx])
     581           0 :                     stack[stackidx] = mpi_new (0);
     582           0 :                   if (scan_mpi (stack[stackidx], strbuf))
     583           0 :                     fputs ("invalid number\n", stderr);
     584             :                   else
     585           0 :                     stackidx++;
     586             :                 }
     587             :               else
     588           0 :                 fputs ("stack overflow\n", stderr);
     589             :             }
     590             :           else
     591             :             { /* Store a digit.  */
     592           0 :               if (stridx < sizeof strbuf - 1)
     593           0 :                 strbuf[stridx++] = c;
     594           0 :               else if (stridx == sizeof strbuf - 1)
     595             :                 {
     596           0 :                   strbuf[stridx] = 0;
     597           0 :                   fputs ("input too large - truncated\n", stderr);
     598           0 :                   stridx++;
     599             :                 }
     600             :             }
     601             :         }
     602           0 :       else if (state == 2) /* In a comment. */
     603             :         {
     604           0 :           if (c == '\n')
     605           0 :             state = 0;
     606             :         }
     607             : 
     608             :     }
     609             : 
     610           0 :   for (i = 0; i < stackidx; i++)
     611           0 :     mpi_release (stack[i]);
     612           0 :   return 0;
     613             : }

Generated by: LCOV version 1.13