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