xref: /freebsd/contrib/bc/src/library.c (revision 3332f1b444d4a73238e9f59cca27bfc95fe936bd)
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 	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 
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 
136 void bcl_popContext(void) {
137 	if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
138 }
139 
140 BclContext bcl_context(void) {
141 	if (!vm.ctxts.len) return NULL;
142 	return *((BclContext*) bc_vec_top(&vm.ctxts));
143 }
144 
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 
174 void bcl_gc(void) {
175 	BC_SIG_LOCK;
176 	bc_vm_freeTemps();
177 	BC_SIG_UNLOCK;
178 }
179 
180 bool bcl_abortOnFatalError(void) {
181 	return vm.abrt;
182 }
183 
184 void bcl_setAbortOnFatalError(bool abrt) {
185 	vm.abrt = abrt;
186 }
187 
188 bool bcl_leadingZeroes(void) {
189 	return vm.leading_zeroes;
190 }
191 
192 void bcl_setLeadingZeroes(bool leadingZeroes) {
193 	vm.leading_zeroes = leadingZeroes;
194 }
195 
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 
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 
235 void bcl_ctxt_freeNums(BclContext ctxt) {
236 	bc_vec_popAll(&ctxt->nums);
237 	bc_vec_popAll(&ctxt->free_nums);
238 }
239 
240 size_t bcl_ctxt_scale(BclContext ctxt) {
241 	return ctxt->scale;
242 }
243 
244 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
245 	ctxt->scale = scale;
246 }
247 
248 size_t bcl_ctxt_ibase(BclContext ctxt) {
249 	return ctxt->ibase;
250 }
251 
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 
258 size_t bcl_ctxt_obase(BclContext ctxt) {
259 	return ctxt->obase;
260 }
261 
262 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
263 	ctxt->obase = obase;
264 }
265 
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  */
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 
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
649 BclNumber bcl_add(BclNumber a, BclNumber b) {
650 	return bcl_binary(a, b, bc_num_add, bc_num_addReq);
651 }
652 
653 BclNumber bcl_sub(BclNumber a, BclNumber b) {
654 	return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
655 }
656 
657 BclNumber bcl_mul(BclNumber a, BclNumber b) {
658 	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
659 }
660 
661 BclNumber bcl_div(BclNumber a, BclNumber b) {
662 	return bcl_binary(a, b, bc_num_div, bc_num_divReq);
663 }
664 
665 BclNumber bcl_mod(BclNumber a, BclNumber b) {
666 	return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
667 }
668 
669 BclNumber bcl_pow(BclNumber a, BclNumber b) {
670 	return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
671 }
672 
673 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
674 	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
675 }
676 
677 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
678 	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
679 }
680 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
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  */
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 
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 
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 
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 
1239 void bcl_rand_reseed(void) {
1240 	bc_rand_srand(bc_vec_top(&vm.rng.v));
1241 }
1242 
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 
1272 BclRandInt bcl_rand_int(void) {
1273 	return (BclRandInt) bc_rand_int(&vm.rng);
1274 }
1275 
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