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