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
48 // The asserts in this file are important to testing; in many cases, the test
49 // would not work without the asserts, so don't remove them without reason.
50 //
51 // Also, there are many uses of bc_num_clear() here; that is because numbers are
52 // being reused, and a clean slate is required.
53 //
54 // Also, there are a bunch of BC_UNSETJMP and BC_SETJMP_LOCKED() between calls
55 // to bc_num_init(). That is because locals are being initialized, and unlike bc
56 // proper, this code cannot assume that allocation failures are fatal. So we
57 // have to reset the jumps every time to ensure that the locals will be correct
58 // after jumping.
59
bcl_handleSignal(void)60 void bcl_handleSignal(void) {
61
62 // Signal already in flight, or bc is not executing.
63 if (vm.sig || !vm.running) return;
64
65 vm.sig = 1;
66
67 assert(vm.jmp_bufs.len);
68
69 if (!vm.sig_lock) BC_JMP;
70 }
71
bcl_running(void)72 bool bcl_running(void) {
73 return vm.running != 0;
74 }
75
bcl_init(void)76 BclError bcl_init(void) {
77
78 BclError e = BCL_ERROR_NONE;
79
80 vm.refs += 1;
81
82 if (vm.refs > 1) return e;
83
84 // Setting these to NULL ensures that if an error occurs, we only free what
85 // is necessary.
86 vm.ctxts.v = NULL;
87 vm.jmp_bufs.v = NULL;
88 vm.out.v = NULL;
89
90 vm.abrt = false;
91
92 BC_SIG_LOCK;
93
94 // The jmp_bufs always has to be initialized first.
95 bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE);
96
97 BC_FUNC_HEADER_INIT(err);
98
99 bc_vm_init();
100
101 bc_vec_init(&vm.ctxts, sizeof(BclContext), BC_DTOR_NONE);
102 bc_vec_init(&vm.out, sizeof(uchar), BC_DTOR_NONE);
103
104 // We need to seed this in case /dev/random and /dev/urandm don't work.
105 srand((unsigned int) time(NULL));
106 bc_rand_init(&vm.rng);
107
108 err:
109 // This is why we had to set them to NULL.
110 if (BC_ERR(vm.err)) {
111 if (vm.out.v != NULL) bc_vec_free(&vm.out);
112 if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs);
113 if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts);
114 }
115
116 BC_FUNC_FOOTER_UNLOCK(e);
117
118 assert(!vm.running && !vm.sig && !vm.sig_lock);
119
120 return e;
121 }
122
bcl_pushContext(BclContext ctxt)123 BclError bcl_pushContext(BclContext ctxt) {
124
125 BclError e = BCL_ERROR_NONE;
126
127 BC_FUNC_HEADER_LOCK(err);
128
129 bc_vec_push(&vm.ctxts, &ctxt);
130
131 err:
132 BC_FUNC_FOOTER_UNLOCK(e);
133 return e;
134 }
135
bcl_popContext(void)136 void bcl_popContext(void) {
137 if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
138 }
139
bcl_context(void)140 BclContext bcl_context(void) {
141 if (!vm.ctxts.len) return NULL;
142 return *((BclContext*) bc_vec_top(&vm.ctxts));
143 }
144
bcl_free(void)145 void bcl_free(void) {
146
147 size_t i;
148
149 vm.refs -= 1;
150
151 if (vm.refs) return;
152
153 BC_SIG_LOCK;
154
155 bc_rand_free(&vm.rng);
156 bc_vec_free(&vm.out);
157
158 for (i = 0; i < vm.ctxts.len; ++i) {
159 BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i));
160 bcl_ctxt_free(ctxt);
161 }
162
163 bc_vec_free(&vm.ctxts);
164
165 bc_vm_atexit();
166
167 BC_SIG_UNLOCK;
168
169 memset(&vm, 0, sizeof(BcVm));
170
171 assert(!vm.running && !vm.sig && !vm.sig_lock);
172 }
173
bcl_gc(void)174 void bcl_gc(void) {
175 BC_SIG_LOCK;
176 bc_vm_freeTemps();
177 BC_SIG_UNLOCK;
178 }
179
bcl_abortOnFatalError(void)180 bool bcl_abortOnFatalError(void) {
181 return vm.abrt;
182 }
183
bcl_setAbortOnFatalError(bool abrt)184 void bcl_setAbortOnFatalError(bool abrt) {
185 vm.abrt = abrt;
186 }
187
bcl_leadingZeroes(void)188 bool bcl_leadingZeroes(void) {
189 return vm.leading_zeroes;
190 }
191
bcl_setLeadingZeroes(bool leadingZeroes)192 void bcl_setLeadingZeroes(bool leadingZeroes) {
193 vm.leading_zeroes = leadingZeroes;
194 }
195
bcl_ctxt_create(void)196 BclContext bcl_ctxt_create(void) {
197
198 BclContext ctxt = NULL;
199
200 BC_FUNC_HEADER_LOCK(err);
201
202 // We want the context to be free of any interference of other parties, so
203 // malloc() is appropriate here.
204 ctxt = bc_vm_malloc(sizeof(BclCtxt));
205
206 bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM);
207 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
208
209 ctxt->scale = 0;
210 ctxt->ibase = 10;
211 ctxt->obase= 10;
212
213 err:
214 if (BC_ERR(vm.err && ctxt != NULL)) {
215 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
216 free(ctxt);
217 ctxt = NULL;
218 }
219
220 BC_FUNC_FOOTER_NO_ERR;
221
222 assert(!vm.running && !vm.sig && !vm.sig_lock);
223
224 return ctxt;
225 }
226
bcl_ctxt_free(BclContext ctxt)227 void bcl_ctxt_free(BclContext ctxt) {
228 BC_SIG_LOCK;
229 bc_vec_free(&ctxt->free_nums);
230 bc_vec_free(&ctxt->nums);
231 free(ctxt);
232 BC_SIG_UNLOCK;
233 }
234
bcl_ctxt_freeNums(BclContext ctxt)235 void bcl_ctxt_freeNums(BclContext ctxt) {
236 bc_vec_popAll(&ctxt->nums);
237 bc_vec_popAll(&ctxt->free_nums);
238 }
239
bcl_ctxt_scale(BclContext ctxt)240 size_t bcl_ctxt_scale(BclContext ctxt) {
241 return ctxt->scale;
242 }
243
bcl_ctxt_setScale(BclContext ctxt,size_t scale)244 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
245 ctxt->scale = scale;
246 }
247
bcl_ctxt_ibase(BclContext ctxt)248 size_t bcl_ctxt_ibase(BclContext ctxt) {
249 return ctxt->ibase;
250 }
251
bcl_ctxt_setIbase(BclContext ctxt,size_t ibase)252 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) {
253 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
254 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
255 ctxt->ibase = ibase;
256 }
257
bcl_ctxt_obase(BclContext ctxt)258 size_t bcl_ctxt_obase(BclContext ctxt) {
259 return ctxt->obase;
260 }
261
bcl_ctxt_setObase(BclContext ctxt,size_t obase)262 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
263 ctxt->obase = obase;
264 }
265
bcl_err(BclNumber n)266 BclError bcl_err(BclNumber n) {
267
268 BclContext ctxt;
269
270 BC_CHECK_CTXT_ERR(ctxt);
271
272 // Errors are encoded as (0 - error_code). If the index is in that range, it
273 // is an encoded error.
274 if (n.i >= ctxt->nums.len) {
275 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
276 else return BCL_ERROR_INVALID_NUM;
277 }
278 else return BCL_ERROR_NONE;
279 }
280
281 /**
282 * Inserts a BcNum into a context's list of numbers.
283 * @param ctxt The context to insert into.
284 * @param n The BcNum to insert.
285 * @return The resulting BclNumber from the insert.
286 */
bcl_num_insert(BclContext ctxt,BcNum * restrict n)287 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) {
288
289 BclNumber idx;
290
291 // If there is a free spot...
292 if (ctxt->free_nums.len) {
293
294 BcNum *ptr;
295
296 // Get the index of the free spot and remove it.
297 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
298 bc_vec_pop(&ctxt->free_nums);
299
300 // Copy the number into the spot.
301 ptr = bc_vec_item(&ctxt->nums, idx.i);
302 memcpy(ptr, n, sizeof(BcNum));
303 }
304 else {
305 // Just push the number onto the vector.
306 idx.i = ctxt->nums.len;
307 bc_vec_push(&ctxt->nums, n);
308 }
309
310 assert(!vm.running && !vm.sig && !vm.sig_lock);
311
312 return idx;
313 }
314
bcl_num_create(void)315 BclNumber bcl_num_create(void) {
316
317 BclError e = BCL_ERROR_NONE;
318 BcNum n;
319 BclNumber idx;
320 BclContext ctxt;
321
322 BC_CHECK_CTXT(ctxt);
323
324 BC_FUNC_HEADER_LOCK(err);
325
326 bc_vec_grow(&ctxt->nums, 1);
327
328 bc_num_init(&n, BC_NUM_DEF_SIZE);
329
330 err:
331 BC_FUNC_FOOTER_UNLOCK(e);
332 BC_MAYBE_SETUP(ctxt, e, n, idx);
333
334 assert(!vm.running && !vm.sig && !vm.sig_lock);
335
336 return idx;
337 }
338
339 /**
340 * Destructs a number and marks its spot as free.
341 * @param ctxt The context.
342 * @param n The index of the number.
343 * @param num The number to destroy.
344 */
bcl_num_dtor(BclContext ctxt,BclNumber n,BcNum * restrict num)345 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) {
346
347 BC_SIG_ASSERT_LOCKED;
348
349 assert(num != NULL && num->num != NULL);
350
351 bcl_num_destruct(num);
352 bc_vec_push(&ctxt->free_nums, &n);
353 }
354
bcl_num_free(BclNumber n)355 void bcl_num_free(BclNumber n) {
356
357 BcNum *num;
358 BclContext ctxt;
359
360 BC_CHECK_CTXT_ASSERT(ctxt);
361
362 BC_SIG_LOCK;
363
364 assert(n.i < ctxt->nums.len);
365
366 num = BC_NUM(ctxt, n);
367
368 bcl_num_dtor(ctxt, n, num);
369
370 BC_SIG_UNLOCK;
371 }
372
bcl_copy(BclNumber d,BclNumber s)373 BclError bcl_copy(BclNumber d, BclNumber s) {
374
375 BclError e = BCL_ERROR_NONE;
376 BcNum *dest, *src;
377 BclContext ctxt;
378
379 BC_CHECK_CTXT_ERR(ctxt);
380
381 BC_FUNC_HEADER_LOCK(err);
382
383 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
384
385 dest = BC_NUM(ctxt, d);
386 src = BC_NUM(ctxt, s);
387
388 assert(dest != NULL && src != NULL);
389 assert(dest->num != NULL && src->num != NULL);
390
391 bc_num_copy(dest, src);
392
393 err:
394 BC_FUNC_FOOTER_UNLOCK(e);
395
396 assert(!vm.running && !vm.sig && !vm.sig_lock);
397
398 return e;
399 }
400
bcl_dup(BclNumber s)401 BclNumber bcl_dup(BclNumber s) {
402
403 BclError e = BCL_ERROR_NONE;
404 BcNum *src, dest;
405 BclNumber idx;
406 BclContext ctxt;
407
408 BC_CHECK_CTXT(ctxt);
409
410 BC_FUNC_HEADER_LOCK(err);
411
412 bc_vec_grow(&ctxt->nums, 1);
413
414 assert(s.i < ctxt->nums.len);
415
416 src = BC_NUM(ctxt, s);
417
418 assert(src != NULL && src->num != NULL);
419
420 // Copy the number.
421 bc_num_clear(&dest);
422 bc_num_createCopy(&dest, src);
423
424 err:
425 BC_FUNC_FOOTER_UNLOCK(e);
426 BC_MAYBE_SETUP(ctxt, e, dest, idx);
427
428 assert(!vm.running && !vm.sig && !vm.sig_lock);
429
430 return idx;
431 }
432
bcl_num_destruct(void * num)433 void bcl_num_destruct(void *num) {
434
435 BcNum *n = (BcNum*) num;
436
437 assert(n != NULL);
438
439 if (n->num == NULL) return;
440
441 bc_num_free(num);
442 bc_num_clear(num);
443 }
444
bcl_num_neg(BclNumber n)445 bool bcl_num_neg(BclNumber n) {
446
447 BcNum *num;
448 BclContext ctxt;
449
450 BC_CHECK_CTXT_ASSERT(ctxt);
451
452 assert(n.i < ctxt->nums.len);
453
454 num = BC_NUM(ctxt, n);
455
456 assert(num != NULL && num->num != NULL);
457
458 return BC_NUM_NEG(num) != 0;
459 }
460
bcl_num_setNeg(BclNumber n,bool neg)461 void bcl_num_setNeg(BclNumber n, bool neg) {
462
463 BcNum *num;
464 BclContext ctxt;
465
466 BC_CHECK_CTXT_ASSERT(ctxt);
467
468 assert(n.i < ctxt->nums.len);
469
470 num = BC_NUM(ctxt, n);
471
472 assert(num != NULL && num->num != NULL);
473
474 num->rdx = BC_NUM_NEG_VAL(num, neg);
475 }
476
bcl_num_scale(BclNumber n)477 size_t bcl_num_scale(BclNumber n) {
478
479 BcNum *num;
480 BclContext ctxt;
481
482 BC_CHECK_CTXT_ASSERT(ctxt);
483
484 assert(n.i < ctxt->nums.len);
485
486 num = BC_NUM(ctxt, n);
487
488 assert(num != NULL && num->num != NULL);
489
490 return bc_num_scale(num);
491 }
492
bcl_num_setScale(BclNumber n,size_t scale)493 BclError bcl_num_setScale(BclNumber n, size_t scale) {
494
495 BclError e = BCL_ERROR_NONE;
496 BcNum *nptr;
497 BclContext ctxt;
498
499 BC_CHECK_CTXT_ERR(ctxt);
500
501 BC_CHECK_NUM_ERR(ctxt, n);
502
503 BC_FUNC_HEADER(err);
504
505 assert(n.i < ctxt->nums.len);
506
507 nptr = BC_NUM(ctxt, n);
508
509 assert(nptr != NULL && nptr->num != NULL);
510
511 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
512 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
513
514 err:
515 BC_SIG_MAYLOCK;
516 BC_FUNC_FOOTER(e);
517
518 assert(!vm.running && !vm.sig && !vm.sig_lock);
519
520 return e;
521 }
522
bcl_num_len(BclNumber n)523 size_t bcl_num_len(BclNumber n) {
524
525 BcNum *num;
526 BclContext ctxt;
527
528 BC_CHECK_CTXT_ASSERT(ctxt);
529
530 assert(n.i < ctxt->nums.len);
531
532 num = BC_NUM(ctxt, n);
533
534 assert(num != NULL && num->num != NULL);
535
536 return bc_num_len(num);
537 }
538
bcl_bigdig(BclNumber n,BclBigDig * result)539 BclError bcl_bigdig(BclNumber n, BclBigDig *result) {
540
541 BclError e = BCL_ERROR_NONE;
542 BcNum *num;
543 BclContext ctxt;
544
545 BC_CHECK_CTXT_ERR(ctxt);
546
547 BC_FUNC_HEADER_LOCK(err);
548
549 assert(n.i < ctxt->nums.len);
550 assert(result != NULL);
551
552 num = BC_NUM(ctxt, n);
553
554 assert(num != NULL && num->num != NULL);
555
556 *result = bc_num_bigdig(num);
557
558 err:
559 bcl_num_dtor(ctxt, n, num);
560 BC_FUNC_FOOTER_UNLOCK(e);
561
562 assert(!vm.running && !vm.sig && !vm.sig_lock);
563
564 return e;
565 }
566
bcl_bigdig2num(BclBigDig val)567 BclNumber bcl_bigdig2num(BclBigDig val) {
568
569 BclError e = BCL_ERROR_NONE;
570 BcNum n;
571 BclNumber idx;
572 BclContext ctxt;
573
574 BC_CHECK_CTXT(ctxt);
575
576 BC_FUNC_HEADER_LOCK(err);
577
578 bc_vec_grow(&ctxt->nums, 1);
579
580 bc_num_createFromBigdig(&n, val);
581
582 err:
583 BC_FUNC_FOOTER_UNLOCK(e);
584 BC_MAYBE_SETUP(ctxt, e, n, idx);
585
586 assert(!vm.running && !vm.sig && !vm.sig_lock);
587
588 return idx;
589 }
590
591 /**
592 * Sets up and executes a binary operator operation.
593 * @param a The first operand.
594 * @param b The second operand.
595 * @param op The operation.
596 * @param req The function to get the size of the result for preallocation.
597 * @return The result of the operation.
598 */
bcl_binary(BclNumber a,BclNumber b,const BcNumBinaryOp op,const BcNumBinaryOpReq req)599 static BclNumber bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
600 const BcNumBinaryOpReq req)
601 {
602 BclError e = BCL_ERROR_NONE;
603 BcNum *aptr, *bptr;
604 BcNum c;
605 BclNumber idx;
606 BclContext ctxt;
607
608 BC_CHECK_CTXT(ctxt);
609
610 BC_CHECK_NUM(ctxt, a);
611 BC_CHECK_NUM(ctxt, b);
612
613 BC_FUNC_HEADER_LOCK(err);
614
615 bc_vec_grow(&ctxt->nums, 1);
616
617 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
618
619 aptr = BC_NUM(ctxt, a);
620 bptr = BC_NUM(ctxt, b);
621
622 assert(aptr != NULL && bptr != NULL);
623 assert(aptr->num != NULL && bptr->num != NULL);
624
625 // Clear and initialize the result.
626 bc_num_clear(&c);
627 bc_num_init(&c, req(aptr, bptr, ctxt->scale));
628
629 BC_SIG_UNLOCK;
630
631 op(aptr, bptr, &c, ctxt->scale);
632
633 err:
634
635 BC_SIG_MAYLOCK;
636
637 // Eat the operands.
638 bcl_num_dtor(ctxt, a, aptr);
639 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
640
641 BC_FUNC_FOOTER(e);
642 BC_MAYBE_SETUP(ctxt, e, c, idx);
643
644 assert(!vm.running && !vm.sig && !vm.sig_lock);
645
646 return idx;
647 }
648
bcl_add(BclNumber a,BclNumber b)649 BclNumber bcl_add(BclNumber a, BclNumber b) {
650 return bcl_binary(a, b, bc_num_add, bc_num_addReq);
651 }
652
bcl_sub(BclNumber a,BclNumber b)653 BclNumber bcl_sub(BclNumber a, BclNumber b) {
654 return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
655 }
656
bcl_mul(BclNumber a,BclNumber b)657 BclNumber bcl_mul(BclNumber a, BclNumber b) {
658 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
659 }
660
bcl_div(BclNumber a,BclNumber b)661 BclNumber bcl_div(BclNumber a, BclNumber b) {
662 return bcl_binary(a, b, bc_num_div, bc_num_divReq);
663 }
664
bcl_mod(BclNumber a,BclNumber b)665 BclNumber bcl_mod(BclNumber a, BclNumber b) {
666 return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
667 }
668
bcl_pow(BclNumber a,BclNumber b)669 BclNumber bcl_pow(BclNumber a, BclNumber b) {
670 return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
671 }
672
bcl_lshift(BclNumber a,BclNumber b)673 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
674 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
675 }
676
bcl_rshift(BclNumber a,BclNumber b)677 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
678 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
679 }
680
bcl_sqrt(BclNumber a)681 BclNumber bcl_sqrt(BclNumber a) {
682
683 BclError e = BCL_ERROR_NONE;
684 BcNum *aptr;
685 BcNum b;
686 BclNumber idx;
687 BclContext ctxt;
688
689 BC_CHECK_CTXT(ctxt);
690
691 BC_CHECK_NUM(ctxt, a);
692
693 BC_FUNC_HEADER(err);
694
695 bc_vec_grow(&ctxt->nums, 1);
696
697 assert(a.i < ctxt->nums.len);
698
699 aptr = BC_NUM(ctxt, a);
700
701 bc_num_sqrt(aptr, &b, ctxt->scale);
702
703 err:
704 BC_SIG_MAYLOCK;
705 bcl_num_dtor(ctxt, a, aptr);
706 BC_FUNC_FOOTER(e);
707 BC_MAYBE_SETUP(ctxt, e, b, idx);
708
709 assert(!vm.running && !vm.sig && !vm.sig_lock);
710
711 return idx;
712 }
713
bcl_divmod(BclNumber a,BclNumber b,BclNumber * c,BclNumber * d)714 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) {
715
716 BclError e = BCL_ERROR_NONE;
717 size_t req;
718 BcNum *aptr, *bptr;
719 BcNum cnum, dnum;
720 BclContext ctxt;
721
722 BC_CHECK_CTXT_ERR(ctxt);
723
724 BC_CHECK_NUM_ERR(ctxt, a);
725 BC_CHECK_NUM_ERR(ctxt, b);
726
727 BC_FUNC_HEADER_LOCK(err);
728
729 bc_vec_grow(&ctxt->nums, 2);
730
731 assert(c != NULL && d != NULL);
732
733 aptr = BC_NUM(ctxt, a);
734 bptr = BC_NUM(ctxt, b);
735
736 assert(aptr != NULL && bptr != NULL);
737 assert(aptr->num != NULL && bptr->num != NULL);
738
739 bc_num_clear(&cnum);
740 bc_num_clear(&dnum);
741
742 req = bc_num_divReq(aptr, bptr, ctxt->scale);
743
744 // Initialize the numbers.
745 bc_num_init(&cnum, req);
746 BC_UNSETJMP;
747 BC_SETJMP_LOCKED(err);
748 bc_num_init(&dnum, req);
749
750 BC_SIG_UNLOCK;
751
752 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
753
754 err:
755 BC_SIG_MAYLOCK;
756
757 // Eat the operands.
758 bcl_num_dtor(ctxt, a, aptr);
759 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
760
761 // If there was an error...
762 if (BC_ERR(vm.err)) {
763
764 // Free the results.
765 if (cnum.num != NULL) bc_num_free(&cnum);
766 if (dnum.num != NULL) bc_num_free(&dnum);
767
768 // Make sure the return values are invalid.
769 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
770 d->i = c->i;
771
772 BC_FUNC_FOOTER(e);
773 }
774 else {
775
776 BC_FUNC_FOOTER(e);
777
778 // Insert the results into the context.
779 *c = bcl_num_insert(ctxt, &cnum);
780 *d = bcl_num_insert(ctxt, &dnum);
781 }
782
783 assert(!vm.running && !vm.sig && !vm.sig_lock);
784
785 return e;
786 }
787
bcl_modexp(BclNumber a,BclNumber b,BclNumber c)788 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) {
789
790 BclError e = BCL_ERROR_NONE;
791 size_t req;
792 BcNum *aptr, *bptr, *cptr;
793 BcNum d;
794 BclNumber idx;
795 BclContext ctxt;
796
797 BC_CHECK_CTXT(ctxt);
798
799 BC_CHECK_NUM(ctxt, a);
800 BC_CHECK_NUM(ctxt, b);
801 BC_CHECK_NUM(ctxt, c);
802
803 BC_FUNC_HEADER_LOCK(err);
804
805 bc_vec_grow(&ctxt->nums, 1);
806
807 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
808 assert(c.i < ctxt->nums.len);
809
810 aptr = BC_NUM(ctxt, a);
811 bptr = BC_NUM(ctxt, b);
812 cptr = BC_NUM(ctxt, c);
813
814 assert(aptr != NULL && bptr != NULL && cptr != NULL);
815 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
816
817 // Prepare the result.
818 bc_num_clear(&d);
819
820 req = bc_num_divReq(aptr, cptr, 0);
821
822 // Initialize the result.
823 bc_num_init(&d, req);
824
825 BC_SIG_UNLOCK;
826
827 bc_num_modexp(aptr, bptr, cptr, &d);
828
829 err:
830 BC_SIG_MAYLOCK;
831
832 // Eat the operands.
833 bcl_num_dtor(ctxt, a, aptr);
834 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
835 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
836
837 BC_FUNC_FOOTER(e);
838 BC_MAYBE_SETUP(ctxt, e, d, idx);
839
840 assert(!vm.running && !vm.sig && !vm.sig_lock);
841
842 return idx;
843 }
844
bcl_cmp(BclNumber a,BclNumber b)845 ssize_t bcl_cmp(BclNumber a, BclNumber b) {
846
847 BcNum *aptr, *bptr;
848 BclContext ctxt;
849
850 BC_CHECK_CTXT_ASSERT(ctxt);
851
852 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
853
854 aptr = BC_NUM(ctxt, a);
855 bptr = BC_NUM(ctxt, b);
856
857 assert(aptr != NULL && bptr != NULL);
858 assert(aptr->num != NULL && bptr->num != NULL);
859
860 return bc_num_cmp(aptr, bptr);
861 }
862
bcl_zero(BclNumber n)863 void bcl_zero(BclNumber n) {
864
865 BcNum *nptr;
866 BclContext ctxt;
867
868 BC_CHECK_CTXT_ASSERT(ctxt);
869
870 assert(n.i < ctxt->nums.len);
871
872 nptr = BC_NUM(ctxt, n);
873
874 assert(nptr != NULL && nptr->num != NULL);
875
876 bc_num_zero(nptr);
877 }
878
bcl_one(BclNumber n)879 void bcl_one(BclNumber n) {
880
881 BcNum *nptr;
882 BclContext ctxt;
883
884 BC_CHECK_CTXT_ASSERT(ctxt);
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_num_one(nptr);
893 }
894
bcl_parse(const char * restrict val)895 BclNumber bcl_parse(const char *restrict val) {
896
897 BclError e = BCL_ERROR_NONE;
898 BcNum n;
899 BclNumber idx;
900 BclContext ctxt;
901 bool neg;
902
903 BC_CHECK_CTXT(ctxt);
904
905 BC_FUNC_HEADER_LOCK(err);
906
907 bc_vec_grow(&ctxt->nums, 1);
908
909 assert(val != NULL);
910
911 // We have to take care of negative here because bc's number parsing does
912 // not.
913 neg = (val[0] == '-');
914
915 if (neg) val += 1;
916
917 if (!bc_num_strValid(val)) {
918 vm.err = BCL_ERROR_PARSE_INVALID_STR;
919 goto err;
920 }
921
922 // Clear and initialize the number.
923 bc_num_clear(&n);
924 bc_num_init(&n, BC_NUM_DEF_SIZE);
925
926 BC_SIG_UNLOCK;
927
928 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
929
930 // Set the negative.
931 n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
932
933 err:
934 BC_SIG_MAYLOCK;
935 BC_FUNC_FOOTER(e);
936 BC_MAYBE_SETUP(ctxt, e, n, idx);
937
938 assert(!vm.running && !vm.sig && !vm.sig_lock);
939
940 return idx;
941 }
942
bcl_string(BclNumber n)943 char* bcl_string(BclNumber n) {
944
945 BcNum *nptr;
946 char *str = NULL;
947 BclContext ctxt;
948
949 BC_CHECK_CTXT_ASSERT(ctxt);
950
951 if (BC_ERR(n.i >= ctxt->nums.len)) return str;
952
953 BC_FUNC_HEADER(err);
954
955 assert(n.i < ctxt->nums.len);
956
957 nptr = BC_NUM(ctxt, n);
958
959 assert(nptr != NULL && nptr->num != NULL);
960
961 // Clear the buffer.
962 bc_vec_popAll(&vm.out);
963
964 // Print to the buffer.
965 bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
966 bc_vec_pushByte(&vm.out, '\0');
967
968 BC_SIG_LOCK;
969
970 // Just dup the string; the caller is responsible for it.
971 str = bc_vm_strdup(vm.out.v);
972
973 err:
974
975 // Eat the operand.
976 bcl_num_dtor(ctxt, n, nptr);
977
978 BC_FUNC_FOOTER_NO_ERR;
979
980 assert(!vm.running && !vm.sig && !vm.sig_lock);
981
982 return str;
983 }
984
bcl_irand(BclNumber a)985 BclNumber bcl_irand(BclNumber a) {
986
987 BclError e = BCL_ERROR_NONE;
988 BcNum *aptr;
989 BcNum b;
990 BclNumber idx;
991 BclContext ctxt;
992
993 BC_CHECK_CTXT(ctxt);
994
995 BC_CHECK_NUM(ctxt, a);
996
997 BC_FUNC_HEADER_LOCK(err);
998
999 bc_vec_grow(&ctxt->nums, 1);
1000
1001 assert(a.i < ctxt->nums.len);
1002
1003 aptr = BC_NUM(ctxt, a);
1004
1005 assert(aptr != NULL && aptr->num != NULL);
1006
1007 // Clear and initialize the result.
1008 bc_num_clear(&b);
1009 bc_num_init(&b, BC_NUM_DEF_SIZE);
1010
1011 BC_SIG_UNLOCK;
1012
1013 bc_num_irand(aptr, &b, &vm.rng);
1014
1015 err:
1016 BC_SIG_MAYLOCK;
1017
1018 // Eat the operand.
1019 bcl_num_dtor(ctxt, a, aptr);
1020
1021 BC_FUNC_FOOTER(e);
1022 BC_MAYBE_SETUP(ctxt, e, b, idx);
1023
1024 assert(!vm.running && !vm.sig && !vm.sig_lock);
1025
1026 return idx;
1027 }
1028
1029 /**
1030 * Helps bcl_frand(). This is separate because the error handling is easier that
1031 * way. It is also easier to do ifrand that way.
1032 * @param b The return parameter.
1033 * @param places The number of decimal places to generate.
1034 */
bcl_frandHelper(BcNum * restrict b,size_t places)1035 static void bcl_frandHelper(BcNum *restrict b, size_t places) {
1036
1037 BcNum exp, pow, ten;
1038 BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
1039 BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
1040
1041 // Set up temporaries.
1042 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
1043 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
1044
1045 ten.num[0] = 10;
1046 ten.len = 1;
1047
1048 bc_num_bigdig2num(&exp, (BcBigDig) places);
1049
1050 // Clear the temporary that might need to grow.
1051 bc_num_clear(&pow);
1052
1053 BC_SIG_LOCK;
1054
1055 // Initialize the temporary that might need to grow.
1056 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
1057
1058 BC_SETJMP_LOCKED(err);
1059
1060 BC_SIG_UNLOCK;
1061
1062 // Generate the number.
1063 bc_num_pow(&ten, &exp, &pow, 0);
1064 bc_num_irand(&pow, b, &vm.rng);
1065
1066 // Make the number entirely fraction.
1067 bc_num_shiftRight(b, places);
1068
1069 err:
1070 BC_SIG_MAYLOCK;
1071 bc_num_free(&pow);
1072 BC_LONGJMP_CONT;
1073 }
1074
bcl_frand(size_t places)1075 BclNumber bcl_frand(size_t places) {
1076
1077 BclError e = BCL_ERROR_NONE;
1078 BcNum n;
1079 BclNumber idx;
1080 BclContext ctxt;
1081
1082 BC_CHECK_CTXT(ctxt);
1083
1084 BC_FUNC_HEADER_LOCK(err);
1085
1086 bc_vec_grow(&ctxt->nums, 1);
1087
1088 // Clear and initialize the number.
1089 bc_num_clear(&n);
1090 bc_num_init(&n, BC_NUM_DEF_SIZE);
1091
1092 BC_SIG_UNLOCK;
1093
1094 bcl_frandHelper(&n, places);
1095
1096 err:
1097 BC_SIG_MAYLOCK;
1098
1099 BC_FUNC_FOOTER(e);
1100 BC_MAYBE_SETUP(ctxt, e, n, idx);
1101
1102 assert(!vm.running && !vm.sig && !vm.sig_lock);
1103
1104 return idx;
1105 }
1106
1107 /**
1108 * Helps bc_ifrand(). This is separate because error handling is easier that
1109 * way.
1110 * @param a The limit for bc_num_irand().
1111 * @param b The return parameter.
1112 * @param places The number of decimal places to generate.
1113 */
bcl_ifrandHelper(BcNum * restrict a,BcNum * restrict b,size_t places)1114 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b,
1115 size_t places)
1116 {
1117 BcNum ir, fr;
1118
1119 // Clear the integer and fractional numbers.
1120 bc_num_clear(&ir);
1121 bc_num_clear(&fr);
1122
1123 BC_SIG_LOCK;
1124
1125 // Initialize the integer and fractional numbers.
1126 bc_num_init(&ir, BC_NUM_DEF_SIZE);
1127 bc_num_init(&fr, BC_NUM_DEF_SIZE);
1128
1129 BC_SETJMP_LOCKED(err);
1130
1131 BC_SIG_UNLOCK;
1132
1133 bc_num_irand(a, &ir, &vm.rng);
1134 bcl_frandHelper(&fr, places);
1135
1136 bc_num_add(&ir, &fr, b, 0);
1137
1138 err:
1139 BC_SIG_MAYLOCK;
1140 bc_num_free(&fr);
1141 bc_num_free(&ir);
1142 BC_LONGJMP_CONT;
1143 }
1144
bcl_ifrand(BclNumber a,size_t places)1145 BclNumber bcl_ifrand(BclNumber a, size_t places) {
1146
1147 BclError e = BCL_ERROR_NONE;
1148 BcNum *aptr;
1149 BcNum b;
1150 BclNumber idx;
1151 BclContext ctxt;
1152
1153 BC_CHECK_CTXT(ctxt);
1154 BC_CHECK_NUM(ctxt, a);
1155
1156 BC_FUNC_HEADER_LOCK(err);
1157
1158 bc_vec_grow(&ctxt->nums, 1);
1159
1160 assert(a.i < ctxt->nums.len);
1161
1162 aptr = BC_NUM(ctxt, a);
1163
1164 assert(aptr != NULL && aptr->num != NULL);
1165
1166 // Clear and initialize the number.
1167 bc_num_clear(&b);
1168 bc_num_init(&b, BC_NUM_DEF_SIZE);
1169
1170 BC_SIG_UNLOCK;
1171
1172 bcl_ifrandHelper(aptr, &b, places);
1173
1174 err:
1175 BC_SIG_MAYLOCK;
1176
1177 // Eat the oprand.
1178 bcl_num_dtor(ctxt, a, aptr);
1179
1180 BC_FUNC_FOOTER(e);
1181 BC_MAYBE_SETUP(ctxt, e, b, idx);
1182
1183 assert(!vm.running && !vm.sig && !vm.sig_lock);
1184
1185 return idx;
1186 }
1187
bcl_rand_seedWithNum(BclNumber n)1188 BclError bcl_rand_seedWithNum(BclNumber n) {
1189
1190 BclError e = BCL_ERROR_NONE;
1191 BcNum *nptr;
1192 BclContext ctxt;
1193
1194 BC_CHECK_CTXT_ERR(ctxt);
1195 BC_CHECK_NUM_ERR(ctxt, n);
1196
1197 BC_FUNC_HEADER(err);
1198
1199 assert(n.i < ctxt->nums.len);
1200
1201 nptr = BC_NUM(ctxt, n);
1202
1203 assert(nptr != NULL && nptr->num != NULL);
1204
1205 bc_num_rng(nptr, &vm.rng);
1206
1207 err:
1208 BC_SIG_MAYLOCK;
1209 BC_FUNC_FOOTER(e);
1210
1211 assert(!vm.running && !vm.sig && !vm.sig_lock);
1212
1213 return e;
1214 }
1215
bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE])1216 BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) {
1217
1218 BclError e = BCL_ERROR_NONE;
1219 size_t i;
1220 ulong vals[BCL_SEED_ULONGS];
1221
1222 BC_FUNC_HEADER(err);
1223
1224 // Fill the array.
1225 for (i = 0; i < BCL_SEED_SIZE; ++i) {
1226 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) *
1227 (i % sizeof(ulong)));
1228 vals[i / sizeof(long)] |= val;
1229 }
1230
1231 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]);
1232
1233 err:
1234 BC_SIG_MAYLOCK;
1235 BC_FUNC_FOOTER(e);
1236 return e;
1237 }
1238
bcl_rand_reseed(void)1239 void bcl_rand_reseed(void) {
1240 bc_rand_srand(bc_vec_top(&vm.rng.v));
1241 }
1242
bcl_rand_seed2num(void)1243 BclNumber bcl_rand_seed2num(void) {
1244
1245 BclError e = BCL_ERROR_NONE;
1246 BcNum n;
1247 BclNumber idx;
1248 BclContext ctxt;
1249
1250 BC_CHECK_CTXT(ctxt);
1251
1252 BC_FUNC_HEADER_LOCK(err);
1253
1254 // Clear and initialize the number.
1255 bc_num_clear(&n);
1256 bc_num_init(&n, BC_NUM_DEF_SIZE);
1257
1258 BC_SIG_UNLOCK;
1259
1260 bc_num_createFromRNG(&n, &vm.rng);
1261
1262 err:
1263 BC_SIG_MAYLOCK;
1264 BC_FUNC_FOOTER(e);
1265 BC_MAYBE_SETUP(ctxt, e, n, idx);
1266
1267 assert(!vm.running && !vm.sig && !vm.sig_lock);
1268
1269 return idx;
1270 }
1271
bcl_rand_int(void)1272 BclRandInt bcl_rand_int(void) {
1273 return (BclRandInt) bc_rand_int(&vm.rng);
1274 }
1275
bcl_rand_bounded(BclRandInt bound)1276 BclRandInt bcl_rand_bounded(BclRandInt bound) {
1277 if (bound <= 1) return 0;
1278 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound);
1279 }
1280
1281 #endif // BC_ENABLE_LIBRARY
1282