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