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