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