Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34385058
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
12 KB
Subscribers
None
View Options
diff --git a/src/mpicalc.c b/src/mpicalc.c
index dd852277..335b7c39 100644
--- a/src/mpicalc.c
+++ b/src/mpicalc.c
@@ -1,552 +1,554 @@
/* 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 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 = mpi_new (0);
if (stackidx < 2)
{
fputs ("stack underflow\n", stderr);
return;
}
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 = mpi_new (0);
if (stackidx < 2)
{
fputs ("stack underflow\n", stderr);
return;
}
mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]);
mpi_set (stack[stackidx - 2], a);
mpi_release (a);
stackidx--;
}
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 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"
"> 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"
"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 i, c;
int state = 0;
char strbuf[1000];
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",
pgm, gcry_check_version (NULL));
exit (0);
}
}
if (argc)
{
fprintf (stderr, "usage: %s [options] (--help for help)\n", pgm);
exit (1);
}
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'))
+ 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_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 '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;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 4, 5:43 AM (1 d, 17 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
de/ed/899fa52e9f8c43b5496703681be9
Attached To
rC libgcrypt
Event Timeline
Log In to Comment