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 BclContext bcl_ctxt_create(void) { 189 190 BclContext ctxt = NULL; 191 192 BC_FUNC_HEADER_LOCK(err); 193 194 // We want the context to be free of any interference of other parties, so 195 // malloc() is appropriate here. 196 ctxt = bc_vm_malloc(sizeof(BclCtxt)); 197 198 bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM); 199 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE); 200 201 ctxt->scale = 0; 202 ctxt->ibase = 10; 203 ctxt->obase= 10; 204 205 err: 206 if (BC_ERR(vm.err && ctxt != NULL)) { 207 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums); 208 free(ctxt); 209 ctxt = NULL; 210 } 211 212 BC_FUNC_FOOTER_NO_ERR; 213 214 assert(!vm.running && !vm.sig && !vm.sig_lock); 215 216 return ctxt; 217 } 218 219 void bcl_ctxt_free(BclContext ctxt) { 220 BC_SIG_LOCK; 221 bc_vec_free(&ctxt->free_nums); 222 bc_vec_free(&ctxt->nums); 223 free(ctxt); 224 BC_SIG_UNLOCK; 225 } 226 227 void bcl_ctxt_freeNums(BclContext ctxt) { 228 bc_vec_popAll(&ctxt->nums); 229 bc_vec_popAll(&ctxt->free_nums); 230 } 231 232 size_t bcl_ctxt_scale(BclContext ctxt) { 233 return ctxt->scale; 234 } 235 236 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) { 237 ctxt->scale = scale; 238 } 239 240 size_t bcl_ctxt_ibase(BclContext ctxt) { 241 return ctxt->ibase; 242 } 243 244 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) { 245 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE; 246 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE; 247 ctxt->ibase = ibase; 248 } 249 250 size_t bcl_ctxt_obase(BclContext ctxt) { 251 return ctxt->obase; 252 } 253 254 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) { 255 ctxt->obase = obase; 256 } 257 258 BclError bcl_err(BclNumber n) { 259 260 BclContext ctxt; 261 262 BC_CHECK_CTXT_ERR(ctxt); 263 264 // Errors are encoded as (0 - error_code). If the index is in that range, it 265 // is an encoded error. 266 if (n.i >= ctxt->nums.len) { 267 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i); 268 else return BCL_ERROR_INVALID_NUM; 269 } 270 else return BCL_ERROR_NONE; 271 } 272 273 /** 274 * Inserts a BcNum into a context's list of numbers. 275 * @param ctxt The context to insert into. 276 * @param n The BcNum to insert. 277 * @return The resulting BclNumber from the insert. 278 */ 279 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) { 280 281 BclNumber idx; 282 283 // If there is a free spot... 284 if (ctxt->free_nums.len) { 285 286 BcNum *ptr; 287 288 // Get the index of the free spot and remove it. 289 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums)); 290 bc_vec_pop(&ctxt->free_nums); 291 292 // Copy the number into the spot. 293 ptr = bc_vec_item(&ctxt->nums, idx.i); 294 memcpy(ptr, n, sizeof(BcNum)); 295 } 296 else { 297 // Just push the number onto the vector. 298 idx.i = ctxt->nums.len; 299 bc_vec_push(&ctxt->nums, n); 300 } 301 302 assert(!vm.running && !vm.sig && !vm.sig_lock); 303 304 return idx; 305 } 306 307 BclNumber bcl_num_create(void) { 308 309 BclError e = BCL_ERROR_NONE; 310 BcNum n; 311 BclNumber idx; 312 BclContext ctxt; 313 314 BC_CHECK_CTXT(ctxt); 315 316 BC_FUNC_HEADER_LOCK(err); 317 318 bc_vec_grow(&ctxt->nums, 1); 319 320 bc_num_init(&n, BC_NUM_DEF_SIZE); 321 322 err: 323 BC_FUNC_FOOTER_UNLOCK(e); 324 BC_MAYBE_SETUP(ctxt, e, n, idx); 325 326 assert(!vm.running && !vm.sig && !vm.sig_lock); 327 328 return idx; 329 } 330 331 /** 332 * Destructs a number and marks its spot as free. 333 * @param ctxt The context. 334 * @param n The index of the number. 335 * @param num The number to destroy. 336 */ 337 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) { 338 339 BC_SIG_ASSERT_LOCKED; 340 341 assert(num != NULL && num->num != NULL); 342 343 bcl_num_destruct(num); 344 bc_vec_push(&ctxt->free_nums, &n); 345 } 346 347 void bcl_num_free(BclNumber n) { 348 349 BcNum *num; 350 BclContext ctxt; 351 352 BC_CHECK_CTXT_ASSERT(ctxt); 353 354 BC_SIG_LOCK; 355 356 assert(n.i < ctxt->nums.len); 357 358 num = BC_NUM(ctxt, n); 359 360 bcl_num_dtor(ctxt, n, num); 361 362 BC_SIG_UNLOCK; 363 } 364 365 BclError bcl_copy(BclNumber d, BclNumber s) { 366 367 BclError e = BCL_ERROR_NONE; 368 BcNum *dest, *src; 369 BclContext ctxt; 370 371 BC_CHECK_CTXT_ERR(ctxt); 372 373 BC_FUNC_HEADER_LOCK(err); 374 375 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len); 376 377 dest = BC_NUM(ctxt, d); 378 src = BC_NUM(ctxt, s); 379 380 assert(dest != NULL && src != NULL); 381 assert(dest->num != NULL && src->num != NULL); 382 383 bc_num_copy(dest, src); 384 385 err: 386 BC_FUNC_FOOTER_UNLOCK(e); 387 388 assert(!vm.running && !vm.sig && !vm.sig_lock); 389 390 return e; 391 } 392 393 BclNumber bcl_dup(BclNumber s) { 394 395 BclError e = BCL_ERROR_NONE; 396 BcNum *src, dest; 397 BclNumber idx; 398 BclContext ctxt; 399 400 BC_CHECK_CTXT(ctxt); 401 402 BC_FUNC_HEADER_LOCK(err); 403 404 bc_vec_grow(&ctxt->nums, 1); 405 406 assert(s.i < ctxt->nums.len); 407 408 src = BC_NUM(ctxt, s); 409 410 assert(src != NULL && src->num != NULL); 411 412 // Copy the number. 413 bc_num_clear(&dest); 414 bc_num_createCopy(&dest, src); 415 416 err: 417 BC_FUNC_FOOTER_UNLOCK(e); 418 BC_MAYBE_SETUP(ctxt, e, dest, idx); 419 420 assert(!vm.running && !vm.sig && !vm.sig_lock); 421 422 return idx; 423 } 424 425 void bcl_num_destruct(void *num) { 426 427 BcNum *n = (BcNum*) num; 428 429 assert(n != NULL); 430 431 if (n->num == NULL) return; 432 433 bc_num_free(num); 434 bc_num_clear(num); 435 } 436 437 bool bcl_num_neg(BclNumber n) { 438 439 BcNum *num; 440 BclContext ctxt; 441 442 BC_CHECK_CTXT_ASSERT(ctxt); 443 444 assert(n.i < ctxt->nums.len); 445 446 num = BC_NUM(ctxt, n); 447 448 assert(num != NULL && num->num != NULL); 449 450 return BC_NUM_NEG(num) != 0; 451 } 452 453 void bcl_num_setNeg(BclNumber n, bool neg) { 454 455 BcNum *num; 456 BclContext ctxt; 457 458 BC_CHECK_CTXT_ASSERT(ctxt); 459 460 assert(n.i < ctxt->nums.len); 461 462 num = BC_NUM(ctxt, n); 463 464 assert(num != NULL && num->num != NULL); 465 466 num->rdx = BC_NUM_NEG_VAL(num, neg); 467 } 468 469 size_t bcl_num_scale(BclNumber n) { 470 471 BcNum *num; 472 BclContext ctxt; 473 474 BC_CHECK_CTXT_ASSERT(ctxt); 475 476 assert(n.i < ctxt->nums.len); 477 478 num = BC_NUM(ctxt, n); 479 480 assert(num != NULL && num->num != NULL); 481 482 return bc_num_scale(num); 483 } 484 485 BclError bcl_num_setScale(BclNumber n, size_t scale) { 486 487 BclError e = BCL_ERROR_NONE; 488 BcNum *nptr; 489 BclContext ctxt; 490 491 BC_CHECK_CTXT_ERR(ctxt); 492 493 BC_CHECK_NUM_ERR(ctxt, n); 494 495 BC_FUNC_HEADER(err); 496 497 assert(n.i < ctxt->nums.len); 498 499 nptr = BC_NUM(ctxt, n); 500 501 assert(nptr != NULL && nptr->num != NULL); 502 503 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale); 504 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale); 505 506 err: 507 BC_SIG_MAYLOCK; 508 BC_FUNC_FOOTER(e); 509 510 assert(!vm.running && !vm.sig && !vm.sig_lock); 511 512 return e; 513 } 514 515 size_t bcl_num_len(BclNumber n) { 516 517 BcNum *num; 518 BclContext ctxt; 519 520 BC_CHECK_CTXT_ASSERT(ctxt); 521 522 assert(n.i < ctxt->nums.len); 523 524 num = BC_NUM(ctxt, n); 525 526 assert(num != NULL && num->num != NULL); 527 528 return bc_num_len(num); 529 } 530 531 BclError bcl_bigdig(BclNumber n, BclBigDig *result) { 532 533 BclError e = BCL_ERROR_NONE; 534 BcNum *num; 535 BclContext ctxt; 536 537 BC_CHECK_CTXT_ERR(ctxt); 538 539 BC_FUNC_HEADER_LOCK(err); 540 541 assert(n.i < ctxt->nums.len); 542 assert(result != NULL); 543 544 num = BC_NUM(ctxt, n); 545 546 assert(num != NULL && num->num != NULL); 547 548 *result = bc_num_bigdig(num); 549 550 err: 551 bcl_num_dtor(ctxt, n, num); 552 BC_FUNC_FOOTER_UNLOCK(e); 553 554 assert(!vm.running && !vm.sig && !vm.sig_lock); 555 556 return e; 557 } 558 559 BclNumber bcl_bigdig2num(BclBigDig val) { 560 561 BclError e = BCL_ERROR_NONE; 562 BcNum n; 563 BclNumber idx; 564 BclContext ctxt; 565 566 BC_CHECK_CTXT(ctxt); 567 568 BC_FUNC_HEADER_LOCK(err); 569 570 bc_vec_grow(&ctxt->nums, 1); 571 572 bc_num_createFromBigdig(&n, val); 573 574 err: 575 BC_FUNC_FOOTER_UNLOCK(e); 576 BC_MAYBE_SETUP(ctxt, e, n, idx); 577 578 assert(!vm.running && !vm.sig && !vm.sig_lock); 579 580 return idx; 581 } 582 583 /** 584 * Sets up and executes a binary operator operation. 585 * @param a The first operand. 586 * @param b The second operand. 587 * @param op The operation. 588 * @param req The function to get the size of the result for preallocation. 589 * @return The result of the operation. 590 */ 591 static BclNumber bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op, 592 const BcNumBinaryOpReq req) 593 { 594 BclError e = BCL_ERROR_NONE; 595 BcNum *aptr, *bptr; 596 BcNum c; 597 BclNumber idx; 598 BclContext ctxt; 599 600 BC_CHECK_CTXT(ctxt); 601 602 BC_CHECK_NUM(ctxt, a); 603 BC_CHECK_NUM(ctxt, b); 604 605 BC_FUNC_HEADER_LOCK(err); 606 607 bc_vec_grow(&ctxt->nums, 1); 608 609 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 610 611 aptr = BC_NUM(ctxt, a); 612 bptr = BC_NUM(ctxt, b); 613 614 assert(aptr != NULL && bptr != NULL); 615 assert(aptr->num != NULL && bptr->num != NULL); 616 617 // Clear and initialize the result. 618 bc_num_clear(&c); 619 bc_num_init(&c, req(aptr, bptr, ctxt->scale)); 620 621 BC_SIG_UNLOCK; 622 623 op(aptr, bptr, &c, ctxt->scale); 624 625 err: 626 627 BC_SIG_MAYLOCK; 628 629 // Eat the operands. 630 bcl_num_dtor(ctxt, a, aptr); 631 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 632 633 BC_FUNC_FOOTER(e); 634 BC_MAYBE_SETUP(ctxt, e, c, idx); 635 636 assert(!vm.running && !vm.sig && !vm.sig_lock); 637 638 return idx; 639 } 640 641 BclNumber bcl_add(BclNumber a, BclNumber b) { 642 return bcl_binary(a, b, bc_num_add, bc_num_addReq); 643 } 644 645 BclNumber bcl_sub(BclNumber a, BclNumber b) { 646 return bcl_binary(a, b, bc_num_sub, bc_num_addReq); 647 } 648 649 BclNumber bcl_mul(BclNumber a, BclNumber b) { 650 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq); 651 } 652 653 BclNumber bcl_div(BclNumber a, BclNumber b) { 654 return bcl_binary(a, b, bc_num_div, bc_num_divReq); 655 } 656 657 BclNumber bcl_mod(BclNumber a, BclNumber b) { 658 return bcl_binary(a, b, bc_num_mod, bc_num_divReq); 659 } 660 661 BclNumber bcl_pow(BclNumber a, BclNumber b) { 662 return bcl_binary(a, b, bc_num_pow, bc_num_powReq); 663 } 664 665 BclNumber bcl_lshift(BclNumber a, BclNumber b) { 666 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq); 667 } 668 669 BclNumber bcl_rshift(BclNumber a, BclNumber b) { 670 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq); 671 } 672 673 BclNumber bcl_sqrt(BclNumber a) { 674 675 BclError e = BCL_ERROR_NONE; 676 BcNum *aptr; 677 BcNum b; 678 BclNumber idx; 679 BclContext ctxt; 680 681 BC_CHECK_CTXT(ctxt); 682 683 BC_CHECK_NUM(ctxt, a); 684 685 BC_FUNC_HEADER(err); 686 687 bc_vec_grow(&ctxt->nums, 1); 688 689 assert(a.i < ctxt->nums.len); 690 691 aptr = BC_NUM(ctxt, a); 692 693 bc_num_sqrt(aptr, &b, ctxt->scale); 694 695 err: 696 BC_SIG_MAYLOCK; 697 bcl_num_dtor(ctxt, a, aptr); 698 BC_FUNC_FOOTER(e); 699 BC_MAYBE_SETUP(ctxt, e, b, idx); 700 701 assert(!vm.running && !vm.sig && !vm.sig_lock); 702 703 return idx; 704 } 705 706 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) { 707 708 BclError e = BCL_ERROR_NONE; 709 size_t req; 710 BcNum *aptr, *bptr; 711 BcNum cnum, dnum; 712 BclContext ctxt; 713 714 BC_CHECK_CTXT_ERR(ctxt); 715 716 BC_CHECK_NUM_ERR(ctxt, a); 717 BC_CHECK_NUM_ERR(ctxt, b); 718 719 BC_FUNC_HEADER_LOCK(err); 720 721 bc_vec_grow(&ctxt->nums, 2); 722 723 assert(c != NULL && d != NULL); 724 725 aptr = BC_NUM(ctxt, a); 726 bptr = BC_NUM(ctxt, b); 727 728 assert(aptr != NULL && bptr != NULL); 729 assert(aptr->num != NULL && bptr->num != NULL); 730 731 bc_num_clear(&cnum); 732 bc_num_clear(&dnum); 733 734 req = bc_num_divReq(aptr, bptr, ctxt->scale); 735 736 // Initialize the numbers. 737 bc_num_init(&cnum, req); 738 BC_UNSETJMP; 739 BC_SETJMP_LOCKED(err); 740 bc_num_init(&dnum, req); 741 742 BC_SIG_UNLOCK; 743 744 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale); 745 746 err: 747 BC_SIG_MAYLOCK; 748 749 // Eat the operands. 750 bcl_num_dtor(ctxt, a, aptr); 751 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 752 753 // If there was an error... 754 if (BC_ERR(vm.err)) { 755 756 // Free the results. 757 if (cnum.num != NULL) bc_num_free(&cnum); 758 if (dnum.num != NULL) bc_num_free(&dnum); 759 760 // Make sure the return values are invalid. 761 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM; 762 d->i = c->i; 763 764 BC_FUNC_FOOTER(e); 765 } 766 else { 767 768 BC_FUNC_FOOTER(e); 769 770 // Insert the results into the context. 771 *c = bcl_num_insert(ctxt, &cnum); 772 *d = bcl_num_insert(ctxt, &dnum); 773 } 774 775 assert(!vm.running && !vm.sig && !vm.sig_lock); 776 777 return e; 778 } 779 780 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) { 781 782 BclError e = BCL_ERROR_NONE; 783 size_t req; 784 BcNum *aptr, *bptr, *cptr; 785 BcNum d; 786 BclNumber idx; 787 BclContext ctxt; 788 789 BC_CHECK_CTXT(ctxt); 790 791 BC_CHECK_NUM(ctxt, a); 792 BC_CHECK_NUM(ctxt, b); 793 BC_CHECK_NUM(ctxt, c); 794 795 BC_FUNC_HEADER_LOCK(err); 796 797 bc_vec_grow(&ctxt->nums, 1); 798 799 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 800 assert(c.i < ctxt->nums.len); 801 802 aptr = BC_NUM(ctxt, a); 803 bptr = BC_NUM(ctxt, b); 804 cptr = BC_NUM(ctxt, c); 805 806 assert(aptr != NULL && bptr != NULL && cptr != NULL); 807 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL); 808 809 // Prepare the result. 810 bc_num_clear(&d); 811 812 req = bc_num_divReq(aptr, cptr, 0); 813 814 // Initialize the result. 815 bc_num_init(&d, req); 816 817 BC_SIG_UNLOCK; 818 819 bc_num_modexp(aptr, bptr, cptr, &d); 820 821 err: 822 BC_SIG_MAYLOCK; 823 824 // Eat the operands. 825 bcl_num_dtor(ctxt, a, aptr); 826 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 827 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); 828 829 BC_FUNC_FOOTER(e); 830 BC_MAYBE_SETUP(ctxt, e, d, idx); 831 832 assert(!vm.running && !vm.sig && !vm.sig_lock); 833 834 return idx; 835 } 836 837 ssize_t bcl_cmp(BclNumber a, BclNumber b) { 838 839 BcNum *aptr, *bptr; 840 BclContext ctxt; 841 842 BC_CHECK_CTXT_ASSERT(ctxt); 843 844 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 845 846 aptr = BC_NUM(ctxt, a); 847 bptr = BC_NUM(ctxt, b); 848 849 assert(aptr != NULL && bptr != NULL); 850 assert(aptr->num != NULL && bptr->num != NULL); 851 852 return bc_num_cmp(aptr, bptr); 853 } 854 855 void bcl_zero(BclNumber n) { 856 857 BcNum *nptr; 858 BclContext ctxt; 859 860 BC_CHECK_CTXT_ASSERT(ctxt); 861 862 assert(n.i < ctxt->nums.len); 863 864 nptr = BC_NUM(ctxt, n); 865 866 assert(nptr != NULL && nptr->num != NULL); 867 868 bc_num_zero(nptr); 869 } 870 871 void bcl_one(BclNumber n) { 872 873 BcNum *nptr; 874 BclContext ctxt; 875 876 BC_CHECK_CTXT_ASSERT(ctxt); 877 878 assert(n.i < ctxt->nums.len); 879 880 nptr = BC_NUM(ctxt, n); 881 882 assert(nptr != NULL && nptr->num != NULL); 883 884 bc_num_one(nptr); 885 } 886 887 BclNumber bcl_parse(const char *restrict val) { 888 889 BclError e = BCL_ERROR_NONE; 890 BcNum n; 891 BclNumber idx; 892 BclContext ctxt; 893 bool neg; 894 895 BC_CHECK_CTXT(ctxt); 896 897 BC_FUNC_HEADER_LOCK(err); 898 899 bc_vec_grow(&ctxt->nums, 1); 900 901 assert(val != NULL); 902 903 // We have to take care of negative here because bc's number parsing does 904 // not. 905 neg = (val[0] == '-'); 906 907 if (neg) val += 1; 908 909 if (!bc_num_strValid(val)) { 910 vm.err = BCL_ERROR_PARSE_INVALID_STR; 911 goto err; 912 } 913 914 // Clear and initialize the number. 915 bc_num_clear(&n); 916 bc_num_init(&n, BC_NUM_DEF_SIZE); 917 918 BC_SIG_UNLOCK; 919 920 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase); 921 922 // Set the negative. 923 n.rdx = BC_NUM_NEG_VAL_NP(n, neg); 924 925 err: 926 BC_SIG_MAYLOCK; 927 BC_FUNC_FOOTER(e); 928 BC_MAYBE_SETUP(ctxt, e, n, idx); 929 930 assert(!vm.running && !vm.sig && !vm.sig_lock); 931 932 return idx; 933 } 934 935 char* bcl_string(BclNumber n) { 936 937 BcNum *nptr; 938 char *str = NULL; 939 BclContext ctxt; 940 941 BC_CHECK_CTXT_ASSERT(ctxt); 942 943 if (BC_ERR(n.i >= ctxt->nums.len)) return str; 944 945 BC_FUNC_HEADER(err); 946 947 assert(n.i < ctxt->nums.len); 948 949 nptr = BC_NUM(ctxt, n); 950 951 assert(nptr != NULL && nptr->num != NULL); 952 953 // Clear the buffer. 954 bc_vec_popAll(&vm.out); 955 956 // Print to the buffer. 957 bc_num_print(nptr, (BcBigDig) ctxt->obase, false); 958 bc_vec_pushByte(&vm.out, '\0'); 959 960 BC_SIG_LOCK; 961 962 // Just dup the string; the caller is responsible for it. 963 str = bc_vm_strdup(vm.out.v); 964 965 err: 966 967 // Eat the operand. 968 bcl_num_dtor(ctxt, n, nptr); 969 970 BC_FUNC_FOOTER_NO_ERR; 971 972 assert(!vm.running && !vm.sig && !vm.sig_lock); 973 974 return str; 975 } 976 977 BclNumber bcl_irand(BclNumber a) { 978 979 BclError e = BCL_ERROR_NONE; 980 BcNum *aptr; 981 BcNum b; 982 BclNumber idx; 983 BclContext ctxt; 984 985 BC_CHECK_CTXT(ctxt); 986 987 BC_CHECK_NUM(ctxt, a); 988 989 BC_FUNC_HEADER_LOCK(err); 990 991 bc_vec_grow(&ctxt->nums, 1); 992 993 assert(a.i < ctxt->nums.len); 994 995 aptr = BC_NUM(ctxt, a); 996 997 assert(aptr != NULL && aptr->num != NULL); 998 999 // Clear and initialize the result. 1000 bc_num_clear(&b); 1001 bc_num_init(&b, BC_NUM_DEF_SIZE); 1002 1003 BC_SIG_UNLOCK; 1004 1005 bc_num_irand(aptr, &b, &vm.rng); 1006 1007 err: 1008 BC_SIG_MAYLOCK; 1009 1010 // Eat the operand. 1011 bcl_num_dtor(ctxt, a, aptr); 1012 1013 BC_FUNC_FOOTER(e); 1014 BC_MAYBE_SETUP(ctxt, e, b, idx); 1015 1016 assert(!vm.running && !vm.sig && !vm.sig_lock); 1017 1018 return idx; 1019 } 1020 1021 /** 1022 * Helps bcl_frand(). This is separate because the error handling is easier that 1023 * way. It is also easier to do ifrand that way. 1024 * @param b The return parameter. 1025 * @param places The number of decimal places to generate. 1026 */ 1027 static void bcl_frandHelper(BcNum *restrict b, size_t places) { 1028 1029 BcNum exp, pow, ten; 1030 BcDig exp_digs[BC_NUM_BIGDIG_LOG10]; 1031 BcDig ten_digs[BC_NUM_BIGDIG_LOG10]; 1032 1033 // Set up temporaries. 1034 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10); 1035 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10); 1036 1037 ten.num[0] = 10; 1038 ten.len = 1; 1039 1040 bc_num_bigdig2num(&exp, (BcBigDig) places); 1041 1042 // Clear the temporary that might need to grow. 1043 bc_num_clear(&pow); 1044 1045 BC_SIG_LOCK; 1046 1047 // Initialize the temporary that might need to grow. 1048 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0)); 1049 1050 BC_SETJMP_LOCKED(err); 1051 1052 BC_SIG_UNLOCK; 1053 1054 // Generate the number. 1055 bc_num_pow(&ten, &exp, &pow, 0); 1056 bc_num_irand(&pow, b, &vm.rng); 1057 1058 // Make the number entirely fraction. 1059 bc_num_shiftRight(b, places); 1060 1061 err: 1062 BC_SIG_MAYLOCK; 1063 bc_num_free(&pow); 1064 BC_LONGJMP_CONT; 1065 } 1066 1067 BclNumber bcl_frand(size_t places) { 1068 1069 BclError e = BCL_ERROR_NONE; 1070 BcNum n; 1071 BclNumber idx; 1072 BclContext ctxt; 1073 1074 BC_CHECK_CTXT(ctxt); 1075 1076 BC_FUNC_HEADER_LOCK(err); 1077 1078 bc_vec_grow(&ctxt->nums, 1); 1079 1080 // Clear and initialize the number. 1081 bc_num_clear(&n); 1082 bc_num_init(&n, BC_NUM_DEF_SIZE); 1083 1084 BC_SIG_UNLOCK; 1085 1086 bcl_frandHelper(&n, places); 1087 1088 err: 1089 BC_SIG_MAYLOCK; 1090 1091 BC_FUNC_FOOTER(e); 1092 BC_MAYBE_SETUP(ctxt, e, n, idx); 1093 1094 assert(!vm.running && !vm.sig && !vm.sig_lock); 1095 1096 return idx; 1097 } 1098 1099 /** 1100 * Helps bc_ifrand(). This is separate because error handling is easier that 1101 * way. 1102 * @param a The limit for bc_num_irand(). 1103 * @param b The return parameter. 1104 * @param places The number of decimal places to generate. 1105 */ 1106 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b, 1107 size_t places) 1108 { 1109 BcNum ir, fr; 1110 1111 // Clear the integer and fractional numbers. 1112 bc_num_clear(&ir); 1113 bc_num_clear(&fr); 1114 1115 BC_SIG_LOCK; 1116 1117 // Initialize the integer and fractional numbers. 1118 bc_num_init(&ir, BC_NUM_DEF_SIZE); 1119 bc_num_init(&fr, BC_NUM_DEF_SIZE); 1120 1121 BC_SETJMP_LOCKED(err); 1122 1123 BC_SIG_UNLOCK; 1124 1125 bc_num_irand(a, &ir, &vm.rng); 1126 bcl_frandHelper(&fr, places); 1127 1128 bc_num_add(&ir, &fr, b, 0); 1129 1130 err: 1131 BC_SIG_MAYLOCK; 1132 bc_num_free(&fr); 1133 bc_num_free(&ir); 1134 BC_LONGJMP_CONT; 1135 } 1136 1137 BclNumber bcl_ifrand(BclNumber a, size_t places) { 1138 1139 BclError e = BCL_ERROR_NONE; 1140 BcNum *aptr; 1141 BcNum b; 1142 BclNumber idx; 1143 BclContext ctxt; 1144 1145 BC_CHECK_CTXT(ctxt); 1146 BC_CHECK_NUM(ctxt, a); 1147 1148 BC_FUNC_HEADER_LOCK(err); 1149 1150 bc_vec_grow(&ctxt->nums, 1); 1151 1152 assert(a.i < ctxt->nums.len); 1153 1154 aptr = BC_NUM(ctxt, a); 1155 1156 assert(aptr != NULL && aptr->num != NULL); 1157 1158 // Clear and initialize the number. 1159 bc_num_clear(&b); 1160 bc_num_init(&b, BC_NUM_DEF_SIZE); 1161 1162 BC_SIG_UNLOCK; 1163 1164 bcl_ifrandHelper(aptr, &b, places); 1165 1166 err: 1167 BC_SIG_MAYLOCK; 1168 1169 // Eat the oprand. 1170 bcl_num_dtor(ctxt, a, aptr); 1171 1172 BC_FUNC_FOOTER(e); 1173 BC_MAYBE_SETUP(ctxt, e, b, idx); 1174 1175 assert(!vm.running && !vm.sig && !vm.sig_lock); 1176 1177 return idx; 1178 } 1179 1180 BclError bcl_rand_seedWithNum(BclNumber n) { 1181 1182 BclError e = BCL_ERROR_NONE; 1183 BcNum *nptr; 1184 BclContext ctxt; 1185 1186 BC_CHECK_CTXT_ERR(ctxt); 1187 BC_CHECK_NUM_ERR(ctxt, n); 1188 1189 BC_FUNC_HEADER(err); 1190 1191 assert(n.i < ctxt->nums.len); 1192 1193 nptr = BC_NUM(ctxt, n); 1194 1195 assert(nptr != NULL && nptr->num != NULL); 1196 1197 bc_num_rng(nptr, &vm.rng); 1198 1199 err: 1200 BC_SIG_MAYLOCK; 1201 BC_FUNC_FOOTER(e); 1202 1203 assert(!vm.running && !vm.sig && !vm.sig_lock); 1204 1205 return e; 1206 } 1207 1208 BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) { 1209 1210 BclError e = BCL_ERROR_NONE; 1211 size_t i; 1212 ulong vals[BCL_SEED_ULONGS]; 1213 1214 BC_FUNC_HEADER(err); 1215 1216 // Fill the array. 1217 for (i = 0; i < BCL_SEED_SIZE; ++i) { 1218 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) * 1219 (i % sizeof(ulong))); 1220 vals[i / sizeof(long)] |= val; 1221 } 1222 1223 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]); 1224 1225 err: 1226 BC_SIG_MAYLOCK; 1227 BC_FUNC_FOOTER(e); 1228 return e; 1229 } 1230 1231 void bcl_rand_reseed(void) { 1232 bc_rand_srand(bc_vec_top(&vm.rng.v)); 1233 } 1234 1235 BclNumber bcl_rand_seed2num(void) { 1236 1237 BclError e = BCL_ERROR_NONE; 1238 BcNum n; 1239 BclNumber idx; 1240 BclContext ctxt; 1241 1242 BC_CHECK_CTXT(ctxt); 1243 1244 BC_FUNC_HEADER_LOCK(err); 1245 1246 // Clear and initialize the number. 1247 bc_num_clear(&n); 1248 bc_num_init(&n, BC_NUM_DEF_SIZE); 1249 1250 BC_SIG_UNLOCK; 1251 1252 bc_num_createFromRNG(&n, &vm.rng); 1253 1254 err: 1255 BC_SIG_MAYLOCK; 1256 BC_FUNC_FOOTER(e); 1257 BC_MAYBE_SETUP(ctxt, e, n, idx); 1258 1259 assert(!vm.running && !vm.sig && !vm.sig_lock); 1260 1261 return idx; 1262 } 1263 1264 BclRandInt bcl_rand_int(void) { 1265 return (BclRandInt) bc_rand_int(&vm.rng); 1266 } 1267 1268 BclRandInt bcl_rand_bounded(BclRandInt bound) { 1269 if (bound <= 1) return 0; 1270 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound); 1271 } 1272 1273 #endif // BC_ENABLE_LIBRARY 1274