aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2023-03-10 10:33:33 +0000
committerStefan Eßer <se@FreeBSD.org>2023-03-10 10:33:33 +0000
commit175a4d10428e1c2f26f1426003757daf25d4726f (patch)
tree59ad09c74c6dcbc99cac0e388e42ffdff76845b8
parentcc0fe048ec39636216ed59fa47eb311b2537cfc5 (diff)
downloadsrc-175a4d10428e1c2f26f1426003757daf25d4726f.tar.gz
src-175a4d10428e1c2f26f1426003757daf25d4726f.zip
contrib/bc: update to version 6.4.0
This version contains a fix for an issue that can affect complex bc scripts that use multiple read() functions that receive input from an interactive user. The same value could be returned multiple times. MFC after: 2 weeks
-rw-r--r--contrib/bc/Makefile.in2
-rw-r--r--contrib/bc/NEWS.md19
-rwxr-xr-xcontrib/bc/configure.sh2
-rw-r--r--contrib/bc/include/bcl.h51
-rw-r--r--contrib/bc/include/library.h210
-rw-r--r--contrib/bc/include/program.h210
-rw-r--r--contrib/bc/include/version.h2
-rw-r--r--contrib/bc/include/vm.h4
-rw-r--r--contrib/bc/manuals/bcl.3422
-rw-r--r--contrib/bc/manuals/bcl.3.md320
-rw-r--r--contrib/bc/src/data.c75
-rw-r--r--contrib/bc/src/library.c739
-rw-r--r--contrib/bc/src/program.c13
-rw-r--r--contrib/bc/src/vm.c2
-rw-r--r--contrib/bc/tests/bcl.c52
-rwxr-xr-xcontrib/bc/tests/read.sh13
16 files changed, 1693 insertions, 443 deletions
diff --git a/contrib/bc/Makefile.in b/contrib/bc/Makefile.in
index 89ddb7589c47..f936fc2c6de6 100644
--- a/contrib/bc/Makefile.in
+++ b/contrib/bc/Makefile.in
@@ -536,7 +536,6 @@ clean:%%CLEAN_PREREQS%%
@$(RM) -f $(BC_HELP_C) $(BC_HELP_O)
@$(RM) -f $(DC_HELP_C) $(DC_HELP_O)
@$(RM) -fr vs/bin/ vs/lib/
- @$(RM) -f $(BCL_PC)
clean_benchmarks:
@printf 'Cleaning benchmarks...\n'
@@ -550,6 +549,7 @@ clean_config: clean clean_benchmarks
@$(RM) -f $(BC_MD) $(BC_MANPAGE)
@$(RM) -f $(DC_MD) $(DC_MANPAGE)
@$(RM) -f compile_commands.json
+ @$(RM) -f $(BCL_PC)
clean_coverage:
@printf 'Cleaning coverage files...\n'
diff --git a/contrib/bc/NEWS.md b/contrib/bc/NEWS.md
index ad118e401c32..6dff6822fb16 100644
--- a/contrib/bc/NEWS.md
+++ b/contrib/bc/NEWS.md
@@ -1,5 +1,24 @@
# News
+## 6.4.0
+
+This is a production release that fixes a `read()`/`?` bug and adds features to
+`bcl`.
+
+The bug was that multiple read calls could repeat old data.
+
+The new features in `bcl` are functions to preserve `BclNumber` arguments and
+not free them.
+
+***WARNING for `bcl` Users***: The `bcl_rand_seedWithNum()` function used to not
+consume its arguments. Now it does. This change could have made this version
+`7.0.0`, but I'm 99.9% confident that there are no `bcl` users, or if there are,
+they probably don't use the PRNG. So I took a risk and didn't update the major
+version.
+
+`bcl` now includes more capacity to check for invalid numbers when built to run
+under Valgrind.
+
## 6.3.1
This is a production release that fixes a `bc` dependency loop for minimal
diff --git a/contrib/bc/configure.sh b/contrib/bc/configure.sh
index 3ada5298e9ed..021d30807ffb 100755
--- a/contrib/bc/configure.sh
+++ b/contrib/bc/configure.sh
@@ -1801,7 +1801,7 @@ if [ "$library" -ne 0 ]; then
contents=$(replace "$contents" "LIBDIR" "$LIBDIR")
contents=$(replace "$contents" "VERSION" "$version")
- printf '%s\n' "$contents" > "./bcl.pc"
+ printf '%s\n' "$contents" > "$scriptdir/bcl.pc"
pkg_config_install="\$(SAFE_INSTALL) \$(PC_INSTALL_ARGS) \"\$(BCL_PC)\" \"\$(DESTDIR)\$(PC_PATH)/\$(BCL_PC)\""
pkg_config_uninstall="\$(RM) -f \"\$(DESTDIR)\$(PC_PATH)/\$(BCL_PC)\""
diff --git a/contrib/bc/include/bcl.h b/contrib/bc/include/bcl.h
index 253138231c66..0908e215182c 100644
--- a/contrib/bc/include/bcl.h
+++ b/contrib/bc/include/bcl.h
@@ -36,6 +36,9 @@
#ifndef BC_BCL_H
#define BC_BCL_H
+// TODO: Add a generation index when building with Valgrind to check for
+// use-after-free's or double frees.
+
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
@@ -238,6 +241,9 @@ bcl_dup(BclNumber s);
BclError
bcl_bigdig(BclNumber n, BclBigDig* result);
+BclError
+bcl_bigdig_keep(BclNumber n, BclBigDig* result);
+
BclNumber
bcl_bigdig2num(BclBigDig val);
@@ -245,35 +251,68 @@ BclNumber
bcl_add(BclNumber a, BclNumber b);
BclNumber
+bcl_add_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_sub(BclNumber a, BclNumber b);
BclNumber
+bcl_sub_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_mul(BclNumber a, BclNumber b);
BclNumber
+bcl_mul_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_div(BclNumber a, BclNumber b);
BclNumber
+bcl_div_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_mod(BclNumber a, BclNumber b);
BclNumber
+bcl_mod_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_pow(BclNumber a, BclNumber b);
BclNumber
+bcl_pow_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_lshift(BclNumber a, BclNumber b);
BclNumber
+bcl_lshift_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_rshift(BclNumber a, BclNumber b);
BclNumber
+bcl_rshift_keep(BclNumber a, BclNumber b);
+
+BclNumber
bcl_sqrt(BclNumber a);
+BclNumber
+bcl_sqrt_keep(BclNumber a);
+
BclError
bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d);
+BclError
+bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d);
+
BclNumber
bcl_modexp(BclNumber a, BclNumber b, BclNumber c);
+BclNumber
+bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c);
+
ssize_t
bcl_cmp(BclNumber a, BclNumber b);
@@ -289,19 +328,31 @@ bcl_parse(const char* restrict val);
char*
bcl_string(BclNumber n);
+char*
+bcl_string_keep(BclNumber n);
+
BclNumber
bcl_irand(BclNumber a);
BclNumber
+bcl_irand_keep(BclNumber a);
+
+BclNumber
bcl_frand(size_t places);
BclNumber
bcl_ifrand(BclNumber a, size_t places);
+BclNumber
+bcl_ifrand_keep(BclNumber a, size_t places);
+
BclError
bcl_rand_seedWithNum(BclNumber n);
BclError
+bcl_rand_seedWithNum_keep(BclNumber n);
+
+BclError
bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]);
void
diff --git a/contrib/bc/include/library.h b/contrib/bc/include/library.h
index 76df91392da1..1edd3757444c 100644
--- a/contrib/bc/include/library.h
+++ b/contrib/bc/include/library.h
@@ -47,6 +47,145 @@
#include <num.h>
#include <vm.h>
+#if BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for Valgrind builds. This is to add a generation index for error
+ * checking.
+ */
+typedef struct BclNum
+{
+ /// The number.
+ BcNum n;
+
+ /// The generation index.
+ size_t gen_idx;
+
+} BclNum;
+
+/**
+ * Clears the generation byte in a BclNumber and returns the value.
+ * @param n The BclNumber.
+ * @return The value of the index.
+ */
+#define BCL_NO_GEN(n) \
+ ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
+
+/**
+ * Gets the generation index in a BclNumber.
+ * @param n The BclNumber.
+ * @return The generation index.
+ */
+#define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
+
+/**
+ * Turns a BclNumber into a BcNum.
+ * @param c The context.
+ * @param n The BclNumber.
+ */
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
+
+/**
+ * Clears the generation index top byte in the BclNumber.
+ * @param n The BclNumber.
+ */
+#define BCL_CLEAR_GEN(n) \
+ do \
+ { \
+ (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
+ } \
+ while (0)
+
+#define BCL_CHECK_NUM_GEN(c, bn) \
+ do \
+ { \
+ size_t gen_ = BCL_GET_GEN(bn); \
+ BclNum* ptr_ = BCL_NUM(c, bn); \
+ if (BCL_NUM_ARRAY(ptr_) == NULL) \
+ { \
+ bcl_nonexistentNum(); \
+ } \
+ if (gen_ != ptr_->gen_idx) \
+ { \
+ bcl_invalidGeneration(); \
+ } \
+ } \
+ while (0)
+
+#define BCL_CHECK_NUM_VALID(c, bn) \
+ do \
+ { \
+ size_t idx_ = BCL_NO_GEN(bn); \
+ if ((c)->nums.len <= idx_) \
+ { \
+ bcl_numIdxOutOfRange(); \
+ } \
+ BCL_CHECK_NUM_GEN(c, bn); \
+ } \
+ while (0)
+
+/**
+ * Returns the limb array of the number.
+ * @param bn The number.
+ * @return The limb array.
+ */
+#define BCL_NUM_ARRAY(bn) ((bn)->n.num)
+
+/**
+ * Returns the limb array of the number for a non-pointer.
+ * @param bn The number.
+ * @return The limb array.
+ */
+#define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
+
+/**
+ * Returns the BcNum pointer.
+ * @param bn The number.
+ * @return The BcNum pointer.
+ */
+#define BCL_NUM_NUM(bn) (&(bn)->n)
+
+/**
+ * Returns the BcNum pointer for a non-pointer.
+ * @param bn The number.
+ * @return The BcNum pointer.
+ */
+#define BCL_NUM_NUM_NP(bn) (&(bn).n)
+
+// These functions only abort. They exist to give developers some idea of what
+// went wrong when bugs are found, if they look at the Valgrind stack trace.
+
+BC_NORETURN void
+bcl_invalidGeneration(void);
+
+BC_NORETURN void
+bcl_nonexistentNum(void);
+
+BC_NORETURN void
+bcl_numIdxOutOfRange(void);
+
+#else // BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for non-Valgrind builds.
+ */
+typedef BcNum BclNum;
+
+#define BCL_NO_GEN(n) ((n).i)
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i))
+#define BCL_CLEAR_GEN(n) ((void) (n))
+
+#define BCL_CHECK_NUM_GEN(c, bn)
+#define BCL_CHECK_NUM_VALID(c, n)
+
+#define BCL_NUM_ARRAY(bn) ((bn)->num)
+#define BCL_NUM_ARRAY_NP(bn) ((bn).num)
+
+#define BCL_NUM_NUM(bn) (bn)
+#define BCL_NUM_NUM_NP(bn) (&(bn))
+
+#endif // BC_ENABLE_MEMCHECK
+
/**
* A header that sets a jump.
* @param vm The thread data.
@@ -88,19 +227,19 @@
* idx.
* @param c The context.
* @param e The error.
- * @param n The number.
+ * @param bn The number.
* @param idx The idx to set as the return value.
*/
-#define BC_MAYBE_SETUP(c, e, n, idx) \
- do \
- { \
- if (BC_ERR((e) != BCL_ERROR_NONE)) \
- { \
- if ((n).num != NULL) bc_num_free(&(n)); \
- idx.i = 0 - (size_t) (e); \
- } \
- else idx = bcl_num_insert(c, &(n)); \
- } \
+#define BC_MAYBE_SETUP(c, e, bn, idx) \
+ do \
+ { \
+ if (BC_ERR((e) != BCL_ERROR_NONE)) \
+ { \
+ if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
+ idx.i = 0 - (size_t) (e); \
+ } \
+ else idx = bcl_num_insert(c, &(bn)); \
+ } \
while (0)
/**
@@ -108,17 +247,17 @@
* is bad.
* @param c The context.
*/
-#define BC_CHECK_CTXT(vm, c) \
- do \
- { \
- c = bcl_contextHelper(vm); \
- if (BC_ERR(c == NULL)) \
- { \
- BclNumber n_num; \
- n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
- return n_num; \
- } \
- } \
+#define BC_CHECK_CTXT(vm, c) \
+ do \
+ { \
+ c = bcl_contextHelper(vm); \
+ if (BC_ERR(c == NULL)) \
+ { \
+ BclNumber n_num_; \
+ n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
+ return n_num_; \
+ } \
+ } \
while (0)
/**
@@ -157,16 +296,18 @@
#define BC_CHECK_NUM(c, n) \
do \
{ \
- if (BC_ERR((n).i >= (c)->nums.len)) \
+ size_t no_gen_ = BCL_NO_GEN(n); \
+ if (BC_ERR(no_gen_ >= (c)->nums.len)) \
{ \
if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
else \
{ \
- BclNumber n_num; \
- n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
- return n_num; \
+ BclNumber n_num_; \
+ n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
+ return n_num_; \
} \
} \
+ BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
@@ -181,7 +322,8 @@
#define BC_CHECK_NUM_ERR(c, n) \
do \
{ \
- if (BC_ERR((n).i >= (c)->nums.len)) \
+ size_t no_gen_ = BCL_NO_GEN(n); \
+ if (BC_ERR(no_gen_ >= (c)->nums.len)) \
{ \
if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
{ \
@@ -189,17 +331,25 @@
} \
else return BCL_ERROR_INVALID_NUM; \
} \
+ BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
//clang-format on
/**
- * Turns a BclNumber into a BcNum.
+ * Grows the context's nums array if necessary.
* @param c The context.
- * @param n The BclNumber.
*/
-#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
+#define BCL_GROW_NUMS(c) \
+ do \
+ { \
+ if ((c)->free_nums.len == 0) \
+ { \
+ bc_vec_grow(&((c)->nums), 1); \
+ } \
+ } \
+ while (0)
/**
* Frees a BcNum for bcl. This is a destructor.
diff --git a/contrib/bc/include/program.h b/contrib/bc/include/program.h
index ff32d5db7760..1df753afad22 100644
--- a/contrib/bc/include/program.h
+++ b/contrib/bc/include/program.h
@@ -904,148 +904,82 @@ extern const char bc_program_esc_seqs[];
#if BC_ENABLE_EXTRA_MATH
-#define BC_PROG_LBLS \
- static const void* const bc_program_inst_lbls[] = { \
- &&lbl_BC_INST_NEG, \
- &&lbl_BC_INST_BOOL_NOT, \
- &&lbl_BC_INST_TRUNC, \
- &&lbl_BC_INST_POWER, \
- &&lbl_BC_INST_MULTIPLY, \
- &&lbl_BC_INST_DIVIDE, \
- &&lbl_BC_INST_MODULUS, \
- &&lbl_BC_INST_PLUS, \
- &&lbl_BC_INST_MINUS, \
- &&lbl_BC_INST_PLACES, \
- &&lbl_BC_INST_LSHIFT, \
- &&lbl_BC_INST_RSHIFT, \
- &&lbl_BC_INST_REL_EQ, \
- &&lbl_BC_INST_REL_LE, \
- &&lbl_BC_INST_REL_GE, \
- &&lbl_BC_INST_REL_NE, \
- &&lbl_BC_INST_REL_LT, \
- &&lbl_BC_INST_REL_GT, \
- &&lbl_BC_INST_BOOL_OR, \
- &&lbl_BC_INST_BOOL_AND, \
- &&lbl_BC_INST_ASSIGN_NO_VAL, \
- &&lbl_BC_INST_NUM, \
- &&lbl_BC_INST_VAR, \
- &&lbl_BC_INST_ARRAY_ELEM, \
- &&lbl_BC_INST_ARRAY, \
- &&lbl_BC_INST_ZERO, \
- &&lbl_BC_INST_ONE, \
- &&lbl_BC_INST_IBASE, \
- &&lbl_BC_INST_OBASE, \
- &&lbl_BC_INST_SCALE, \
- &&lbl_BC_INST_SEED, \
- &&lbl_BC_INST_LENGTH, \
- &&lbl_BC_INST_SCALE_FUNC, \
- &&lbl_BC_INST_SQRT, \
- &&lbl_BC_INST_ABS, \
- &&lbl_BC_INST_IS_NUMBER, \
- &&lbl_BC_INST_IS_STRING, \
- &&lbl_BC_INST_IRAND, \
- &&lbl_BC_INST_ASCIIFY, \
- &&lbl_BC_INST_READ, \
- &&lbl_BC_INST_RAND, \
- &&lbl_BC_INST_MAXIBASE, \
- &&lbl_BC_INST_MAXOBASE, \
- &&lbl_BC_INST_MAXSCALE, \
- &&lbl_BC_INST_MAXRAND, \
- &&lbl_BC_INST_LINE_LENGTH, \
- &&lbl_BC_INST_LEADING_ZERO, \
- &&lbl_BC_INST_PRINT, \
- &&lbl_BC_INST_PRINT_POP, \
- &&lbl_BC_INST_STR, \
- &&lbl_BC_INST_POP, \
- &&lbl_BC_INST_SWAP, \
- &&lbl_BC_INST_MODEXP, \
- &&lbl_BC_INST_DIVMOD, \
- &&lbl_BC_INST_PRINT_STREAM, \
- &&lbl_BC_INST_EXTENDED_REGISTERS, \
- &&lbl_BC_INST_POP_EXEC, \
- &&lbl_BC_INST_EXECUTE, \
- &&lbl_BC_INST_EXEC_COND, \
- &&lbl_BC_INST_PRINT_STACK, \
- &&lbl_BC_INST_CLEAR_STACK, \
- &&lbl_BC_INST_REG_STACK_LEN, \
- &&lbl_BC_INST_STACK_LEN, \
- &&lbl_BC_INST_DUPLICATE, \
- &&lbl_BC_INST_LOAD, \
- &&lbl_BC_INST_PUSH_VAR, \
- &&lbl_BC_INST_PUSH_TO_VAR, \
- &&lbl_BC_INST_QUIT, \
- &&lbl_BC_INST_NQUIT, \
- &&lbl_BC_INST_EXEC_STACK_LEN, \
- &&lbl_BC_INST_INVALID, \
+#define BC_PROG_LBLS \
+ static const void* const bc_program_inst_lbls[] = { \
+ &&lbl_BC_INST_NEG, &&lbl_BC_INST_BOOL_NOT, \
+ &&lbl_BC_INST_TRUNC, &&lbl_BC_INST_POWER, \
+ &&lbl_BC_INST_MULTIPLY, &&lbl_BC_INST_DIVIDE, \
+ &&lbl_BC_INST_MODULUS, &&lbl_BC_INST_PLUS, \
+ &&lbl_BC_INST_MINUS, &&lbl_BC_INST_PLACES, \
+ &&lbl_BC_INST_LSHIFT, &&lbl_BC_INST_RSHIFT, \
+ &&lbl_BC_INST_REL_EQ, &&lbl_BC_INST_REL_LE, \
+ &&lbl_BC_INST_REL_GE, &&lbl_BC_INST_REL_NE, \
+ &&lbl_BC_INST_REL_LT, &&lbl_BC_INST_REL_GT, \
+ &&lbl_BC_INST_BOOL_OR, &&lbl_BC_INST_BOOL_AND, \
+ &&lbl_BC_INST_ASSIGN_NO_VAL, &&lbl_BC_INST_NUM, \
+ &&lbl_BC_INST_VAR, &&lbl_BC_INST_ARRAY_ELEM, \
+ &&lbl_BC_INST_ARRAY, &&lbl_BC_INST_ZERO, \
+ &&lbl_BC_INST_ONE, &&lbl_BC_INST_IBASE, \
+ &&lbl_BC_INST_OBASE, &&lbl_BC_INST_SCALE, \
+ &&lbl_BC_INST_SEED, &&lbl_BC_INST_LENGTH, \
+ &&lbl_BC_INST_SCALE_FUNC, &&lbl_BC_INST_SQRT, \
+ &&lbl_BC_INST_ABS, &&lbl_BC_INST_IS_NUMBER, \
+ &&lbl_BC_INST_IS_STRING, &&lbl_BC_INST_IRAND, \
+ &&lbl_BC_INST_ASCIIFY, &&lbl_BC_INST_READ, \
+ &&lbl_BC_INST_RAND, &&lbl_BC_INST_MAXIBASE, \
+ &&lbl_BC_INST_MAXOBASE, &&lbl_BC_INST_MAXSCALE, \
+ &&lbl_BC_INST_MAXRAND, &&lbl_BC_INST_LINE_LENGTH, \
+ &&lbl_BC_INST_LEADING_ZERO, &&lbl_BC_INST_PRINT, \
+ &&lbl_BC_INST_PRINT_POP, &&lbl_BC_INST_STR, \
+ &&lbl_BC_INST_POP, &&lbl_BC_INST_SWAP, \
+ &&lbl_BC_INST_MODEXP, &&lbl_BC_INST_DIVMOD, \
+ &&lbl_BC_INST_PRINT_STREAM, &&lbl_BC_INST_EXTENDED_REGISTERS, \
+ &&lbl_BC_INST_POP_EXEC, &&lbl_BC_INST_EXECUTE, \
+ &&lbl_BC_INST_EXEC_COND, &&lbl_BC_INST_PRINT_STACK, \
+ &&lbl_BC_INST_CLEAR_STACK, &&lbl_BC_INST_REG_STACK_LEN, \
+ &&lbl_BC_INST_STACK_LEN, &&lbl_BC_INST_DUPLICATE, \
+ &&lbl_BC_INST_LOAD, &&lbl_BC_INST_PUSH_VAR, \
+ &&lbl_BC_INST_PUSH_TO_VAR, &&lbl_BC_INST_QUIT, \
+ &&lbl_BC_INST_NQUIT, &&lbl_BC_INST_EXEC_STACK_LEN, \
+ &&lbl_BC_INST_INVALID, \
}
#else // BC_ENABLE_EXTRA_MATH
-#define BC_PROG_LBLS \
- static const void* const bc_program_inst_lbls[] = { \
- &&lbl_BC_INST_NEG, \
- &&lbl_BC_INST_BOOL_NOT, \
- &&lbl_BC_INST_POWER, \
- &&lbl_BC_INST_MULTIPLY, \
- &&lbl_BC_INST_DIVIDE, \
- &&lbl_BC_INST_MODULUS, \
- &&lbl_BC_INST_PLUS, \
- &&lbl_BC_INST_MINUS, \
- &&lbl_BC_INST_REL_EQ, \
- &&lbl_BC_INST_REL_LE, \
- &&lbl_BC_INST_REL_GE, \
- &&lbl_BC_INST_REL_NE, \
- &&lbl_BC_INST_REL_LT, \
- &&lbl_BC_INST_REL_GT, \
- &&lbl_BC_INST_BOOL_OR, \
- &&lbl_BC_INST_BOOL_AND, \
- &&lbl_BC_INST_ASSIGN_NO_VAL, \
- &&lbl_BC_INST_NUM, \
- &&lbl_BC_INST_VAR, \
- &&lbl_BC_INST_ARRAY_ELEM, \
- &&lbl_BC_INST_ARRAY, \
- &&lbl_BC_INST_ZERO, \
- &&lbl_BC_INST_ONE, \
- &&lbl_BC_INST_IBASE, \
- &&lbl_BC_INST_OBASE, \
- &&lbl_BC_INST_SCALE, \
- &&lbl_BC_INST_LENGTH, \
- &&lbl_BC_INST_SCALE_FUNC, \
- &&lbl_BC_INST_SQRT, \
- &&lbl_BC_INST_ABS, \
- &&lbl_BC_INST_IS_NUMBER, \
- &&lbl_BC_INST_IS_STRING, \
- &&lbl_BC_INST_ASCIIFY, \
- &&lbl_BC_INST_READ, \
- &&lbl_BC_INST_MAXIBASE, \
- &&lbl_BC_INST_MAXOBASE, \
- &&lbl_BC_INST_MAXSCALE, \
- &&lbl_BC_INST_LINE_LENGTH, \
- &&lbl_BC_INST_LEADING_ZERO, \
- &&lbl_BC_INST_PRINT, \
- &&lbl_BC_INST_PRINT_POP, \
- &&lbl_BC_INST_STR, \
- &&lbl_BC_INST_POP, \
- &&lbl_BC_INST_SWAP, \
- &&lbl_BC_INST_MODEXP, \
- &&lbl_BC_INST_DIVMOD, \
- &&lbl_BC_INST_PRINT_STREAM, \
- &&lbl_BC_INST_EXTENDED_REGISTERS, \
- &&lbl_BC_INST_POP_EXEC, \
- &&lbl_BC_INST_EXECUTE, \
- &&lbl_BC_INST_EXEC_COND, \
- &&lbl_BC_INST_PRINT_STACK, \
- &&lbl_BC_INST_CLEAR_STACK, \
- &&lbl_BC_INST_REG_STACK_LEN, \
- &&lbl_BC_INST_STACK_LEN, \
- &&lbl_BC_INST_DUPLICATE, \
- &&lbl_BC_INST_LOAD, \
- &&lbl_BC_INST_PUSH_VAR, \
- &&lbl_BC_INST_PUSH_TO_VAR, \
- &&lbl_BC_INST_QUIT, \
- &&lbl_BC_INST_NQUIT, \
- &&lbl_BC_INST_EXEC_STACK_LEN, \
- &&lbl_BC_INST_INVALID, \
+#define BC_PROG_LBLS \
+ static const void* const bc_program_inst_lbls[] = { \
+ &&lbl_BC_INST_NEG, &&lbl_BC_INST_BOOL_NOT, \
+ &&lbl_BC_INST_POWER, &&lbl_BC_INST_MULTIPLY, \
+ &&lbl_BC_INST_DIVIDE, &&lbl_BC_INST_MODULUS, \
+ &&lbl_BC_INST_PLUS, &&lbl_BC_INST_MINUS, \
+ &&lbl_BC_INST_REL_EQ, &&lbl_BC_INST_REL_LE, \
+ &&lbl_BC_INST_REL_GE, &&lbl_BC_INST_REL_NE, \
+ &&lbl_BC_INST_REL_LT, &&lbl_BC_INST_REL_GT, \
+ &&lbl_BC_INST_BOOL_OR, &&lbl_BC_INST_BOOL_AND, \
+ &&lbl_BC_INST_ASSIGN_NO_VAL, &&lbl_BC_INST_NUM, \
+ &&lbl_BC_INST_VAR, &&lbl_BC_INST_ARRAY_ELEM, \
+ &&lbl_BC_INST_ARRAY, &&lbl_BC_INST_ZERO, \
+ &&lbl_BC_INST_ONE, &&lbl_BC_INST_IBASE, \
+ &&lbl_BC_INST_OBASE, &&lbl_BC_INST_SCALE, \
+ &&lbl_BC_INST_LENGTH, &&lbl_BC_INST_SCALE_FUNC, \
+ &&lbl_BC_INST_SQRT, &&lbl_BC_INST_ABS, \
+ &&lbl_BC_INST_IS_NUMBER, &&lbl_BC_INST_IS_STRING, \
+ &&lbl_BC_INST_ASCIIFY, &&lbl_BC_INST_READ, \
+ &&lbl_BC_INST_MAXIBASE, &&lbl_BC_INST_MAXOBASE, \
+ &&lbl_BC_INST_MAXSCALE, &&lbl_BC_INST_LINE_LENGTH, \
+ &&lbl_BC_INST_LEADING_ZERO, &&lbl_BC_INST_PRINT, \
+ &&lbl_BC_INST_PRINT_POP, &&lbl_BC_INST_STR, \
+ &&lbl_BC_INST_POP, &&lbl_BC_INST_SWAP, \
+ &&lbl_BC_INST_MODEXP, &&lbl_BC_INST_DIVMOD, \
+ &&lbl_BC_INST_PRINT_STREAM, &&lbl_BC_INST_EXTENDED_REGISTERS, \
+ &&lbl_BC_INST_POP_EXEC, &&lbl_BC_INST_EXECUTE, \
+ &&lbl_BC_INST_EXEC_COND, &&lbl_BC_INST_PRINT_STACK, \
+ &&lbl_BC_INST_CLEAR_STACK, &&lbl_BC_INST_REG_STACK_LEN, \
+ &&lbl_BC_INST_STACK_LEN, &&lbl_BC_INST_DUPLICATE, \
+ &&lbl_BC_INST_LOAD, &&lbl_BC_INST_PUSH_VAR, \
+ &&lbl_BC_INST_PUSH_TO_VAR, &&lbl_BC_INST_QUIT, \
+ &&lbl_BC_INST_NQUIT, &&lbl_BC_INST_EXEC_STACK_LEN, \
+ &&lbl_BC_INST_INVALID, \
}
#endif // BC_ENABLE_EXTRA_MATH
diff --git a/contrib/bc/include/version.h b/contrib/bc/include/version.h
index f5e345b3b189..3745ed9b5f74 100644
--- a/contrib/bc/include/version.h
+++ b/contrib/bc/include/version.h
@@ -37,6 +37,6 @@
#define BC_VERSION_H
/// The current version.
-#define VERSION 6.3.1
+#define VERSION 6.4.0
#endif // BC_VERSION_H
diff --git a/contrib/bc/include/vm.h b/contrib/bc/include/vm.h
index dd21d43f5260..c56cc8e7370a 100644
--- a/contrib/bc/include/vm.h
+++ b/contrib/bc/include/vm.h
@@ -560,9 +560,13 @@ typedef struct BcVm
/// The vector for creating strings to pass to the client.
BcVec out;
+#if BC_ENABLE_EXTRA_MATH
+
/// The PRNG.
BcRNG rng;
+#endif // BC_ENABLE_EXTRA_MATH
+
/// The current error.
BclError err;
diff --git a/contrib/bc/manuals/bcl.3 b/contrib/bc/manuals/bcl.3
index 5c3731a141eb..cb65a2b8b991 100644
--- a/contrib/bc/manuals/bcl.3
+++ b/contrib/bc/manuals/bcl.3
@@ -139,9 +139,14 @@ integers.
.PP
\f[B]char* bcl_string(BclNumber\f[R] \f[I]n\f[R]\f[B]);\f[R]
.PP
+\f[B]char* bcl_string_keep(BclNumber\f[R] \f[I]n\f[R]\f[B]);\f[R]
+.PP
\f[B]BclError bcl_bigdig(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig
*\f[R]\f[I]result\f[R]\f[B]);\f[R]
.PP
+\f[B]BclError bcl_bigdig_keep(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig
+*\f[R]\f[I]result\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_bigdig2num(BclBigDig\f[R] \f[I]val\f[R]\f[B]);\f[R]
.SS Math
.PP
@@ -150,35 +155,68 @@ These items allow clients to run math on numbers.
\f[B]BclNumber bcl_add(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_add_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_sub(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_sub_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_mul(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_mul_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_div(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_div_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_mod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_mod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_pow(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_pow_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_lshift(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_lshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_rshift(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_rshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_sqrt(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_sqrt_keep(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
+.PP
\f[B]BclError bcl_divmod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R]
\f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber
*\f[R]\f[I]d\f[R]\f[B]);\f[R]
.PP
+\f[B]BclError bcl_divmod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B],
+BclNumber *\f[R]\f[I]d\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_modexp(BclNumber\f[R] \f[I]a\f[R]\f[B],
BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B]);\f[R]
+.PP
+\f[B]BclNumber bcl_modexp_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B]);\f[R]
.SS Miscellaneous
.PP
These items are miscellaneous.
@@ -209,14 +247,22 @@ generator in bcl(3).
.PP
\f[B]BclNumber bcl_irand(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_irand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B]);\f[R]
+.PP
\f[B]BclNumber bcl_frand(size_t\f[R] \f[I]places\f[R]\f[B]);\f[R]
.PP
\f[B]BclNumber bcl_ifrand(BclNumber\f[R] \f[I]a\f[R]\f[B], size_t\f[R]
\f[I]places\f[R]\f[B]);\f[R]
.PP
+\f[B]BclNumber bcl_ifrand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B],
+size_t\f[R] \f[I]places\f[R]\f[B]);\f[R]
+.PP
\f[B]BclError bcl_rand_seedWithNum(BclNumber\f[R]
\f[I]n\f[R]\f[B]);\f[R]
.PP
+\f[B]BclError bcl_rand_seedWithNum_keep(BclNumber\f[R]
+\f[I]n\f[R]\f[B]);\f[R]
+.PP
\f[B]BclError bcl_rand_seed(unsigned char\f[R]
\f[I]seed\f[R]\f[B][\f[R]\f[I]BCL_SEED_SIZE\f[R]\f[B]]);\f[R]
.PP
@@ -608,8 +654,9 @@ Returns the number of \f[I]significant decimal digits\f[R] in
.PP
All procedures in this section require a valid current context.
.PP
-All procedures in this section consume the given \f[B]BclNumber\f[R]
-arguments that are not given to pointer arguments.
+All procedures in this section without the \f[B]_keep\f[R] suffix in
+their name consume the given \f[B]BclNumber\f[R] arguments that are not
+given to pointer arguments.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.TP
\f[B]BclNumber bcl_parse(const char *restrict\f[R] \f[I]val\f[R]\f[B])\f[R]
@@ -644,6 +691,11 @@ The string is dynamically allocated and must be freed by the caller.
See the \f[B]Consumption and Propagation\f[R] subsection below.
.RE
.TP
+\f[B]char* bcl_string_keep(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
+Returns a string representation of \f[I]n\f[R] according the the current
+context\[cq]s \f[B]ibase\f[R].
+The string is dynamically allocated and must be freed by the caller.
+.TP
\f[B]BclError bcl_bigdig(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig *\f[R]\f[I]result\f[R]\f[B])\f[R]
Converts \f[I]n\f[R] into a \f[B]BclBigDig\f[R] and returns the result
in the space pointed to by \f[I]result\f[R].
@@ -665,6 +717,24 @@ Otherwise, this function can return:
See the \f[B]Consumption and Propagation\f[R] subsection below.
.RE
.TP
+\f[B]BclError bcl_bigdig_keep(BclNumber\f[R] \f[I]n\f[R]\f[B], BclBigDig *\f[R]\f[I]result\f[R]\f[B])\f[R]
+Converts \f[I]n\f[R] into a \f[B]BclBigDig\f[R] and returns the result
+in the space pointed to by \f[I]result\f[R].
+.RS
+.PP
+\f[I]a\f[R] must be smaller than \f[B]BC_OVERFLOW_MAX\f[R].
+See the \f[B]LIMITS\f[R] section.
+.PP
+If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
+Otherwise, this function can return:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_OVERFLOW\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_bigdig2num(BclBigDig\f[R] \f[I]val\f[R]\f[B])\f[R]
Creates a \f[B]BclNumber\f[R] from \f[I]val\f[R].
.RS
@@ -681,6 +751,11 @@ Possible errors include:
.PP
All procedures in this section require a valid current context.
.PP
+All procedures in this section without the \f[B]_keep\f[R] suffix in
+their name consume the given \f[B]BclNumber\f[R] arguments that are not
+given to pointer arguments.
+See the \f[B]Consumption and Propagation\f[R] subsection below.
+.PP
All procedures in this section can return the following errors:
.IP \[bu] 2
\f[B]BCL_ERROR_INVALID_NUM\f[R]
@@ -712,6 +787,25 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_add_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Adds \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
+The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
+\f[I]a\f[R] and \f[I]b\f[R].
+.RS
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_sub(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Subtracts \f[I]b\f[R] from \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
@@ -735,6 +829,25 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_sub_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Subtracts \f[I]b\f[R] from \f[I]a\f[R] and returns the result.
+The \f[I]scale\f[R] of the result is the max of the \f[I]scale\f[R]s of
+\f[I]a\f[R] and \f[I]b\f[R].
+.RS
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_mul(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Multiplies \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
If \f[I]ascale\f[R] is the \f[I]scale\f[R] of \f[I]a\f[R] and
@@ -761,6 +874,28 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_mul_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Multiplies \f[I]a\f[R] and \f[I]b\f[R] and returns the result.
+If \f[I]ascale\f[R] is the \f[I]scale\f[R] of \f[I]a\f[R] and
+\f[I]bscale\f[R] is the \f[I]scale\f[R] of \f[I]b\f[R], the
+\f[I]scale\f[R] of the result is equal to
+\f[B]min(ascale+bscale,max(scale,ascale,bscale))\f[R], where
+\f[B]min()\f[R] and \f[B]max()\f[R] return the obvious values.
+.RS
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_div(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the result.
The \f[I]scale\f[R] of the result is the \f[I]scale\f[R] of the current
@@ -788,6 +923,29 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_div_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the result.
+The \f[I]scale\f[R] of the result is the \f[I]scale\f[R] of the current
+context.
+.RS
+.PP
+\f[I]b\f[R] cannot be \f[B]0\f[R].
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_mod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] to the \f[I]scale\f[R] of the current
context, computes the modulus \f[B]a-(a/b)*b\f[R], and returns the
@@ -815,6 +973,29 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_mod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Divides \f[I]a\f[R] by \f[I]b\f[R] to the \f[I]scale\f[R] of the current
+context, computes the modulus \f[B]a-(a/b)*b\f[R], and returns the
+modulus.
+.RS
+.PP
+\f[I]b\f[R] cannot be \f[B]0\f[R].
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_pow(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Calculates \f[I]a\f[R] to the power of \f[I]b\f[R] to the
\f[I]scale\f[R] of the current context.
@@ -851,6 +1032,38 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_pow_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Calculates \f[I]a\f[R] to the power of \f[I]b\f[R] to the
+\f[I]scale\f[R] of the current context.
+\f[I]b\f[R] must be an integer, but can be negative.
+If it is negative, \f[I]a\f[R] must be non-zero.
+.RS
+.PP
+\f[I]b\f[R] must be an integer.
+If \f[I]b\f[R] is negative, \f[I]a\f[R] must not be \f[B]0\f[R].
+.PP
+\f[I]a\f[R] must be smaller than \f[B]BC_OVERFLOW_MAX\f[R].
+See the \f[B]LIMITS\f[R] section.
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_OVERFLOW\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_lshift(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] left (moves the radix right) by \f[I]b\f[R] places
and returns the result.
@@ -879,6 +1092,30 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_lshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Shifts \f[I]a\f[R] left (moves the radix right) by \f[I]b\f[R] places
+and returns the result.
+This is done in decimal.
+\f[I]b\f[R] must be an integer.
+.RS
+.PP
+\f[I]b\f[R] must be an integer.
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_rshift(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
Shifts \f[I]a\f[R] right (moves the radix left) by \f[I]b\f[R] places
and returns the result.
@@ -907,6 +1144,30 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_rshift_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B])\f[R]
+Shifts \f[I]a\f[R] right (moves the radix left) by \f[I]b\f[R] places
+and returns the result.
+This is done in decimal.
+\f[I]b\f[R] must be an integer.
+.RS
+.PP
+\f[I]b\f[R] must be an integer.
+.PP
+\f[I]a\f[R] and \f[I]b\f[R] can be the same number.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_sqrt(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
Calculates the square root of \f[I]a\f[R] and returns the result.
The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
@@ -931,6 +1192,27 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_sqrt_keep(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
+Calculates the square root of \f[I]a\f[R] and returns the result.
+The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
+current context.
+.RS
+.PP
+\f[I]a\f[R] cannot be negative.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclError bcl_divmod(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber *\f[R]\f[I]d\f[R]\f[B])\f[R]
Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the quotient in a new
number which is put into the space pointed to by \f[I]c\f[R], and puts
@@ -959,6 +1241,30 @@ Otherwise, this function can return:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclError bcl_divmod_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber *\f[R]\f[I]c\f[R]\f[B], BclNumber *\f[R]\f[I]d\f[R]\f[B])\f[R]
+Divides \f[I]a\f[R] by \f[I]b\f[R] and returns the quotient in a new
+number which is put into the space pointed to by \f[I]c\f[R], and puts
+the modulus in a new number which is put into the space pointed to by
+\f[I]d\f[R].
+.RS
+.PP
+\f[I]b\f[R] cannot be \f[B]0\f[R].
+.PP
+\f[I]c\f[R] and \f[I]d\f[R] cannot point to the same place, nor can they
+point to the space occupied by \f[I]a\f[R] or \f[I]b\f[R].
+.PP
+If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
+Otherwise, this function can return:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_modexp(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B])\f[R]
Computes a modular exponentiation where \f[I]a\f[R] is the base,
\f[I]b\f[R] is the exponent, and \f[I]c\f[R] is the modulus, and returns
@@ -991,6 +1297,35 @@ Possible errors include:
.IP \[bu] 2
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
+.TP
+\f[B]BclNumber bcl_modexp_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], BclNumber\f[R] \f[I]b\f[R]\f[B], BclNumber\f[R] \f[I]c\f[R]\f[B])\f[R]
+Computes a modular exponentiation where \f[I]a\f[R] is the base,
+\f[I]b\f[R] is the exponent, and \f[I]c\f[R] is the modulus, and returns
+the result.
+The \f[I]scale\f[R] of the result is equal to the \f[B]scale\f[R] of the
+current context.
+.RS
+.PP
+\f[I]a\f[R], \f[I]b\f[R], and \f[I]c\f[R] must be integers.
+\f[I]c\f[R] must not be \f[B]0\f[R].
+\f[I]b\f[R] must not be negative.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_DIVIDE_BY_ZERO\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
.SS Miscellaneous
.TP
\f[B]void bcl_zero(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
@@ -1060,6 +1395,11 @@ char[\f[R]\f[I]BCL_SEED_SIZE\f[R]\f[B]])\f[R]
.IP \[bu] 2
\f[B]bcl_rand_reseed(\f[R]\f[I]void\f[R]\f[B])\f[R]
.PP
+All procedures in this section without the \f[B]_keep\f[R] suffix in
+their name consume the given \f[B]BclNumber\f[R] arguments that are not
+given to pointer arguments.
+See the \f[B]Consumption and Propagation\f[R] subsection below.
+.PP
The following items allow clients to use the pseudo-random number
generator.
All procedures require a valid current context.
@@ -1112,6 +1452,36 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_irand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B])\f[R]
+Returns a random number that is not larger than \f[I]a\f[R] in a new
+number.
+If \f[I]a\f[R] is \f[B]0\f[R] or \f[B]1\f[R], the new number is equal to
+\f[B]0\f[R].
+The bound is unlimited, so it is not bound to the size of
+\f[B]BclRandInt\f[R].
+This is done by generating as many random numbers as necessary,
+multiplying them by certain exponents, and adding them all together.
+.RS
+.PP
+\f[I]a\f[R] must be an integer and non-negative.
+.PP
+This procedure requires a valid current context.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclNumber bcl_frand(size_t\f[R] \f[I]places\f[R]\f[B])\f[R]
Returns a random number between \f[B]0\f[R] (inclusive) and \f[B]1\f[R]
(exclusive) that has \f[I]places\f[R] decimal digits after the radix
@@ -1158,11 +1528,55 @@ Possible errors include:
\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
.RE
.TP
+\f[B]BclNumber bcl_ifrand_keep(BclNumber\f[R] \f[I]a\f[R]\f[B], size_t\f[R] \f[I]places\f[R]\f[B])\f[R]
+Returns a random number less than \f[I]a\f[R] with \f[I]places\f[R]
+decimal digits after the radix (decimal point).
+There are no limits on \f[I]a\f[R] or \f[I]places\f[R].
+.RS
+.PP
+\f[I]a\f[R] must be an integer and non-negative.
+.PP
+This procedure requires a valid current context.
+.PP
+bcl(3) will encode an error in the return value, if there was one.
+The error can be queried with \f[B]bcl_err(BclNumber)\f[R].
+Possible errors include:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NEGATIVE\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_MATH_NON_INTEGER\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_FATAL_ALLOC_ERR\f[R]
+.RE
+.TP
\f[B]BclError bcl_rand_seedWithNum(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
Seeds the PRNG with \f[I]n\f[R].
.RS
.PP
-\f[I]n\f[R] is \f[I]not\f[R] consumed.
+\f[I]n\f[R] is consumed.
+.PP
+This procedure requires a valid current context.
+.PP
+If there was no error, \f[B]BCL_ERROR_NONE\f[R] is returned.
+Otherwise, this function can return:
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_NUM\f[R]
+.IP \[bu] 2
+\f[B]BCL_ERROR_INVALID_CONTEXT\f[R]
+.PP
+Note that if \f[B]bcl_rand_seed2num(\f[R]\f[I]void\f[R]\f[B])\f[R] or
+\f[B]bcl_rand_seed2num_err(BclNumber)\f[R] are called right after this
+function, they are not guaranteed to return a number equal to
+\f[I]n\f[R].
+.RE
+.TP
+\f[B]BclError bcl_rand_seedWithNum_keep(BclNumber\f[R] \f[I]n\f[R]\f[B])\f[R]
+Seeds the PRNG with \f[I]n\f[R].
+.RS
.PP
This procedure requires a valid current context.
.PP
@@ -1253,7 +1667,7 @@ so the example above should properly be:
.nf
\f[C]
BclNumber n = bcl_num_add(bcl_num_mul(a, b), bcl_num_div(c, d));
-if (bc_num_err(n) != BCL_ERROR_NONE) {
+if (bcl_err(n) != BCL_ERROR_NONE) {
// Handle the error.
}
\f[R]
diff --git a/contrib/bc/manuals/bcl.3.md b/contrib/bc/manuals/bcl.3.md
index 6c6967b44770..fa566d161c43 100644
--- a/contrib/bc/manuals/bcl.3.md
+++ b/contrib/bc/manuals/bcl.3.md
@@ -136,8 +136,12 @@ These items allow clients to convert numbers into and from strings and integers.
**char\* bcl_string(BclNumber** _n_**);**
+**char\* bcl_string_keep(BclNumber** _n_**);**
+
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**);**
+**BclError bcl_bigdig_keep(BclNumber** _n_**, BclBigDig \***_result_**);**
+
**BclNumber bcl_bigdig2num(BclBigDig** _val_**);**
## Math
@@ -146,26 +150,48 @@ These items allow clients to run math on numbers.
**BclNumber bcl_add(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_add_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_sub_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_mul_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_div_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_mod_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_pow_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_lshift_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**);**
+**BclNumber bcl_rshift_keep(BclNumber** _a_**, BclNumber** _b_**);**
+
**BclNumber bcl_sqrt(BclNumber** _a_**);**
+**BclNumber bcl_sqrt_keep(BclNumber** _a_**);**
+
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**);**
+**BclError bcl_divmod_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**);**
+
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**);**
+**BclNumber bcl_modexp_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**);**
+
## Miscellaneous
These items are miscellaneous.
@@ -195,12 +221,18 @@ generator in bcl(3).
**BclNumber bcl_irand(BclNumber** _a_**);**
+**BclNumber bcl_irand_keep(BclNumber** _a_**);**
+
**BclNumber bcl_frand(size_t** _places_**);**
**BclNumber bcl_ifrand(BclNumber** _a_**, size_t** _places_**);**
+**BclNumber bcl_ifrand_keep(BclNumber** _a_**, size_t** _places_**);**
+
**BclError bcl_rand_seedWithNum(BclNumber** _n_**);**
+**BclError bcl_rand_seedWithNum_keep(BclNumber** _n_**);**
+
**BclError bcl_rand_seed(unsigned char** _seed_**[**_BCL_SEED_SIZE_**]);**
**void bcl_rand_reseed(**_void_**);**
@@ -548,9 +580,9 @@ All procedures in this section require a valid current context.
All procedures in this section require a valid current context.
-All procedures in this section consume the given **BclNumber** arguments that
-are not given to pointer arguments. See the **Consumption and Propagation**
-subsection below.
+All procedures in this section without the **_keep** suffix in their name
+consume the given **BclNumber** arguments that are not given to pointer
+arguments. See the **Consumption and Propagation** subsection below.
**BclNumber bcl_parse(const char \*restrict** _val_**)**
@@ -578,6 +610,12 @@ subsection below.
*n* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
+**char\* bcl_string_keep(BclNumber** _n_**)**
+
+: Returns a string representation of *n* according the the current context's
+ **ibase**. The string is dynamically allocated and must be freed by the
+ caller.
+
**BclError bcl_bigdig(BclNumber** _n_**, BclBigDig \***_result_**)**
: Converts *n* into a **BclBigDig** and returns the result in the space
@@ -595,6 +633,20 @@ subsection below.
*n* is consumed; it cannot be used after the call. See the
**Consumption and Propagation** subsection below.
+**BclError bcl_bigdig_keep(BclNumber** _n_**, BclBigDig \***_result_**)**
+
+: Converts *n* into a **BclBigDig** and returns the result in the space
+ pointed to by *result*.
+
+ *a* must be smaller than **BC_OVERFLOW_MAX**. See the **LIMITS** section.
+
+ If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
+ function can return:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_OVERFLOW**
+
**BclNumber bcl_bigdig2num(BclBigDig** _val_**)**
: Creates a **BclNumber** from *val*.
@@ -609,6 +661,10 @@ subsection below.
All procedures in this section require a valid current context.
+All procedures in this section without the **_keep** suffix in their name
+consume the given **BclNumber** arguments that are not given to pointer
+arguments. See the **Consumption and Propagation** subsection below.
+
All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_NUM**
@@ -632,6 +688,20 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_add_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Adds *a* and *b* and returns the result. The *scale* of the result is the
+ max of the *scale*s of *a* and *b*.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_sub(BclNumber** _a_**, BclNumber** _b_**)**
: Subtracts *b* from *a* and returns the result. The *scale* of the result is
@@ -649,6 +719,20 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_sub_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Subtracts *b* from *a* and returns the result. The *scale* of the result is
+ the max of the *scale*s of *a* and *b*.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_mul(BclNumber** _a_**, BclNumber** _b_**)**
: Multiplies *a* and *b* and returns the result. If *ascale* is the *scale* of
@@ -668,6 +752,22 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_INVALID_CONTEXT**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_mul_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Multiplies *a* and *b* and returns the result. If *ascale* is the *scale* of
+ *a* and *bscale* is the *scale* of *b*, the *scale* of the result is equal
+ to **min(ascale+bscale,max(scale,ascale,bscale))**, where **min()** and
+ **max()** return the obvious values.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_div(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* and returns the result. The *scale* of the result is the
@@ -688,6 +788,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_div_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Divides *a* by *b* and returns the result. The *scale* of the result is the
+ *scale* of the current context.
+
+ *b* cannot be **0**.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_mod(BclNumber** _a_**, BclNumber** _b_**)**
: Divides *a* by *b* to the *scale* of the current context, computes the
@@ -708,6 +825,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_mod_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Divides *a* by *b* to the *scale* of the current context, computes the
+ modulus **a-(a/b)\*b**, and returns the modulus.
+
+ *b* cannot be **0**.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_pow(BclNumber** _a_**, BclNumber** _b_**)**
: Calculates *a* to the power of *b* to the *scale* of the current context.
@@ -733,6 +867,28 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_pow_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Calculates *a* to the power of *b* to the *scale* of the current context.
+ *b* must be an integer, but can be negative. If it is negative, *a* must
+ be non-zero.
+
+ *b* must be an integer. If *b* is negative, *a* must not be **0**.
+
+ *a* must be smaller than **BC_OVERFLOW_MAX**. See the **LIMITS** section.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_MATH_OVERFLOW**
+ * **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_lshift(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* left (moves the radix right) by *b* places and returns the
@@ -753,6 +909,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_lshift_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Shifts *a* left (moves the radix right) by *b* places and returns the
+ result. This is done in decimal. *b* must be an integer.
+
+ *b* must be an integer.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_rshift(BclNumber** _a_**, BclNumber** _b_**)**
: Shifts *a* right (moves the radix left) by *b* places and returns the
@@ -773,6 +946,23 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NON_INTEGER**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_rshift_keep(BclNumber** _a_**, BclNumber** _b_**)**
+
+: Shifts *a* right (moves the radix left) by *b* places and returns the
+ result. This is done in decimal. *b* must be an integer.
+
+ *b* must be an integer.
+
+ *a* and *b* can be the same number.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_sqrt(BclNumber** _a_**)**
: Calculates the square root of *a* and returns the result. The *scale* of the
@@ -791,6 +981,21 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_NEGATIVE**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_sqrt_keep(BclNumber** _a_**)**
+
+: Calculates the square root of *a* and returns the result. The *scale* of the
+ result is equal to the **scale** of the current context.
+
+ *a* cannot be negative.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NEGATIVE**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclError bcl_divmod(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**)**
: Divides *a* by *b* and returns the quotient in a new number which is put
@@ -813,6 +1018,25 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclError bcl_divmod_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber \***_c_**, BclNumber \***_d_**)**
+
+: Divides *a* by *b* and returns the quotient in a new number which is put
+ into the space pointed to by *c*, and puts the modulus in a new number which
+ is put into the space pointed to by *d*.
+
+ *b* cannot be **0**.
+
+ *c* and *d* cannot point to the same place, nor can they point to the space
+ occupied by *a* or *b*.
+
+ If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
+ function can return:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
**BclNumber bcl_modexp(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**)**
: Computes a modular exponentiation where *a* is the base, *b* is the
@@ -835,6 +1059,25 @@ All procedures in this section can return the following errors:
* **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
* **BCL_ERROR_FATAL_ALLOC_ERR**
+**BclNumber bcl_modexp_keep(BclNumber** _a_**, BclNumber** _b_**, BclNumber** _c_**)**
+
+: Computes a modular exponentiation where *a* is the base, *b* is the
+ exponent, and *c* is the modulus, and returns the result. The *scale* of the
+ result is equal to the **scale** of the current context.
+
+ *a*, *b*, and *c* must be integers. *c* must not be **0**. *b* must not be
+ negative.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NEGATIVE**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_MATH_DIVIDE_BY_ZERO**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
## Miscellaneous
**void bcl_zero(BclNumber** _n_**)**
@@ -891,6 +1134,10 @@ If necessary, the PRNG can be reseeded with one of the following functions:
* **bcl_rand_seed(unsigned char[**_BCL_SEED_SIZE_**])**
* **bcl_rand_reseed(**_void_**)**
+All procedures in this section without the **_keep** suffix in their name
+consume the given **BclNumber** arguments that are not given to pointer
+arguments. See the **Consumption and Propagation** subsection below.
+
The following items allow clients to use the pseudo-random number generator. All
procedures require a valid current context.
@@ -921,8 +1168,29 @@ procedures require a valid current context.
*a* must be an integer and non-negative.
- *a* is consumed; it cannot be used after the call. See the
- **Consumption and Propagation** subsection below.
+ *a* is consumed; it cannot be used after the call. See the **Consumption and
+ Propagation** subsection below.
+
+ This procedure requires a valid current context.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NEGATIVE**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
+**BclNumber bcl_irand_keep(BclNumber** _a_**)**
+
+: Returns a random number that is not larger than *a* in a new number. If *a*
+ is **0** or **1**, the new number is equal to **0**. The bound is unlimited,
+ so it is not bound to the size of **BclRandInt**. This is done by generating
+ as many random numbers as necessary, multiplying them by certain exponents,
+ and adding them all together.
+
+ *a* must be an integer and non-negative.
This procedure requires a valid current context.
@@ -956,8 +1224,26 @@ procedures require a valid current context.
*a* must be an integer and non-negative.
- *a* is consumed; it cannot be used after the call. See the
- **Consumption and Propagation** subsection below.
+ *a* is consumed; it cannot be used after the call. See the **Consumption and
+ Propagation** subsection below.
+
+ This procedure requires a valid current context.
+
+ bcl(3) will encode an error in the return value, if there was one. The error
+ can be queried with **bcl_err(BclNumber)**. Possible errors include:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+ * **BCL_ERROR_MATH_NEGATIVE**
+ * **BCL_ERROR_MATH_NON_INTEGER**
+ * **BCL_ERROR_FATAL_ALLOC_ERR**
+
+**BclNumber bcl_ifrand_keep(BclNumber** _a_**, size_t** _places_**)**
+
+: Returns a random number less than *a* with *places* decimal digits after the
+ radix (decimal point). There are no limits on *a* or *places*.
+
+ *a* must be an integer and non-negative.
This procedure requires a valid current context.
@@ -974,7 +1260,23 @@ procedures require a valid current context.
: Seeds the PRNG with *n*.
- *n* is *not* consumed.
+ *n* is consumed.
+
+ This procedure requires a valid current context.
+
+ If there was no error, **BCL_ERROR_NONE** is returned. Otherwise, this
+ function can return:
+
+ * **BCL_ERROR_INVALID_NUM**
+ * **BCL_ERROR_INVALID_CONTEXT**
+
+ Note that if **bcl_rand_seed2num(**_void_**)** or
+ **bcl_rand_seed2num_err(BclNumber)** are called right after this function,
+ they are not guaranteed to return a number equal to *n*.
+
+**BclError bcl_rand_seedWithNum_keep(BclNumber** _n_**)**
+
+: Seeds the PRNG with *n*.
This procedure requires a valid current context.
@@ -1046,7 +1348,7 @@ checked with **bcl_err(BclNumber)**, so the example above should properly
be:
BclNumber n = bcl_num_add(bcl_num_mul(a, b), bcl_num_div(c, d));
- if (bc_num_err(n) != BCL_ERROR_NONE) {
+ if (bcl_err(n) != BCL_ERROR_NONE) {
// Handle the error.
}
diff --git a/contrib/bc/src/data.c b/contrib/bc/src/data.c
index abaf3b8e39ab..b57e1fc4c02d 100644
--- a/contrib/bc/src/data.c
+++ b/contrib/bc/src/data.c
@@ -1151,47 +1151,60 @@ const uchar dc_parse_insts[] = {
#if BC_ENABLE_EXTRA_MATH
BC_INST_TRUNC,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
- BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
+ BC_INST_POWER, BC_INST_MULTIPLY,
+ BC_INST_DIVIDE, BC_INST_MODULUS,
+ BC_INST_PLUS, BC_INST_MINUS,
#if BC_ENABLE_EXTRA_MATH
- BC_INST_PLACES, BC_INST_LSHIFT, BC_INST_RSHIFT,
+ BC_INST_PLACES, BC_INST_LSHIFT,
+ BC_INST_RSHIFT,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
BC_INST_BOOL_OR, BC_INST_BOOL_AND,
#if BC_ENABLED
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID,
#endif // BC_ENABLE_EXTRA_MATH
#endif // BC_ENABLED
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_REL_GT, BC_INST_REL_LT, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
- BC_INST_INVALID, BC_INST_REL_LE, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_REL_GT,
+ BC_INST_REL_LT, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_REL_GE, BC_INST_INVALID,
+ BC_INST_REL_LE, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
#if BC_ENABLED
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID,
#endif // BC_ENABLED
- BC_INST_IBASE, BC_INST_OBASE, BC_INST_SCALE,
+ BC_INST_IBASE, BC_INST_OBASE,
+ BC_INST_SCALE,
#if BC_ENABLE_EXTRA_MATH
BC_INST_SEED,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_LENGTH, BC_INST_PRINT, BC_INST_SQRT,
- BC_INST_ABS, BC_INST_IS_NUMBER, BC_INST_IS_STRING,
+ BC_INST_LENGTH, BC_INST_PRINT,
+ BC_INST_SQRT, BC_INST_ABS,
+ BC_INST_IS_NUMBER, BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
BC_INST_IRAND,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_ASCIIFY, BC_INST_MODEXP, BC_INST_DIVMOD,
- BC_INST_QUIT, BC_INST_INVALID,
+ BC_INST_ASCIIFY, BC_INST_MODEXP,
+ BC_INST_DIVMOD, BC_INST_QUIT,
+ BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
BC_INST_RAND,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_MAXIBASE, BC_INST_MAXOBASE, BC_INST_MAXSCALE,
+ BC_INST_MAXIBASE, BC_INST_MAXOBASE,
+ BC_INST_MAXSCALE,
#if BC_ENABLE_EXTRA_MATH
BC_INST_MAXRAND,
#endif // BC_ENABLE_EXTRA_MATH
@@ -1199,17 +1212,21 @@ const uchar dc_parse_insts[] = {
#if BC_ENABLED
BC_INST_INVALID,
#endif // BC_ENABLED
- BC_INST_LEADING_ZERO, BC_INST_PRINT_STREAM, BC_INST_INVALID,
- BC_INST_EXTENDED_REGISTERS, BC_INST_REL_EQ, BC_INST_INVALID,
- BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
- BC_INST_INVALID, BC_INST_STACK_LEN, BC_INST_DUPLICATE,
- BC_INST_SWAP, BC_INST_POP, BC_INST_INVALID,
- BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_LEADING_ZERO, BC_INST_PRINT_STREAM,
+ BC_INST_INVALID, BC_INST_EXTENDED_REGISTERS,
+ BC_INST_REL_EQ, BC_INST_INVALID,
+ BC_INST_EXECUTE, BC_INST_PRINT_STACK,
+ BC_INST_CLEAR_STACK, BC_INST_INVALID,
+ BC_INST_STACK_LEN, BC_INST_DUPLICATE,
+ BC_INST_SWAP, BC_INST_POP,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID,
#if BC_ENABLE_EXTRA_MATH
BC_INST_INVALID,
#endif // BC_ENABLE_EXTRA_MATH
- BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
- BC_INST_PRINT_POP, BC_INST_NQUIT, BC_INST_EXEC_STACK_LEN,
+ BC_INST_INVALID, BC_INST_INVALID,
+ BC_INST_INVALID, BC_INST_PRINT_POP,
+ BC_INST_NQUIT, BC_INST_EXEC_STACK_LEN,
BC_INST_SCALE_FUNC, BC_INST_INVALID,
};
#endif // DC_ENABLED
diff --git a/contrib/bc/src/library.c b/contrib/bc/src/library.c
index 6283d198139e..cc32a3a3a98c 100644
--- a/contrib/bc/src/library.c
+++ b/contrib/bc/src/library.c
@@ -60,6 +60,28 @@
// cannot assume that allocation failures are fatal. So we have to reset the
// jumps every time to ensure that the locals will be correct after jumping.
+#if BC_ENABLE_MEMCHECK
+
+BC_NORETURN void
+bcl_invalidGeneration(void)
+{
+ abort();
+}
+
+BC_NORETURN void
+bcl_nonexistentNum(void)
+{
+ abort();
+}
+
+BC_NORETURN void
+bcl_numIdxOutOfRange(void)
+{
+ abort();
+}
+
+#endif // BC_ENABLE_MEMCHECK
+
static BclTls* tls = NULL;
static BclTls tls_real;
@@ -195,10 +217,14 @@ bcl_init(void)
bc_vec_init(&vm->ctxts, sizeof(BclContext), BC_DTOR_NONE);
bc_vec_init(&vm->out, sizeof(uchar), BC_DTOR_NONE);
- // We need to seed this in case /dev/random and /dev/urandm don't work.
+#if BC_ENABLE_EXTRA_MATH
+
+ // We need to seed this in case /dev/random and /dev/urandom don't work.
srand((unsigned int) time(NULL));
bc_rand_init(&vm->rng);
+#endif // BC_ENABLE_EXTRA_MATH
+
err:
BC_FUNC_FOOTER(vm, e);
@@ -227,6 +253,7 @@ bcl_pushContext(BclContext ctxt)
bc_vec_push(&vm->ctxts, &ctxt);
err:
+
BC_FUNC_FOOTER(vm, e);
return e;
}
@@ -262,7 +289,9 @@ bcl_free(void)
vm->refs -= 1;
if (vm->refs) return;
+#if BC_ENABLE_EXTRA_MATH
bc_rand_free(&vm->rng);
+#endif // BC_ENABLE_EXTRA_MATH
bc_vec_free(&vm->out);
for (i = 0; i < vm->ctxts.len; ++i)
@@ -363,7 +392,7 @@ bcl_ctxt_create(void)
// malloc() is appropriate here.
ctxt = bc_vm_malloc(sizeof(BclCtxt));
- bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM);
+ bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM);
bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
ctxt->scale = 0;
@@ -445,6 +474,10 @@ bcl_err(BclNumber n)
BC_CHECK_CTXT_ERR(vm, ctxt);
+ // We need to clear the top byte in memcheck mode. We can do this because
+ // the parameter is a copy.
+ BCL_CLEAR_GEN(n);
+
// Errors are encoded as (0 - error_code). If the index is in that range, it
// is an encoded error.
if (n.i >= ctxt->nums.len)
@@ -462,14 +495,14 @@ bcl_err(BclNumber n)
* @return The resulting BclNumber from the insert.
*/
static BclNumber
-bcl_num_insert(BclContext ctxt, BcNum* restrict n)
+bcl_num_insert(BclContext ctxt, BclNum* restrict n)
{
BclNumber idx;
// If there is a free spot...
if (ctxt->free_nums.len)
{
- BcNum* ptr;
+ BclNum* ptr;
// Get the index of the free spot and remove it.
idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
@@ -477,11 +510,30 @@ bcl_num_insert(BclContext ctxt, BcNum* restrict n)
// Copy the number into the spot.
ptr = bc_vec_item(&ctxt->nums, idx.i);
- memcpy(ptr, n, sizeof(BcNum));
+
+ memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum));
+
+#if BC_ENABLE_MEMCHECK
+
+ ptr->gen_idx += 1;
+
+ if (ptr->gen_idx == UCHAR_MAX)
+ {
+ ptr->gen_idx = 0;
+ }
+
+ idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT));
+
+#endif // BC_ENABLE_MEMCHECK
}
else
{
- // Just push the number onto the vector.
+#if BC_ENABLE_MEMCHECK
+ n->gen_idx = 0;
+#endif // BC_ENABLE_MEMCHECK
+
+ // Just push the number onto the vector because the generation index is
+ // 0.
idx.i = ctxt->nums.len;
bc_vec_push(&ctxt->nums, n);
}
@@ -493,7 +545,7 @@ BclNumber
bcl_num_create(void)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -502,11 +554,12 @@ bcl_num_create(void)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- bc_num_init(&n, BC_NUM_DEF_SIZE);
+ bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
err:
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, n, idx);
@@ -520,26 +573,34 @@ err:
* @param num The number to destroy.
*/
static void
-bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum* restrict num)
+bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num)
{
- assert(num != NULL && num->num != NULL);
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
+
+ BCL_CLEAR_GEN(n);
bcl_num_destruct(num);
bc_vec_push(&ctxt->free_nums, &n);
+
+#if BC_ENABLE_MEMCHECK
+ num->n.num = NULL;
+#endif // BC_ENABLE_MEMCHECK
}
void
bcl_num_free(BclNumber n)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- num = BC_NUM(ctxt, n);
+ num = BCL_NUM(ctxt, n);
bcl_num_dtor(ctxt, n, num);
}
@@ -548,26 +609,31 @@ BclError
bcl_copy(BclNumber d, BclNumber s)
{
BclError e = BCL_ERROR_NONE;
- BcNum* dest;
- BcNum* src;
+ BclNum* dest;
+ BclNum* src;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ERR(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, d);
+ BCL_CHECK_NUM_VALID(ctxt, s);
+
BC_FUNC_HEADER(vm, err);
- assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(d) < ctxt->nums.len);
+ assert(BCL_NO_GEN(s) < ctxt->nums.len);
- dest = BC_NUM(ctxt, d);
- src = BC_NUM(ctxt, s);
+ dest = BCL_NUM(ctxt, d);
+ src = BCL_NUM(ctxt, s);
assert(dest != NULL && src != NULL);
- assert(dest->num != NULL && src->num != NULL);
+ assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL);
- bc_num_copy(dest, src);
+ bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src));
err:
+
BC_FUNC_FOOTER(vm, e);
return e;
@@ -577,28 +643,31 @@ BclNumber
bcl_dup(BclNumber s)
{
BclError e = BCL_ERROR_NONE;
- BcNum *src, dest;
+ BclNum *src, dest;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, s);
+
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(s.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(s) < ctxt->nums.len);
- src = BC_NUM(ctxt, s);
+ src = BCL_NUM(ctxt, s);
- assert(src != NULL && src->num != NULL);
+ assert(src != NULL && BCL_NUM_NUM(src) != NULL);
// Copy the number.
- bc_num_clear(&dest);
- bc_num_createCopy(&dest, src);
+ bc_num_clear(BCL_NUM_NUM(&dest));
+ bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src));
err:
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, dest, idx);
@@ -608,75 +677,81 @@ err:
void
bcl_num_destruct(void* num)
{
- BcNum* n = (BcNum*) num;
+ BclNum* n = (BclNum*) num;
assert(n != NULL);
- if (n->num == NULL) return;
+ if (BCL_NUM_ARRAY(n) == NULL) return;
- bc_num_free(num);
- bc_num_clear(num);
+ bc_num_free(BCL_NUM_NUM(n));
+ bc_num_clear(BCL_NUM_NUM(n));
}
bool
bcl_num_neg(BclNumber n)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
- num = BC_NUM(ctxt, n);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- assert(num != NULL && num->num != NULL);
+ num = BCL_NUM(ctxt, n);
- return BC_NUM_NEG(num) != 0;
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
+
+ return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0;
}
void
bcl_num_setNeg(BclNumber n, bool neg)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- num = BC_NUM(ctxt, n);
+ num = BCL_NUM(ctxt, n);
- assert(num != NULL && num->num != NULL);
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
- num->rdx = BC_NUM_NEG_VAL(num, neg);
+ BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg);
}
size_t
bcl_num_scale(BclNumber n)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- num = BC_NUM(ctxt, n);
+ num = BCL_NUM(ctxt, n);
- assert(num != NULL && num->num != NULL);
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
- return bc_num_scale(num);
+ return bc_num_scale(BCL_NUM_NUM(num));
}
BclError
bcl_num_setScale(BclNumber n, size_t scale)
{
BclError e = BCL_ERROR_NONE;
- BcNum* nptr;
+ BclNum* nptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -684,18 +759,27 @@ bcl_num_setScale(BclNumber n, size_t scale)
BC_CHECK_NUM_ERR(ctxt, n);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
BC_FUNC_HEADER(vm, err);
- assert(n.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- nptr = BC_NUM(ctxt, n);
+ nptr = BCL_NUM(ctxt, n);
- assert(nptr != NULL && nptr->num != NULL);
+ assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL);
- if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
- else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
+ if (scale > BCL_NUM_NUM(nptr)->scale)
+ {
+ bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale);
+ }
+ else if (scale < BCL_NUM_NUM(nptr)->scale)
+ {
+ bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale);
+ }
err:
+
BC_FUNC_FOOTER(vm, e);
return e;
@@ -704,54 +788,75 @@ err:
size_t
bcl_num_len(BclNumber n)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
- num = BC_NUM(ctxt, n);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- assert(num != NULL && num->num != NULL);
+ num = BCL_NUM(ctxt, n);
- return bc_num_len(num);
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
+
+ return bc_num_len(BCL_NUM_NUM(num));
}
-BclError
-bcl_bigdig(BclNumber n, BclBigDig* result)
+static BclError
+bcl_bigdig_helper(BclNumber n, BclBigDig* result, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ERR(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
BC_FUNC_HEADER(vm, err);
- assert(n.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
assert(result != NULL);
- num = BC_NUM(ctxt, n);
+ num = BCL_NUM(ctxt, n);
- assert(num != NULL && num->num != NULL);
+ assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
- *result = bc_num_bigdig(num);
+ *result = bc_num_bigdig(BCL_NUM_NUM(num));
err:
- bcl_num_dtor(ctxt, n, num);
+
+ if (destruct)
+ {
+ bcl_num_dtor(ctxt, n, num);
+ }
+
BC_FUNC_FOOTER(vm, e);
return e;
}
+BclError
+bcl_bigdig(BclNumber n, BclBigDig* result)
+{
+ return bcl_bigdig_helper(n, result, true);
+}
+
+BclError
+bcl_bigdig_keep(BclNumber n, BclBigDig* result)
+{
+ return bcl_bigdig_helper(n, result, false);
+}
+
BclNumber
bcl_bigdig2num(BclBigDig val)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -760,11 +865,12 @@ bcl_bigdig2num(BclBigDig val)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- bc_num_createFromBigdig(&n, val);
+ bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val);
err:
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, n, idx);
@@ -773,20 +879,22 @@ err:
/**
* Sets up and executes a binary operator operation.
- * @param a The first operand.
- * @param b The second operand.
- * @param op The operation.
- * @param req The function to get the size of the result for preallocation.
- * @return The result of the operation.
+ * @param a The first operand.
+ * @param b The second operand.
+ * @param op The operation.
+ * @param req The function to get the size of the result for
+ * preallocation.
+ * @param destruct True if the parameters should be consumed, false otherwise.
+ * @return The result of the operation.
*/
static BclNumber
bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
- const BcNumBinaryOpReq req)
+ const BcNumBinaryOpReq req, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum* bptr;
- BcNum c;
+ BclNum* aptr;
+ BclNum* bptr;
+ BclNum c;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -798,27 +906,31 @@ bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
- bptr = BC_NUM(ctxt, b);
+ aptr = BCL_NUM(ctxt, a);
+ bptr = BCL_NUM(ctxt, b);
assert(aptr != NULL && bptr != NULL);
- assert(aptr->num != NULL && bptr->num != NULL);
+ assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
// Clear and initialize the result.
- bc_num_clear(&c);
- bc_num_init(&c, req(aptr, bptr, ctxt->scale));
+ bc_num_clear(BCL_NUM_NUM_NP(c));
+ bc_num_init(BCL_NUM_NUM_NP(c),
+ req(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale));
- op(aptr, bptr, &c, ctxt->scale);
+ op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale);
err:
- // Eat the operands.
- bcl_num_dtor(ctxt, a, aptr);
- if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
+ if (destruct)
+ {
+ // Eat the operands.
+ bcl_num_dtor(ctxt, a, aptr);
+ if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
+ }
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, c, idx);
@@ -829,57 +941,105 @@ err:
BclNumber
bcl_add(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_add, bc_num_addReq);
+ return bcl_binary(a, b, bc_num_add, bc_num_addReq, true);
+}
+
+BclNumber
+bcl_add_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_add, bc_num_addReq, false);
}
BclNumber
bcl_sub(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
+ return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true);
+}
+
+BclNumber
+bcl_sub_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false);
}
BclNumber
bcl_mul(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
+ return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true);
+}
+
+BclNumber
+bcl_mul_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false);
}
BclNumber
bcl_div(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_div, bc_num_divReq);
+ return bcl_binary(a, b, bc_num_div, bc_num_divReq, true);
+}
+
+BclNumber
+bcl_div_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_div, bc_num_divReq, false);
}
BclNumber
bcl_mod(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
+ return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true);
+}
+
+BclNumber
+bcl_mod_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false);
}
BclNumber
bcl_pow(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
+ return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true);
+}
+
+BclNumber
+bcl_pow_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false);
}
BclNumber
bcl_lshift(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
+ return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true);
+}
+
+BclNumber
+bcl_lshift_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false);
}
BclNumber
bcl_rshift(BclNumber a, BclNumber b)
{
- return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
+ return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true);
}
BclNumber
-bcl_sqrt(BclNumber a)
+bcl_rshift_keep(BclNumber a, BclNumber b)
+{
+ return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false);
+}
+
+static BclNumber
+bcl_sqrt_helper(BclNumber a, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -890,30 +1050,48 @@ bcl_sqrt(BclNumber a)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(a.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(a) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
+ aptr = BCL_NUM(ctxt, a);
- bc_num_sqrt(aptr, &b, ctxt->scale);
+ bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale);
err:
- bcl_num_dtor(ctxt, a, aptr);
+
+ if (destruct)
+ {
+ bcl_num_dtor(ctxt, a, aptr);
+ }
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, b, idx);
return idx;
}
-BclError
-bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
+BclNumber
+bcl_sqrt(BclNumber a)
+{
+ return bcl_sqrt_helper(a, true);
+}
+
+BclNumber
+bcl_sqrt_keep(BclNumber a)
+{
+ return bcl_sqrt_helper(a, false);
+}
+
+static BclError
+bcl_divmod_helper(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d,
+ bool destruct)
{
BclError e = BCL_ERROR_NONE;
size_t req;
- BcNum* aptr;
- BcNum* bptr;
- BcNum cnum, dnum;
+ BclNum* aptr;
+ BclNum* bptr;
+ BclNum cnum, dnum;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -924,41 +1102,45 @@ bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 2);
+ BCL_GROW_NUMS(ctxt);
assert(c != NULL && d != NULL);
- aptr = BC_NUM(ctxt, a);
- bptr = BC_NUM(ctxt, b);
+ aptr = BCL_NUM(ctxt, a);
+ bptr = BCL_NUM(ctxt, b);
assert(aptr != NULL && bptr != NULL);
- assert(aptr->num != NULL && bptr->num != NULL);
+ assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
- bc_num_clear(&cnum);
- bc_num_clear(&dnum);
+ bc_num_clear(BCL_NUM_NUM_NP(cnum));
+ bc_num_clear(BCL_NUM_NUM_NP(dnum));
- req = bc_num_divReq(aptr, bptr, ctxt->scale);
+ req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale);
// Initialize the numbers.
- bc_num_init(&cnum, req);
+ bc_num_init(BCL_NUM_NUM_NP(cnum), req);
BC_UNSETJMP(vm);
BC_SETJMP(vm, err);
- bc_num_init(&dnum, req);
+ bc_num_init(BCL_NUM_NUM_NP(dnum), req);
- bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
+ bc_num_divmod(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(cnum),
+ BCL_NUM_NUM_NP(dnum), ctxt->scale);
err:
- // Eat the operands.
- bcl_num_dtor(ctxt, a, aptr);
- if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
+ if (destruct)
+ {
+ // Eat the operands.
+ bcl_num_dtor(ctxt, a, aptr);
+ if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
+ }
// If there was an error...
if (BC_ERR(vm->err))
{
// Free the results.
- if (cnum.num != NULL) bc_num_free(&cnum);
- if (dnum.num != NULL) bc_num_free(&dnum);
+ if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&cnum);
+ if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&dnum);
// Make sure the return values are invalid.
c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
@@ -978,15 +1160,27 @@ err:
return e;
}
-BclNumber
-bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
+BclError
+bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
+{
+ return bcl_divmod_helper(a, b, c, d, true);
+}
+
+BclError
+bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
+{
+ return bcl_divmod_helper(a, b, c, d, false);
+}
+
+static BclNumber
+bcl_modexp_helper(BclNumber a, BclNumber b, BclNumber c, bool destruct)
{
BclError e = BCL_ERROR_NONE;
size_t req;
- BcNum* aptr;
- BcNum* bptr;
- BcNum* cptr;
- BcNum d;
+ BclNum* aptr;
+ BclNum* bptr;
+ BclNum* cptr;
+ BclNum d;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -999,34 +1193,39 @@ bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
- assert(c.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
+ assert(BCL_NO_GEN(c) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
- bptr = BC_NUM(ctxt, b);
- cptr = BC_NUM(ctxt, c);
+ aptr = BCL_NUM(ctxt, a);
+ bptr = BCL_NUM(ctxt, b);
+ cptr = BCL_NUM(ctxt, c);
assert(aptr != NULL && bptr != NULL && cptr != NULL);
- assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
+ assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr) != NULL &&
+ BCL_NUM_NUM(cptr) != NULL);
// Prepare the result.
- bc_num_clear(&d);
+ bc_num_clear(BCL_NUM_NUM_NP(d));
- req = bc_num_divReq(aptr, cptr, 0);
+ req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0);
// Initialize the result.
- bc_num_init(&d, req);
+ bc_num_init(BCL_NUM_NUM_NP(d), req);
- bc_num_modexp(aptr, bptr, cptr, &d);
+ bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr),
+ BCL_NUM_NUM_NP(d));
err:
- // Eat the operands.
- bcl_num_dtor(ctxt, a, aptr);
- if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
- if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
+ if (destruct)
+ {
+ // Eat the operands.
+ bcl_num_dtor(ctxt, a, aptr);
+ if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
+ if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
+ }
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, d, idx);
@@ -1034,68 +1233,87 @@ err:
return idx;
}
+BclNumber
+bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
+{
+ return bcl_modexp_helper(a, b, c, true);
+}
+
+BclNumber
+bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c)
+{
+ return bcl_modexp_helper(a, b, c, false);
+}
+
ssize_t
bcl_cmp(BclNumber a, BclNumber b)
{
- BcNum* aptr;
- BcNum* bptr;
+ BclNum* aptr;
+ BclNum* bptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, a);
+ BCL_CHECK_NUM_VALID(ctxt, b);
+
+ assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
- bptr = BC_NUM(ctxt, b);
+ aptr = BCL_NUM(ctxt, a);
+ bptr = BCL_NUM(ctxt, b);
assert(aptr != NULL && bptr != NULL);
- assert(aptr->num != NULL && bptr->num != NULL);
+ assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr));
- return bc_num_cmp(aptr, bptr);
+ return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr));
}
void
bcl_zero(BclNumber n)
{
- BcNum* nptr;
+ BclNum* nptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
- nptr = BC_NUM(ctxt, n);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- assert(nptr != NULL && nptr->num != NULL);
+ nptr = BCL_NUM(ctxt, n);
- bc_num_zero(nptr);
+ assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
+
+ bc_num_zero(BCL_NUM_NUM(nptr));
}
void
bcl_one(BclNumber n)
{
- BcNum* nptr;
+ BclNum* nptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- assert(n.i < ctxt->nums.len);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- nptr = BC_NUM(ctxt, n);
+ nptr = BCL_NUM(ctxt, n);
- assert(nptr != NULL && nptr->num != NULL);
+ assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
- bc_num_one(nptr);
+ bc_num_one(BCL_NUM_NUM(nptr));
}
BclNumber
bcl_parse(const char* restrict val)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1105,7 +1323,7 @@ bcl_parse(const char* restrict val)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
assert(val != NULL);
@@ -1122,46 +1340,53 @@ bcl_parse(const char* restrict val)
}
// Clear and initialize the number.
- bc_num_clear(&n);
- bc_num_init(&n, BC_NUM_DEF_SIZE);
+ bc_num_clear(BCL_NUM_NUM_NP(n));
+ bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
- bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
+ bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase);
// Set the negative.
+#if BC_ENABLE_MEMCHECK
+ n.n.rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM_NP(n), neg);
+#else // BC_ENABLE_MEMCHECK
n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
+#endif // BC_ENABLE_MEMCHECK
err:
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, n, idx);
return idx;
}
-char*
-bcl_string(BclNumber n)
+static char*
+bcl_string_helper(BclNumber n, bool destruct)
{
- BcNum* nptr;
+ BclNum* nptr;
char* str = NULL;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
- if (BC_ERR(n.i >= ctxt->nums.len)) return str;
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
+ if (BC_ERR(BCL_NO_GEN(n) >= ctxt->nums.len)) return str;
BC_FUNC_HEADER(vm, err);
- assert(n.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- nptr = BC_NUM(ctxt, n);
+ nptr = BCL_NUM(ctxt, n);
- assert(nptr != NULL && nptr->num != NULL);
+ assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
// Clear the buffer.
bc_vec_popAll(&vm->out);
// Print to the buffer.
- bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
+ bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false);
bc_vec_pushByte(&vm->out, '\0');
// Just dup the string; the caller is responsible for it.
@@ -1169,20 +1394,37 @@ bcl_string(BclNumber n)
err:
- // Eat the operand.
- bcl_num_dtor(ctxt, n, nptr);
+ if (destruct)
+ {
+ // Eat the operand.
+ bcl_num_dtor(ctxt, n, nptr);
+ }
BC_FUNC_FOOTER_NO_ERR(vm);
return str;
}
-BclNumber
-bcl_irand(BclNumber a)
+char*
+bcl_string(BclNumber n)
+{
+ return bcl_string_helper(n, true);
+}
+
+char*
+bcl_string_keep(BclNumber n)
+{
+ return bcl_string_helper(n, false);
+}
+
+#if BC_ENABLE_EXTRA_MATH
+
+static BclNumber
+bcl_irand_helper(BclNumber a, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1193,24 +1435,27 @@ bcl_irand(BclNumber a)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(a.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(a) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
+ aptr = BCL_NUM(ctxt, a);
- assert(aptr != NULL && aptr->num != NULL);
+ assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
// Clear and initialize the result.
- bc_num_clear(&b);
- bc_num_init(&b, BC_NUM_DEF_SIZE);
+ bc_num_clear(BCL_NUM_NUM_NP(b));
+ bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
- bc_num_irand(aptr, &b, &vm->rng);
+ bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng);
err:
- // Eat the operand.
- bcl_num_dtor(ctxt, a, aptr);
+ if (destruct)
+ {
+ // Eat the operand.
+ bcl_num_dtor(ctxt, a, aptr);
+ }
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, b, idx);
@@ -1218,6 +1463,18 @@ err:
return idx;
}
+BclNumber
+bcl_irand(BclNumber a)
+{
+ return bcl_irand_helper(a, true);
+}
+
+BclNumber
+bcl_irand_keep(BclNumber a)
+{
+ return bcl_irand_helper(a, false);
+}
+
/**
* Helps bcl_frand(). This is separate because the error handling is easier that
* way. It is also easier to do ifrand that way.
@@ -1257,6 +1514,7 @@ bcl_frandHelper(BcNum* restrict b, size_t places)
bc_num_shiftRight(b, places);
err:
+
bc_num_free(&pow);
BC_LONGJMP_CONT(vm);
}
@@ -1265,7 +1523,7 @@ BclNumber
bcl_frand(size_t places)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1274,13 +1532,13 @@ bcl_frand(size_t places)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
// Clear and initialize the number.
- bc_num_clear(&n);
- bc_num_init(&n, BC_NUM_DEF_SIZE);
+ bc_num_clear(BCL_NUM_NUM_NP(n));
+ bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
- bcl_frandHelper(&n, places);
+ bcl_frandHelper(BCL_NUM_NUM_NP(n), places);
err:
@@ -1319,17 +1577,18 @@ bcl_ifrandHelper(BcNum* restrict a, BcNum* restrict b, size_t places)
bc_num_add(&ir, &fr, b, 0);
err:
+
bc_num_free(&fr);
bc_num_free(&ir);
BC_LONGJMP_CONT(vm);
}
-BclNumber
-bcl_ifrand(BclNumber a, size_t places)
+static BclNumber
+bcl_ifrand_helper(BclNumber a, size_t places, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1339,24 +1598,27 @@ bcl_ifrand(BclNumber a, size_t places)
BC_FUNC_HEADER(vm, err);
- bc_vec_grow(&ctxt->nums, 1);
+ BCL_GROW_NUMS(ctxt);
- assert(a.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(a) < ctxt->nums.len);
- aptr = BC_NUM(ctxt, a);
+ aptr = BCL_NUM(ctxt, a);
- assert(aptr != NULL && aptr->num != NULL);
+ assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
// Clear and initialize the number.
- bc_num_clear(&b);
- bc_num_init(&b, BC_NUM_DEF_SIZE);
+ bc_num_clear(BCL_NUM_NUM_NP(b));
+ bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
- bcl_ifrandHelper(aptr, &b, places);
+ bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places);
err:
- // Eat the oprand.
- bcl_num_dtor(ctxt, a, aptr);
+ if (destruct)
+ {
+ // Eat the oprand.
+ bcl_num_dtor(ctxt, a, aptr);
+ }
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, b, idx);
@@ -1364,11 +1626,23 @@ err:
return idx;
}
-BclError
-bcl_rand_seedWithNum(BclNumber n)
+BclNumber
+bcl_ifrand(BclNumber a, size_t places)
+{
+ return bcl_ifrand_helper(a, places, true);
+}
+
+BclNumber
+bcl_ifrand_keep(BclNumber a, size_t places)
+{
+ return bcl_ifrand_helper(a, places, false);
+}
+
+static BclError
+bcl_rand_seedWithNum_helper(BclNumber n, bool destruct)
{
BclError e = BCL_ERROR_NONE;
- BcNum* nptr;
+ BclNum* nptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1377,20 +1651,40 @@ bcl_rand_seedWithNum(BclNumber n)
BC_FUNC_HEADER(vm, err);
- assert(n.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(n) < ctxt->nums.len);
- nptr = BC_NUM(ctxt, n);
+ nptr = BCL_NUM(ctxt, n);
- assert(nptr != NULL && nptr->num != NULL);
+ assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
- bc_num_rng(nptr, &vm->rng);
+ bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng);
err:
+
+ if (destruct)
+ {
+ // Eat the oprand.
+ bcl_num_dtor(ctxt, n, nptr);
+ }
+
BC_FUNC_FOOTER(vm, e);
+
return e;
}
BclError
+bcl_rand_seedWithNum(BclNumber n)
+{
+ return bcl_rand_seedWithNum_helper(n, true);
+}
+
+BclError
+bcl_rand_seedWithNum_keep(BclNumber n)
+{
+ return bcl_rand_seedWithNum_helper(n, false);
+}
+
+BclError
bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE])
{
BclError e = BCL_ERROR_NONE;
@@ -1411,7 +1705,9 @@ bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE])
bc_rand_seed(&vm->rng, vals[0], vals[1], vals[2], vals[3]);
err:
+
BC_FUNC_FOOTER(vm, e);
+
return e;
}
@@ -1427,7 +1723,7 @@ BclNumber
bcl_rand_seed2num(void)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1437,12 +1733,13 @@ bcl_rand_seed2num(void)
BC_FUNC_HEADER(vm, err);
// Clear and initialize the number.
- bc_num_clear(&n);
- bc_num_init(&n, BC_NUM_DEF_SIZE);
+ bc_num_clear(BCL_NUM_NUM_NP(n));
+ bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
- bc_num_createFromRNG(&n, &vm->rng);
+ bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng);
err:
+
BC_FUNC_FOOTER(vm, e);
BC_MAYBE_SETUP(ctxt, e, n, idx);
@@ -1466,4 +1763,6 @@ bcl_rand_bounded(BclRandInt bound)
return (BclRandInt) bc_rand_bounded(&vm->rng, (BcRand) bound);
}
+#endif // BC_ENABLE_EXTRA_MATH
+
#endif // BC_ENABLE_LIBRARY
diff --git a/contrib/bc/src/program.c b/contrib/bc/src/program.c
index b6fac12c7d65..243f827fe98c 100644
--- a/contrib/bc/src/program.c
+++ b/contrib/bc/src/program.c
@@ -757,9 +757,16 @@ bc_program_read(BcProgram* p)
// struct.
bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
}
- // This needs to be updated because the parser could have been used
- // somewhere else
- else bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
+ else
+ {
+ // This needs to be updated because the parser could have been used
+ // somewhere else.
+ bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
+
+ // The read buffer also needs to be emptied or else it will still
+ // contain previous read expressions.
+ bc_vec_empty(&vm->read_buf);
+ }
BC_SETJMP_LOCKED(vm, exec_err);
diff --git a/contrib/bc/src/vm.c b/contrib/bc/src/vm.c
index 3a7913e30c86..29c2715d0271 100644
--- a/contrib/bc/src/vm.c
+++ b/contrib/bc/src/vm.c
@@ -643,12 +643,14 @@ bc_vm_shutdown(void)
if (vm->catalog != BC_VM_INVALID_CATALOG) catclose(vm->catalog);
#endif // BC_ENABLE_NLS
+#if !BC_ENABLE_LIBRARY
#if BC_ENABLE_HISTORY
// This must always run to ensure that the terminal is back to normal, i.e.,
// has raw mode disabled. But we should only do it if we did not have a bad
// terminal because history was not initialized if it is a bad terminal.
if (BC_TTY && !vm->history.badTerm) bc_history_free(&vm->history);
#endif // BC_ENABLE_HISTORY
+#endif // !BC_ENABLE_LIBRARY
#if BC_DEBUG
#if !BC_ENABLE_LIBRARY
diff --git a/contrib/bc/tests/bcl.c b/contrib/bc/tests/bcl.c
index cea63f457cd4..5bb50c29a753 100644
--- a/contrib/bc/tests/bcl.c
+++ b/contrib/bc/tests/bcl.c
@@ -55,7 +55,7 @@ main(void)
BclError e;
BclContext ctxt;
size_t scale;
- BclNumber n, n2, n3, n4, n5, n6;
+ BclNumber n, n2, n3, n4, n5, n6, n7;
char* res;
BclBigDig b = 0;
@@ -124,9 +124,21 @@ main(void)
if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
// Add them and check the result.
+ n5 = bcl_add_keep(n3, n4);
+ err(bcl_err(n5));
+ res = bcl_string(n5);
+ if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
+ if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
+
+ // We want to ensure all memory gets freed because we run this under
+ // Valgrind.
+ free(res);
+
+ // Add them and check the result.
n3 = bcl_add(n3, n4);
err(bcl_err(n3));
- res = bcl_string(bcl_dup(n3));
+ res = bcl_string_keep(n3);
+ if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
// We want to ensure all memory gets freed because we run this under
@@ -136,19 +148,29 @@ main(void)
// Ensure that divmod, a special case, works.
n4 = bcl_parse("8937458902.2890347");
err(bcl_err(n4));
- e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6);
+ e = bcl_divmod_keep(n4, n3, &n5, &n6);
err(e);
res = bcl_string(n5);
-
if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
-
free(res);
res = bcl_string(n6);
-
if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
+ free(res);
+
+ // Ensure that divmod, a special case, works.
+ n4 = bcl_parse("8937458902.2890347");
+ err(bcl_err(n4));
+ e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6);
+ err(e);
+
+ res = bcl_string(n5);
+ if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
+ free(res);
+ res = bcl_string(n6);
+ if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
free(res);
// Ensure that sqrt works. This is also a special case. The reason is
@@ -214,10 +236,18 @@ main(void)
err(bcl_err(n3));
// Repeat.
+ n2 = bcl_ifrand_keep(n3, 10);
+ err(bcl_err(n2));
+
+ // Repeat.
n2 = bcl_ifrand(bcl_dup(n3), 10);
err(bcl_err(n2));
// Still checking asserts.
+ e = bcl_rand_seedWithNum_keep(n3);
+ err(e);
+
+ // Still checking asserts.
e = bcl_rand_seedWithNum(n3);
err(e);
@@ -229,9 +259,12 @@ main(void)
n5 = bcl_parse("10");
err(bcl_err(n5));
- n6 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
+ n6 = bcl_modexp_keep(n5, n5, n5);
err(bcl_err(n6));
+ n7 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
+ err(bcl_err(n7));
+
// Clean up.
bcl_num_free(n);
@@ -250,6 +283,11 @@ main(void)
n4 = bcl_parse("-1.01");
err(bcl_err(n4));
+ res = bcl_string_keep(n);
+ if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
+
+ free(res);
+
res = bcl_string(bcl_dup(n));
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
diff --git a/contrib/bc/tests/read.sh b/contrib/bc/tests/read.sh
index d7be18fdcecb..4881c10db58c 100755
--- a/contrib/bc/tests/read.sh
+++ b/contrib/bc/tests/read.sh
@@ -74,6 +74,7 @@ results="$testdir/$d/read_results.txt"
errors="$testdir/$d/read_errors.txt"
out="$outputdir/${d}_outputs/read_results.txt"
+multiple_res="$outputdir/${d}_outputs/read_multiple_results.txt"
outdir=$(dirname "$out")
# Make sure the directory exists.
@@ -89,11 +90,13 @@ if [ "$d" = "bc" ]; then
halt="halt"
read_call="read()"
read_expr="${read_call}\n5+5;"
+ read_multiple=$(printf '%s\n%s\n%s\n' "3" "2" "1")
else
options="-x"
halt="q"
read_call="?"
read_expr="${read_call}"
+ read_multiple=$(printf '%spR\n%spR\n%spR\n' "3" "2" "1")
fi
# I use these, so unset them to make the tests work.
@@ -116,6 +119,16 @@ done < "$name"
printf 'pass\n'
+printf 'Running %s read multiple...' "$d"
+
+printf '3\n2\n1\n' > "$multiple_res"
+
+# Run multiple read() calls.
+printf '%s\n' "$read_multiple" | "$exe" "$@" "$options" -e "$read_call" -e "$read_call" -e "$read_call" > "$out"
+checktest "$d" "$?" 'read multiple' "$multiple_res" "$out"
+
+printf 'pass\n'
+
printf 'Running %s read errors...' "$d"
# Run read on every line.