Annotation of src/usr.bin/dc/bcode.c, Revision 1.1
1.1 ! otto 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #ifndef lint
! 20: static const char rcsid[] = "$OpenBSD$";
! 21: #endif /* not lint */
! 22:
! 23: #include <ssl/ssl.h>
! 24: #include <err.h>
! 25: #include <limits.h>
! 26: #include <stdio.h>
! 27: #include <stdlib.h>
! 28: #include <string.h>
! 29:
! 30: #include "extern.h"
! 31:
! 32: BIGNUM zero;
! 33: static bool trace = false;
! 34:
! 35: #define MAX_ARRAY_INDEX 2048
! 36: #define MAX_RECURSION 100
! 37:
! 38: struct bmachine {
! 39: struct stack stack;
! 40: u_int scale;
! 41: u_int obase;
! 42: u_int ibase;
! 43: int readsp;
! 44: struct stack reg[UCHAR_MAX];
! 45: struct source readstack[MAX_RECURSION];
! 46: };
! 47:
! 48: static struct bmachine bmachine;
! 49:
! 50: static __inline int readch(void);
! 51: static __inline int unreadch(void);
! 52: static __inline char *readline(void);
! 53: static __inline void src_free(void);
! 54:
! 55: static __inline u_int max(u_int, u_int);
! 56: static u_long get_ulong(struct number *);
! 57:
! 58: static __inline void push_number(struct number *);
! 59: static __inline void push_string(char *);
! 60: static __inline void push(struct value *);
! 61: static __inline struct value *tos(void);
! 62: static __inline struct number *pop_number(void);
! 63: static __inline char *pop_string(void);
! 64: static __inline void clear_stack(void);
! 65: static __inline void print_tos(void);
! 66: static __inline void pop_print(void);
! 67: static __inline void print_stack();
! 68: static __inline void dup(void);
! 69:
! 70: static void get_scale(void);
! 71: static void set_scale(void);
! 72: static void get_obase(void);
! 73: static void set_obase(void);
! 74: static void get_ibase(void);
! 75: static void set_ibase(void);
! 76: static void stackdepth(void);
! 77: static void push_scale(void);
! 78: static u_int count_digits(const struct number *);
! 79: static void num_digits(void);
! 80:
! 81: static void push_line(void);
! 82: static void bexec(char *);
! 83: static void badd(void);
! 84: static void bsub(void);
! 85: static void bmul(void);
! 86: static void bdiv(void);
! 87: static void bmod(void);
! 88: static void bexp(void);
! 89: static bool bsqrt_stop(const BIGNUM *, const BIGNUM *);
! 90: static void bsqrt(void);
! 91: static void equal(void);
! 92: static void not_equal(void);
! 93: static void less(void);
! 94: static void not_less(void);
! 95: static void greater(void);
! 96: static void not_greater(void);
! 97: static void not_compare(void);
! 98: static void compare(enum bcode_compare);
! 99: static void load(void);
! 100: static void store(void);
! 101: static void load_stack(void);
! 102: static void store_stack(void);
! 103: static void load_array(void);
! 104: static void store_array(void);
! 105: static void nop(void);
! 106: static void quit(void);
! 107: static void quitN(void);
! 108: static void parse_number(void);
! 109: static void unknown(void);
! 110: static void eval_string(char *);
! 111: static void eval_line(void);
! 112: static void eval_tos(void);
! 113:
! 114:
! 115: typedef void (*opcode_function)(void);
! 116:
! 117: struct jump_entry {
! 118: u_char ch;
! 119: opcode_function f;
! 120: };
! 121:
! 122: static opcode_function jump_table[UCHAR_MAX];
! 123:
! 124: static const struct jump_entry jump_table_data[] = {
! 125: { '0', parse_number },
! 126: { '1', parse_number },
! 127: { '2', parse_number },
! 128: { '3', parse_number },
! 129: { '4', parse_number },
! 130: { '5', parse_number },
! 131: { '6', parse_number },
! 132: { '7', parse_number },
! 133: { '8', parse_number },
! 134: { '9', parse_number },
! 135: { 'A', parse_number },
! 136: { 'B', parse_number },
! 137: { 'C', parse_number },
! 138: { 'D', parse_number },
! 139: { 'E', parse_number },
! 140: { 'F', parse_number },
! 141: { '_', parse_number },
! 142: { '.', parse_number },
! 143: { '+', badd },
! 144: { '-', bsub },
! 145: { '*', bmul },
! 146: { '/', bdiv },
! 147: { '%', bmod },
! 148: { '^', bexp },
! 149: { 's', store },
! 150: { 'S', store_stack },
! 151: { 'l', load },
! 152: { 'L', load_stack },
! 153: { 'd', dup },
! 154: { 'p', print_tos },
! 155: { 'P', pop_print },
! 156: { 'f', print_stack },
! 157: { 'x', eval_tos },
! 158: { 'X', push_scale },
! 159: { '[', push_line },
! 160: { 'q', quit },
! 161: { 'Q', quitN },
! 162: { '<', less },
! 163: { '>', greater },
! 164: { '=', equal },
! 165: { '!', not_compare },
! 166: { 'v', bsqrt },
! 167: { 'c', clear_stack },
! 168: { 'i', set_ibase },
! 169: { 'I', get_ibase },
! 170: { 'o', set_obase },
! 171: { 'O', get_obase },
! 172: { 'k', set_scale },
! 173: { 'K', get_scale },
! 174: { 'z', stackdepth },
! 175: { 'Z', num_digits },
! 176: { '?', eval_line },
! 177: { ';', load_array },
! 178: { ':', store_array },
! 179: { ' ', nop },
! 180: { '\t', nop },
! 181: { '\n', nop },
! 182: { '\f', nop },
! 183: { '\r', nop }
! 184: };
! 185:
! 186: #define JUMP_TABLE_DATA_SIZE \
! 187: (sizeof(jump_table_data)/sizeof(jump_table_data[0]))
! 188:
! 189: void
! 190: init_bmachine(void)
! 191: {
! 192: int i;
! 193:
! 194: for (i = 0; i < UCHAR_MAX; i++)
! 195: jump_table[i] = unknown;
! 196: for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++)
! 197: jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
! 198:
! 199: stack_init(&bmachine.stack);
! 200:
! 201: for (i = 0; i < UCHAR_MAX; i++)
! 202: stack_init(&bmachine.reg[i]);
! 203:
! 204: bmachine.obase = bmachine.ibase = 10;
! 205: BN_init(&zero);
! 206: bn_check(BN_zero(&zero));
! 207: }
! 208:
! 209: /* Reset the things needed before processing a (new) file */
! 210: void
! 211: reset_bmachine(struct source *src)
! 212: {
! 213: bmachine.readsp = 0;
! 214: bmachine.readstack[0] = *src;
! 215: }
! 216:
! 217: static __inline int
! 218: readch(void)
! 219: {
! 220: struct source *src = &bmachine.readstack[bmachine.readsp];
! 221:
! 222: return src->vtable->readchar(src);
! 223: }
! 224:
! 225: static __inline int
! 226: unreadch(void)
! 227: {
! 228: struct source *src = &bmachine.readstack[bmachine.readsp];
! 229:
! 230: return src->vtable->unreadchar(src);
! 231: }
! 232:
! 233: static __inline char *
! 234: readline(void)
! 235: {
! 236: struct source *src = &bmachine.readstack[bmachine.readsp];
! 237:
! 238: return src->vtable->readline(src);
! 239: }
! 240:
! 241: static __inline void
! 242: src_free(void)
! 243: {
! 244: struct source *src = &bmachine.readstack[bmachine.readsp];
! 245:
! 246: src->vtable->free(src);
! 247: }
! 248:
! 249: #if 1
! 250: void
! 251: pn(const char * str, const struct number *n)
! 252: {
! 253: char *p = BN_bn2dec(n->number);
! 254: if (p == NULL)
! 255: err(1, "BN_bn2dec failed");
! 256: fputs(str, stderr);
! 257: fprintf(stderr, " %s (%u)\n" , p, n->scale);
! 258: OPENSSL_free(p);
! 259: }
! 260:
! 261: void
! 262: pbn(const char * str, const BIGNUM *n)
! 263: {
! 264: char *p = BN_bn2dec(n);
! 265: if (p == NULL)
! 266: err(1, "BN_bn2dec failed");
! 267: fputs(str, stderr);
! 268: fprintf(stderr, " %s\n", p);
! 269: OPENSSL_free(p);
! 270: }
! 271:
! 272: #endif
! 273:
! 274: static __inline u_int
! 275: max(u_int a, u_int b)
! 276: {
! 277: return a > b ? a : b;
! 278: }
! 279:
! 280: static unsigned long factors[] = {
! 281: 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
! 282: 100000000, 1000000000
! 283: };
! 284:
! 285: void
! 286: scale_number(BIGNUM *n, int s)
! 287: {
! 288: int abs_scale;
! 289:
! 290: if (s == 0)
! 291: return;
! 292:
! 293: abs_scale = s > 0 ? s : -s;
! 294:
! 295: if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
! 296: if (s > 0)
! 297: bn_check(BN_mul_word(n, factors[abs_scale]));
! 298: else
! 299: BN_div_word(n, factors[abs_scale]);
! 300: } else {
! 301: BIGNUM *a, *p;
! 302: BN_CTX *ctx;
! 303:
! 304: a = BN_new();
! 305: bn_checkp(a);
! 306: p = BN_new();
! 307: bn_checkp(p);
! 308: ctx = BN_CTX_new();
! 309: bn_checkp(ctx);
! 310:
! 311: bn_check(BN_set_word(a, 10));
! 312: bn_check(BN_set_word(p, abs_scale));
! 313: bn_check(BN_exp(a, a, p, ctx));
! 314: if (s > 0)
! 315: bn_check(BN_mul(n, n, a, ctx));
! 316: else
! 317: bn_check(BN_div(n, NULL, n, a, ctx));
! 318: BN_CTX_free(ctx);
! 319: BN_free(a);
! 320: BN_free(p);
! 321: }
! 322: }
! 323:
! 324: void
! 325: split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
! 326: {
! 327: u_long rem;
! 328:
! 329: bn_checkp(BN_copy(i, n->number));
! 330:
! 331: if (n->scale == 0 && f != NULL)
! 332: BN_zero(f);
! 333: else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
! 334: rem = BN_div_word(i, factors[n->scale]);
! 335: if (f != NULL)
! 336: BN_set_word(f, rem);
! 337: } else {
! 338: BIGNUM *a, *p;
! 339: BN_CTX *ctx;
! 340:
! 341: a = BN_new();
! 342: bn_checkp(a);
! 343: p = BN_new();
! 344: bn_checkp(p);
! 345: ctx = BN_CTX_new();
! 346: bn_checkp(ctx);
! 347:
! 348: bn_check(BN_set_word(a, 10));
! 349: bn_check(BN_set_word(p, n->scale));
! 350: bn_check(BN_exp(a, a, p, ctx));
! 351: bn_check(BN_div(i, f, n->number, a, ctx));
! 352: BN_CTX_free(ctx);
! 353: BN_free(a);
! 354: BN_free(p);
! 355: }
! 356: }
! 357:
! 358: __inline void
! 359: normalize(struct number *n, u_int s)
! 360: {
! 361: scale_number(n->number, s - n->scale);
! 362: n->scale = s;
! 363: }
! 364:
! 365: static u_long
! 366: get_ulong(struct number *n)
! 367: {
! 368: normalize(n, 0);
! 369: return BN_get_word(n->number);
! 370: }
! 371:
! 372: void
! 373: negate(struct number *n)
! 374: {
! 375: bn_check(BN_sub(n->number, &zero, n->number));
! 376: }
! 377:
! 378: static __inline void
! 379: push_number(struct number *n)
! 380: {
! 381: stack_pushnumber(&bmachine.stack, n);
! 382: }
! 383:
! 384: static __inline void
! 385: push_string(char *string)
! 386: {
! 387: stack_pushstring(&bmachine.stack, string);
! 388: }
! 389:
! 390: static __inline void
! 391: push(struct value *v)
! 392: {
! 393: stack_push(&bmachine.stack, v);
! 394: }
! 395:
! 396: static __inline struct value *
! 397: tos(void)
! 398: {
! 399: return stack_tos(&bmachine.stack);
! 400: }
! 401:
! 402: static __inline struct value *
! 403: pop(void)
! 404: {
! 405: return stack_pop(&bmachine.stack);
! 406: }
! 407:
! 408: static __inline struct number *
! 409: pop_number(void)
! 410: {
! 411: return stack_popnumber(&bmachine.stack);
! 412: }
! 413:
! 414: static __inline char *
! 415: pop_string(void)
! 416: {
! 417: return stack_popstring(&bmachine.stack);
! 418: }
! 419:
! 420: static __inline void
! 421: clear_stack(void)
! 422: {
! 423: stack_clear(&bmachine.stack);
! 424: }
! 425:
! 426: static __inline void
! 427: print_stack(void)
! 428: {
! 429: stack_print(stdout, &bmachine.stack, "", bmachine.obase);
! 430: }
! 431:
! 432: static __inline void
! 433: print_tos(void)
! 434: {
! 435: struct value *value = tos();
! 436: if (value != NULL) {
! 437: print_value(stdout, value, "", bmachine.obase);
! 438: putchar('\n');
! 439: }
! 440: else
! 441: warnx("stack empty");
! 442: }
! 443:
! 444: static __inline void
! 445: pop_print(void)
! 446: {
! 447: struct value *value = pop();
! 448: if (value != NULL) {
! 449: switch (value->type) {
! 450: case BCODE_NONE:
! 451: break;
! 452: case BCODE_NUMBER:
! 453: normalize(value->u.num, 0);
! 454: print_ascii(stdout, value->u.num);
! 455: break;
! 456: case BCODE_STRING:
! 457: printf("%s", value->u.string);
! 458: break;
! 459: }
! 460: stack_free_value(value);
! 461: }
! 462: }
! 463:
! 464: static __inline void
! 465: dup(void)
! 466: {
! 467: stack_dup(&bmachine.stack);
! 468: }
! 469:
! 470: static void
! 471: get_scale(void)
! 472: {
! 473: struct number *n;
! 474:
! 475: n = new_number();
! 476: bn_check(BN_set_word(n->number, bmachine.scale));
! 477: push_number(n);
! 478: }
! 479:
! 480: static void
! 481: set_scale(void)
! 482: {
! 483: struct number *n;
! 484: u_long scale;
! 485:
! 486: n = pop_number();
! 487: if (n != NULL) {
! 488: if (BN_cmp(n->number, &zero) < 0)
! 489: warnx("scale must be a nonnegative number");
! 490: else {
! 491: scale = get_ulong(n);
! 492: if (scale != BN_MASK2)
! 493: bmachine.scale = scale;
! 494: else
! 495: warnx("scale too large");
! 496: }
! 497: free_number(n);
! 498: }
! 499: }
! 500:
! 501: static void
! 502: get_obase(void)
! 503: {
! 504: struct number *n;
! 505:
! 506: n = new_number();
! 507: bn_check(BN_set_word(n->number, bmachine.obase));
! 508: push_number(n);
! 509: }
! 510:
! 511: static void
! 512: set_obase(void)
! 513: {
! 514: struct number *n;
! 515: u_long base;
! 516:
! 517: n = pop_number();
! 518: if (n != NULL) {
! 519: base = get_ulong(n);
! 520: if (base != BN_MASK2 && base > 1)
! 521: bmachine.obase = base;
! 522: else
! 523: warnx("output base must be a number greater than 1");
! 524: free_number(n);
! 525: }
! 526: }
! 527:
! 528: static void
! 529: get_ibase(void)
! 530: {
! 531: struct number *n;
! 532:
! 533: n = new_number();
! 534: bn_check(BN_set_word(n->number, bmachine.ibase));
! 535: push_number(n);
! 536: }
! 537:
! 538: static void
! 539: set_ibase(void)
! 540: {
! 541: struct number *n;
! 542: u_long base;
! 543:
! 544: n = pop_number();
! 545: if (n != NULL) {
! 546: base = get_ulong(n);
! 547: if (base != BN_MASK2 && 2 <= base && base <= 16)
! 548: bmachine.ibase = base;
! 549: else
! 550: warnx("input base must be a number between 2 and 16 "
! 551: "(inclusive)");
! 552: free_number(n);
! 553: }
! 554: }
! 555:
! 556: static void
! 557: stackdepth(void)
! 558: {
! 559: u_int i;
! 560: struct number *n;
! 561:
! 562: i = stack_size(&bmachine.stack);
! 563: n = new_number();
! 564: bn_check(BN_set_word(n->number, i));
! 565: push_number(n);
! 566: }
! 567:
! 568: static void
! 569: push_scale(void)
! 570: {
! 571: struct value *value;
! 572: u_int scale = 0;
! 573: struct number *n;
! 574:
! 575:
! 576: value = pop();
! 577: if (value != NULL) {
! 578: switch (value->type) {
! 579: case BCODE_NONE:
! 580: return;
! 581: case BCODE_NUMBER:
! 582: scale = value->u.num->scale;
! 583: break;
! 584: case BCODE_STRING:
! 585: break;
! 586: }
! 587: stack_free_value(value);
! 588: n = new_number();
! 589: bn_check(BN_set_word(n->number, scale));
! 590: push_number(n);
! 591: }
! 592: }
! 593:
! 594: static u_int
! 595: count_digits(const struct number *n)
! 596: {
! 597: struct number *int_part, *fract_part;
! 598: u_int i;
! 599:
! 600: if (BN_is_zero(n->number))
! 601: return 1;
! 602:
! 603: int_part = new_number();
! 604: fract_part = new_number();
! 605: fract_part->scale = n->scale;
! 606: split_number(n, int_part->number, fract_part->number);
! 607:
! 608: i = 0;
! 609: while (!BN_is_zero(int_part->number)) {
! 610: BN_div_word(int_part->number, 10);
! 611: i++;
! 612: }
! 613: free_number(int_part);
! 614: free_number(fract_part);
! 615: return i + n->scale;
! 616: }
! 617:
! 618: static void
! 619: num_digits(void)
! 620: {
! 621: struct value *value;
! 622: u_int digits;
! 623: struct number *n;
! 624:
! 625: value = pop();
! 626: if (value != NULL) {
! 627: switch (value->type) {
! 628: case BCODE_NONE:
! 629: break;
! 630: case BCODE_NUMBER:
! 631: digits = count_digits(value->u.num);
! 632: n = new_number();
! 633: bn_check(BN_set_word(n->number, digits));
! 634: /* free first, then reassign */
! 635: BN_free(value->u.num->number);
! 636: push_number(n);
! 637: break;
! 638: case BCODE_STRING:
! 639: digits = strlen(value->u.string);
! 640: n = new_number();
! 641: bn_check(BN_set_word(n->number, digits));
! 642: /* free first, then reassign */
! 643: free(value->u.string);
! 644: push_number(n);
! 645: break;
! 646: }
! 647: }
! 648: }
! 649:
! 650: static void
! 651: load(void)
! 652: {
! 653: int index;
! 654: struct value *v, copy;
! 655:
! 656: index = readch();
! 657: if (0 <= index && index < UCHAR_MAX) {
! 658: v = stack_tos(&bmachine.reg[index]);
! 659: if (v == NULL)
! 660: warnx("register '%c' (0%o) is empty", index, index);
! 661: else
! 662: push(stack_dup_value(v, ©));
! 663: } else
! 664: warnx("internal error: reg num = %d", index);
! 665: }
! 666:
! 667: static void
! 668: store(void)
! 669: {
! 670: int index;
! 671: struct value *val;
! 672:
! 673: index = readch();
! 674: if (0 <= index && index < UCHAR_MAX) {
! 675: val = pop();
! 676: if (val == NULL) {
! 677: return;
! 678: }
! 679: stack_set_tos(&bmachine.reg[index], val);
! 680: } else
! 681: warnx("internal error: reg num = %d", index);
! 682: }
! 683:
! 684: static void
! 685: load_stack(void)
! 686: {
! 687: int index;
! 688: struct stack *stack;
! 689: struct value *value, copy;
! 690:
! 691: index = readch();
! 692: if (0 <= index && index < UCHAR_MAX) {
! 693: stack = &bmachine.reg[index];
! 694: value = NULL;
! 695: if (stack_size(stack) > 0) {
! 696: /*frame_free(stack);*/
! 697: value = stack_pop(stack);
! 698: }
! 699: if (value != NULL)
! 700: push(stack_dup_value(value, ©));
! 701: else
! 702: warnx("stack register '%c' (0%o) is empty",
! 703: index, index);
! 704: } else
! 705: warnx("internal error: reg num = %d", index);
! 706: }
! 707:
! 708: static void
! 709: store_stack(void)
! 710: {
! 711: int index;
! 712: struct value *value;
! 713:
! 714: index = readch();
! 715: if (0 <= index && index < UCHAR_MAX) {
! 716: value = pop();
! 717: if (value == NULL)
! 718: return;
! 719: stack_push(&bmachine.reg[index], value);
! 720: } else
! 721: warnx("internal error: reg num = %d", index);
! 722: }
! 723:
! 724: static void
! 725: load_array(void)
! 726: {
! 727: int reg;
! 728: struct number *inumber, *n;
! 729: u_long index;
! 730: struct stack *stack;
! 731: struct value *v, copy;
! 732:
! 733: reg = readch();
! 734: if (0 <= reg && reg < UCHAR_MAX) {
! 735: inumber = pop_number();
! 736: if (inumber == NULL)
! 737: return;
! 738: index = get_ulong(inumber);
! 739: if (BN_cmp(inumber->number, &zero) < 0)
! 740: warnx("negative index");
! 741: else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX)
! 742: warnx("index too big");
! 743: else {
! 744: stack = &bmachine.reg[reg];
! 745: v = frame_retrieve(stack, index);
! 746: if (v == NULL) {
! 747: n = new_number();
! 748: bn_check(BN_zero(n->number));
! 749: push_number(n);
! 750: }
! 751: else
! 752: push(stack_dup_value(v, ©));
! 753: }
! 754: free_number(inumber);
! 755: } else
! 756: warnx("internal error: reg num = %d", reg);
! 757: }
! 758:
! 759: static void
! 760: store_array(void)
! 761: {
! 762: int reg;
! 763: struct number *inumber;
! 764: u_long index;
! 765: struct value *value;
! 766: struct stack *stack;
! 767:
! 768: reg = readch();
! 769: if (0 <= reg && reg < UCHAR_MAX) {
! 770: inumber = pop_number();
! 771: value = pop();
! 772: if (inumber == NULL) {
! 773: if (value != NULL)
! 774: stack_free_value(value);
! 775: return;
! 776: }
! 777: index = get_ulong(inumber);
! 778: if (BN_cmp(inumber->number, &zero) < 0) {
! 779: warnx("negative index");
! 780: stack_free_value(value);
! 781: } else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX) {
! 782: warnx("index too big");
! 783: stack_free_value(value);
! 784: } else {
! 785: stack = &bmachine.reg[reg];
! 786: frame_assign(stack, index, value);
! 787: }
! 788: free_number(inumber);
! 789: } else
! 790: warnx("internal error: reg num = %d", reg);
! 791: }
! 792:
! 793: static void
! 794: push_line(void)
! 795: {
! 796: push_string(read_string(&bmachine.readstack[bmachine.readsp]));
! 797: }
! 798:
! 799: static void
! 800: bexec(char *line)
! 801: {
! 802: system(line);
! 803: free(line);
! 804: }
! 805:
! 806: static void
! 807: badd(void)
! 808: {
! 809: struct number *a, *b;
! 810: struct number *r;
! 811:
! 812: a = pop_number();
! 813: if (a == NULL) {
! 814: return;
! 815: }
! 816: b = pop_number();
! 817: if (b == NULL) {
! 818: push_number(a);
! 819: return;
! 820: }
! 821:
! 822: r = new_number();
! 823: r->scale = max(a->scale, b->scale);
! 824: if (r->scale > a->scale)
! 825: normalize(a, r->scale);
! 826: else if (r->scale > b->scale)
! 827: normalize(b, r->scale);
! 828: bn_check(BN_add(r->number, a->number, b->number));
! 829: push_number(r);
! 830: free_number(a);
! 831: free_number(b);
! 832: }
! 833:
! 834: static void
! 835: bsub(void)
! 836: {
! 837: struct number *a, *b;
! 838: struct number *r;
! 839:
! 840: a = pop_number();
! 841: if (a == NULL) {
! 842: return;
! 843: }
! 844: b = pop_number();
! 845: if (b == NULL) {
! 846: push_number(a);
! 847: return;
! 848: }
! 849:
! 850: r = new_number();
! 851:
! 852: r->scale = max(a->scale, b->scale);
! 853: if (r->scale > a->scale)
! 854: normalize(a, r->scale);
! 855: else if (r->scale > b->scale)
! 856: normalize(b, r->scale);
! 857: bn_check(BN_sub(r->number, b->number, a->number));
! 858: push_number(r);
! 859: free_number(a);
! 860: free_number(b);
! 861: }
! 862:
! 863: void
! 864: bmul_number(struct number *r, struct number *a, struct number *b)
! 865: {
! 866: BN_CTX *ctx;
! 867:
! 868: /* Create copies of the scales, since r might be equal to a or b */
! 869: u_int ascale = a->scale;
! 870: u_int bscale = b->scale;
! 871: u_int rscale = ascale + bscale;
! 872:
! 873: ctx = BN_CTX_new();
! 874: bn_checkp(ctx);
! 875: bn_check(BN_mul(r->number, a->number, b->number, ctx));
! 876: BN_CTX_free(ctx);
! 877:
! 878: if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
! 879: r->scale = rscale;
! 880: normalize(r, max(bmachine.scale, max(ascale, bscale)));
! 881: } else
! 882: r->scale = rscale;
! 883: }
! 884:
! 885: static void
! 886: bmul(void)
! 887: {
! 888: struct number *a, *b;
! 889: struct number *r;
! 890:
! 891: a = pop_number();
! 892: if (a == NULL) {
! 893: return;
! 894: }
! 895: b = pop_number();
! 896: if (b == NULL) {
! 897: push_number(a);
! 898: return;
! 899: }
! 900:
! 901: r = new_number();
! 902: bmul_number(r, a, b);
! 903:
! 904: push_number(r);
! 905: free_number(a);
! 906: free_number(b);
! 907: }
! 908:
! 909: static void
! 910: bdiv(void)
! 911: {
! 912: struct number *a, *b;
! 913: struct number *r;
! 914: u_int scale;
! 915: BN_CTX *ctx;
! 916:
! 917: a = pop_number();
! 918: if (a == NULL) {
! 919: return;
! 920: }
! 921: b = pop_number();
! 922: if (b == NULL) {
! 923: push_number(a);
! 924: return;
! 925: }
! 926:
! 927: r = new_number();
! 928: r->scale = bmachine.scale;
! 929: scale = max(a->scale, b->scale);
! 930:
! 931: if (BN_is_zero(a->number))
! 932: warnx("divide by zero");
! 933: else {
! 934: normalize(a, scale);
! 935: normalize(b, scale + r->scale);
! 936:
! 937: ctx = BN_CTX_new();
! 938: bn_checkp(ctx);
! 939: bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
! 940: BN_CTX_free(ctx);
! 941: }
! 942: push_number(r);
! 943: free_number(a);
! 944: free_number(b);
! 945: }
! 946:
! 947: static void
! 948: bmod(void)
! 949: {
! 950: struct number *a, *b;
! 951: struct number *r;
! 952: u_int scale;
! 953: BN_CTX *ctx;
! 954:
! 955: a = pop_number();
! 956: if (a == NULL) {
! 957: return;
! 958: }
! 959: b = pop_number();
! 960: if (b == NULL) {
! 961: push_number(a);
! 962: return;
! 963: }
! 964:
! 965: r = new_number();
! 966: /*
! 967: * XXX gives incorrect results for scale > 0, but is AT&T and
! 968: * GNU compatible
! 969: */
! 970: scale = max(a->scale, b->scale);
! 971: r->scale = max(b->scale, a->scale + bmachine.scale);
! 972:
! 973: if (BN_is_zero(a->number))
! 974: warnx("remainder by zero");
! 975: else {
! 976: normalize(a, scale);
! 977: normalize(b, scale + bmachine.scale);
! 978:
! 979: ctx = BN_CTX_new();
! 980: bn_checkp(ctx);
! 981: bn_check(BN_mod(r->number, b->number, a->number, ctx));
! 982: BN_CTX_free(ctx);
! 983: }
! 984: push_number(r);
! 985: free_number(a);
! 986: free_number(b);
! 987: }
! 988:
! 989: static void
! 990: bexp(void)
! 991: {
! 992: struct number *a, *p;
! 993: struct number *r;
! 994: bool neg;
! 995: u_int scale;
! 996:
! 997: p = pop_number();
! 998: if (p == NULL) {
! 999: return;
! 1000: }
! 1001: a = pop_number();
! 1002: if (a == NULL) {
! 1003: push_number(p);
! 1004: return;
! 1005: }
! 1006:
! 1007: if (p->scale != 0)
! 1008: warnx("Runtime warning: non-zero scale in exponent");
! 1009: normalize(p, 0);
! 1010:
! 1011: neg = false;
! 1012: if (BN_cmp(p->number, &zero) < 0) {
! 1013: neg = true;
! 1014: negate(p);
! 1015: scale = bmachine.scale;
! 1016: } else {
! 1017: /* Posix bc says min(a.scale * b, max(a.scale, scale) */
! 1018: u_long b;
! 1019: u_int m;
! 1020:
! 1021: b = BN_get_word(p->number);
! 1022: m = max(a->scale, bmachine.scale);
! 1023: scale = a->scale * b;
! 1024: if (scale > m || b == BN_MASK2)
! 1025: scale = m;
! 1026: }
! 1027:
! 1028: if (BN_is_zero(p->number)) {
! 1029: r = new_number();
! 1030: bn_check(BN_one(r->number));
! 1031: normalize(r, scale);
! 1032: } else {
! 1033: while (!BN_is_bit_set(p->number, 0)) {
! 1034: bmul_number(a, a, a);
! 1035: bn_check(BN_rshift1(p->number, p->number));
! 1036: }
! 1037:
! 1038: r = dup_number(a);
! 1039: normalize(r, scale);
! 1040: bn_check(BN_rshift1(p->number, p->number));
! 1041:
! 1042: while (!BN_is_zero(p->number)) {
! 1043: bmul_number(a, a, a);
! 1044: if (BN_is_bit_set(p->number, 0))
! 1045: bmul_number(r, r, a);
! 1046: bn_check(BN_rshift1(p->number, p->number));
! 1047: }
! 1048:
! 1049: if (neg) {
! 1050: BN_CTX *ctx;
! 1051: BIGNUM *one;
! 1052:
! 1053: one = BN_new();
! 1054: bn_checkp(one);
! 1055: BN_one(one);
! 1056: ctx = BN_CTX_new();
! 1057: bn_checkp(ctx);
! 1058: r->scale = scale;
! 1059: scale_number(one, r->scale);
! 1060: bn_check(BN_div(r->number, NULL, one, r->number, ctx));
! 1061: BN_free(one);
! 1062: BN_CTX_free(ctx);
! 1063: }
! 1064: }
! 1065: push_number(r);
! 1066: free_number(a);
! 1067: free_number(p);
! 1068: }
! 1069:
! 1070: static bool
! 1071: bsqrt_stop(const BIGNUM *x, const BIGNUM *y)
! 1072: {
! 1073: BIGNUM *r;
! 1074: bool ret;
! 1075:
! 1076: r = BN_new();
! 1077: bn_checkp(r);
! 1078: bn_check(BN_sub(r, x, y));
! 1079: ret = BN_is_one(r) || BN_is_zero(r);
! 1080: BN_free(r);
! 1081: return ret;
! 1082: }
! 1083:
! 1084: static void
! 1085: bsqrt(void)
! 1086: {
! 1087: struct number *n;
! 1088: struct number *r;
! 1089: BIGNUM *x, *y;
! 1090: u_int scale;
! 1091: BN_CTX *ctx;
! 1092:
! 1093: n = pop_number();
! 1094: if (n == NULL) {
! 1095: return;
! 1096: }
! 1097: if (BN_is_zero(n->number)) {
! 1098: r = new_number();
! 1099: push_number(r);
! 1100: } else if (BN_cmp(n->number, &zero) < 0)
! 1101: warnx("square root of negative number");
! 1102: else {
! 1103: scale = max(bmachine.scale, n->scale);
! 1104: normalize(n, 2*scale);
! 1105: x = BN_dup(n->number);
! 1106: bn_checkp(x);
! 1107: bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
! 1108: y = BN_new();
! 1109: bn_checkp(y);
! 1110: ctx = BN_CTX_new();
! 1111: bn_checkp(ctx);
! 1112: for (;;) {
! 1113: bn_checkp(BN_copy(y, x));
! 1114: bn_check(BN_div(x, NULL, n->number, x, ctx));
! 1115: bn_check(BN_add(x, x, y));
! 1116: bn_check(BN_rshift1(x, x));
! 1117: if (bsqrt_stop(x, y))
! 1118: break;
! 1119: }
! 1120: r = bmalloc(sizeof(*r));
! 1121: r->scale = scale;
! 1122: r->number = y;
! 1123: BN_free(x);
! 1124: BN_CTX_free(ctx);
! 1125: push_number(r);
! 1126: }
! 1127:
! 1128: free_number(n);
! 1129: }
! 1130:
! 1131: static void
! 1132: equal(void)
! 1133: {
! 1134: compare(BCODE_EQUAL);
! 1135: }
! 1136:
! 1137: static void
! 1138: not_equal(void)
! 1139: {
! 1140: compare(BCODE_NOT_EQUAL);
! 1141: }
! 1142:
! 1143: static void
! 1144: less(void)
! 1145: {
! 1146: compare(BCODE_LESS);
! 1147: }
! 1148:
! 1149: static void
! 1150: not_compare(void)
! 1151: {
! 1152: switch (readch()) {
! 1153: case '<':
! 1154: not_less();
! 1155: break;
! 1156: case '>':
! 1157: not_greater();
! 1158: break;
! 1159: case '=':
! 1160: not_equal();
! 1161: break;
! 1162: default:
! 1163: unreadch();
! 1164: bexec(readline());
! 1165: break;
! 1166: }
! 1167: }
! 1168:
! 1169: static void
! 1170: not_less(void)
! 1171: {
! 1172: compare(BCODE_NOT_LESS);
! 1173: }
! 1174:
! 1175: static void
! 1176: greater(void)
! 1177: {
! 1178: compare(BCODE_GREATER);
! 1179: }
! 1180:
! 1181: static void
! 1182: not_greater(void)
! 1183: {
! 1184: compare(BCODE_NOT_GREATER);
! 1185: }
! 1186:
! 1187: static void
! 1188: compare(enum bcode_compare type)
! 1189: {
! 1190: int index;
! 1191: struct number *a, *b;
! 1192: u_int scale;
! 1193: int cmp;
! 1194: bool ok;
! 1195: struct value *v;
! 1196:
! 1197: index = readch();
! 1198:
! 1199: a = pop_number();
! 1200: if (a == NULL) {
! 1201: return;
! 1202: }
! 1203: b = pop_number();
! 1204: if (b == NULL) {
! 1205: push_number(a);
! 1206: return;
! 1207: }
! 1208:
! 1209: scale = max(a->scale, b->scale);
! 1210: if (scale > a->scale)
! 1211: normalize(a, scale);
! 1212: else if (scale > scale)
! 1213: normalize(b, scale);
! 1214:
! 1215: cmp = BN_cmp(a->number, b->number);
! 1216:
! 1217: free_number(a);
! 1218: free_number(b);
! 1219:
! 1220: ok = false;
! 1221: switch (type) {
! 1222: case BCODE_EQUAL:
! 1223: ok = cmp == 0;
! 1224: break;
! 1225: case BCODE_NOT_EQUAL:
! 1226: ok = cmp != 0;
! 1227: break;
! 1228: case BCODE_LESS:
! 1229: ok = cmp < 0;
! 1230: break;
! 1231: case BCODE_NOT_LESS:
! 1232: ok = cmp >= 0;
! 1233: break;
! 1234: case BCODE_GREATER:
! 1235: ok = cmp > 0;
! 1236: break;
! 1237: case BCODE_NOT_GREATER:
! 1238: ok = cmp <= 0;
! 1239: break;
! 1240: }
! 1241:
! 1242: if (ok) {
! 1243: v = stack_tos(&bmachine.reg[index]);
! 1244: if (v == NULL)
! 1245: warn("stack empty");
! 1246: else {
! 1247: switch(v->type) {
! 1248: case BCODE_NONE:
! 1249: warnx("register '%c' (0%o) is empty",
! 1250: index, index);
! 1251: break;
! 1252: case BCODE_NUMBER:
! 1253: warn("eval called with non-string argument");
! 1254: break;
! 1255: case BCODE_STRING:
! 1256: eval_string(bstrdup(v->u.string));
! 1257: break;
! 1258: }
! 1259: }
! 1260: }
! 1261: }
! 1262:
! 1263:
! 1264: static void
! 1265: nop(void)
! 1266: {
! 1267: }
! 1268:
! 1269: static void
! 1270: quit(void)
! 1271: {
! 1272: if (bmachine.readsp < 2)
! 1273: exit(0);
! 1274: src_free();
! 1275: bmachine.readsp--;
! 1276: src_free();
! 1277: bmachine.readsp--;
! 1278: }
! 1279:
! 1280: static void
! 1281: quitN(void)
! 1282: {
! 1283: struct number *n;
! 1284: u_long i;
! 1285:
! 1286: n = pop_number();
! 1287: if (n == NULL)
! 1288: return;
! 1289: i = get_ulong(n);
! 1290: if (i == BN_MASK2 || i == 0)
! 1291: warnx("Q command requires a number >= 1");
! 1292: else if (bmachine.readsp < i)
! 1293: warnx("Q command argument exceeded string execution depth");
! 1294: else {
! 1295: while (i-- > 0) {
! 1296: src_free();
! 1297: bmachine.readsp--;
! 1298: }
! 1299: }
! 1300: }
! 1301:
! 1302: static void
! 1303: parse_number(void)
! 1304: {
! 1305: unreadch();
! 1306: push_number(readnumber(&bmachine.readstack[bmachine.readsp],
! 1307: bmachine.ibase));
! 1308: }
! 1309:
! 1310: static void
! 1311: unknown(void)
! 1312: {
! 1313: int ch = bmachine.readstack[bmachine.readsp].lastchar;
! 1314: warnx("%c (0%o) is unimplemented", ch, ch);
! 1315: }
! 1316:
! 1317: static void
! 1318: eval_string(char *p)
! 1319: {
! 1320: int ch;
! 1321:
! 1322: if (bmachine.readsp > 0) {
! 1323: /* Check for tail call. Do not recurse in that case. */
! 1324: ch = readch();
! 1325: if (ch == EOF) {
! 1326: src_free();
! 1327: src_setstring(&bmachine.readstack[bmachine.readsp], p);
! 1328: return;
! 1329: } else
! 1330: unreadch();
! 1331: }
! 1332: if (bmachine.readsp == MAX_RECURSION)
! 1333: errx(1, "recursion too deep");
! 1334: src_setstring(&bmachine.readstack[++bmachine.readsp], p);
! 1335: }
! 1336:
! 1337: static void
! 1338: eval_line(void)
! 1339: {
! 1340: /* Always read from stdin */
! 1341: struct source in;
! 1342: char *p;
! 1343:
! 1344: src_setstream(&in, stdin);
! 1345: p = (*in.vtable->readline)(&in);
! 1346: eval_string(p);
! 1347: }
! 1348:
! 1349: static void
! 1350: eval_tos(void)
! 1351: {
! 1352: char *p;
! 1353:
! 1354: p = pop_string();
! 1355: if (p == NULL)
! 1356: return;
! 1357: eval_string(p);
! 1358: }
! 1359:
! 1360: void
! 1361: eval(void)
! 1362: {
! 1363: int ch;
! 1364:
! 1365: for (;;) {
! 1366: ch = readch();
! 1367: if (ch == EOF) {
! 1368: if (bmachine.readsp == 0)
! 1369: exit(0);
! 1370: src_free();
! 1371: bmachine.readsp--;
! 1372: continue;
! 1373: }
! 1374: if (trace) {
! 1375: fprintf(stderr, "# %c\n", ch);
! 1376: stack_print(stderr, &bmachine.stack, "* ",
! 1377: bmachine.obase);
! 1378: fprintf(stderr, "%d =>\n", bmachine.readsp);
! 1379: }
! 1380:
! 1381: if (0 <= ch && ch < UCHAR_MAX)
! 1382: (*jump_table[ch])();
! 1383: else
! 1384: warnx("internal error: opcode %d", ch);
! 1385:
! 1386: if (trace) {
! 1387: stack_print(stderr, &bmachine.stack, "* ",
! 1388: bmachine.obase);
! 1389: fprintf(stderr, "%d ==\n", bmachine.readsp);
! 1390: }
! 1391: }
! 1392: }