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