aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2023-03-03 22:15:06 +0000
committerStefan Eßer <se@FreeBSD.org>2023-03-03 22:15:06 +0000
commit0ff539eb7ca570d65a23a7ad13a91a673d89abcf (patch)
treed22a622e1a23b8541471a7a7531aa2fd9c48f937
parent61e1a12bb6c3bfdb0a4e499c88e8eaa2b548e427 (diff)
downloadsrc-0ff539eb7ca570d65a23a7ad13a91a673d89abcf.tar.gz
src-0ff539eb7ca570d65a23a7ad13a91a673d89abcf.zip
vendor/bc: import version 6.4.0vendor/bc/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.
-rw-r--r--Makefile.in2
-rw-r--r--NEWS.md19
-rwxr-xr-xconfigure.sh2
-rw-r--r--include/bcl.h51
-rw-r--r--include/library.h210
-rw-r--r--include/program.h210
-rw-r--r--include/version.h2
-rw-r--r--include/vm.h4
-rw-r--r--manuals/bcl.3422
-rw-r--r--manuals/bcl.3.md320
-rw-r--r--src/data.c75
-rw-r--r--src/library.c739
-rw-r--r--src/program.c13
-rw-r--r--src/vm.c2
-rw-r--r--tests/bcl.c52
-rwxr-xr-xtests/read.sh13
16 files changed, 1693 insertions, 443 deletions
diff --git a/Makefile.in b/Makefile.in
index 89ddb7589c47..f936fc2c6de6 100644
--- a/Makefile.in
+++ b/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/NEWS.md b/NEWS.md
index ad118e401c32..6dff6822fb16 100644
--- a/NEWS.md
+++ b/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/configure.sh b/configure.sh
index 3ada5298e9ed..021d30807ffb 100755
--- a/configure.sh
+++ b/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/include/bcl.h b/include/bcl.h
index 253138231c66..0908e215182c 100644
--- a/include/bcl.h
+++ b/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/include/library.h b/include/library.h
index 76df91392da1..1edd3757444c 100644
--- a/include/library.h
+++ b/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/include/program.h b/include/program.h
index ff32d5db7760..1df753afad22 100644
--- a/include/program.h
+++ b/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/include/version.h b/include/version.h
index f5e345b3b189..3745ed9b5f74 100644
--- a/include/version.h
+++ b/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/include/vm.h b/include/vm.h
index dd21d43f5260..c56cc8e7370a 100644
--- a/include/vm.h
+++ b/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/manuals/bcl.3 b/manuals/bcl.3
index 5c3731a141eb..cb65a2b8b991 100644
--- a/manuals/bcl.3
+++ b/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/manuals/bcl.3.md b/manuals/bcl.3.md
index 6c6967b44770..fa566d161c43 100644
--- a/manuals/bcl.3.md
+++ b/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/src/data.c b/src/data.c
index abaf3b8e39ab..b57e1fc4c02d 100644
--- a/src/data.c
+++ b/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/src/library.c b/src/library.c
index 6283d198139e..cc32a3a3a98c 100644
--- a/src/library.c
+++ b/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/src/program.c b/src/program.c
index b6fac12c7d65..243f827fe98c 100644
--- a/src/program.c
+++ b/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/src/vm.c b/src/vm.c
index 3a7913e30c86..29c2715d0271 100644
--- a/src/vm.c
+++ b/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/tests/bcl.c b/tests/bcl.c
index cea63f457cd4..5bb50c29a753 100644
--- a/tests/bcl.c
+++ b/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/tests/read.sh b/tests/read.sh
index d7be18fdcecb..4881c10db58c 100755
--- a/tests/read.sh
+++ b/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.