Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F32914222
mpicalc.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
12 KB
Subscribers
None
mpicalc.c
View Options
/* 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
=
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
print_config
=
0
;
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
"
" --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_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-c
Expires
Mon, Nov 17, 9:26 PM (1 d, 10 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2a/a4/b05a648b4bb673045d8445174833
Attached To
rC libgcrypt
Event Timeline
Log In to Comment