xref: /freebsd/contrib/bc/src/library.c (revision eea7c61590ae8968b3f1f609cf0bc8633222a94f)
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 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 
72 bool bcl_running(void) {
73 	return vm.running != 0;
74 }
75 
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 
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 
139 void bcl_popContext(void) {
140 	if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
141 }
142 
143 BclContext bcl_context(void) {
144 	if (!vm.ctxts.len) return NULL;
145 	return *((BclContext*) bc_vec_top(&vm.ctxts));
146 }
147 
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 
180 void bcl_gc(void) {
181 	BC_SIG_LOCK;
182 	bc_vm_freeTemps();
183 	BC_SIG_UNLOCK;
184 }
185 
186 bool bcl_abortOnFatalError(void) {
187 	return vm.abrt;
188 }
189 
190 void bcl_setAbortOnFatalError(bool abrt) {
191 	vm.abrt = abrt;
192 }
193 
194 bool bcl_leadingZeroes(void) {
195 	return vm.leading_zeroes;
196 }
197 
198 void bcl_setLeadingZeroes(bool leadingZeroes) {
199 	vm.leading_zeroes = leadingZeroes;
200 }
201 
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 
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 
241 void bcl_ctxt_freeNums(BclContext ctxt) {
242 	bc_vec_popAll(&ctxt->nums);
243 	bc_vec_popAll(&ctxt->free_nums);
244 }
245 
246 size_t bcl_ctxt_scale(BclContext ctxt) {
247 	return ctxt->scale;
248 }
249 
250 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
251 	ctxt->scale = scale;
252 }
253 
254 size_t bcl_ctxt_ibase(BclContext ctxt) {
255 	return ctxt->ibase;
256 }
257 
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 
264 size_t bcl_ctxt_obase(BclContext ctxt) {
265 	return ctxt->obase;
266 }
267 
268 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
269 	ctxt->obase = obase;
270 }
271 
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  */
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 
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
655 BclNumber bcl_add(BclNumber a, BclNumber b) {
656 	return bcl_binary(a, b, bc_num_add, bc_num_addReq);
657 }
658 
659 BclNumber bcl_sub(BclNumber a, BclNumber b) {
660 	return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
661 }
662 
663 BclNumber bcl_mul(BclNumber a, BclNumber b) {
664 	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
665 }
666 
667 BclNumber bcl_div(BclNumber a, BclNumber b) {
668 	return bcl_binary(a, b, bc_num_div, bc_num_divReq);
669 }
670 
671 BclNumber bcl_mod(BclNumber a, BclNumber b) {
672 	return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
673 }
674 
675 BclNumber bcl_pow(BclNumber a, BclNumber b) {
676 	return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
677 }
678 
679 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
680 	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
681 }
682 
683 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
684 	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
685 }
686 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
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  */
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 
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 
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 
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 
1245 void bcl_rand_reseed(void) {
1246 	bc_rand_srand(bc_vec_top(&vm.rng.v));
1247 }
1248 
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 
1278 BclRandInt bcl_rand_int(void) {
1279 	return (BclRandInt) bc_rand_int(&vm.rng);
1280 }
1281 
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