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