1 /* mpicalc.c - Simple RPN calculator using gcry_mpi functions
2 * Copyright (C) 1997, 1998, 1999, 2004, 2006, 2013 Werner Koch
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.
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.
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/>.
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
34 #ifdef _GCRYPT_IN_LIBGCRYPT
35 # undef _GCRYPT_IN_LIBGCRYPT
42 #define MPICALC_VERSION "2.0"
43 #define NEED_LIBGCRYPT_VERSION "1.6.0"
46 static gcry_mpi_t stack[STACKSIZE];
51 scan_mpi (gcry_mpi_t retval, const char *string)
56 err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
59 fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err));
62 mpi_set (retval, val);
69 print_mpi (gcry_mpi_t a)
75 err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
77 fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (err));
92 fputs ("stack underflow\n", stderr);
95 mpi_add (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
104 fputs ("stack underflow\n", stderr);
107 mpi_sub (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
116 fputs ("stack underflow\n", stderr);
119 mpi_add_ui (stack[stackidx - 1], stack[stackidx - 1], 1);
127 fputs ("stack underflow\n", stderr);
130 /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
138 fputs ("stack underflow\n", stderr);
141 mpi_mul (stack[stackidx - 2], stack[stackidx - 2], stack[stackidx - 1]);
150 fputs ("stack underflow\n", stderr);
153 mpi_mulm (stack[stackidx - 3], stack[stackidx - 3],
154 stack[stackidx - 2], stack[stackidx - 1]);
163 fputs ("stack underflow\n", stderr);
166 mpi_fdiv (stack[stackidx - 2], NULL,
167 stack[stackidx - 2], stack[stackidx - 1]);
176 fputs ("stack underflow\n", stderr);
179 mpi_mod (stack[stackidx - 2],
180 stack[stackidx - 2], stack[stackidx - 1]);
190 fputs ("stack underflow\n", stderr);
194 mpi_powm (a, stack[stackidx - 3], stack[stackidx - 2], stack[stackidx - 1]);
195 mpi_release (stack[stackidx - 3]);
196 stack[stackidx - 3] = a;
203 gcry_mpi_t a = mpi_new (0);
206 fputs ("stack underflow\n", stderr);
209 mpi_invm (a, stack[stackidx - 2], stack[stackidx - 1]);
210 mpi_set (stack[stackidx - 2], a);
218 gcry_mpi_t a = mpi_new (0);
221 fputs ("stack underflow\n", stderr);
224 mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]);
225 mpi_set (stack[stackidx - 2], a);
235 fputs ("stack underflow\n", stderr);
238 mpi_rshift (stack[stackidx - 1], stack[stackidx - 1], 1);
249 fputs ("stack underflow\n", stderr);
252 n = mpi_get_nbits (stack[stackidx - 1]);
253 mpi_set_ui (stack[stackidx - 1], n);
264 fputs ("stack underflow\n", stderr);
267 err = gcry_prime_check (stack[stackidx - 1], 0);
268 mpi_set_ui (stack[stackidx - 1], !err);
269 if (err && gpg_err_code (err) != GPG_ERR_NO_PRIME)
270 fprintf (stderr, "checking prime failed: %s\n", gpg_strerror (err));
282 if ((c = getc (stdin)) == EOF)
290 fputs ("note: Non ASCII characters are ignored\n", stderr);
299 fputs ("+ add [0] := [1] + [0] {-1}\n"
300 "- subtract [0] := [1] - [0] {-1}\n"
301 "* multiply [0] := [1] * [0] {-1}\n"
302 "/ divide [0] := [1] - [0] {-1}\n"
303 "% modulo [0] := [1] % [0] {-1}\n"
304 "> right shift [0] := [0] >> 1 {0}\n"
305 "++ increment [0] := [0]++ {0}\n"
306 "-- decrement [0] := [0]-- {0}\n"
307 "m multiply mod [0] := [2] * [1] mod [0] {-2}\n"
308 "^ power mod [0] := [2] ^ [1] mod [0] {-2}\n"
309 "I inverse mod [0] := [1]^-1 mod [0] {-1}\n"
310 "G gcd [0] := gcd([1],[0]) {-1}\n"
311 "i remove item [0] := [1] {-1}\n"
312 "d dup item [-1] := [0] {+1}\n"
313 "r reverse [0] := [1], [1] := [0] {0}\n"
314 "b # of bits [0] := nbits([0]) {0}\n"
315 "P prime check [0] := is_prime([0])?1:0 {0}\n"
318 "f print the stack\n"
319 "# ignore until end of line\n"
320 "? print this help\n"
327 main (int argc, char **argv)
331 int print_config = 0;
339 pgm = strrchr (*argv, '/');
349 while (argc && last_argc != argc )
352 if (!strcmp (*argv, "--"))
357 else if (!strcmp (*argv, "--version")
358 || !strcmp (*argv, "--help"))
360 printf ("%s " MPICALC_VERSION "\n"
362 "Copyright (C) 1997, 2013 Werner Koch\n"
363 "License LGPLv2.1+: GNU LGPL version 2.1 or later "
364 "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n"
365 "This is free software: you are free to change and "
367 "There is NO WARRANTY, to the extent permitted by law.\n"
369 "Syntax: mpicalc [options]\n"
370 "Simple interactive big integer RPN calculator\n"
373 " --version print version information\n"
374 " --print-config print the Libgcrypt config\n"
375 " --disable-hwf NAME disable feature NAME\n",
376 pgm, gcry_check_version (NULL));
379 else if (!strcmp (*argv, "--print-config"))
384 else if (!strcmp (*argv, "--disable-hwf"))
389 if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
390 fprintf (stderr, "%s: unknown hardware feature `%s'"
391 " - option ignored\n", pgm, *argv);
399 fprintf (stderr, "usage: %s [options] (--help for help)\n", pgm);
403 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
405 fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
406 pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
409 gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
410 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
413 gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
417 for (i = 0; i < STACKSIZE; i++)
421 while ((c = my_getc ()) != EOF)
423 if (!state) /* waiting */
433 else if (isspace (c))
443 if ((c = my_getc ()) == '+')
452 if ((c = my_getc ()) == '-')
455 || (c >= 'A' && c <= 'F')
456 || (c >= 'a' && c <= 'f'))
495 case 'i': /* dummy */
497 fputs ("stack underflow\n", stderr);
500 mpi_release (stack[stackidx - 1]);
504 case 'd': /* duplicate the tos */
506 fputs ("stack underflow\n", stderr);
507 else if (stackidx < STACKSIZE)
509 mpi_release (stack[stackidx]);
510 stack[stackidx] = mpi_copy (stack[stackidx - 1]);
514 fputs ("stack overflow\n", stderr);
516 case 'r': /* swap top elements */
518 fputs ("stack underflow\n", stderr);
519 else if (stackidx < STACKSIZE)
521 gcry_mpi_t tmp = stack[stackidx-1];
522 stack[stackidx-1] = stack[stackidx - 2];
523 stack[stackidx-2] = tmp;
533 for (i = 0; i < stackidx; i++)
535 mpi_release (stack[i]); stack[i] = NULL;
539 case 'p': /* print the tos */
541 puts ("stack is empty");
544 print_mpi (stack[stackidx - 1]);
548 case 'f': /* print the stack */
549 for (i = stackidx - 1; i >= 0; i--)
551 printf ("[%2d]: ", i);
552 print_mpi (stack[i]);
560 fputs ("invalid operator\n", stderr);
564 else if (state == 1) /* In a number. */
568 /* Store the number */
571 if (stridx < sizeof strbuf)
574 if (stackidx < STACKSIZE)
576 if (!stack[stackidx])
577 stack[stackidx] = mpi_new (0);
578 if (scan_mpi (stack[stackidx], strbuf))
579 fputs ("invalid number\n", stderr);
584 fputs ("stack overflow\n", stderr);
587 { /* Store a digit. */
588 if (stridx < sizeof strbuf - 1)
589 strbuf[stridx++] = c;
590 else if (stridx == sizeof strbuf - 1)
593 fputs ("input too large - truncated\n", stderr);
598 else if (state == 2) /* In a comment. */
606 for (i = 0; i < stackidx; i++)
607 mpi_release (stack[i]);