1/*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 *   list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 *   this list of conditions and the following disclaimer in the documentation
16 *   and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * The public functions for libbc.
33 *
34 */
35
36#if BC_ENABLE_LIBRARY
37
38#include <setjmp.h>
39#include <string.h>
40#include <time.h>
41
42#include <bcl.h>
43
44#include <library.h>
45#include <num.h>
46#include <vm.h>
47
48static void bcl_num_destruct(void *num);
49
50void bcl_handleSignal(void) {
51
52	// Signal already in flight, or bc is not executing.
53	if (vm.sig || !vm.running) return;
54
55	vm.sig = 1;
56
57	assert(vm.jmp_bufs.len);
58
59	if (!vm.sig_lock) BC_VM_JMP;
60}
61
62bool bcl_running(void) {
63	return vm.running != 0;
64}
65
66BclError bcl_init(void) {
67
68	BclError e = BCL_ERROR_NONE;
69
70	vm.refs += 1;
71
72	if (vm.refs > 1) return e;
73
74	vm.ctxts.v = NULL;
75	vm.jmp_bufs.v = NULL;
76	vm.out.v = NULL;
77
78	vm.abrt = false;
79
80	BC_SIG_LOCK;
81
82	bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), NULL);
83
84	BC_FUNC_HEADER_INIT(err);
85
86	bc_vm_init();
87
88	bc_vec_init(&vm.ctxts, sizeof(BclContext), NULL);
89	bc_vec_init(&vm.out, sizeof(uchar), NULL);
90
91	srand((unsigned int) time(NULL));
92	bc_rand_init(&vm.rng);
93
94err:
95	if (BC_ERR(vm.err)) {
96		if (vm.out.v != NULL) bc_vec_free(&vm.out);
97		if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs);
98		if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts);
99	}
100
101	BC_FUNC_FOOTER_UNLOCK(e);
102
103	assert(!vm.running && !vm.sig && !vm.sig_lock);
104
105	return e;
106}
107
108BclError bcl_pushContext(BclContext ctxt) {
109
110	BclError e = BCL_ERROR_NONE;
111
112	BC_FUNC_HEADER_LOCK(err);
113
114	bc_vec_push(&vm.ctxts, &ctxt);
115
116err:
117	BC_FUNC_FOOTER_UNLOCK(e);
118	return e;
119}
120
121void bcl_popContext(void) {
122	if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
123}
124
125BclContext bcl_context(void) {
126	if (!vm.ctxts.len) return NULL;
127	return *((BclContext*) bc_vec_top(&vm.ctxts));
128}
129
130void bcl_free(void) {
131
132	vm.refs -= 1;
133
134	if (vm.refs) return;
135
136	BC_SIG_LOCK;
137
138#ifndef NDEBUG
139	bc_rand_free(&vm.rng);
140	bc_vec_free(&vm.out);
141
142	{
143		size_t i;
144
145		for (i = 0; i < vm.ctxts.len; ++i) {
146			BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i));
147			bcl_ctxt_free(ctxt);
148		}
149	}
150
151	bc_vec_free(&vm.ctxts);
152#endif // NDEBUG
153
154	bc_vm_atexit();
155
156	BC_SIG_UNLOCK;
157
158	memset(&vm, 0, sizeof(BcVm));
159
160	assert(!vm.running && !vm.sig && !vm.sig_lock);
161}
162
163void bcl_gc(void) {
164	bc_vm_freeTemps();
165	vm.temps.len = 0;
166}
167
168bool bcl_abortOnFatalError(void) {
169	return vm.abrt;
170}
171
172void bcl_setAbortOnFatalError(bool abrt) {
173	vm.abrt = abrt;
174}
175
176BclContext bcl_ctxt_create(void) {
177
178	BclContext ctxt = NULL;
179
180	BC_FUNC_HEADER_LOCK(err);
181
182	ctxt = bc_vm_malloc(sizeof(BclCtxt));
183
184	bc_vec_init(&ctxt->nums, sizeof(BcNum), bcl_num_destruct);
185	bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), NULL);
186
187	ctxt->scale = 0;
188	ctxt->ibase = 10;
189	ctxt->obase= 10;
190
191err:
192	if (BC_ERR(vm.err && ctxt != NULL)) {
193		if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
194		free(ctxt);
195		ctxt = NULL;
196	}
197
198	BC_FUNC_FOOTER_NO_ERR;
199
200	assert(!vm.running && !vm.sig && !vm.sig_lock);
201
202	return ctxt;
203}
204
205void bcl_ctxt_free(BclContext ctxt) {
206	BC_SIG_LOCK;
207	bc_vec_free(&ctxt->free_nums);
208	bc_vec_free(&ctxt->nums);
209	free(ctxt);
210	BC_SIG_UNLOCK;
211}
212
213void bcl_ctxt_freeNums(BclContext ctxt) {
214	bc_vec_popAll(&ctxt->nums);
215	bc_vec_popAll(&ctxt->free_nums);
216}
217
218size_t bcl_ctxt_scale(BclContext ctxt) {
219	return ctxt->scale;
220}
221
222void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
223	ctxt->scale = scale;
224}
225
226size_t bcl_ctxt_ibase(BclContext ctxt) {
227	return ctxt->ibase;
228}
229
230void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) {
231	if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
232	else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
233	ctxt->ibase = ibase;
234}
235
236size_t bcl_ctxt_obase(BclContext ctxt) {
237	return ctxt->obase;
238}
239
240void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
241	ctxt->obase = obase;
242}
243
244BclError bcl_err(BclNumber n) {
245
246	BclContext ctxt;
247
248	BC_CHECK_CTXT_ERR(ctxt);
249
250	if (n.i >= ctxt->nums.len) {
251		if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
252		else return BCL_ERROR_INVALID_NUM;
253	}
254	else return BCL_ERROR_NONE;
255}
256
257static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) {
258
259	BclNumber idx;
260
261	if (ctxt->free_nums.len) {
262
263		BcNum *ptr;
264
265		idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
266
267		bc_vec_pop(&ctxt->free_nums);
268
269		ptr = bc_vec_item(&ctxt->nums, idx.i);
270		memcpy(ptr, n, sizeof(BcNum));
271	}
272	else {
273		idx.i = ctxt->nums.len;
274		bc_vec_push(&ctxt->nums, n);
275	}
276
277	assert(!vm.running && !vm.sig && !vm.sig_lock);
278
279	return idx;
280}
281
282BclNumber bcl_num_create(void) {
283
284	BclError e = BCL_ERROR_NONE;
285	BcNum n;
286	BclNumber idx;
287	BclContext ctxt;
288
289	BC_CHECK_CTXT(ctxt);
290
291	BC_FUNC_HEADER_LOCK(err);
292
293	bc_vec_grow(&ctxt->nums, 1);
294
295	bc_num_init(&n, BC_NUM_DEF_SIZE);
296
297err:
298	BC_FUNC_FOOTER_UNLOCK(e);
299	BC_MAYBE_SETUP(ctxt, e, n, idx);
300
301	assert(!vm.running && !vm.sig && !vm.sig_lock);
302
303	return idx;
304}
305
306static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) {
307
308	BC_SIG_ASSERT_LOCKED;
309
310	assert(num != NULL && num->num != NULL);
311
312	bcl_num_destruct(num);
313	bc_vec_push(&ctxt->free_nums, &n);
314}
315
316void bcl_num_free(BclNumber n) {
317
318	BcNum *num;
319	BclContext ctxt;
320
321	BC_CHECK_CTXT_ASSERT(ctxt);
322
323	BC_SIG_LOCK;
324
325	assert(n.i < ctxt->nums.len);
326
327	num = BC_NUM(ctxt, n);
328
329	bcl_num_dtor(ctxt, n, num);
330
331	BC_SIG_UNLOCK;
332}
333
334BclError bcl_copy(BclNumber d, BclNumber s) {
335
336	BclError e = BCL_ERROR_NONE;
337	BcNum *dest, *src;
338	BclContext ctxt;
339
340	BC_CHECK_CTXT_ERR(ctxt);
341
342	BC_FUNC_HEADER_LOCK(err);
343
344	assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
345
346	dest = BC_NUM(ctxt, d);
347	src = BC_NUM(ctxt, s);
348
349	assert(dest != NULL && src != NULL);
350	assert(dest->num != NULL && src->num != NULL);
351
352	bc_num_copy(dest, src);
353
354err:
355	BC_FUNC_FOOTER_UNLOCK(e);
356
357	assert(!vm.running && !vm.sig && !vm.sig_lock);
358
359	return e;
360}
361
362BclNumber bcl_dup(BclNumber s) {
363
364	BclError e = BCL_ERROR_NONE;
365	BcNum *src, dest;
366	BclNumber idx;
367	BclContext ctxt;
368
369	BC_CHECK_CTXT(ctxt);
370
371	BC_FUNC_HEADER_LOCK(err);
372
373	bc_vec_grow(&ctxt->nums, 1);
374
375	assert(s.i < ctxt->nums.len);
376
377	src = BC_NUM(ctxt, s);
378
379	assert(src != NULL && src->num != NULL);
380
381	bc_num_clear(&dest);
382
383	bc_num_createCopy(&dest, src);
384
385err:
386	BC_FUNC_FOOTER_UNLOCK(e);
387	BC_MAYBE_SETUP(ctxt, e, dest, idx);
388
389	assert(!vm.running && !vm.sig && !vm.sig_lock);
390
391	return idx;
392}
393
394static void bcl_num_destruct(void *num) {
395
396	BcNum *n = (BcNum*) num;
397
398	assert(n != NULL);
399
400	if (n->num == NULL) return;
401
402	bc_num_free(num);
403	bc_num_clear(num);
404}
405
406bool bcl_num_neg(BclNumber n) {
407
408	BcNum *num;
409	BclContext ctxt;
410
411	BC_CHECK_CTXT_ASSERT(ctxt);
412
413	assert(n.i < ctxt->nums.len);
414
415	num = BC_NUM(ctxt, n);
416
417	assert(num != NULL && num->num != NULL);
418
419	return BC_NUM_NEG(num) != 0;
420}
421
422void bcl_num_setNeg(BclNumber n, bool neg) {
423
424	BcNum *num;
425	BclContext ctxt;
426
427	BC_CHECK_CTXT_ASSERT(ctxt);
428
429	assert(n.i < ctxt->nums.len);
430
431	num = BC_NUM(ctxt, n);
432
433	assert(num != NULL && num->num != NULL);
434
435	num->rdx = BC_NUM_NEG_VAL(num, neg);
436}
437
438size_t bcl_num_scale(BclNumber n) {
439
440	BcNum *num;
441	BclContext ctxt;
442
443	BC_CHECK_CTXT_ASSERT(ctxt);
444
445	assert(n.i < ctxt->nums.len);
446
447	num = BC_NUM(ctxt, n);
448
449	assert(num != NULL && num->num != NULL);
450
451	return bc_num_scale(num);
452}
453
454BclError bcl_num_setScale(BclNumber n, size_t scale) {
455
456	BclError e = BCL_ERROR_NONE;
457	BcNum *nptr;
458	BclContext ctxt;
459
460	BC_CHECK_CTXT_ERR(ctxt);
461
462	BC_CHECK_NUM_ERR(ctxt, n);
463
464	BC_FUNC_HEADER(err);
465
466	assert(n.i < ctxt->nums.len);
467
468	nptr = BC_NUM(ctxt, n);
469
470	assert(nptr != NULL && nptr->num != NULL);
471
472	if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
473	else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
474
475err:
476	BC_SIG_MAYLOCK;
477	BC_FUNC_FOOTER(e);
478
479	assert(!vm.running && !vm.sig && !vm.sig_lock);
480
481	return e;
482}
483
484size_t bcl_num_len(BclNumber n) {
485
486	BcNum *num;
487	BclContext ctxt;
488
489	BC_CHECK_CTXT_ASSERT(ctxt);
490
491	assert(n.i < ctxt->nums.len);
492
493	num = BC_NUM(ctxt, n);
494
495	assert(num != NULL && num->num != NULL);
496
497	return bc_num_len(num);
498}
499
500BclError bcl_bigdig(BclNumber n, BclBigDig *result) {
501
502	BclError e = BCL_ERROR_NONE;
503	BcNum *num;
504	BclContext ctxt;
505
506	BC_CHECK_CTXT_ERR(ctxt);
507
508	BC_FUNC_HEADER_LOCK(err);
509
510	assert(n.i < ctxt->nums.len);
511	assert(result != NULL);
512
513	num = BC_NUM(ctxt, n);
514
515	assert(num != NULL && num->num != NULL);
516
517	bc_num_bigdig(num, result);
518
519err:
520	bcl_num_dtor(ctxt, n, num);
521	BC_FUNC_FOOTER_UNLOCK(e);
522
523	assert(!vm.running && !vm.sig && !vm.sig_lock);
524
525	return e;
526}
527
528BclNumber bcl_bigdig2num(BclBigDig val) {
529
530	BclError e = BCL_ERROR_NONE;
531	BcNum n;
532	BclNumber idx;
533	BclContext ctxt;
534
535	BC_CHECK_CTXT(ctxt);
536
537	BC_FUNC_HEADER_LOCK(err);
538
539	bc_vec_grow(&ctxt->nums, 1);
540
541	bc_num_createFromBigdig(&n, val);
542
543err:
544	BC_FUNC_FOOTER_UNLOCK(e);
545	BC_MAYBE_SETUP(ctxt, e, n, idx);
546
547	assert(!vm.running && !vm.sig && !vm.sig_lock);
548
549	return idx;
550}
551
552static BclNumber bcl_binary(BclNumber a, BclNumber b,
553                                const BcNumBinaryOp op,
554                                const BcNumBinaryOpReq req)
555{
556	BclError e = BCL_ERROR_NONE;
557	BcNum *aptr, *bptr;
558	BcNum c;
559	BclNumber idx;
560	BclContext ctxt;
561
562	BC_CHECK_CTXT(ctxt);
563
564	BC_CHECK_NUM(ctxt, a);
565	BC_CHECK_NUM(ctxt, b);
566
567	BC_FUNC_HEADER_LOCK(err);
568
569	bc_vec_grow(&ctxt->nums, 1);
570
571	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
572
573	aptr = BC_NUM(ctxt, a);
574	bptr = BC_NUM(ctxt, b);
575
576	assert(aptr != NULL && bptr != NULL);
577	assert(aptr->num != NULL && bptr->num != NULL);
578
579	bc_num_clear(&c);
580
581	bc_num_init(&c, req(aptr, bptr, ctxt->scale));
582
583	BC_SIG_UNLOCK;
584
585	op(aptr, bptr, &c, ctxt->scale);
586
587err:
588	BC_SIG_MAYLOCK;
589	bcl_num_dtor(ctxt, a, aptr);
590	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
591	BC_FUNC_FOOTER(e);
592	BC_MAYBE_SETUP(ctxt, e, c, idx);
593
594	assert(!vm.running && !vm.sig && !vm.sig_lock);
595
596	return idx;
597}
598
599BclNumber bcl_add(BclNumber a, BclNumber b) {
600	return bcl_binary(a, b, bc_num_add, bc_num_addReq);
601}
602
603BclNumber bcl_sub(BclNumber a, BclNumber b) {
604	return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
605}
606
607BclNumber bcl_mul(BclNumber a, BclNumber b) {
608	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
609}
610
611BclNumber bcl_div(BclNumber a, BclNumber b) {
612	return bcl_binary(a, b, bc_num_div, bc_num_divReq);
613}
614
615BclNumber bcl_mod(BclNumber a, BclNumber b) {
616	return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
617}
618
619BclNumber bcl_pow(BclNumber a, BclNumber b) {
620	return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
621}
622
623BclNumber bcl_lshift(BclNumber a, BclNumber b) {
624	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
625}
626
627BclNumber bcl_rshift(BclNumber a, BclNumber b) {
628	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
629}
630
631BclNumber bcl_sqrt(BclNumber a) {
632
633	BclError e = BCL_ERROR_NONE;
634	BcNum *aptr;
635	BcNum b;
636	BclNumber idx;
637	BclContext ctxt;
638
639	BC_CHECK_CTXT(ctxt);
640
641	BC_CHECK_NUM(ctxt, a);
642
643	BC_FUNC_HEADER(err);
644
645	bc_vec_grow(&ctxt->nums, 1);
646
647	assert(a.i < ctxt->nums.len);
648
649	aptr = BC_NUM(ctxt, a);
650
651	bc_num_sqrt(aptr, &b, ctxt->scale);
652
653err:
654	BC_SIG_MAYLOCK;
655	bcl_num_dtor(ctxt, a, aptr);
656	BC_FUNC_FOOTER(e);
657	BC_MAYBE_SETUP(ctxt, e, b, idx);
658
659	assert(!vm.running && !vm.sig && !vm.sig_lock);
660
661	return idx;
662}
663
664BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) {
665
666	BclError e = BCL_ERROR_NONE;
667	size_t req;
668	BcNum *aptr, *bptr;
669	BcNum cnum, dnum;
670	BclContext ctxt;
671
672	BC_CHECK_CTXT_ERR(ctxt);
673
674	BC_CHECK_NUM_ERR(ctxt, a);
675	BC_CHECK_NUM_ERR(ctxt, b);
676
677	BC_FUNC_HEADER_LOCK(err);
678
679	bc_vec_grow(&ctxt->nums, 2);
680
681	assert(c != NULL && d != NULL);
682
683	aptr = BC_NUM(ctxt, a);
684	bptr = BC_NUM(ctxt, b);
685
686	assert(aptr != NULL && bptr != NULL);
687	assert(aptr->num != NULL && bptr->num != NULL);
688
689	bc_num_clear(&cnum);
690	bc_num_clear(&dnum);
691
692	req = bc_num_divReq(aptr, bptr, ctxt->scale);
693
694	bc_num_init(&cnum, req);
695	bc_num_init(&dnum, req);
696
697	BC_SIG_UNLOCK;
698
699	bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
700
701err:
702	BC_SIG_MAYLOCK;
703
704	bcl_num_dtor(ctxt, a, aptr);
705	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
706
707	if (BC_ERR(vm.err)) {
708		if (cnum.num != NULL) bc_num_free(&cnum);
709		if (dnum.num != NULL) bc_num_free(&dnum);
710		c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
711		d->i = c->i;
712		BC_FUNC_FOOTER(e);
713	}
714	else {
715		BC_FUNC_FOOTER(e);
716		*c = bcl_num_insert(ctxt, &cnum);
717		*d = bcl_num_insert(ctxt, &dnum);
718	}
719
720	assert(!vm.running && !vm.sig && !vm.sig_lock);
721
722	return e;
723}
724
725BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) {
726
727	BclError e = BCL_ERROR_NONE;
728	size_t req;
729	BcNum *aptr, *bptr, *cptr;
730	BcNum d;
731	BclNumber idx;
732	BclContext ctxt;
733
734	BC_CHECK_CTXT(ctxt);
735
736	BC_CHECK_NUM(ctxt, a);
737	BC_CHECK_NUM(ctxt, b);
738	BC_CHECK_NUM(ctxt, c);
739
740	BC_FUNC_HEADER_LOCK(err);
741
742	bc_vec_grow(&ctxt->nums, 1);
743
744	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
745	assert(c.i < ctxt->nums.len);
746
747	aptr = BC_NUM(ctxt, a);
748	bptr = BC_NUM(ctxt, b);
749	cptr = BC_NUM(ctxt, c);
750
751	assert(aptr != NULL && bptr != NULL && cptr != NULL);
752	assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
753
754	bc_num_clear(&d);
755
756	req = bc_num_divReq(aptr, cptr, 0);
757
758	bc_num_init(&d, req);
759
760	BC_SIG_UNLOCK;
761
762	bc_num_modexp(aptr, bptr, cptr, &d);
763
764err:
765	BC_SIG_MAYLOCK;
766
767	bcl_num_dtor(ctxt, a, aptr);
768	if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
769	if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
770
771	BC_FUNC_FOOTER(e);
772	BC_MAYBE_SETUP(ctxt, e, d, idx);
773
774	assert(!vm.running && !vm.sig && !vm.sig_lock);
775
776	return idx;
777}
778
779ssize_t bcl_cmp(BclNumber a, BclNumber b) {
780
781	BcNum *aptr, *bptr;
782	BclContext ctxt;
783
784	BC_CHECK_CTXT_ASSERT(ctxt);
785
786	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
787
788	aptr = BC_NUM(ctxt, a);
789	bptr = BC_NUM(ctxt, b);
790
791	assert(aptr != NULL && bptr != NULL);
792	assert(aptr->num != NULL && bptr->num != NULL);
793
794	return bc_num_cmp(aptr, bptr);
795}
796
797void bcl_zero(BclNumber n) {
798
799	BcNum *nptr;
800	BclContext ctxt;
801
802	BC_CHECK_CTXT_ASSERT(ctxt);
803
804	assert(n.i < ctxt->nums.len);
805
806	nptr = BC_NUM(ctxt, n);
807
808	assert(nptr != NULL && nptr->num != NULL);
809
810	bc_num_zero(nptr);
811}
812
813void bcl_one(BclNumber n) {
814
815	BcNum *nptr;
816	BclContext ctxt;
817
818	BC_CHECK_CTXT_ASSERT(ctxt);
819
820	assert(n.i < ctxt->nums.len);
821
822	nptr = BC_NUM(ctxt, n);
823
824	assert(nptr != NULL && nptr->num != NULL);
825
826	bc_num_one(nptr);
827}
828
829BclNumber bcl_parse(const char *restrict val) {
830
831	BclError e = BCL_ERROR_NONE;
832	BcNum n;
833	BclNumber idx;
834	BclContext ctxt;
835	bool neg;
836
837	BC_CHECK_CTXT(ctxt);
838
839	BC_FUNC_HEADER_LOCK(err);
840
841	bc_vec_grow(&ctxt->nums, 1);
842
843	assert(val != NULL);
844
845	neg = (val[0] == '-');
846
847	if (neg) val += 1;
848
849	if (!bc_num_strValid(val)) {
850		vm.err = BCL_ERROR_PARSE_INVALID_STR;
851		goto err;
852	}
853
854	bc_num_clear(&n);
855
856	bc_num_init(&n, BC_NUM_DEF_SIZE);
857
858	BC_SIG_UNLOCK;
859
860	bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
861
862	n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
863
864err:
865	BC_SIG_MAYLOCK;
866	BC_FUNC_FOOTER(e);
867	BC_MAYBE_SETUP(ctxt, e, n, idx);
868
869	assert(!vm.running && !vm.sig && !vm.sig_lock);
870
871	return idx;
872}
873
874char* bcl_string(BclNumber n) {
875
876	BcNum *nptr;
877	char *str = NULL;
878	BclContext ctxt;
879
880	BC_CHECK_CTXT_ASSERT(ctxt);
881
882	if (BC_ERR(n.i >= ctxt->nums.len)) return str;
883
884	BC_FUNC_HEADER(err);
885
886	assert(n.i < ctxt->nums.len);
887
888	nptr = BC_NUM(ctxt, n);
889
890	assert(nptr != NULL && nptr->num != NULL);
891
892	bc_vec_popAll(&vm.out);
893
894	bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
895	bc_vec_pushByte(&vm.out, '\0');
896
897	BC_SIG_LOCK;
898	str = bc_vm_strdup(vm.out.v);
899
900err:
901	bcl_num_dtor(ctxt, n, nptr);
902
903	BC_FUNC_FOOTER_NO_ERR;
904
905	assert(!vm.running && !vm.sig && !vm.sig_lock);
906
907	return str;
908}
909
910BclNumber bcl_irand(BclNumber a) {
911
912	BclError e = BCL_ERROR_NONE;
913	BcNum *aptr;
914	BcNum b;
915	BclNumber idx;
916	BclContext ctxt;
917
918	BC_CHECK_CTXT(ctxt);
919
920	BC_CHECK_NUM(ctxt, a);
921
922	BC_FUNC_HEADER_LOCK(err);
923
924	bc_vec_grow(&ctxt->nums, 1);
925
926	assert(a.i < ctxt->nums.len);
927
928	aptr = BC_NUM(ctxt, a);
929
930	assert(aptr != NULL && aptr->num != NULL);
931
932	bc_num_clear(&b);
933
934	bc_num_init(&b, BC_NUM_DEF_SIZE);
935
936	BC_SIG_UNLOCK;
937
938	bc_num_irand(aptr, &b, &vm.rng);
939
940err:
941	BC_SIG_MAYLOCK;
942	bcl_num_dtor(ctxt, a, aptr);
943	BC_FUNC_FOOTER(e);
944	BC_MAYBE_SETUP(ctxt, e, b, idx);
945
946	assert(!vm.running && !vm.sig && !vm.sig_lock);
947
948	return idx;
949}
950
951static void bcl_frandHelper(BcNum *restrict b, size_t places) {
952
953	BcNum exp, pow, ten;
954	BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
955	BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
956
957	bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
958	bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
959
960	ten.num[0] = 10;
961	ten.len = 1;
962
963	bc_num_bigdig2num(&exp, (BcBigDig) places);
964
965	bc_num_clear(&pow);
966
967	BC_SIG_LOCK;
968
969	BC_SETJMP_LOCKED(err);
970
971	bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
972
973	BC_SIG_UNLOCK;
974
975	bc_num_pow(&ten, &exp, &pow, 0);
976
977	bc_num_irand(&pow, b, &vm.rng);
978
979	bc_num_shiftRight(b, places);
980
981err:
982	BC_SIG_MAYLOCK;
983	bc_num_free(&pow);
984	BC_LONGJMP_CONT;
985}
986
987BclNumber bcl_frand(size_t places) {
988
989	BclError e = BCL_ERROR_NONE;
990	BcNum n;
991	BclNumber idx;
992	BclContext ctxt;
993
994	BC_CHECK_CTXT(ctxt);
995
996	BC_FUNC_HEADER_LOCK(err);
997
998	bc_vec_grow(&ctxt->nums, 1);
999
1000	bc_num_clear(&n);
1001
1002	bc_num_init(&n, BC_NUM_DEF_SIZE);
1003
1004	BC_SIG_UNLOCK;
1005
1006	bcl_frandHelper(&n, places);
1007
1008err:
1009	BC_SIG_MAYLOCK;
1010	BC_FUNC_FOOTER(e);
1011	BC_MAYBE_SETUP(ctxt, e, n, idx);
1012
1013	assert(!vm.running && !vm.sig && !vm.sig_lock);
1014
1015	return idx;
1016}
1017
1018static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b,
1019                             size_t places)
1020{
1021	BcNum ir, fr;
1022
1023	bc_num_clear(&ir);
1024	bc_num_clear(&fr);
1025
1026	BC_SIG_LOCK;
1027
1028	BC_SETJMP_LOCKED(err);
1029
1030	bc_num_init(&ir, BC_NUM_DEF_SIZE);
1031	bc_num_init(&fr, BC_NUM_DEF_SIZE);
1032
1033	BC_SIG_UNLOCK;
1034
1035	bc_num_irand(a, &ir, &vm.rng);
1036	bcl_frandHelper(&fr, places);
1037
1038	bc_num_add(&ir, &fr, b, 0);
1039
1040err:
1041	BC_SIG_MAYLOCK;
1042	bc_num_free(&fr);
1043	bc_num_free(&ir);
1044	BC_LONGJMP_CONT;
1045}
1046
1047BclNumber bcl_ifrand(BclNumber a, size_t places) {
1048
1049	BclError e = BCL_ERROR_NONE;
1050	BcNum *aptr;
1051	BcNum b;
1052	BclNumber idx;
1053	BclContext ctxt;
1054
1055	BC_CHECK_CTXT(ctxt);
1056
1057	BC_CHECK_NUM(ctxt, a);
1058
1059	BC_FUNC_HEADER_LOCK(err);
1060
1061	bc_vec_grow(&ctxt->nums, 1);
1062
1063	assert(a.i < ctxt->nums.len);
1064
1065	aptr = BC_NUM(ctxt, a);
1066
1067	assert(aptr != NULL && aptr->num != NULL);
1068
1069	bc_num_clear(&b);
1070
1071	bc_num_init(&b, BC_NUM_DEF_SIZE);
1072
1073	BC_SIG_UNLOCK;
1074
1075	bcl_ifrandHelper(aptr, &b, places);
1076
1077err:
1078	BC_SIG_MAYLOCK;
1079	bcl_num_dtor(ctxt, a, aptr);
1080	BC_FUNC_FOOTER(e);
1081	BC_MAYBE_SETUP(ctxt, e, b, idx);
1082
1083	assert(!vm.running && !vm.sig && !vm.sig_lock);
1084
1085	return idx;
1086}
1087
1088BclError bcl_rand_seedWithNum(BclNumber n) {
1089
1090	BclError e = BCL_ERROR_NONE;
1091	BcNum *nptr;
1092	BclContext ctxt;
1093
1094	BC_CHECK_CTXT_ERR(ctxt);
1095
1096	BC_CHECK_NUM_ERR(ctxt, n);
1097
1098	BC_FUNC_HEADER(err);
1099
1100	assert(n.i < ctxt->nums.len);
1101
1102	nptr = BC_NUM(ctxt, n);
1103
1104	assert(nptr != NULL && nptr->num != NULL);
1105
1106	bc_num_rng(nptr, &vm.rng);
1107
1108err:
1109	BC_SIG_MAYLOCK;
1110	BC_FUNC_FOOTER(e);
1111
1112	assert(!vm.running && !vm.sig && !vm.sig_lock);
1113
1114	return e;
1115}
1116
1117BclError bcl_rand_seed(unsigned char seed[BC_SEED_SIZE]) {
1118
1119	BclError e = BCL_ERROR_NONE;
1120	size_t i;
1121	ulong vals[BC_SEED_ULONGS];
1122
1123	BC_FUNC_HEADER(err);
1124
1125	for (i = 0; i < BC_SEED_SIZE; ++i) {
1126		ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) *
1127		                                  (i % sizeof(ulong)));
1128		vals[i / sizeof(long)] |= val;
1129	}
1130
1131	bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]);
1132
1133err:
1134	BC_SIG_MAYLOCK;
1135	BC_FUNC_FOOTER(e);
1136	return e;
1137}
1138
1139void bcl_rand_reseed(void) {
1140	bc_rand_srand(bc_vec_top(&vm.rng.v));
1141}
1142
1143BclNumber bcl_rand_seed2num(void) {
1144
1145	BclError e = BCL_ERROR_NONE;
1146	BcNum n;
1147	BclNumber idx;
1148	BclContext ctxt;
1149
1150	BC_CHECK_CTXT(ctxt);
1151
1152	BC_FUNC_HEADER_LOCK(err);
1153
1154	bc_num_clear(&n);
1155
1156	bc_num_init(&n, BC_NUM_DEF_SIZE);
1157
1158	BC_SIG_UNLOCK;
1159
1160	bc_num_createFromRNG(&n, &vm.rng);
1161
1162err:
1163	BC_SIG_MAYLOCK;
1164	BC_FUNC_FOOTER(e);
1165	BC_MAYBE_SETUP(ctxt, e, n, idx);
1166
1167	assert(!vm.running && !vm.sig && !vm.sig_lock);
1168
1169	return idx;
1170}
1171
1172BclRandInt bcl_rand_int(void) {
1173	return (BclRandInt) bc_rand_int(&vm.rng);
1174}
1175
1176BclRandInt bcl_rand_bounded(BclRandInt bound) {
1177	if (bound <= 1) return 0;
1178	return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound);
1179}
1180
1181#endif // BC_ENABLE_LIBRARY
1182