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