diff options
Diffstat (limited to 'libotr/libgcrypt-1.8.7/src/mpicalc.c')
-rw-r--r-- | libotr/libgcrypt-1.8.7/src/mpicalc.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/src/mpicalc.c b/libotr/libgcrypt-1.8.7/src/mpicalc.c new file mode 100644 index 0000000..11246f3 --- /dev/null +++ b/libotr/libgcrypt-1.8.7/src/mpicalc.c @@ -0,0 +1,627 @@ +/* mpicalc.c - Simple RPN calculator using gcry_mpi functions + * Copyright (C) 1997, 1998, 1999, 2004, 2006, 2013 Werner Koch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This program is a simple RPN calculator which was originally used + to develop the mpi functions of GnuPG. Values must be given in + hex. Operation is like dc(1) except that the input/output radix is + always 16 and you can use a '-' to prefix a negative number. + Addition operators: ++ and --. All operators must be delimited by + a blank. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#ifdef _GCRYPT_IN_LIBGCRYPT +# undef _GCRYPT_IN_LIBGCRYPT +# include "gcrypt.h" +#else +# include <gcrypt.h> +#endif + + +#define MPICALC_VERSION "2.0" +#define NEED_LIBGCRYPT_VERSION "1.6.0" + +#define STACKSIZE 500 +static gcry_mpi_t stack[STACKSIZE]; +static int stackidx; + + +static int +scan_mpi (gcry_mpi_t retval, const char *string) +{ + gpg_error_t err; + gcry_mpi_t val; + + err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (err) + { + fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err)); + return -1; + } + mpi_set (retval, val); + mpi_release (val); + return 0; +} + + +static void +print_mpi (gcry_mpi_t a) +{ + gpg_error_t err; + char *buf; + void *bufaddr = &buf; + + err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); + if (err) + fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (err)); + else + { + fputs (buf, stdout); + gcry_free (buf); + } +} + + + +static void +do_add (void) +{ + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_add (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]); + stackidx--; +} + +static void +do_sub (void) +{ + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_sub (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]); + stackidx--; +} + +static void +do_inc (void) +{ + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_add_ui (stack[stackidx - 1], stack[stackidx - 1], 1); +} + +static void +do_dec (void) +{ + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */ +} + +static void +do_mul (void) +{ + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_mul (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]); + stackidx--; +} + +static void +do_mulm (void) +{ + if (stackidx < 3) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_mulm (stack[stackidx - 3], stack[stackidx - 3], + stack[stackidx - 2], stack[stackidx - 1]); + stackidx -= 2; +} + +static void +do_div (void) +{ + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_fdiv (stack[stackidx - 2], NULL, + stack[stackidx - 2], stack[stackidx - 1]); + stackidx--; +} + +static void +do_rem (void) +{ + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_mod (stack[stackidx - 2], + stack[stackidx - 2], stack[stackidx - 1]); + stackidx--; +} + +static void +do_powm (void) +{ + gcry_mpi_t a; + if (stackidx < 3) + { + fputs ("stack underflow\n", stderr); + return; + } + a = mpi_new (0); + mpi_powm (a, stack[stackidx - 3], stack[stackidx - 2], stack[stackidx - 1]); + mpi_release (stack[stackidx - 3]); + stack[stackidx - 3] = a; + stackidx -= 2; +} + +static void +do_inv (void) +{ + gcry_mpi_t a; + + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + a = mpi_new (0); + mpi_invm (a, stack[stackidx - 2], stack[stackidx - 1]); + mpi_set (stack[stackidx - 2], a); + mpi_release (a); + stackidx--; +} + +static void +do_gcd (void) +{ + gcry_mpi_t a; + + if (stackidx < 2) + { + fputs ("stack underflow\n", stderr); + return; + } + a = mpi_new (0); + mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]); + mpi_set (stack[stackidx - 2], a); + mpi_release (a); + stackidx--; +} + +static void +do_lshift (void) +{ + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_lshift (stack[stackidx - 1], stack[stackidx - 1], 1); +} + +static void +do_rshift (void) +{ + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + mpi_rshift (stack[stackidx - 1], stack[stackidx - 1], 1); +} + +static void +do_nbits (void) +{ + unsigned int n; + + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + n = mpi_get_nbits (stack[stackidx - 1]); + mpi_set_ui (stack[stackidx - 1], n); +} + + +static void +do_primecheck (void) +{ + gpg_error_t err; + + if (stackidx < 1) + { + fputs ("stack underflow\n", stderr); + return; + } + err = gcry_prime_check (stack[stackidx - 1], 0); + mpi_set_ui (stack[stackidx - 1], !err); + if (err && gpg_err_code (err) != GPG_ERR_NO_PRIME) + fprintf (stderr, "checking prime failed: %s\n", gpg_strerror (err)); +} + + +static int +my_getc (void) +{ + static int shown; + int c; + + for (;;) + { + if ((c = getc (stdin)) == EOF) + return EOF; + if (!(c & 0x80)) + return c; + + if (!shown) + { + shown = 1; + fputs ("note: Non ASCII characters are ignored\n", stderr); + } + } +} + + +static void +print_help (void) +{ + fputs ("+ add [0] := [1] + [0] {-1}\n" + "- subtract [0] := [1] - [0] {-1}\n" + "* multiply [0] := [1] * [0] {-1}\n" + "/ divide [0] := [1] - [0] {-1}\n" + "% modulo [0] := [1] % [0] {-1}\n" + "< left shift [0] := [0] << 1 {0}\n" + "> right shift [0] := [0] >> 1 {0}\n" + "++ increment [0] := [0]++ {0}\n" + "-- decrement [0] := [0]-- {0}\n" + "m multiply mod [0] := [2] * [1] mod [0] {-2}\n" + "^ power mod [0] := [2] ^ [1] mod [0] {-2}\n" + "I inverse mod [0] := [1]^-1 mod [0] {-1}\n" + "G gcd [0] := gcd([1],[0]) {-1}\n" + "i remove item [0] := [1] {-1}\n" + "d dup item [-1] := [0] {+1}\n" + "r reverse [0] := [1], [1] := [0] {0}\n" + "b # of bits [0] := nbits([0]) {0}\n" + "P prime check [0] := is_prime([0])?1:0 {0}\n" + "c clear stack\n" + "p print top item\n" + "f print the stack\n" + "# ignore until end of line\n" + "? print this help\n" + , stdout); +} + + + +int +main (int argc, char **argv) +{ + const char *pgm; + int last_argc = -1; + int print_config = 0; + int i, c; + int state = 0; + char strbuf[4096]; + int stridx = 0; + + if (argc) + { + pgm = strrchr (*argv, '/'); + if (pgm) + pgm++; + else + pgm = *argv; + argc--; argv++; + } + else + pgm = "?"; + + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--version") + || !strcmp (*argv, "--help")) + { + printf ("%s " MPICALC_VERSION "\n" + "libgcrypt %s\n" + "Copyright (C) 1997, 2013 Werner Koch\n" + "License LGPLv2.1+: GNU LGPL version 2.1 or later " + "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n" + "This is free software: you are free to change and " + "redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" + "\n" + "Syntax: mpicalc [options]\n" + "Simple interactive big integer RPN calculator\n" + "\n" + "Options:\n" + " --version print version information\n" + " --print-config print the Libgcrypt config\n" + " --disable-hwf NAME disable feature NAME\n", + pgm, gcry_check_version (NULL)); + exit (0); + } + else if (!strcmp (*argv, "--print-config")) + { + argc--; argv++; + print_config = 1; + } + else if (!strcmp (*argv, "--disable-hwf")) + { + argc--; argv++; + if (argc) + { + if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL)) + fprintf (stderr, "%s: unknown hardware feature `%s'" + " - option ignored\n", pgm, *argv); + argc--; argv++; + } + } + } + + if (argc) + { + fprintf (stderr, "usage: %s [options] (--help for help)\n", pgm); + exit (1); + } + + if (!gcry_check_version (NEED_LIBGCRYPT_VERSION)) + { + fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n", + pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); + exit (1); + } + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + if (print_config) + { + gcry_control (GCRYCTL_PRINT_CONFIG, stdout); + exit (0); + } + + for (i = 0; i < STACKSIZE; i++) + stack[i] = NULL; + stackidx = 0; + + while ((c = my_getc ()) != EOF) + { + if (!state) /* waiting */ + { + if (isdigit (c)) + { + state = 1; + ungetc (c, stdin); + strbuf[0] = '0'; + strbuf[1] = 'x'; + stridx = 2; + } + else if (isspace (c)) + ; + else + { + switch (c) + { + case '#': + state = 2; + break; + case '+': + if ((c = my_getc ()) == '+') + do_inc (); + else + { + ungetc (c, stdin); + do_add (); + } + break; + case '-': + if ((c = my_getc ()) == '-') + do_dec (); + else if (isdigit (c) + || (c >= 'A' && c <= 'F') + || (c >= 'a' && c <= 'f')) + { + state = 1; + ungetc (c, stdin); + strbuf[0] = '-'; + strbuf[1] = '0'; + strbuf[2] = 'x'; + stridx = 3; + } + else + { + ungetc (c, stdin); + do_sub (); + } + break; + case '*': + do_mul (); + break; + case 'm': + do_mulm (); + break; + case '/': + do_div (); + break; + case '%': + do_rem (); + break; + case '^': + do_powm (); + break; + case '<': + do_lshift (); + break; + case '>': + do_rshift (); + break; + case 'I': + do_inv (); + break; + case 'G': + do_gcd (); + break; + case 'i': /* dummy */ + if (!stackidx) + fputs ("stack underflow\n", stderr); + else + { + mpi_release (stack[stackidx - 1]); + stackidx--; + } + break; + case 'd': /* duplicate the tos */ + if (!stackidx) + fputs ("stack underflow\n", stderr); + else if (stackidx < STACKSIZE) + { + mpi_release (stack[stackidx]); + stack[stackidx] = mpi_copy (stack[stackidx - 1]); + stackidx++; + } + else + fputs ("stack overflow\n", stderr); + break; + case 'r': /* swap top elements */ + if (stackidx < 2) + fputs ("stack underflow\n", stderr); + else if (stackidx < STACKSIZE) + { + gcry_mpi_t tmp = stack[stackidx-1]; + stack[stackidx-1] = stack[stackidx - 2]; + stack[stackidx-2] = tmp; + } + break; + case 'b': + do_nbits (); + break; + case 'P': + do_primecheck (); + break; + case 'c': + for (i = 0; i < stackidx; i++) + { + mpi_release (stack[i]); stack[i] = NULL; + } + stackidx = 0; + break; + case 'p': /* print the tos */ + if (!stackidx) + puts ("stack is empty"); + else + { + print_mpi (stack[stackidx - 1]); + putchar ('\n'); + } + break; + case 'f': /* print the stack */ + for (i = stackidx - 1; i >= 0; i--) + { + printf ("[%2d]: ", i); + print_mpi (stack[i]); + putchar ('\n'); + } + break; + case '?': + print_help (); + break; + default: + fputs ("invalid operator\n", stderr); + } + } + } + else if (state == 1) /* In a number. */ + { + if (!isxdigit (c)) + { + /* Store the number */ + state = 0; + ungetc (c, stdin); + if (stridx < sizeof strbuf) + strbuf[stridx] = 0; + + if (stackidx < STACKSIZE) + { + if (!stack[stackidx]) + stack[stackidx] = mpi_new (0); + if (scan_mpi (stack[stackidx], strbuf)) + fputs ("invalid number\n", stderr); + else + stackidx++; + } + else + fputs ("stack overflow\n", stderr); + } + else + { /* Store a digit. */ + if (stridx < sizeof strbuf - 1) + strbuf[stridx++] = c; + else if (stridx == sizeof strbuf - 1) + { + strbuf[stridx] = 0; + fputs ("input too large - truncated\n", stderr); + stridx++; + } + } + } + else if (state == 2) /* In a comment. */ + { + if (c == '\n') + state = 0; + } + + } + + for (i = 0; i < stackidx; i++) + mpi_release (stack[i]); + return 0; +} |