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