xref: /freebsd/contrib/bc/src/library.c (revision 44d4804d1945435745518cd09eb8ae6ab22ecef4)
150696a6eSStefan Eßer /*
250696a6eSStefan Eßer  * *****************************************************************************
350696a6eSStefan Eßer  *
450696a6eSStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
550696a6eSStefan Eßer  *
610328f8bSStefan Eßer  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
750696a6eSStefan Eßer  *
850696a6eSStefan Eßer  * Redistribution and use in source and binary forms, with or without
950696a6eSStefan Eßer  * modification, are permitted provided that the following conditions are met:
1050696a6eSStefan Eßer  *
1150696a6eSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
1250696a6eSStefan Eßer  *   list of conditions and the following disclaimer.
1350696a6eSStefan Eßer  *
1450696a6eSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
1550696a6eSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
1650696a6eSStefan Eßer  *   and/or other materials provided with the distribution.
1750696a6eSStefan Eßer  *
1850696a6eSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1950696a6eSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2050696a6eSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2150696a6eSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2250696a6eSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2350696a6eSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2450696a6eSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2550696a6eSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2650696a6eSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2750696a6eSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2850696a6eSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
2950696a6eSStefan Eßer  *
3050696a6eSStefan Eßer  * *****************************************************************************
3150696a6eSStefan Eßer  *
3250696a6eSStefan Eßer  * The public functions for libbc.
3350696a6eSStefan Eßer  *
3450696a6eSStefan Eßer  */
3550696a6eSStefan Eßer 
3650696a6eSStefan Eßer #if BC_ENABLE_LIBRARY
3750696a6eSStefan Eßer 
3850696a6eSStefan Eßer #include <setjmp.h>
3950696a6eSStefan Eßer #include <string.h>
4050696a6eSStefan Eßer #include <time.h>
4150696a6eSStefan Eßer 
4250696a6eSStefan Eßer #include <bcl.h>
4350696a6eSStefan Eßer 
4450696a6eSStefan Eßer #include <library.h>
4550696a6eSStefan Eßer #include <num.h>
4650696a6eSStefan Eßer #include <vm.h>
4750696a6eSStefan Eßer 
48*44d4804dSStefan Eßer // The asserts in this file are important to testing; in many cases, the test
49*44d4804dSStefan Eßer // would not work without the asserts, so don't remove them without reason.
50*44d4804dSStefan Eßer //
51*44d4804dSStefan Eßer // Also, there are many uses of bc_num_clear() here; that is because numbers are
52*44d4804dSStefan Eßer // being reused, and a clean slate is required.
53*44d4804dSStefan Eßer //
54*44d4804dSStefan Eßer // Also, there are a bunch of BC_UNSETJMP and BC_SETJMP_LOCKED() between calls
55*44d4804dSStefan Eßer // to bc_num_init(). That is because locals are being initialized, and unlike bc
56*44d4804dSStefan Eßer // proper, this code cannot assume that allocation failures are fatal. So we
57*44d4804dSStefan Eßer // have to reset the jumps every time to ensure that the locals will be correct
58*44d4804dSStefan Eßer // after jumping.
5950696a6eSStefan Eßer 
6050696a6eSStefan Eßer void bcl_handleSignal(void) {
6150696a6eSStefan Eßer 
6250696a6eSStefan Eßer 	// Signal already in flight, or bc is not executing.
6350696a6eSStefan Eßer 	if (vm.sig || !vm.running) return;
6450696a6eSStefan Eßer 
6550696a6eSStefan Eßer 	vm.sig = 1;
6650696a6eSStefan Eßer 
6750696a6eSStefan Eßer 	assert(vm.jmp_bufs.len);
6850696a6eSStefan Eßer 
69*44d4804dSStefan Eßer 	if (!vm.sig_lock) BC_JMP;
7050696a6eSStefan Eßer }
7150696a6eSStefan Eßer 
7250696a6eSStefan Eßer bool bcl_running(void) {
7350696a6eSStefan Eßer 	return vm.running != 0;
7450696a6eSStefan Eßer }
7550696a6eSStefan Eßer 
7650696a6eSStefan Eßer BclError bcl_init(void) {
7750696a6eSStefan Eßer 
7850696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
7950696a6eSStefan Eßer 
8050696a6eSStefan Eßer 	vm.refs += 1;
8150696a6eSStefan Eßer 
8250696a6eSStefan Eßer 	if (vm.refs > 1) return e;
8350696a6eSStefan Eßer 
84*44d4804dSStefan Eßer 	// Setting these to NULL ensures that if an error occurs, we only free what
85*44d4804dSStefan Eßer 	// is necessary.
8650696a6eSStefan Eßer 	vm.ctxts.v = NULL;
8750696a6eSStefan Eßer 	vm.jmp_bufs.v = NULL;
8850696a6eSStefan Eßer 	vm.out.v = NULL;
8950696a6eSStefan Eßer 
9050696a6eSStefan Eßer 	vm.abrt = false;
9150696a6eSStefan Eßer 
9250696a6eSStefan Eßer 	BC_SIG_LOCK;
9350696a6eSStefan Eßer 
94*44d4804dSStefan Eßer 	// The jmp_bufs always has to be initialized first.
95*44d4804dSStefan Eßer 	bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE);
9650696a6eSStefan Eßer 
9750696a6eSStefan Eßer 	BC_FUNC_HEADER_INIT(err);
9850696a6eSStefan Eßer 
9950696a6eSStefan Eßer 	bc_vm_init();
10050696a6eSStefan Eßer 
101*44d4804dSStefan Eßer 	bc_vec_init(&vm.ctxts, sizeof(BclContext), BC_DTOR_NONE);
102*44d4804dSStefan Eßer 	bc_vec_init(&vm.out, sizeof(uchar), BC_DTOR_NONE);
10350696a6eSStefan Eßer 
104*44d4804dSStefan Eßer 	// We need to seed this in case /dev/random and /dev/urandm don't work.
10550696a6eSStefan Eßer 	srand((unsigned int) time(NULL));
10650696a6eSStefan Eßer 	bc_rand_init(&vm.rng);
10750696a6eSStefan Eßer 
10850696a6eSStefan Eßer err:
109*44d4804dSStefan Eßer 	// This is why we had to set them to NULL.
11050696a6eSStefan Eßer 	if (BC_ERR(vm.err)) {
11150696a6eSStefan Eßer 		if (vm.out.v != NULL) bc_vec_free(&vm.out);
11250696a6eSStefan Eßer 		if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs);
11350696a6eSStefan Eßer 		if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts);
11450696a6eSStefan Eßer 	}
11550696a6eSStefan Eßer 
11650696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
11750696a6eSStefan Eßer 
11850696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
11950696a6eSStefan Eßer 
12050696a6eSStefan Eßer 	return e;
12150696a6eSStefan Eßer }
12250696a6eSStefan Eßer 
12350696a6eSStefan Eßer BclError bcl_pushContext(BclContext ctxt) {
12450696a6eSStefan Eßer 
12550696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
12650696a6eSStefan Eßer 
12750696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
12850696a6eSStefan Eßer 
12950696a6eSStefan Eßer 	bc_vec_push(&vm.ctxts, &ctxt);
13050696a6eSStefan Eßer 
13150696a6eSStefan Eßer err:
13250696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
13350696a6eSStefan Eßer 	return e;
13450696a6eSStefan Eßer }
13550696a6eSStefan Eßer 
13650696a6eSStefan Eßer void bcl_popContext(void) {
13750696a6eSStefan Eßer 	if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
13850696a6eSStefan Eßer }
13950696a6eSStefan Eßer 
14050696a6eSStefan Eßer BclContext bcl_context(void) {
14150696a6eSStefan Eßer 	if (!vm.ctxts.len) return NULL;
14250696a6eSStefan Eßer 	return *((BclContext*) bc_vec_top(&vm.ctxts));
14350696a6eSStefan Eßer }
14450696a6eSStefan Eßer 
14550696a6eSStefan Eßer void bcl_free(void) {
14650696a6eSStefan Eßer 
147*44d4804dSStefan Eßer 	size_t i;
148*44d4804dSStefan Eßer 
14950696a6eSStefan Eßer 	vm.refs -= 1;
15050696a6eSStefan Eßer 
15150696a6eSStefan Eßer 	if (vm.refs) return;
15250696a6eSStefan Eßer 
15350696a6eSStefan Eßer 	BC_SIG_LOCK;
15450696a6eSStefan Eßer 
15550696a6eSStefan Eßer 	bc_rand_free(&vm.rng);
15650696a6eSStefan Eßer 	bc_vec_free(&vm.out);
15750696a6eSStefan Eßer 
15850696a6eSStefan Eßer 	for (i = 0; i < vm.ctxts.len; ++i) {
15950696a6eSStefan Eßer 		BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i));
16050696a6eSStefan Eßer 		bcl_ctxt_free(ctxt);
16150696a6eSStefan Eßer 	}
16250696a6eSStefan Eßer 
16350696a6eSStefan Eßer 	bc_vec_free(&vm.ctxts);
16450696a6eSStefan Eßer 
16510328f8bSStefan Eßer 	bc_vm_atexit();
16650696a6eSStefan Eßer 
16750696a6eSStefan Eßer 	BC_SIG_UNLOCK;
16850696a6eSStefan Eßer 
16950696a6eSStefan Eßer 	memset(&vm, 0, sizeof(BcVm));
17050696a6eSStefan Eßer 
17150696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
17250696a6eSStefan Eßer }
17350696a6eSStefan Eßer 
17450696a6eSStefan Eßer void bcl_gc(void) {
175*44d4804dSStefan Eßer 	BC_SIG_LOCK;
17650696a6eSStefan Eßer 	bc_vm_freeTemps();
177*44d4804dSStefan Eßer 	BC_SIG_UNLOCK;
17850696a6eSStefan Eßer }
17950696a6eSStefan Eßer 
18050696a6eSStefan Eßer bool bcl_abortOnFatalError(void) {
18150696a6eSStefan Eßer 	return vm.abrt;
18250696a6eSStefan Eßer }
18350696a6eSStefan Eßer 
18450696a6eSStefan Eßer void bcl_setAbortOnFatalError(bool abrt) {
18550696a6eSStefan Eßer 	vm.abrt = abrt;
18650696a6eSStefan Eßer }
18750696a6eSStefan Eßer 
18850696a6eSStefan Eßer BclContext bcl_ctxt_create(void) {
18950696a6eSStefan Eßer 
19050696a6eSStefan Eßer 	BclContext ctxt = NULL;
19150696a6eSStefan Eßer 
19250696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
19350696a6eSStefan Eßer 
194*44d4804dSStefan Eßer 	// We want the context to be free of any interference of other parties, so
195*44d4804dSStefan Eßer 	// malloc() is appropriate here.
19650696a6eSStefan Eßer 	ctxt = bc_vm_malloc(sizeof(BclCtxt));
19750696a6eSStefan Eßer 
198*44d4804dSStefan Eßer 	bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM);
199*44d4804dSStefan Eßer 	bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
20050696a6eSStefan Eßer 
20150696a6eSStefan Eßer 	ctxt->scale = 0;
20250696a6eSStefan Eßer 	ctxt->ibase = 10;
20350696a6eSStefan Eßer 	ctxt->obase= 10;
20450696a6eSStefan Eßer 
20550696a6eSStefan Eßer err:
20650696a6eSStefan Eßer 	if (BC_ERR(vm.err && ctxt != NULL)) {
20750696a6eSStefan Eßer 		if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
20850696a6eSStefan Eßer 		free(ctxt);
20950696a6eSStefan Eßer 		ctxt = NULL;
21050696a6eSStefan Eßer 	}
21150696a6eSStefan Eßer 
21250696a6eSStefan Eßer 	BC_FUNC_FOOTER_NO_ERR;
21350696a6eSStefan Eßer 
21450696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
21550696a6eSStefan Eßer 
21650696a6eSStefan Eßer 	return ctxt;
21750696a6eSStefan Eßer }
21850696a6eSStefan Eßer 
21950696a6eSStefan Eßer void bcl_ctxt_free(BclContext ctxt) {
22050696a6eSStefan Eßer 	BC_SIG_LOCK;
22150696a6eSStefan Eßer 	bc_vec_free(&ctxt->free_nums);
22250696a6eSStefan Eßer 	bc_vec_free(&ctxt->nums);
22350696a6eSStefan Eßer 	free(ctxt);
22450696a6eSStefan Eßer 	BC_SIG_UNLOCK;
22550696a6eSStefan Eßer }
22650696a6eSStefan Eßer 
22750696a6eSStefan Eßer void bcl_ctxt_freeNums(BclContext ctxt) {
22810328f8bSStefan Eßer 	bc_vec_popAll(&ctxt->nums);
22910328f8bSStefan Eßer 	bc_vec_popAll(&ctxt->free_nums);
23050696a6eSStefan Eßer }
23150696a6eSStefan Eßer 
23250696a6eSStefan Eßer size_t bcl_ctxt_scale(BclContext ctxt) {
23350696a6eSStefan Eßer 	return ctxt->scale;
23450696a6eSStefan Eßer }
23550696a6eSStefan Eßer 
23650696a6eSStefan Eßer void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
23750696a6eSStefan Eßer 	ctxt->scale = scale;
23850696a6eSStefan Eßer }
23950696a6eSStefan Eßer 
24050696a6eSStefan Eßer size_t bcl_ctxt_ibase(BclContext ctxt) {
24150696a6eSStefan Eßer 	return ctxt->ibase;
24250696a6eSStefan Eßer }
24350696a6eSStefan Eßer 
24450696a6eSStefan Eßer void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) {
24550696a6eSStefan Eßer 	if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
24650696a6eSStefan Eßer 	else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
24750696a6eSStefan Eßer 	ctxt->ibase = ibase;
24850696a6eSStefan Eßer }
24950696a6eSStefan Eßer 
25050696a6eSStefan Eßer size_t bcl_ctxt_obase(BclContext ctxt) {
25150696a6eSStefan Eßer 	return ctxt->obase;
25250696a6eSStefan Eßer }
25350696a6eSStefan Eßer 
25450696a6eSStefan Eßer void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
25550696a6eSStefan Eßer 	ctxt->obase = obase;
25650696a6eSStefan Eßer }
25750696a6eSStefan Eßer 
25850696a6eSStefan Eßer BclError bcl_err(BclNumber n) {
25950696a6eSStefan Eßer 
26050696a6eSStefan Eßer 	BclContext ctxt;
26150696a6eSStefan Eßer 
26250696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
26350696a6eSStefan Eßer 
264*44d4804dSStefan Eßer 	// Errors are encoded as (0 - error_code). If the index is in that range, it
265*44d4804dSStefan Eßer 	// is an encoded error.
26650696a6eSStefan Eßer 	if (n.i >= ctxt->nums.len) {
26750696a6eSStefan Eßer 		if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
26850696a6eSStefan Eßer 		else return BCL_ERROR_INVALID_NUM;
26950696a6eSStefan Eßer 	}
27050696a6eSStefan Eßer 	else return BCL_ERROR_NONE;
27150696a6eSStefan Eßer }
27250696a6eSStefan Eßer 
273*44d4804dSStefan Eßer /**
274*44d4804dSStefan Eßer  * Inserts a BcNum into a context's list of numbers.
275*44d4804dSStefan Eßer  * @param ctxt  The context to insert into.
276*44d4804dSStefan Eßer  * @param n     The BcNum to insert.
277*44d4804dSStefan Eßer  * @return      The resulting BclNumber from the insert.
278*44d4804dSStefan Eßer  */
27950696a6eSStefan Eßer static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) {
28050696a6eSStefan Eßer 
28150696a6eSStefan Eßer 	BclNumber idx;
28250696a6eSStefan Eßer 
283*44d4804dSStefan Eßer 	// If there is a free spot...
28450696a6eSStefan Eßer 	if (ctxt->free_nums.len) {
28550696a6eSStefan Eßer 
28650696a6eSStefan Eßer 		BcNum *ptr;
28750696a6eSStefan Eßer 
288*44d4804dSStefan Eßer 		// Get the index of the free spot and remove it.
28950696a6eSStefan Eßer 		idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
29050696a6eSStefan Eßer 		bc_vec_pop(&ctxt->free_nums);
29150696a6eSStefan Eßer 
292*44d4804dSStefan Eßer 		// Copy the number into the spot.
29350696a6eSStefan Eßer 		ptr = bc_vec_item(&ctxt->nums, idx.i);
29450696a6eSStefan Eßer 		memcpy(ptr, n, sizeof(BcNum));
29550696a6eSStefan Eßer 	}
29650696a6eSStefan Eßer 	else {
297*44d4804dSStefan Eßer 		// Just push the number onto the vector.
29850696a6eSStefan Eßer 		idx.i = ctxt->nums.len;
29950696a6eSStefan Eßer 		bc_vec_push(&ctxt->nums, n);
30050696a6eSStefan Eßer 	}
30150696a6eSStefan Eßer 
30250696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
30350696a6eSStefan Eßer 
30450696a6eSStefan Eßer 	return idx;
30550696a6eSStefan Eßer }
30650696a6eSStefan Eßer 
30750696a6eSStefan Eßer BclNumber bcl_num_create(void) {
30850696a6eSStefan Eßer 
30950696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
31050696a6eSStefan Eßer 	BcNum n;
31150696a6eSStefan Eßer 	BclNumber idx;
31250696a6eSStefan Eßer 	BclContext ctxt;
31350696a6eSStefan Eßer 
31450696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
31550696a6eSStefan Eßer 
31650696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
31750696a6eSStefan Eßer 
31850696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
31950696a6eSStefan Eßer 
32050696a6eSStefan Eßer 	bc_num_init(&n, BC_NUM_DEF_SIZE);
32150696a6eSStefan Eßer 
32250696a6eSStefan Eßer err:
32350696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
32450696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, n, idx);
32550696a6eSStefan Eßer 
32650696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
32750696a6eSStefan Eßer 
32850696a6eSStefan Eßer 	return idx;
32950696a6eSStefan Eßer }
33050696a6eSStefan Eßer 
331*44d4804dSStefan Eßer /**
332*44d4804dSStefan Eßer  * Destructs a number and marks its spot as free.
333*44d4804dSStefan Eßer  * @param ctxt  The context.
334*44d4804dSStefan Eßer  * @param n     The index of the number.
335*44d4804dSStefan Eßer  * @param num   The number to destroy.
336*44d4804dSStefan Eßer  */
33750696a6eSStefan Eßer static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) {
33850696a6eSStefan Eßer 
33950696a6eSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
34050696a6eSStefan Eßer 
34150696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
34250696a6eSStefan Eßer 
34350696a6eSStefan Eßer 	bcl_num_destruct(num);
34450696a6eSStefan Eßer 	bc_vec_push(&ctxt->free_nums, &n);
34550696a6eSStefan Eßer }
34650696a6eSStefan Eßer 
34750696a6eSStefan Eßer void bcl_num_free(BclNumber n) {
34850696a6eSStefan Eßer 
34950696a6eSStefan Eßer 	BcNum *num;
35050696a6eSStefan Eßer 	BclContext ctxt;
35150696a6eSStefan Eßer 
35250696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
35350696a6eSStefan Eßer 
35450696a6eSStefan Eßer 	BC_SIG_LOCK;
35550696a6eSStefan Eßer 
35650696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
35750696a6eSStefan Eßer 
35850696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
35950696a6eSStefan Eßer 
36050696a6eSStefan Eßer 	bcl_num_dtor(ctxt, n, num);
36150696a6eSStefan Eßer 
36250696a6eSStefan Eßer 	BC_SIG_UNLOCK;
36350696a6eSStefan Eßer }
36450696a6eSStefan Eßer 
36550696a6eSStefan Eßer BclError bcl_copy(BclNumber d, BclNumber s) {
36650696a6eSStefan Eßer 
36750696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
36850696a6eSStefan Eßer 	BcNum *dest, *src;
36950696a6eSStefan Eßer 	BclContext ctxt;
37050696a6eSStefan Eßer 
37150696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
37250696a6eSStefan Eßer 
37350696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
37450696a6eSStefan Eßer 
37550696a6eSStefan Eßer 	assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
37650696a6eSStefan Eßer 
37750696a6eSStefan Eßer 	dest = BC_NUM(ctxt, d);
37850696a6eSStefan Eßer 	src = BC_NUM(ctxt, s);
37950696a6eSStefan Eßer 
38050696a6eSStefan Eßer 	assert(dest != NULL && src != NULL);
38150696a6eSStefan Eßer 	assert(dest->num != NULL && src->num != NULL);
38250696a6eSStefan Eßer 
38350696a6eSStefan Eßer 	bc_num_copy(dest, src);
38450696a6eSStefan Eßer 
38550696a6eSStefan Eßer err:
38650696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
38750696a6eSStefan Eßer 
38850696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
38950696a6eSStefan Eßer 
39050696a6eSStefan Eßer 	return e;
39150696a6eSStefan Eßer }
39250696a6eSStefan Eßer 
39350696a6eSStefan Eßer BclNumber bcl_dup(BclNumber s) {
39450696a6eSStefan Eßer 
39550696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
39650696a6eSStefan Eßer 	BcNum *src, dest;
39750696a6eSStefan Eßer 	BclNumber idx;
39850696a6eSStefan Eßer 	BclContext ctxt;
39950696a6eSStefan Eßer 
40050696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
40150696a6eSStefan Eßer 
40250696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
40350696a6eSStefan Eßer 
40450696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
40550696a6eSStefan Eßer 
40650696a6eSStefan Eßer 	assert(s.i < ctxt->nums.len);
40750696a6eSStefan Eßer 
40850696a6eSStefan Eßer 	src = BC_NUM(ctxt, s);
40950696a6eSStefan Eßer 
41050696a6eSStefan Eßer 	assert(src != NULL && src->num != NULL);
41150696a6eSStefan Eßer 
412*44d4804dSStefan Eßer 	// Copy the number.
41350696a6eSStefan Eßer 	bc_num_clear(&dest);
41450696a6eSStefan Eßer 	bc_num_createCopy(&dest, src);
41550696a6eSStefan Eßer 
41650696a6eSStefan Eßer err:
41750696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
41850696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, dest, idx);
41950696a6eSStefan Eßer 
42050696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
42150696a6eSStefan Eßer 
42250696a6eSStefan Eßer 	return idx;
42350696a6eSStefan Eßer }
42450696a6eSStefan Eßer 
425*44d4804dSStefan Eßer void bcl_num_destruct(void *num) {
42650696a6eSStefan Eßer 
42750696a6eSStefan Eßer 	BcNum *n = (BcNum*) num;
42850696a6eSStefan Eßer 
42950696a6eSStefan Eßer 	assert(n != NULL);
43050696a6eSStefan Eßer 
43150696a6eSStefan Eßer 	if (n->num == NULL) return;
43250696a6eSStefan Eßer 
43350696a6eSStefan Eßer 	bc_num_free(num);
43450696a6eSStefan Eßer 	bc_num_clear(num);
43550696a6eSStefan Eßer }
43650696a6eSStefan Eßer 
43750696a6eSStefan Eßer bool bcl_num_neg(BclNumber n) {
43850696a6eSStefan Eßer 
43950696a6eSStefan Eßer 	BcNum *num;
44050696a6eSStefan Eßer 	BclContext ctxt;
44150696a6eSStefan Eßer 
44250696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
44350696a6eSStefan Eßer 
44450696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
44550696a6eSStefan Eßer 
44650696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
44750696a6eSStefan Eßer 
44850696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
44950696a6eSStefan Eßer 
45050696a6eSStefan Eßer 	return BC_NUM_NEG(num) != 0;
45150696a6eSStefan Eßer }
45250696a6eSStefan Eßer 
45350696a6eSStefan Eßer void bcl_num_setNeg(BclNumber n, bool neg) {
45450696a6eSStefan Eßer 
45550696a6eSStefan Eßer 	BcNum *num;
45650696a6eSStefan Eßer 	BclContext ctxt;
45750696a6eSStefan Eßer 
45850696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
45950696a6eSStefan Eßer 
46050696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
46150696a6eSStefan Eßer 
46250696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
46350696a6eSStefan Eßer 
46450696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
46550696a6eSStefan Eßer 
46650696a6eSStefan Eßer 	num->rdx = BC_NUM_NEG_VAL(num, neg);
46750696a6eSStefan Eßer }
46850696a6eSStefan Eßer 
46950696a6eSStefan Eßer size_t bcl_num_scale(BclNumber n) {
47050696a6eSStefan Eßer 
47150696a6eSStefan Eßer 	BcNum *num;
47250696a6eSStefan Eßer 	BclContext ctxt;
47350696a6eSStefan Eßer 
47450696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
47550696a6eSStefan Eßer 
47650696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
47750696a6eSStefan Eßer 
47850696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
47950696a6eSStefan Eßer 
48050696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
48150696a6eSStefan Eßer 
48250696a6eSStefan Eßer 	return bc_num_scale(num);
48350696a6eSStefan Eßer }
48450696a6eSStefan Eßer 
48550696a6eSStefan Eßer BclError bcl_num_setScale(BclNumber n, size_t scale) {
48650696a6eSStefan Eßer 
48750696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
48850696a6eSStefan Eßer 	BcNum *nptr;
48950696a6eSStefan Eßer 	BclContext ctxt;
49050696a6eSStefan Eßer 
49150696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
49250696a6eSStefan Eßer 
49350696a6eSStefan Eßer 	BC_CHECK_NUM_ERR(ctxt, n);
49450696a6eSStefan Eßer 
49550696a6eSStefan Eßer 	BC_FUNC_HEADER(err);
49650696a6eSStefan Eßer 
49750696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
49850696a6eSStefan Eßer 
49950696a6eSStefan Eßer 	nptr = BC_NUM(ctxt, n);
50050696a6eSStefan Eßer 
50150696a6eSStefan Eßer 	assert(nptr != NULL && nptr->num != NULL);
50250696a6eSStefan Eßer 
50350696a6eSStefan Eßer 	if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
50450696a6eSStefan Eßer 	else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
50550696a6eSStefan Eßer 
50650696a6eSStefan Eßer err:
50750696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
50850696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
50950696a6eSStefan Eßer 
51050696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
51150696a6eSStefan Eßer 
51250696a6eSStefan Eßer 	return e;
51350696a6eSStefan Eßer }
51450696a6eSStefan Eßer 
51550696a6eSStefan Eßer size_t bcl_num_len(BclNumber n) {
51650696a6eSStefan Eßer 
51750696a6eSStefan Eßer 	BcNum *num;
51850696a6eSStefan Eßer 	BclContext ctxt;
51950696a6eSStefan Eßer 
52050696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
52150696a6eSStefan Eßer 
52250696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
52350696a6eSStefan Eßer 
52450696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
52550696a6eSStefan Eßer 
52650696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
52750696a6eSStefan Eßer 
52850696a6eSStefan Eßer 	return bc_num_len(num);
52950696a6eSStefan Eßer }
53050696a6eSStefan Eßer 
53150696a6eSStefan Eßer BclError bcl_bigdig(BclNumber n, BclBigDig *result) {
53250696a6eSStefan Eßer 
53350696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
53450696a6eSStefan Eßer 	BcNum *num;
53550696a6eSStefan Eßer 	BclContext ctxt;
53650696a6eSStefan Eßer 
53750696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
53850696a6eSStefan Eßer 
53950696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
54050696a6eSStefan Eßer 
54150696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
54250696a6eSStefan Eßer 	assert(result != NULL);
54350696a6eSStefan Eßer 
54450696a6eSStefan Eßer 	num = BC_NUM(ctxt, n);
54550696a6eSStefan Eßer 
54650696a6eSStefan Eßer 	assert(num != NULL && num->num != NULL);
54750696a6eSStefan Eßer 
548*44d4804dSStefan Eßer 	*result = bc_num_bigdig(num);
54950696a6eSStefan Eßer 
55050696a6eSStefan Eßer err:
55150696a6eSStefan Eßer 	bcl_num_dtor(ctxt, n, num);
55250696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
55350696a6eSStefan Eßer 
55450696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
55550696a6eSStefan Eßer 
55650696a6eSStefan Eßer 	return e;
55750696a6eSStefan Eßer }
55850696a6eSStefan Eßer 
55950696a6eSStefan Eßer BclNumber bcl_bigdig2num(BclBigDig val) {
56050696a6eSStefan Eßer 
56150696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
56250696a6eSStefan Eßer 	BcNum n;
56350696a6eSStefan Eßer 	BclNumber idx;
56450696a6eSStefan Eßer 	BclContext ctxt;
56550696a6eSStefan Eßer 
56650696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
56750696a6eSStefan Eßer 
56850696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
56950696a6eSStefan Eßer 
57050696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
57150696a6eSStefan Eßer 
57250696a6eSStefan Eßer 	bc_num_createFromBigdig(&n, val);
57350696a6eSStefan Eßer 
57450696a6eSStefan Eßer err:
57550696a6eSStefan Eßer 	BC_FUNC_FOOTER_UNLOCK(e);
57650696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, n, idx);
57750696a6eSStefan Eßer 
57850696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
57950696a6eSStefan Eßer 
58050696a6eSStefan Eßer 	return idx;
58150696a6eSStefan Eßer }
58250696a6eSStefan Eßer 
583*44d4804dSStefan Eßer /**
584*44d4804dSStefan Eßer  * Sets up and executes a binary operator operation.
585*44d4804dSStefan Eßer  * @param a     The first operand.
586*44d4804dSStefan Eßer  * @param b     The second operand.
587*44d4804dSStefan Eßer  * @param op    The operation.
588*44d4804dSStefan Eßer  * @param req   The function to get the size of the result for preallocation.
589*44d4804dSStefan Eßer  * @return      The result of the operation.
590*44d4804dSStefan Eßer  */
591*44d4804dSStefan Eßer static BclNumber bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
59250696a6eSStefan Eßer                             const BcNumBinaryOpReq req)
59350696a6eSStefan Eßer {
59450696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
59550696a6eSStefan Eßer 	BcNum *aptr, *bptr;
59650696a6eSStefan Eßer 	BcNum c;
59750696a6eSStefan Eßer 	BclNumber idx;
59850696a6eSStefan Eßer 	BclContext ctxt;
59950696a6eSStefan Eßer 
60050696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
60150696a6eSStefan Eßer 
60250696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, a);
60350696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, b);
60450696a6eSStefan Eßer 
60550696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
60650696a6eSStefan Eßer 
60750696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
60850696a6eSStefan Eßer 
60950696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
61050696a6eSStefan Eßer 
61150696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
61250696a6eSStefan Eßer 	bptr = BC_NUM(ctxt, b);
61350696a6eSStefan Eßer 
61450696a6eSStefan Eßer 	assert(aptr != NULL && bptr != NULL);
61550696a6eSStefan Eßer 	assert(aptr->num != NULL && bptr->num != NULL);
61650696a6eSStefan Eßer 
617*44d4804dSStefan Eßer 	// Clear and initialize the result.
61850696a6eSStefan Eßer 	bc_num_clear(&c);
61950696a6eSStefan Eßer 	bc_num_init(&c, req(aptr, bptr, ctxt->scale));
62050696a6eSStefan Eßer 
62150696a6eSStefan Eßer 	BC_SIG_UNLOCK;
62250696a6eSStefan Eßer 
62350696a6eSStefan Eßer 	op(aptr, bptr, &c, ctxt->scale);
62450696a6eSStefan Eßer 
62550696a6eSStefan Eßer err:
626*44d4804dSStefan Eßer 
62750696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
628*44d4804dSStefan Eßer 
629*44d4804dSStefan Eßer 	// Eat the operands.
63050696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
63150696a6eSStefan Eßer 	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
632*44d4804dSStefan Eßer 
63350696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
63450696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, c, idx);
63550696a6eSStefan Eßer 
63650696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
63750696a6eSStefan Eßer 
63850696a6eSStefan Eßer 	return idx;
63950696a6eSStefan Eßer }
64050696a6eSStefan Eßer 
64150696a6eSStefan Eßer BclNumber bcl_add(BclNumber a, BclNumber b) {
64250696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_add, bc_num_addReq);
64350696a6eSStefan Eßer }
64450696a6eSStefan Eßer 
64550696a6eSStefan Eßer BclNumber bcl_sub(BclNumber a, BclNumber b) {
64650696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
64750696a6eSStefan Eßer }
64850696a6eSStefan Eßer 
64950696a6eSStefan Eßer BclNumber bcl_mul(BclNumber a, BclNumber b) {
65050696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
65150696a6eSStefan Eßer }
65250696a6eSStefan Eßer 
65350696a6eSStefan Eßer BclNumber bcl_div(BclNumber a, BclNumber b) {
65450696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_div, bc_num_divReq);
65550696a6eSStefan Eßer }
65650696a6eSStefan Eßer 
65750696a6eSStefan Eßer BclNumber bcl_mod(BclNumber a, BclNumber b) {
65850696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
65950696a6eSStefan Eßer }
66050696a6eSStefan Eßer 
66150696a6eSStefan Eßer BclNumber bcl_pow(BclNumber a, BclNumber b) {
66250696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
66350696a6eSStefan Eßer }
66450696a6eSStefan Eßer 
66550696a6eSStefan Eßer BclNumber bcl_lshift(BclNumber a, BclNumber b) {
66650696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
66750696a6eSStefan Eßer }
66850696a6eSStefan Eßer 
66950696a6eSStefan Eßer BclNumber bcl_rshift(BclNumber a, BclNumber b) {
67050696a6eSStefan Eßer 	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
67150696a6eSStefan Eßer }
67250696a6eSStefan Eßer 
67350696a6eSStefan Eßer BclNumber bcl_sqrt(BclNumber a) {
67450696a6eSStefan Eßer 
67550696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
67650696a6eSStefan Eßer 	BcNum *aptr;
67750696a6eSStefan Eßer 	BcNum b;
67850696a6eSStefan Eßer 	BclNumber idx;
67950696a6eSStefan Eßer 	BclContext ctxt;
68050696a6eSStefan Eßer 
68150696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
68250696a6eSStefan Eßer 
68350696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, a);
68450696a6eSStefan Eßer 
68550696a6eSStefan Eßer 	BC_FUNC_HEADER(err);
68650696a6eSStefan Eßer 
68750696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
68850696a6eSStefan Eßer 
68950696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len);
69050696a6eSStefan Eßer 
69150696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
69250696a6eSStefan Eßer 
69350696a6eSStefan Eßer 	bc_num_sqrt(aptr, &b, ctxt->scale);
69450696a6eSStefan Eßer 
69550696a6eSStefan Eßer err:
69650696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
69750696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
69850696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
69950696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, b, idx);
70050696a6eSStefan Eßer 
70150696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
70250696a6eSStefan Eßer 
70350696a6eSStefan Eßer 	return idx;
70450696a6eSStefan Eßer }
70550696a6eSStefan Eßer 
70650696a6eSStefan Eßer BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) {
70750696a6eSStefan Eßer 
70850696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
70950696a6eSStefan Eßer 	size_t req;
71050696a6eSStefan Eßer 	BcNum *aptr, *bptr;
71150696a6eSStefan Eßer 	BcNum cnum, dnum;
71250696a6eSStefan Eßer 	BclContext ctxt;
71350696a6eSStefan Eßer 
71450696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
71550696a6eSStefan Eßer 
71650696a6eSStefan Eßer 	BC_CHECK_NUM_ERR(ctxt, a);
71750696a6eSStefan Eßer 	BC_CHECK_NUM_ERR(ctxt, b);
71850696a6eSStefan Eßer 
71950696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
72050696a6eSStefan Eßer 
72150696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 2);
72250696a6eSStefan Eßer 
72350696a6eSStefan Eßer 	assert(c != NULL && d != NULL);
72450696a6eSStefan Eßer 
72550696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
72650696a6eSStefan Eßer 	bptr = BC_NUM(ctxt, b);
72750696a6eSStefan Eßer 
72850696a6eSStefan Eßer 	assert(aptr != NULL && bptr != NULL);
72950696a6eSStefan Eßer 	assert(aptr->num != NULL && bptr->num != NULL);
73050696a6eSStefan Eßer 
73150696a6eSStefan Eßer 	bc_num_clear(&cnum);
73250696a6eSStefan Eßer 	bc_num_clear(&dnum);
73350696a6eSStefan Eßer 
73450696a6eSStefan Eßer 	req = bc_num_divReq(aptr, bptr, ctxt->scale);
73550696a6eSStefan Eßer 
736*44d4804dSStefan Eßer 	// Initialize the numbers.
73750696a6eSStefan Eßer 	bc_num_init(&cnum, req);
738*44d4804dSStefan Eßer 	BC_UNSETJMP;
739*44d4804dSStefan Eßer 	BC_SETJMP_LOCKED(err);
74050696a6eSStefan Eßer 	bc_num_init(&dnum, req);
74150696a6eSStefan Eßer 
74250696a6eSStefan Eßer 	BC_SIG_UNLOCK;
74350696a6eSStefan Eßer 
74450696a6eSStefan Eßer 	bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
74550696a6eSStefan Eßer 
74650696a6eSStefan Eßer err:
74750696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
74850696a6eSStefan Eßer 
749*44d4804dSStefan Eßer 	// Eat the operands.
75050696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
75150696a6eSStefan Eßer 	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
75250696a6eSStefan Eßer 
753*44d4804dSStefan Eßer 	// If there was an error...
75450696a6eSStefan Eßer 	if (BC_ERR(vm.err)) {
755*44d4804dSStefan Eßer 
756*44d4804dSStefan Eßer 		// Free the results.
75750696a6eSStefan Eßer 		if (cnum.num != NULL) bc_num_free(&cnum);
75850696a6eSStefan Eßer 		if (dnum.num != NULL) bc_num_free(&dnum);
759*44d4804dSStefan Eßer 
760*44d4804dSStefan Eßer 		// Make sure the return values are invalid.
76150696a6eSStefan Eßer 		c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
76250696a6eSStefan Eßer 		d->i = c->i;
763*44d4804dSStefan Eßer 
76450696a6eSStefan Eßer 		BC_FUNC_FOOTER(e);
76550696a6eSStefan Eßer 	}
76650696a6eSStefan Eßer 	else {
767*44d4804dSStefan Eßer 
76850696a6eSStefan Eßer 		BC_FUNC_FOOTER(e);
769*44d4804dSStefan Eßer 
770*44d4804dSStefan Eßer 		// Insert the results into the context.
77150696a6eSStefan Eßer 		*c = bcl_num_insert(ctxt, &cnum);
77250696a6eSStefan Eßer 		*d = bcl_num_insert(ctxt, &dnum);
77350696a6eSStefan Eßer 	}
77450696a6eSStefan Eßer 
77550696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
77650696a6eSStefan Eßer 
77750696a6eSStefan Eßer 	return e;
77850696a6eSStefan Eßer }
77950696a6eSStefan Eßer 
78050696a6eSStefan Eßer BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) {
78150696a6eSStefan Eßer 
78250696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
78350696a6eSStefan Eßer 	size_t req;
78450696a6eSStefan Eßer 	BcNum *aptr, *bptr, *cptr;
78550696a6eSStefan Eßer 	BcNum d;
78650696a6eSStefan Eßer 	BclNumber idx;
78750696a6eSStefan Eßer 	BclContext ctxt;
78850696a6eSStefan Eßer 
78950696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
79050696a6eSStefan Eßer 
79150696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, a);
79250696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, b);
79350696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, c);
79450696a6eSStefan Eßer 
79550696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
79650696a6eSStefan Eßer 
79750696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
79850696a6eSStefan Eßer 
79950696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
80050696a6eSStefan Eßer 	assert(c.i < ctxt->nums.len);
80150696a6eSStefan Eßer 
80250696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
80350696a6eSStefan Eßer 	bptr = BC_NUM(ctxt, b);
80450696a6eSStefan Eßer 	cptr = BC_NUM(ctxt, c);
80550696a6eSStefan Eßer 
80650696a6eSStefan Eßer 	assert(aptr != NULL && bptr != NULL && cptr != NULL);
80750696a6eSStefan Eßer 	assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
80850696a6eSStefan Eßer 
809*44d4804dSStefan Eßer 	// Prepare the result.
81050696a6eSStefan Eßer 	bc_num_clear(&d);
81150696a6eSStefan Eßer 
81250696a6eSStefan Eßer 	req = bc_num_divReq(aptr, cptr, 0);
81350696a6eSStefan Eßer 
814*44d4804dSStefan Eßer 	// Initialize the result.
81550696a6eSStefan Eßer 	bc_num_init(&d, req);
81650696a6eSStefan Eßer 
81750696a6eSStefan Eßer 	BC_SIG_UNLOCK;
81850696a6eSStefan Eßer 
81950696a6eSStefan Eßer 	bc_num_modexp(aptr, bptr, cptr, &d);
82050696a6eSStefan Eßer 
82150696a6eSStefan Eßer err:
82250696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
82350696a6eSStefan Eßer 
824*44d4804dSStefan Eßer 	// Eat the operands.
82550696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
82650696a6eSStefan Eßer 	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
82750696a6eSStefan Eßer 	if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
82850696a6eSStefan Eßer 
82950696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
83050696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, d, idx);
83150696a6eSStefan Eßer 
83250696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
83350696a6eSStefan Eßer 
83450696a6eSStefan Eßer 	return idx;
83550696a6eSStefan Eßer }
83650696a6eSStefan Eßer 
83750696a6eSStefan Eßer ssize_t bcl_cmp(BclNumber a, BclNumber b) {
83850696a6eSStefan Eßer 
83950696a6eSStefan Eßer 	BcNum *aptr, *bptr;
84050696a6eSStefan Eßer 	BclContext ctxt;
84150696a6eSStefan Eßer 
84250696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
84350696a6eSStefan Eßer 
84450696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
84550696a6eSStefan Eßer 
84650696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
84750696a6eSStefan Eßer 	bptr = BC_NUM(ctxt, b);
84850696a6eSStefan Eßer 
84950696a6eSStefan Eßer 	assert(aptr != NULL && bptr != NULL);
85050696a6eSStefan Eßer 	assert(aptr->num != NULL && bptr->num != NULL);
85150696a6eSStefan Eßer 
85250696a6eSStefan Eßer 	return bc_num_cmp(aptr, bptr);
85350696a6eSStefan Eßer }
85450696a6eSStefan Eßer 
85550696a6eSStefan Eßer void bcl_zero(BclNumber n) {
85650696a6eSStefan Eßer 
85750696a6eSStefan Eßer 	BcNum *nptr;
85850696a6eSStefan Eßer 	BclContext ctxt;
85950696a6eSStefan Eßer 
86050696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
86150696a6eSStefan Eßer 
86250696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
86350696a6eSStefan Eßer 
86450696a6eSStefan Eßer 	nptr = BC_NUM(ctxt, n);
86550696a6eSStefan Eßer 
86650696a6eSStefan Eßer 	assert(nptr != NULL && nptr->num != NULL);
86750696a6eSStefan Eßer 
86850696a6eSStefan Eßer 	bc_num_zero(nptr);
86950696a6eSStefan Eßer }
87050696a6eSStefan Eßer 
87150696a6eSStefan Eßer void bcl_one(BclNumber n) {
87250696a6eSStefan Eßer 
87350696a6eSStefan Eßer 	BcNum *nptr;
87450696a6eSStefan Eßer 	BclContext ctxt;
87550696a6eSStefan Eßer 
87650696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
87750696a6eSStefan Eßer 
87850696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
87950696a6eSStefan Eßer 
88050696a6eSStefan Eßer 	nptr = BC_NUM(ctxt, n);
88150696a6eSStefan Eßer 
88250696a6eSStefan Eßer 	assert(nptr != NULL && nptr->num != NULL);
88350696a6eSStefan Eßer 
88450696a6eSStefan Eßer 	bc_num_one(nptr);
88550696a6eSStefan Eßer }
88650696a6eSStefan Eßer 
88750696a6eSStefan Eßer BclNumber bcl_parse(const char *restrict val) {
88850696a6eSStefan Eßer 
88950696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
89050696a6eSStefan Eßer 	BcNum n;
89150696a6eSStefan Eßer 	BclNumber idx;
89250696a6eSStefan Eßer 	BclContext ctxt;
89350696a6eSStefan Eßer 	bool neg;
89450696a6eSStefan Eßer 
89550696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
89650696a6eSStefan Eßer 
89750696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
89850696a6eSStefan Eßer 
89950696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
90050696a6eSStefan Eßer 
90150696a6eSStefan Eßer 	assert(val != NULL);
90250696a6eSStefan Eßer 
903*44d4804dSStefan Eßer 	// We have to take care of negative here because bc's number parsing does
904*44d4804dSStefan Eßer 	// not.
90550696a6eSStefan Eßer 	neg = (val[0] == '-');
90650696a6eSStefan Eßer 
90750696a6eSStefan Eßer 	if (neg) val += 1;
90850696a6eSStefan Eßer 
90950696a6eSStefan Eßer 	if (!bc_num_strValid(val)) {
91050696a6eSStefan Eßer 		vm.err = BCL_ERROR_PARSE_INVALID_STR;
91150696a6eSStefan Eßer 		goto err;
91250696a6eSStefan Eßer 	}
91350696a6eSStefan Eßer 
914*44d4804dSStefan Eßer 	// Clear and initialize the number.
91550696a6eSStefan Eßer 	bc_num_clear(&n);
91650696a6eSStefan Eßer 	bc_num_init(&n, BC_NUM_DEF_SIZE);
91750696a6eSStefan Eßer 
91850696a6eSStefan Eßer 	BC_SIG_UNLOCK;
91950696a6eSStefan Eßer 
92050696a6eSStefan Eßer 	bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
92150696a6eSStefan Eßer 
922*44d4804dSStefan Eßer 	// Set the negative.
92350696a6eSStefan Eßer 	n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
92450696a6eSStefan Eßer 
92550696a6eSStefan Eßer err:
92650696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
92750696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
92850696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, n, idx);
92950696a6eSStefan Eßer 
93050696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
93150696a6eSStefan Eßer 
93250696a6eSStefan Eßer 	return idx;
93350696a6eSStefan Eßer }
93450696a6eSStefan Eßer 
93550696a6eSStefan Eßer char* bcl_string(BclNumber n) {
93650696a6eSStefan Eßer 
93750696a6eSStefan Eßer 	BcNum *nptr;
93850696a6eSStefan Eßer 	char *str = NULL;
93950696a6eSStefan Eßer 	BclContext ctxt;
94050696a6eSStefan Eßer 
94150696a6eSStefan Eßer 	BC_CHECK_CTXT_ASSERT(ctxt);
94250696a6eSStefan Eßer 
94350696a6eSStefan Eßer 	if (BC_ERR(n.i >= ctxt->nums.len)) return str;
94450696a6eSStefan Eßer 
94550696a6eSStefan Eßer 	BC_FUNC_HEADER(err);
94650696a6eSStefan Eßer 
94750696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
94850696a6eSStefan Eßer 
94950696a6eSStefan Eßer 	nptr = BC_NUM(ctxt, n);
95050696a6eSStefan Eßer 
95150696a6eSStefan Eßer 	assert(nptr != NULL && nptr->num != NULL);
95250696a6eSStefan Eßer 
953*44d4804dSStefan Eßer 	// Clear the buffer.
95410328f8bSStefan Eßer 	bc_vec_popAll(&vm.out);
95550696a6eSStefan Eßer 
956*44d4804dSStefan Eßer 	// Print to the buffer.
95750696a6eSStefan Eßer 	bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
95850696a6eSStefan Eßer 	bc_vec_pushByte(&vm.out, '\0');
95950696a6eSStefan Eßer 
96050696a6eSStefan Eßer 	BC_SIG_LOCK;
961*44d4804dSStefan Eßer 
962*44d4804dSStefan Eßer 	// Just dup the string; the caller is responsible for it.
96350696a6eSStefan Eßer 	str = bc_vm_strdup(vm.out.v);
96450696a6eSStefan Eßer 
96550696a6eSStefan Eßer err:
966*44d4804dSStefan Eßer 
967*44d4804dSStefan Eßer 	// Eat the operand.
96850696a6eSStefan Eßer 	bcl_num_dtor(ctxt, n, nptr);
96950696a6eSStefan Eßer 
97050696a6eSStefan Eßer 	BC_FUNC_FOOTER_NO_ERR;
97150696a6eSStefan Eßer 
97250696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
97350696a6eSStefan Eßer 
97450696a6eSStefan Eßer 	return str;
97550696a6eSStefan Eßer }
97650696a6eSStefan Eßer 
97750696a6eSStefan Eßer BclNumber bcl_irand(BclNumber a) {
97850696a6eSStefan Eßer 
97950696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
98050696a6eSStefan Eßer 	BcNum *aptr;
98150696a6eSStefan Eßer 	BcNum b;
98250696a6eSStefan Eßer 	BclNumber idx;
98350696a6eSStefan Eßer 	BclContext ctxt;
98450696a6eSStefan Eßer 
98550696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
98650696a6eSStefan Eßer 
98750696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, a);
98850696a6eSStefan Eßer 
98950696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
99050696a6eSStefan Eßer 
99150696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
99250696a6eSStefan Eßer 
99350696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len);
99450696a6eSStefan Eßer 
99550696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
99650696a6eSStefan Eßer 
99750696a6eSStefan Eßer 	assert(aptr != NULL && aptr->num != NULL);
99850696a6eSStefan Eßer 
999*44d4804dSStefan Eßer 	// Clear and initialize the result.
100050696a6eSStefan Eßer 	bc_num_clear(&b);
100150696a6eSStefan Eßer 	bc_num_init(&b, BC_NUM_DEF_SIZE);
100250696a6eSStefan Eßer 
100350696a6eSStefan Eßer 	BC_SIG_UNLOCK;
100450696a6eSStefan Eßer 
100550696a6eSStefan Eßer 	bc_num_irand(aptr, &b, &vm.rng);
100650696a6eSStefan Eßer 
100750696a6eSStefan Eßer err:
100850696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
1009*44d4804dSStefan Eßer 
1010*44d4804dSStefan Eßer 	// Eat the operand.
101150696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
1012*44d4804dSStefan Eßer 
101350696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
101450696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, b, idx);
101550696a6eSStefan Eßer 
101650696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
101750696a6eSStefan Eßer 
101850696a6eSStefan Eßer 	return idx;
101950696a6eSStefan Eßer }
102050696a6eSStefan Eßer 
1021*44d4804dSStefan Eßer /**
1022*44d4804dSStefan Eßer  * Helps bcl_frand(). This is separate because the error handling is easier that
1023*44d4804dSStefan Eßer  * way. It is also easier to do ifrand that way.
1024*44d4804dSStefan Eßer  * @param b       The return parameter.
1025*44d4804dSStefan Eßer  * @param places  The number of decimal places to generate.
1026*44d4804dSStefan Eßer  */
102750696a6eSStefan Eßer static void bcl_frandHelper(BcNum *restrict b, size_t places) {
102850696a6eSStefan Eßer 
102950696a6eSStefan Eßer 	BcNum exp, pow, ten;
103050696a6eSStefan Eßer 	BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
103150696a6eSStefan Eßer 	BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
103250696a6eSStefan Eßer 
1033*44d4804dSStefan Eßer 	// Set up temporaries.
103450696a6eSStefan Eßer 	bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
103550696a6eSStefan Eßer 	bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
103650696a6eSStefan Eßer 
103750696a6eSStefan Eßer 	ten.num[0] = 10;
103850696a6eSStefan Eßer 	ten.len = 1;
103950696a6eSStefan Eßer 
104050696a6eSStefan Eßer 	bc_num_bigdig2num(&exp, (BcBigDig) places);
104150696a6eSStefan Eßer 
1042*44d4804dSStefan Eßer 	// Clear the temporary that might need to grow.
104350696a6eSStefan Eßer 	bc_num_clear(&pow);
104450696a6eSStefan Eßer 
104550696a6eSStefan Eßer 	BC_SIG_LOCK;
104650696a6eSStefan Eßer 
1047*44d4804dSStefan Eßer 	// Initialize the temporary that might need to grow.
104850696a6eSStefan Eßer 	bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
104950696a6eSStefan Eßer 
1050*44d4804dSStefan Eßer 	BC_SETJMP_LOCKED(err);
1051*44d4804dSStefan Eßer 
105250696a6eSStefan Eßer 	BC_SIG_UNLOCK;
105350696a6eSStefan Eßer 
1054*44d4804dSStefan Eßer 	// Generate the number.
105550696a6eSStefan Eßer 	bc_num_pow(&ten, &exp, &pow, 0);
105650696a6eSStefan Eßer 	bc_num_irand(&pow, b, &vm.rng);
105750696a6eSStefan Eßer 
1058*44d4804dSStefan Eßer 	// Make the number entirely fraction.
105950696a6eSStefan Eßer 	bc_num_shiftRight(b, places);
106050696a6eSStefan Eßer 
106150696a6eSStefan Eßer err:
106250696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
106350696a6eSStefan Eßer 	bc_num_free(&pow);
106450696a6eSStefan Eßer 	BC_LONGJMP_CONT;
106550696a6eSStefan Eßer }
106650696a6eSStefan Eßer 
106750696a6eSStefan Eßer BclNumber bcl_frand(size_t places) {
106850696a6eSStefan Eßer 
106950696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
107050696a6eSStefan Eßer 	BcNum n;
107150696a6eSStefan Eßer 	BclNumber idx;
107250696a6eSStefan Eßer 	BclContext ctxt;
107350696a6eSStefan Eßer 
107450696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
107550696a6eSStefan Eßer 
107650696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
107750696a6eSStefan Eßer 
107850696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
107950696a6eSStefan Eßer 
1080*44d4804dSStefan Eßer 	// Clear and initialize the number.
108150696a6eSStefan Eßer 	bc_num_clear(&n);
108250696a6eSStefan Eßer 	bc_num_init(&n, BC_NUM_DEF_SIZE);
108350696a6eSStefan Eßer 
108450696a6eSStefan Eßer 	BC_SIG_UNLOCK;
108550696a6eSStefan Eßer 
108650696a6eSStefan Eßer 	bcl_frandHelper(&n, places);
108750696a6eSStefan Eßer 
108850696a6eSStefan Eßer err:
108950696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
1090*44d4804dSStefan Eßer 
109150696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
109250696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, n, idx);
109350696a6eSStefan Eßer 
109450696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
109550696a6eSStefan Eßer 
109650696a6eSStefan Eßer 	return idx;
109750696a6eSStefan Eßer }
109850696a6eSStefan Eßer 
1099*44d4804dSStefan Eßer /**
1100*44d4804dSStefan Eßer  * Helps bc_ifrand(). This is separate because error handling is easier that
1101*44d4804dSStefan Eßer  * way.
1102*44d4804dSStefan Eßer  * @param a       The limit for bc_num_irand().
1103*44d4804dSStefan Eßer  * @param b       The return parameter.
1104*44d4804dSStefan Eßer  * @param places  The number of decimal places to generate.
1105*44d4804dSStefan Eßer  */
110650696a6eSStefan Eßer static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b,
110750696a6eSStefan Eßer                              size_t places)
110850696a6eSStefan Eßer {
110950696a6eSStefan Eßer 	BcNum ir, fr;
111050696a6eSStefan Eßer 
1111*44d4804dSStefan Eßer 	// Clear the integer and fractional numbers.
111250696a6eSStefan Eßer 	bc_num_clear(&ir);
111350696a6eSStefan Eßer 	bc_num_clear(&fr);
111450696a6eSStefan Eßer 
111550696a6eSStefan Eßer 	BC_SIG_LOCK;
111650696a6eSStefan Eßer 
1117*44d4804dSStefan Eßer 	// Initialize the integer and fractional numbers.
111850696a6eSStefan Eßer 	bc_num_init(&ir, BC_NUM_DEF_SIZE);
111950696a6eSStefan Eßer 	bc_num_init(&fr, BC_NUM_DEF_SIZE);
112050696a6eSStefan Eßer 
1121*44d4804dSStefan Eßer 	BC_SETJMP_LOCKED(err);
1122*44d4804dSStefan Eßer 
112350696a6eSStefan Eßer 	BC_SIG_UNLOCK;
112450696a6eSStefan Eßer 
112550696a6eSStefan Eßer 	bc_num_irand(a, &ir, &vm.rng);
112650696a6eSStefan Eßer 	bcl_frandHelper(&fr, places);
112750696a6eSStefan Eßer 
112850696a6eSStefan Eßer 	bc_num_add(&ir, &fr, b, 0);
112950696a6eSStefan Eßer 
113050696a6eSStefan Eßer err:
113150696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
113250696a6eSStefan Eßer 	bc_num_free(&fr);
113350696a6eSStefan Eßer 	bc_num_free(&ir);
113450696a6eSStefan Eßer 	BC_LONGJMP_CONT;
113550696a6eSStefan Eßer }
113650696a6eSStefan Eßer 
113750696a6eSStefan Eßer BclNumber bcl_ifrand(BclNumber a, size_t places) {
113850696a6eSStefan Eßer 
113950696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
114050696a6eSStefan Eßer 	BcNum *aptr;
114150696a6eSStefan Eßer 	BcNum b;
114250696a6eSStefan Eßer 	BclNumber idx;
114350696a6eSStefan Eßer 	BclContext ctxt;
114450696a6eSStefan Eßer 
114550696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
114650696a6eSStefan Eßer 	BC_CHECK_NUM(ctxt, a);
114750696a6eSStefan Eßer 
114850696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
114950696a6eSStefan Eßer 
115050696a6eSStefan Eßer 	bc_vec_grow(&ctxt->nums, 1);
115150696a6eSStefan Eßer 
115250696a6eSStefan Eßer 	assert(a.i < ctxt->nums.len);
115350696a6eSStefan Eßer 
115450696a6eSStefan Eßer 	aptr = BC_NUM(ctxt, a);
115550696a6eSStefan Eßer 
115650696a6eSStefan Eßer 	assert(aptr != NULL && aptr->num != NULL);
115750696a6eSStefan Eßer 
1158*44d4804dSStefan Eßer 	// Clear and initialize the number.
115950696a6eSStefan Eßer 	bc_num_clear(&b);
116050696a6eSStefan Eßer 	bc_num_init(&b, BC_NUM_DEF_SIZE);
116150696a6eSStefan Eßer 
116250696a6eSStefan Eßer 	BC_SIG_UNLOCK;
116350696a6eSStefan Eßer 
116450696a6eSStefan Eßer 	bcl_ifrandHelper(aptr, &b, places);
116550696a6eSStefan Eßer 
116650696a6eSStefan Eßer err:
116750696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
1168*44d4804dSStefan Eßer 
1169*44d4804dSStefan Eßer 	// Eat the oprand.
117050696a6eSStefan Eßer 	bcl_num_dtor(ctxt, a, aptr);
1171*44d4804dSStefan Eßer 
117250696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
117350696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, b, idx);
117450696a6eSStefan Eßer 
117550696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
117650696a6eSStefan Eßer 
117750696a6eSStefan Eßer 	return idx;
117850696a6eSStefan Eßer }
117950696a6eSStefan Eßer 
118050696a6eSStefan Eßer BclError bcl_rand_seedWithNum(BclNumber n) {
118150696a6eSStefan Eßer 
118250696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
118350696a6eSStefan Eßer 	BcNum *nptr;
118450696a6eSStefan Eßer 	BclContext ctxt;
118550696a6eSStefan Eßer 
118650696a6eSStefan Eßer 	BC_CHECK_CTXT_ERR(ctxt);
118750696a6eSStefan Eßer 	BC_CHECK_NUM_ERR(ctxt, n);
118850696a6eSStefan Eßer 
118950696a6eSStefan Eßer 	BC_FUNC_HEADER(err);
119050696a6eSStefan Eßer 
119150696a6eSStefan Eßer 	assert(n.i < ctxt->nums.len);
119250696a6eSStefan Eßer 
119350696a6eSStefan Eßer 	nptr = BC_NUM(ctxt, n);
119450696a6eSStefan Eßer 
119550696a6eSStefan Eßer 	assert(nptr != NULL && nptr->num != NULL);
119650696a6eSStefan Eßer 
119750696a6eSStefan Eßer 	bc_num_rng(nptr, &vm.rng);
119850696a6eSStefan Eßer 
119950696a6eSStefan Eßer err:
120050696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
120150696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
120250696a6eSStefan Eßer 
120350696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
120450696a6eSStefan Eßer 
120550696a6eSStefan Eßer 	return e;
120650696a6eSStefan Eßer }
120750696a6eSStefan Eßer 
1208*44d4804dSStefan Eßer BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) {
120950696a6eSStefan Eßer 
121050696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
121150696a6eSStefan Eßer 	size_t i;
1212*44d4804dSStefan Eßer 	ulong vals[BCL_SEED_ULONGS];
121350696a6eSStefan Eßer 
121450696a6eSStefan Eßer 	BC_FUNC_HEADER(err);
121550696a6eSStefan Eßer 
1216*44d4804dSStefan Eßer 	// Fill the array.
1217*44d4804dSStefan Eßer 	for (i = 0; i < BCL_SEED_SIZE; ++i) {
121850696a6eSStefan Eßer 		ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) *
121950696a6eSStefan Eßer 		                                  (i % sizeof(ulong)));
122050696a6eSStefan Eßer 		vals[i / sizeof(long)] |= val;
122150696a6eSStefan Eßer 	}
122250696a6eSStefan Eßer 
122350696a6eSStefan Eßer 	bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]);
122450696a6eSStefan Eßer 
122550696a6eSStefan Eßer err:
122650696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
122750696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
122850696a6eSStefan Eßer 	return e;
122950696a6eSStefan Eßer }
123050696a6eSStefan Eßer 
123150696a6eSStefan Eßer void bcl_rand_reseed(void) {
123250696a6eSStefan Eßer 	bc_rand_srand(bc_vec_top(&vm.rng.v));
123350696a6eSStefan Eßer }
123450696a6eSStefan Eßer 
123550696a6eSStefan Eßer BclNumber bcl_rand_seed2num(void) {
123650696a6eSStefan Eßer 
123750696a6eSStefan Eßer 	BclError e = BCL_ERROR_NONE;
123850696a6eSStefan Eßer 	BcNum n;
123950696a6eSStefan Eßer 	BclNumber idx;
124050696a6eSStefan Eßer 	BclContext ctxt;
124150696a6eSStefan Eßer 
124250696a6eSStefan Eßer 	BC_CHECK_CTXT(ctxt);
124350696a6eSStefan Eßer 
124450696a6eSStefan Eßer 	BC_FUNC_HEADER_LOCK(err);
124550696a6eSStefan Eßer 
1246*44d4804dSStefan Eßer 	// Clear and initialize the number.
124750696a6eSStefan Eßer 	bc_num_clear(&n);
124850696a6eSStefan Eßer 	bc_num_init(&n, BC_NUM_DEF_SIZE);
124950696a6eSStefan Eßer 
125050696a6eSStefan Eßer 	BC_SIG_UNLOCK;
125150696a6eSStefan Eßer 
125250696a6eSStefan Eßer 	bc_num_createFromRNG(&n, &vm.rng);
125350696a6eSStefan Eßer 
125450696a6eSStefan Eßer err:
125550696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
125650696a6eSStefan Eßer 	BC_FUNC_FOOTER(e);
125750696a6eSStefan Eßer 	BC_MAYBE_SETUP(ctxt, e, n, idx);
125850696a6eSStefan Eßer 
125950696a6eSStefan Eßer 	assert(!vm.running && !vm.sig && !vm.sig_lock);
126050696a6eSStefan Eßer 
126150696a6eSStefan Eßer 	return idx;
126250696a6eSStefan Eßer }
126350696a6eSStefan Eßer 
126450696a6eSStefan Eßer BclRandInt bcl_rand_int(void) {
126550696a6eSStefan Eßer 	return (BclRandInt) bc_rand_int(&vm.rng);
126650696a6eSStefan Eßer }
126750696a6eSStefan Eßer 
126850696a6eSStefan Eßer BclRandInt bcl_rand_bounded(BclRandInt bound) {
126950696a6eSStefan Eßer 	if (bound <= 1) return 0;
127050696a6eSStefan Eßer 	return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound);
127150696a6eSStefan Eßer }
127250696a6eSStefan Eßer 
127350696a6eSStefan Eßer #endif // BC_ENABLE_LIBRARY
1274