1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2020 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 static void bcl_num_destruct(void *num); 49 50 void bcl_handleSignal(void) { 51 52 // Signal already in flight, or bc is not executing. 53 if (vm.sig || !vm.running) return; 54 55 vm.sig = 1; 56 57 assert(vm.jmp_bufs.len); 58 59 if (!vm.sig_lock) BC_VM_JMP; 60 } 61 62 bool bcl_running(void) { 63 return vm.running != 0; 64 } 65 66 BclError bcl_init(void) { 67 68 BclError e = BCL_ERROR_NONE; 69 70 vm.refs += 1; 71 72 if (vm.refs > 1) return e; 73 74 vm.ctxts.v = NULL; 75 vm.jmp_bufs.v = NULL; 76 vm.out.v = NULL; 77 78 vm.abrt = false; 79 80 BC_SIG_LOCK; 81 82 bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), NULL); 83 84 BC_FUNC_HEADER_INIT(err); 85 86 bc_vm_init(); 87 88 bc_vec_init(&vm.ctxts, sizeof(BclContext), NULL); 89 bc_vec_init(&vm.out, sizeof(uchar), NULL); 90 91 srand((unsigned int) time(NULL)); 92 bc_rand_init(&vm.rng); 93 94 err: 95 if (BC_ERR(vm.err)) { 96 if (vm.out.v != NULL) bc_vec_free(&vm.out); 97 if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs); 98 if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts); 99 } 100 101 BC_FUNC_FOOTER_UNLOCK(e); 102 103 assert(!vm.running && !vm.sig && !vm.sig_lock); 104 105 return e; 106 } 107 108 BclError bcl_pushContext(BclContext ctxt) { 109 110 BclError e = BCL_ERROR_NONE; 111 112 BC_FUNC_HEADER_LOCK(err); 113 114 bc_vec_push(&vm.ctxts, &ctxt); 115 116 err: 117 BC_FUNC_FOOTER_UNLOCK(e); 118 return e; 119 } 120 121 void bcl_popContext(void) { 122 if (vm.ctxts.len) bc_vec_pop(&vm.ctxts); 123 } 124 125 BclContext bcl_context(void) { 126 if (!vm.ctxts.len) return NULL; 127 return *((BclContext*) bc_vec_top(&vm.ctxts)); 128 } 129 130 void bcl_free(void) { 131 132 vm.refs -= 1; 133 134 if (vm.refs) return; 135 136 BC_SIG_LOCK; 137 138 #ifndef NDEBUG 139 bc_rand_free(&vm.rng); 140 bc_vec_free(&vm.out); 141 142 { 143 size_t i; 144 145 for (i = 0; i < vm.ctxts.len; ++i) { 146 BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i)); 147 bcl_ctxt_free(ctxt); 148 } 149 } 150 151 bc_vec_free(&vm.ctxts); 152 #endif // NDEBUG 153 154 bc_vm_shutdown(); 155 156 bc_vec_free(&vm.jmp_bufs); 157 158 BC_SIG_UNLOCK; 159 160 memset(&vm, 0, sizeof(BcVm)); 161 162 assert(!vm.running && !vm.sig && !vm.sig_lock); 163 } 164 165 void bcl_gc(void) { 166 bc_vm_freeTemps(); 167 vm.temps.len = 0; 168 } 169 170 bool bcl_abortOnFatalError(void) { 171 return vm.abrt; 172 } 173 174 void bcl_setAbortOnFatalError(bool abrt) { 175 vm.abrt = abrt; 176 } 177 178 BclContext bcl_ctxt_create(void) { 179 180 BclContext ctxt = NULL; 181 182 BC_FUNC_HEADER_LOCK(err); 183 184 ctxt = bc_vm_malloc(sizeof(BclCtxt)); 185 186 bc_vec_init(&ctxt->nums, sizeof(BcNum), bcl_num_destruct); 187 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), NULL); 188 189 ctxt->scale = 0; 190 ctxt->ibase = 10; 191 ctxt->obase= 10; 192 193 err: 194 if (BC_ERR(vm.err && ctxt != NULL)) { 195 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums); 196 free(ctxt); 197 ctxt = NULL; 198 } 199 200 BC_FUNC_FOOTER_NO_ERR; 201 202 assert(!vm.running && !vm.sig && !vm.sig_lock); 203 204 return ctxt; 205 } 206 207 void bcl_ctxt_free(BclContext ctxt) { 208 BC_SIG_LOCK; 209 bc_vec_free(&ctxt->free_nums); 210 bc_vec_free(&ctxt->nums); 211 free(ctxt); 212 BC_SIG_UNLOCK; 213 } 214 215 void bcl_ctxt_freeNums(BclContext ctxt) { 216 bc_vec_npop(&ctxt->nums, ctxt->nums.len); 217 bc_vec_npop(&ctxt->free_nums, ctxt->free_nums.len); 218 } 219 220 size_t bcl_ctxt_scale(BclContext ctxt) { 221 return ctxt->scale; 222 } 223 224 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) { 225 ctxt->scale = scale; 226 } 227 228 size_t bcl_ctxt_ibase(BclContext ctxt) { 229 return ctxt->ibase; 230 } 231 232 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) { 233 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE; 234 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE; 235 ctxt->ibase = ibase; 236 } 237 238 size_t bcl_ctxt_obase(BclContext ctxt) { 239 return ctxt->obase; 240 } 241 242 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) { 243 ctxt->obase = obase; 244 } 245 246 BclError bcl_err(BclNumber n) { 247 248 BclContext ctxt; 249 250 BC_CHECK_CTXT_ERR(ctxt); 251 252 if (n.i >= ctxt->nums.len) { 253 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i); 254 else return BCL_ERROR_INVALID_NUM; 255 } 256 else return BCL_ERROR_NONE; 257 } 258 259 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) { 260 261 BclNumber idx; 262 263 if (ctxt->free_nums.len) { 264 265 BcNum *ptr; 266 267 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums)); 268 269 bc_vec_pop(&ctxt->free_nums); 270 271 ptr = bc_vec_item(&ctxt->nums, idx.i); 272 memcpy(ptr, n, sizeof(BcNum)); 273 } 274 else { 275 idx.i = ctxt->nums.len; 276 bc_vec_push(&ctxt->nums, n); 277 } 278 279 assert(!vm.running && !vm.sig && !vm.sig_lock); 280 281 return idx; 282 } 283 284 BclNumber bcl_num_create(void) { 285 286 BclError e = BCL_ERROR_NONE; 287 BcNum n; 288 BclNumber idx; 289 BclContext ctxt; 290 291 BC_CHECK_CTXT(ctxt); 292 293 BC_FUNC_HEADER_LOCK(err); 294 295 bc_vec_grow(&ctxt->nums, 1); 296 297 bc_num_init(&n, BC_NUM_DEF_SIZE); 298 299 err: 300 BC_FUNC_FOOTER_UNLOCK(e); 301 BC_MAYBE_SETUP(ctxt, e, n, idx); 302 303 assert(!vm.running && !vm.sig && !vm.sig_lock); 304 305 return idx; 306 } 307 308 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) { 309 310 BC_SIG_ASSERT_LOCKED; 311 312 assert(num != NULL && num->num != NULL); 313 314 bcl_num_destruct(num); 315 bc_vec_push(&ctxt->free_nums, &n); 316 } 317 318 void bcl_num_free(BclNumber n) { 319 320 BcNum *num; 321 BclContext ctxt; 322 323 BC_CHECK_CTXT_ASSERT(ctxt); 324 325 BC_SIG_LOCK; 326 327 assert(n.i < ctxt->nums.len); 328 329 num = BC_NUM(ctxt, n); 330 331 bcl_num_dtor(ctxt, n, num); 332 333 BC_SIG_UNLOCK; 334 } 335 336 BclError bcl_copy(BclNumber d, BclNumber s) { 337 338 BclError e = BCL_ERROR_NONE; 339 BcNum *dest, *src; 340 BclContext ctxt; 341 342 BC_CHECK_CTXT_ERR(ctxt); 343 344 BC_FUNC_HEADER_LOCK(err); 345 346 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len); 347 348 dest = BC_NUM(ctxt, d); 349 src = BC_NUM(ctxt, s); 350 351 assert(dest != NULL && src != NULL); 352 assert(dest->num != NULL && src->num != NULL); 353 354 bc_num_copy(dest, src); 355 356 err: 357 BC_FUNC_FOOTER_UNLOCK(e); 358 359 assert(!vm.running && !vm.sig && !vm.sig_lock); 360 361 return e; 362 } 363 364 BclNumber bcl_dup(BclNumber s) { 365 366 BclError e = BCL_ERROR_NONE; 367 BcNum *src, dest; 368 BclNumber idx; 369 BclContext ctxt; 370 371 BC_CHECK_CTXT(ctxt); 372 373 BC_FUNC_HEADER_LOCK(err); 374 375 bc_vec_grow(&ctxt->nums, 1); 376 377 assert(s.i < ctxt->nums.len); 378 379 src = BC_NUM(ctxt, s); 380 381 assert(src != NULL && src->num != NULL); 382 383 bc_num_clear(&dest); 384 385 bc_num_createCopy(&dest, src); 386 387 err: 388 BC_FUNC_FOOTER_UNLOCK(e); 389 BC_MAYBE_SETUP(ctxt, e, dest, idx); 390 391 assert(!vm.running && !vm.sig && !vm.sig_lock); 392 393 return idx; 394 } 395 396 static void bcl_num_destruct(void *num) { 397 398 BcNum *n = (BcNum*) num; 399 400 assert(n != NULL); 401 402 if (n->num == NULL) return; 403 404 bc_num_free(num); 405 bc_num_clear(num); 406 } 407 408 bool bcl_num_neg(BclNumber n) { 409 410 BcNum *num; 411 BclContext ctxt; 412 413 BC_CHECK_CTXT_ASSERT(ctxt); 414 415 assert(n.i < ctxt->nums.len); 416 417 num = BC_NUM(ctxt, n); 418 419 assert(num != NULL && num->num != NULL); 420 421 return BC_NUM_NEG(num) != 0; 422 } 423 424 void bcl_num_setNeg(BclNumber n, bool neg) { 425 426 BcNum *num; 427 BclContext ctxt; 428 429 BC_CHECK_CTXT_ASSERT(ctxt); 430 431 assert(n.i < ctxt->nums.len); 432 433 num = BC_NUM(ctxt, n); 434 435 assert(num != NULL && num->num != NULL); 436 437 num->rdx = BC_NUM_NEG_VAL(num, neg); 438 } 439 440 size_t bcl_num_scale(BclNumber n) { 441 442 BcNum *num; 443 BclContext ctxt; 444 445 BC_CHECK_CTXT_ASSERT(ctxt); 446 447 assert(n.i < ctxt->nums.len); 448 449 num = BC_NUM(ctxt, n); 450 451 assert(num != NULL && num->num != NULL); 452 453 return bc_num_scale(num); 454 } 455 456 BclError bcl_num_setScale(BclNumber n, size_t scale) { 457 458 BclError e = BCL_ERROR_NONE; 459 BcNum *nptr; 460 BclContext ctxt; 461 462 BC_CHECK_CTXT_ERR(ctxt); 463 464 BC_CHECK_NUM_ERR(ctxt, n); 465 466 BC_FUNC_HEADER(err); 467 468 assert(n.i < ctxt->nums.len); 469 470 nptr = BC_NUM(ctxt, n); 471 472 assert(nptr != NULL && nptr->num != NULL); 473 474 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale); 475 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale); 476 477 err: 478 BC_SIG_MAYLOCK; 479 BC_FUNC_FOOTER(e); 480 481 assert(!vm.running && !vm.sig && !vm.sig_lock); 482 483 return e; 484 } 485 486 size_t bcl_num_len(BclNumber n) { 487 488 BcNum *num; 489 BclContext ctxt; 490 491 BC_CHECK_CTXT_ASSERT(ctxt); 492 493 assert(n.i < ctxt->nums.len); 494 495 num = BC_NUM(ctxt, n); 496 497 assert(num != NULL && num->num != NULL); 498 499 return bc_num_len(num); 500 } 501 502 BclError bcl_bigdig(BclNumber n, BclBigDig *result) { 503 504 BclError e = BCL_ERROR_NONE; 505 BcNum *num; 506 BclContext ctxt; 507 508 BC_CHECK_CTXT_ERR(ctxt); 509 510 BC_FUNC_HEADER_LOCK(err); 511 512 assert(n.i < ctxt->nums.len); 513 assert(result != NULL); 514 515 num = BC_NUM(ctxt, n); 516 517 assert(num != NULL && num->num != NULL); 518 519 bc_num_bigdig(num, result); 520 521 err: 522 bcl_num_dtor(ctxt, n, num); 523 BC_FUNC_FOOTER_UNLOCK(e); 524 525 assert(!vm.running && !vm.sig && !vm.sig_lock); 526 527 return e; 528 } 529 530 BclNumber bcl_bigdig2num(BclBigDig val) { 531 532 BclError e = BCL_ERROR_NONE; 533 BcNum n; 534 BclNumber idx; 535 BclContext ctxt; 536 537 BC_CHECK_CTXT(ctxt); 538 539 BC_FUNC_HEADER_LOCK(err); 540 541 bc_vec_grow(&ctxt->nums, 1); 542 543 bc_num_createFromBigdig(&n, val); 544 545 err: 546 BC_FUNC_FOOTER_UNLOCK(e); 547 BC_MAYBE_SETUP(ctxt, e, n, idx); 548 549 assert(!vm.running && !vm.sig && !vm.sig_lock); 550 551 return idx; 552 } 553 554 static BclNumber bcl_binary(BclNumber a, BclNumber b, 555 const BcNumBinaryOp op, 556 const BcNumBinaryOpReq req) 557 { 558 BclError e = BCL_ERROR_NONE; 559 BcNum *aptr, *bptr; 560 BcNum c; 561 BclNumber idx; 562 BclContext ctxt; 563 564 BC_CHECK_CTXT(ctxt); 565 566 BC_CHECK_NUM(ctxt, a); 567 BC_CHECK_NUM(ctxt, b); 568 569 BC_FUNC_HEADER_LOCK(err); 570 571 bc_vec_grow(&ctxt->nums, 1); 572 573 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 574 575 aptr = BC_NUM(ctxt, a); 576 bptr = BC_NUM(ctxt, b); 577 578 assert(aptr != NULL && bptr != NULL); 579 assert(aptr->num != NULL && bptr->num != NULL); 580 581 bc_num_clear(&c); 582 583 bc_num_init(&c, req(aptr, bptr, ctxt->scale)); 584 585 BC_SIG_UNLOCK; 586 587 op(aptr, bptr, &c, ctxt->scale); 588 589 err: 590 BC_SIG_MAYLOCK; 591 bcl_num_dtor(ctxt, a, aptr); 592 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 593 BC_FUNC_FOOTER(e); 594 BC_MAYBE_SETUP(ctxt, e, c, idx); 595 596 assert(!vm.running && !vm.sig && !vm.sig_lock); 597 598 return idx; 599 } 600 601 BclNumber bcl_add(BclNumber a, BclNumber b) { 602 return bcl_binary(a, b, bc_num_add, bc_num_addReq); 603 } 604 605 BclNumber bcl_sub(BclNumber a, BclNumber b) { 606 return bcl_binary(a, b, bc_num_sub, bc_num_addReq); 607 } 608 609 BclNumber bcl_mul(BclNumber a, BclNumber b) { 610 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq); 611 } 612 613 BclNumber bcl_div(BclNumber a, BclNumber b) { 614 return bcl_binary(a, b, bc_num_div, bc_num_divReq); 615 } 616 617 BclNumber bcl_mod(BclNumber a, BclNumber b) { 618 return bcl_binary(a, b, bc_num_mod, bc_num_divReq); 619 } 620 621 BclNumber bcl_pow(BclNumber a, BclNumber b) { 622 return bcl_binary(a, b, bc_num_pow, bc_num_powReq); 623 } 624 625 BclNumber bcl_lshift(BclNumber a, BclNumber b) { 626 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq); 627 } 628 629 BclNumber bcl_rshift(BclNumber a, BclNumber b) { 630 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq); 631 } 632 633 BclNumber bcl_sqrt(BclNumber a) { 634 635 BclError e = BCL_ERROR_NONE; 636 BcNum *aptr; 637 BcNum b; 638 BclNumber idx; 639 BclContext ctxt; 640 641 BC_CHECK_CTXT(ctxt); 642 643 BC_CHECK_NUM(ctxt, a); 644 645 BC_FUNC_HEADER(err); 646 647 bc_vec_grow(&ctxt->nums, 1); 648 649 assert(a.i < ctxt->nums.len); 650 651 aptr = BC_NUM(ctxt, a); 652 653 bc_num_sqrt(aptr, &b, ctxt->scale); 654 655 err: 656 BC_SIG_MAYLOCK; 657 bcl_num_dtor(ctxt, a, aptr); 658 BC_FUNC_FOOTER(e); 659 BC_MAYBE_SETUP(ctxt, e, b, idx); 660 661 assert(!vm.running && !vm.sig && !vm.sig_lock); 662 663 return idx; 664 } 665 666 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) { 667 668 BclError e = BCL_ERROR_NONE; 669 size_t req; 670 BcNum *aptr, *bptr; 671 BcNum cnum, dnum; 672 BclContext ctxt; 673 674 BC_CHECK_CTXT_ERR(ctxt); 675 676 BC_CHECK_NUM_ERR(ctxt, a); 677 BC_CHECK_NUM_ERR(ctxt, b); 678 679 BC_FUNC_HEADER_LOCK(err); 680 681 bc_vec_grow(&ctxt->nums, 2); 682 683 assert(c != NULL && d != NULL); 684 685 aptr = BC_NUM(ctxt, a); 686 bptr = BC_NUM(ctxt, b); 687 688 assert(aptr != NULL && bptr != NULL); 689 assert(aptr->num != NULL && bptr->num != NULL); 690 691 bc_num_clear(&cnum); 692 bc_num_clear(&dnum); 693 694 req = bc_num_divReq(aptr, bptr, ctxt->scale); 695 696 bc_num_init(&cnum, req); 697 bc_num_init(&dnum, req); 698 699 BC_SIG_UNLOCK; 700 701 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale); 702 703 err: 704 BC_SIG_MAYLOCK; 705 706 bcl_num_dtor(ctxt, a, aptr); 707 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 708 709 if (BC_ERR(vm.err)) { 710 if (cnum.num != NULL) bc_num_free(&cnum); 711 if (dnum.num != NULL) bc_num_free(&dnum); 712 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM; 713 d->i = c->i; 714 BC_FUNC_FOOTER(e); 715 } 716 else { 717 BC_FUNC_FOOTER(e); 718 *c = bcl_num_insert(ctxt, &cnum); 719 *d = bcl_num_insert(ctxt, &dnum); 720 } 721 722 assert(!vm.running && !vm.sig && !vm.sig_lock); 723 724 return e; 725 } 726 727 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) { 728 729 BclError e = BCL_ERROR_NONE; 730 size_t req; 731 BcNum *aptr, *bptr, *cptr; 732 BcNum d; 733 BclNumber idx; 734 BclContext ctxt; 735 736 BC_CHECK_CTXT(ctxt); 737 738 BC_CHECK_NUM(ctxt, a); 739 BC_CHECK_NUM(ctxt, b); 740 BC_CHECK_NUM(ctxt, c); 741 742 BC_FUNC_HEADER_LOCK(err); 743 744 bc_vec_grow(&ctxt->nums, 1); 745 746 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 747 assert(c.i < ctxt->nums.len); 748 749 aptr = BC_NUM(ctxt, a); 750 bptr = BC_NUM(ctxt, b); 751 cptr = BC_NUM(ctxt, c); 752 753 assert(aptr != NULL && bptr != NULL && cptr != NULL); 754 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL); 755 756 bc_num_clear(&d); 757 758 req = bc_num_divReq(aptr, cptr, 0); 759 760 bc_num_init(&d, req); 761 762 BC_SIG_UNLOCK; 763 764 bc_num_modexp(aptr, bptr, cptr, &d); 765 766 err: 767 BC_SIG_MAYLOCK; 768 769 bcl_num_dtor(ctxt, a, aptr); 770 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 771 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); 772 773 BC_FUNC_FOOTER(e); 774 BC_MAYBE_SETUP(ctxt, e, d, idx); 775 776 assert(!vm.running && !vm.sig && !vm.sig_lock); 777 778 return idx; 779 } 780 781 ssize_t bcl_cmp(BclNumber a, BclNumber b) { 782 783 BcNum *aptr, *bptr; 784 BclContext ctxt; 785 786 BC_CHECK_CTXT_ASSERT(ctxt); 787 788 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 789 790 aptr = BC_NUM(ctxt, a); 791 bptr = BC_NUM(ctxt, b); 792 793 assert(aptr != NULL && bptr != NULL); 794 assert(aptr->num != NULL && bptr->num != NULL); 795 796 return bc_num_cmp(aptr, bptr); 797 } 798 799 void bcl_zero(BclNumber n) { 800 801 BcNum *nptr; 802 BclContext ctxt; 803 804 BC_CHECK_CTXT_ASSERT(ctxt); 805 806 assert(n.i < ctxt->nums.len); 807 808 nptr = BC_NUM(ctxt, n); 809 810 assert(nptr != NULL && nptr->num != NULL); 811 812 bc_num_zero(nptr); 813 } 814 815 void bcl_one(BclNumber n) { 816 817 BcNum *nptr; 818 BclContext ctxt; 819 820 BC_CHECK_CTXT_ASSERT(ctxt); 821 822 assert(n.i < ctxt->nums.len); 823 824 nptr = BC_NUM(ctxt, n); 825 826 assert(nptr != NULL && nptr->num != NULL); 827 828 bc_num_one(nptr); 829 } 830 831 BclNumber bcl_parse(const char *restrict val) { 832 833 BclError e = BCL_ERROR_NONE; 834 BcNum n; 835 BclNumber idx; 836 BclContext ctxt; 837 bool neg; 838 839 BC_CHECK_CTXT(ctxt); 840 841 BC_FUNC_HEADER_LOCK(err); 842 843 bc_vec_grow(&ctxt->nums, 1); 844 845 assert(val != NULL); 846 847 neg = (val[0] == '-'); 848 849 if (neg) val += 1; 850 851 if (!bc_num_strValid(val)) { 852 vm.err = BCL_ERROR_PARSE_INVALID_STR; 853 goto err; 854 } 855 856 bc_num_clear(&n); 857 858 bc_num_init(&n, BC_NUM_DEF_SIZE); 859 860 BC_SIG_UNLOCK; 861 862 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase); 863 864 n.rdx = BC_NUM_NEG_VAL_NP(n, neg); 865 866 err: 867 BC_SIG_MAYLOCK; 868 BC_FUNC_FOOTER(e); 869 BC_MAYBE_SETUP(ctxt, e, n, idx); 870 871 assert(!vm.running && !vm.sig && !vm.sig_lock); 872 873 return idx; 874 } 875 876 char* bcl_string(BclNumber n) { 877 878 BcNum *nptr; 879 char *str = NULL; 880 BclContext ctxt; 881 882 BC_CHECK_CTXT_ASSERT(ctxt); 883 884 if (BC_ERR(n.i >= ctxt->nums.len)) return str; 885 886 BC_FUNC_HEADER(err); 887 888 assert(n.i < ctxt->nums.len); 889 890 nptr = BC_NUM(ctxt, n); 891 892 assert(nptr != NULL && nptr->num != NULL); 893 894 bc_vec_npop(&vm.out, vm.out.len); 895 896 bc_num_print(nptr, (BcBigDig) ctxt->obase, false); 897 bc_vec_pushByte(&vm.out, '\0'); 898 899 BC_SIG_LOCK; 900 str = bc_vm_strdup(vm.out.v); 901 902 err: 903 bcl_num_dtor(ctxt, n, nptr); 904 905 BC_FUNC_FOOTER_NO_ERR; 906 907 assert(!vm.running && !vm.sig && !vm.sig_lock); 908 909 return str; 910 } 911 912 BclNumber bcl_irand(BclNumber a) { 913 914 BclError e = BCL_ERROR_NONE; 915 BcNum *aptr; 916 BcNum b; 917 BclNumber idx; 918 BclContext ctxt; 919 920 BC_CHECK_CTXT(ctxt); 921 922 BC_CHECK_NUM(ctxt, a); 923 924 BC_FUNC_HEADER_LOCK(err); 925 926 bc_vec_grow(&ctxt->nums, 1); 927 928 assert(a.i < ctxt->nums.len); 929 930 aptr = BC_NUM(ctxt, a); 931 932 assert(aptr != NULL && aptr->num != NULL); 933 934 bc_num_clear(&b); 935 936 bc_num_init(&b, BC_NUM_DEF_SIZE); 937 938 BC_SIG_UNLOCK; 939 940 bc_num_irand(aptr, &b, &vm.rng); 941 942 err: 943 BC_SIG_MAYLOCK; 944 bcl_num_dtor(ctxt, a, aptr); 945 BC_FUNC_FOOTER(e); 946 BC_MAYBE_SETUP(ctxt, e, b, idx); 947 948 assert(!vm.running && !vm.sig && !vm.sig_lock); 949 950 return idx; 951 } 952 953 static void bcl_frandHelper(BcNum *restrict b, size_t places) { 954 955 BcNum exp, pow, ten; 956 BcDig exp_digs[BC_NUM_BIGDIG_LOG10]; 957 BcDig ten_digs[BC_NUM_BIGDIG_LOG10]; 958 959 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10); 960 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10); 961 962 ten.num[0] = 10; 963 ten.len = 1; 964 965 bc_num_bigdig2num(&exp, (BcBigDig) places); 966 967 bc_num_clear(&pow); 968 969 BC_SIG_LOCK; 970 971 BC_SETJMP_LOCKED(err); 972 973 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0)); 974 975 BC_SIG_UNLOCK; 976 977 bc_num_pow(&ten, &exp, &pow, 0); 978 979 bc_num_irand(&pow, b, &vm.rng); 980 981 bc_num_shiftRight(b, places); 982 983 err: 984 BC_SIG_MAYLOCK; 985 bc_num_free(&pow); 986 BC_LONGJMP_CONT; 987 } 988 989 BclNumber bcl_frand(size_t places) { 990 991 BclError e = BCL_ERROR_NONE; 992 BcNum n; 993 BclNumber idx; 994 BclContext ctxt; 995 996 BC_CHECK_CTXT(ctxt); 997 998 BC_FUNC_HEADER_LOCK(err); 999 1000 bc_vec_grow(&ctxt->nums, 1); 1001 1002 bc_num_clear(&n); 1003 1004 bc_num_init(&n, BC_NUM_DEF_SIZE); 1005 1006 BC_SIG_UNLOCK; 1007 1008 bcl_frandHelper(&n, places); 1009 1010 err: 1011 BC_SIG_MAYLOCK; 1012 BC_FUNC_FOOTER(e); 1013 BC_MAYBE_SETUP(ctxt, e, n, idx); 1014 1015 assert(!vm.running && !vm.sig && !vm.sig_lock); 1016 1017 return idx; 1018 } 1019 1020 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b, 1021 size_t places) 1022 { 1023 BcNum ir, fr; 1024 1025 bc_num_clear(&ir); 1026 bc_num_clear(&fr); 1027 1028 BC_SIG_LOCK; 1029 1030 BC_SETJMP_LOCKED(err); 1031 1032 bc_num_init(&ir, BC_NUM_DEF_SIZE); 1033 bc_num_init(&fr, BC_NUM_DEF_SIZE); 1034 1035 BC_SIG_UNLOCK; 1036 1037 bc_num_irand(a, &ir, &vm.rng); 1038 bcl_frandHelper(&fr, places); 1039 1040 bc_num_add(&ir, &fr, b, 0); 1041 1042 err: 1043 BC_SIG_MAYLOCK; 1044 bc_num_free(&fr); 1045 bc_num_free(&ir); 1046 BC_LONGJMP_CONT; 1047 } 1048 1049 BclNumber bcl_ifrand(BclNumber a, size_t places) { 1050 1051 BclError e = BCL_ERROR_NONE; 1052 BcNum *aptr; 1053 BcNum b; 1054 BclNumber idx; 1055 BclContext ctxt; 1056 1057 BC_CHECK_CTXT(ctxt); 1058 1059 BC_CHECK_NUM(ctxt, a); 1060 1061 BC_FUNC_HEADER_LOCK(err); 1062 1063 bc_vec_grow(&ctxt->nums, 1); 1064 1065 assert(a.i < ctxt->nums.len); 1066 1067 aptr = BC_NUM(ctxt, a); 1068 1069 assert(aptr != NULL && aptr->num != NULL); 1070 1071 bc_num_clear(&b); 1072 1073 bc_num_init(&b, BC_NUM_DEF_SIZE); 1074 1075 BC_SIG_UNLOCK; 1076 1077 bcl_ifrandHelper(aptr, &b, places); 1078 1079 err: 1080 BC_SIG_MAYLOCK; 1081 bcl_num_dtor(ctxt, a, aptr); 1082 BC_FUNC_FOOTER(e); 1083 BC_MAYBE_SETUP(ctxt, e, b, idx); 1084 1085 assert(!vm.running && !vm.sig && !vm.sig_lock); 1086 1087 return idx; 1088 } 1089 1090 BclError bcl_rand_seedWithNum(BclNumber n) { 1091 1092 BclError e = BCL_ERROR_NONE; 1093 BcNum *nptr; 1094 BclContext ctxt; 1095 1096 BC_CHECK_CTXT_ERR(ctxt); 1097 1098 BC_CHECK_NUM_ERR(ctxt, n); 1099 1100 BC_FUNC_HEADER(err); 1101 1102 assert(n.i < ctxt->nums.len); 1103 1104 nptr = BC_NUM(ctxt, n); 1105 1106 assert(nptr != NULL && nptr->num != NULL); 1107 1108 bc_num_rng(nptr, &vm.rng); 1109 1110 err: 1111 BC_SIG_MAYLOCK; 1112 BC_FUNC_FOOTER(e); 1113 1114 assert(!vm.running && !vm.sig && !vm.sig_lock); 1115 1116 return e; 1117 } 1118 1119 BclError bcl_rand_seed(unsigned char seed[BC_SEED_SIZE]) { 1120 1121 BclError e = BCL_ERROR_NONE; 1122 size_t i; 1123 ulong vals[BC_SEED_ULONGS]; 1124 1125 BC_FUNC_HEADER(err); 1126 1127 for (i = 0; i < BC_SEED_SIZE; ++i) { 1128 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) * 1129 (i % sizeof(ulong))); 1130 vals[i / sizeof(long)] |= val; 1131 } 1132 1133 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]); 1134 1135 err: 1136 BC_SIG_MAYLOCK; 1137 BC_FUNC_FOOTER(e); 1138 return e; 1139 } 1140 1141 void bcl_rand_reseed(void) { 1142 bc_rand_srand(bc_vec_top(&vm.rng.v)); 1143 } 1144 1145 BclNumber bcl_rand_seed2num(void) { 1146 1147 BclError e = BCL_ERROR_NONE; 1148 BcNum n; 1149 BclNumber idx; 1150 BclContext ctxt; 1151 1152 BC_CHECK_CTXT(ctxt); 1153 1154 BC_FUNC_HEADER_LOCK(err); 1155 1156 bc_num_clear(&n); 1157 1158 bc_num_init(&n, BC_NUM_DEF_SIZE); 1159 1160 BC_SIG_UNLOCK; 1161 1162 bc_num_createFromRNG(&n, &vm.rng); 1163 1164 err: 1165 BC_SIG_MAYLOCK; 1166 BC_FUNC_FOOTER(e); 1167 BC_MAYBE_SETUP(ctxt, e, n, idx); 1168 1169 assert(!vm.running && !vm.sig && !vm.sig_lock); 1170 1171 return idx; 1172 } 1173 1174 BclRandInt bcl_rand_int(void) { 1175 return (BclRandInt) bc_rand_int(&vm.rng); 1176 } 1177 1178 BclRandInt bcl_rand_bounded(BclRandInt bound) { 1179 if (bound <= 1) return 0; 1180 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound); 1181 } 1182 1183 #endif // BC_ENABLE_LIBRARY 1184