Index: stable/11/usr.bin/dc/bcode.c =================================================================== --- stable/11/usr.bin/dc/bcode.c (revision 315133) +++ stable/11/usr.bin/dc/bcode.c (revision 315134) @@ -1,1776 +1,1763 @@ /* $OpenBSD: bcode.c,v 1.45 2012/11/07 11:06:14 otto Exp $ */ /* * Copyright (c) 2003, Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "extern.h" /* #define DEBUGGING */ #define MAX_ARRAY_INDEX 2048 #define READSTACK_SIZE 8 #define NO_ELSE -2 /* -1 is EOF */ #define REG_ARRAY_SIZE_SMALL (UCHAR_MAX + 1) #define REG_ARRAY_SIZE_BIG (UCHAR_MAX + 1 + USHRT_MAX + 1) struct bmachine { struct source *readstack; struct stack *reg; struct stack stack; u_int scale; u_int obase; u_int ibase; size_t readsp; size_t reg_array_size; size_t readstack_sz; bool extended_regs; }; static struct bmachine bmachine; static __inline int readch(void); static __inline void unreadch(void); static __inline char *readline(void); static __inline void src_free(void); static __inline u_int max(u_int, u_int); static u_long get_ulong(struct number *); static __inline void push_number(struct number *); static __inline void push_string(char *); static __inline void push(struct value *); static __inline struct value *tos(void); static __inline struct number *pop_number(void); static __inline char *pop_string(void); static __inline void clear_stack(void); static __inline void print_tos(void); static void pop_print(void); static void pop_printn(void); static __inline void print_stack(void); static __inline void dup(void); static void swap(void); static void drop(void); static void get_scale(void); static void set_scale(void); static void get_obase(void); static void set_obase(void); static void get_ibase(void); static void set_ibase(void); static void stackdepth(void); static void push_scale(void); static u_int count_digits(const struct number *); static void num_digits(void); static void to_ascii(void); static void push_line(void); static void comment(void); static void bexec(char *); static void badd(void); static void bsub(void); static void bmul(void); static void bdiv(void); static void bmod(void); static void bdivmod(void); static void bexp(void); static bool bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *); static void bsqrt(void); static void not(void); static void equal_numbers(void); static void less_numbers(void); static void lesseq_numbers(void); static void equal(void); static void not_equal(void); static void less(void); static void not_less(void); static void greater(void); static void not_greater(void); static void not_compare(void); static bool compare_numbers(enum bcode_compare, struct number *, struct number *); static void compare(enum bcode_compare); static int readreg(void); static void load(void); static void store(void); static void load_stack(void); static void store_stack(void); static void load_array(void); static void store_array(void); static void nop(void); static void quit(void); static void quitN(void); static void skipN(void); static void skip_until_mark(void); static void parse_number(void); static void unknown(void); static void eval_string(char *); static void eval_line(void); static void eval_tos(void); typedef void (*opcode_function)(void); struct jump_entry { u_char ch; opcode_function f; }; static opcode_function jump_table[UCHAR_MAX]; static const struct jump_entry jump_table_data[] = { { ' ', nop }, { '!', not_compare }, { '#', comment }, { '%', bmod }, { '(', less_numbers }, { '*', bmul }, { '+', badd }, { '-', bsub }, { '.', parse_number }, { '/', bdiv }, { '0', parse_number }, { '1', parse_number }, { '2', parse_number }, { '3', parse_number }, { '4', parse_number }, { '5', parse_number }, { '6', parse_number }, { '7', parse_number }, { '8', parse_number }, { '9', parse_number }, { ':', store_array }, { ';', load_array }, { '<', less }, { '=', equal }, { '>', greater }, { '?', eval_line }, { 'A', parse_number }, { 'B', parse_number }, { 'C', parse_number }, { 'D', parse_number }, { 'E', parse_number }, { 'F', parse_number }, { 'G', equal_numbers }, { 'I', get_ibase }, { 'J', skipN }, { 'K', get_scale }, { 'L', load_stack }, { 'M', nop }, { 'N', not }, { 'O', get_obase }, { 'P', pop_print }, { 'Q', quitN }, { 'R', drop }, { 'S', store_stack }, { 'X', push_scale }, { 'Z', num_digits }, { '[', push_line }, { '\f', nop }, { '\n', nop }, { '\r', nop }, { '\t', nop }, { '^', bexp }, { '_', parse_number }, { 'a', to_ascii }, { 'c', clear_stack }, { 'd', dup }, { 'f', print_stack }, { 'i', set_ibase }, { 'k', set_scale }, { 'l', load }, { 'n', pop_printn }, { 'o', set_obase }, { 'p', print_tos }, { 'q', quit }, { 'r', swap }, { 's', store }, { 'v', bsqrt }, { 'x', eval_tos }, { 'z', stackdepth }, { '{', lesseq_numbers }, { '~', bdivmod } }; #define JUMP_TABLE_DATA_SIZE \ (sizeof(jump_table_data)/sizeof(jump_table_data[0])) void init_bmachine(bool extended_registers) { unsigned int i; bmachine.extended_regs = extended_registers; bmachine.reg_array_size = bmachine.extended_regs ? REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL; bmachine.reg = calloc(bmachine.reg_array_size, sizeof(bmachine.reg[0])); if (bmachine.reg == NULL) err(1, NULL); for (i = 0; i < UCHAR_MAX; i++) jump_table[i] = unknown; for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++) jump_table[jump_table_data[i].ch] = jump_table_data[i].f; stack_init(&bmachine.stack); for (i = 0; i < bmachine.reg_array_size; i++) stack_init(&bmachine.reg[i]); bmachine.readstack_sz = READSTACK_SIZE; bmachine.readstack = calloc(sizeof(struct source), bmachine.readstack_sz); if (bmachine.readstack == NULL) err(1, NULL); bmachine.obase = bmachine.ibase = 10; } u_int bmachine_scale(void) { return bmachine.scale; } /* Reset the things needed before processing a (new) file */ void reset_bmachine(struct source *src) { bmachine.readsp = 0; bmachine.readstack[0] = *src; } static __inline int readch(void) { struct source *src = &bmachine.readstack[bmachine.readsp]; return (src->vtable->readchar(src)); } static __inline void unreadch(void) { struct source *src = &bmachine.readstack[bmachine.readsp]; src->vtable->unreadchar(src); } static __inline char * readline(void) { struct source *src = &bmachine.readstack[bmachine.readsp]; return (src->vtable->readline(src)); } static __inline void src_free(void) { struct source *src = &bmachine.readstack[bmachine.readsp]; src->vtable->free(src); } #ifdef DEBUGGING void pn(const char *str, const struct number *n) { char *p = BN_bn2dec(n->number); if (p == NULL) err(1, "BN_bn2dec failed"); fputs(str, stderr); fprintf(stderr, " %s (%u)\n" , p, n->scale); OPENSSL_free(p); } void pbn(const char *str, const BIGNUM *n) { char *p = BN_bn2dec(n); if (p == NULL) err(1, "BN_bn2dec failed"); fputs(str, stderr); fprintf(stderr, " %s\n", p); OPENSSL_free(p); } #endif static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); } static unsigned long factors[] = { 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; void scale_number(BIGNUM *n, int s) { unsigned int abs_scale; if (s == 0) return; abs_scale = s > 0 ? s : -s; if (abs_scale < sizeof(factors)/sizeof(factors[0])) { if (s > 0) bn_check(BN_mul_word(n, factors[abs_scale])); else BN_div_word(n, factors[abs_scale]); } else { BIGNUM *a, *p; BN_CTX *ctx; a = BN_new(); bn_checkp(a); p = BN_new(); bn_checkp(p); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_set_word(a, 10)); bn_check(BN_set_word(p, abs_scale)); bn_check(BN_exp(a, a, p, ctx)); if (s > 0) bn_check(BN_mul(n, n, a, ctx)); else bn_check(BN_div(n, NULL, n, a, ctx)); BN_CTX_free(ctx); BN_free(a); BN_free(p); } } void split_number(const struct number *n, BIGNUM *i, BIGNUM *f) { u_long rem; bn_checkp(BN_copy(i, n->number)); if (n->scale == 0 && f != NULL) bn_check(BN_zero(f)); else if (n->scale < sizeof(factors)/sizeof(factors[0])) { rem = BN_div_word(i, factors[n->scale]); if (f != NULL) bn_check(BN_set_word(f, rem)); } else { BIGNUM *a, *p; BN_CTX *ctx; a = BN_new(); bn_checkp(a); p = BN_new(); bn_checkp(p); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_set_word(a, 10)); bn_check(BN_set_word(p, n->scale)); bn_check(BN_exp(a, a, p, ctx)); bn_check(BN_div(i, f, n->number, a, ctx)); BN_CTX_free(ctx); BN_free(a); BN_free(p); } } void normalize(struct number *n, u_int s) { scale_number(n->number, s - n->scale); n->scale = s; } static u_long get_ulong(struct number *n) { normalize(n, 0); return (BN_get_word(n->number)); } void negate(struct number *n) { BN_set_negative(n->number, !BN_is_negative(n->number)); } static __inline void push_number(struct number *n) { stack_pushnumber(&bmachine.stack, n); } static __inline void push_string(char *string) { stack_pushstring(&bmachine.stack, string); } static __inline void push(struct value *v) { stack_push(&bmachine.stack, v); } static __inline struct value * tos(void) { return (stack_tos(&bmachine.stack)); } static __inline struct value * pop(void) { return (stack_pop(&bmachine.stack)); } static __inline struct number * pop_number(void) { return (stack_popnumber(&bmachine.stack)); } static __inline char * pop_string(void) { return (stack_popstring(&bmachine.stack)); } static __inline void clear_stack(void) { stack_clear(&bmachine.stack); } static __inline void print_stack(void) { stack_print(stdout, &bmachine.stack, "", bmachine.obase); } static __inline void print_tos(void) { struct value *value = tos(); if (value != NULL) { print_value(stdout, value, "", bmachine.obase); putchar('\n'); } else warnx("stack empty"); } static void pop_print(void) { struct value *value = pop(); if (value != NULL) { switch (value->type) { case BCODE_NONE: break; case BCODE_NUMBER: normalize(value->u.num, 0); print_ascii(stdout, value->u.num); fflush(stdout); break; case BCODE_STRING: fputs(value->u.string, stdout); fflush(stdout); break; } stack_free_value(value); } } static void pop_printn(void) { struct value *value = pop(); if (value != NULL) { print_value(stdout, value, "", bmachine.obase); fflush(stdout); stack_free_value(value); } } static __inline void dup(void) { stack_dup(&bmachine.stack); } static void swap(void) { stack_swap(&bmachine.stack); } static void drop(void) { struct value *v = pop(); if (v != NULL) stack_free_value(v); } static void get_scale(void) { struct number *n; n = new_number(); bn_check(BN_set_word(n->number, bmachine.scale)); push_number(n); } static void set_scale(void) { struct number *n; u_long scale; n = pop_number(); if (n != NULL) { if (BN_is_negative(n->number)) warnx("scale must be a nonnegative number"); else { scale = get_ulong(n); if (scale != BN_MASK2 && scale <= UINT_MAX) bmachine.scale = (u_int)scale; else warnx("scale too large"); } free_number(n); } } static void get_obase(void) { struct number *n; n = new_number(); bn_check(BN_set_word(n->number, bmachine.obase)); push_number(n); } static void set_obase(void) { struct number *n; u_long base; n = pop_number(); if (n != NULL) { base = get_ulong(n); if (base != BN_MASK2 && base > 1 && base <= UINT_MAX) bmachine.obase = (u_int)base; else warnx("output base must be a number greater than 1"); free_number(n); } } static void get_ibase(void) { struct number *n; n = new_number(); bn_check(BN_set_word(n->number, bmachine.ibase)); push_number(n); } static void set_ibase(void) { struct number *n; u_long base; n = pop_number(); if (n != NULL) { base = get_ulong(n); if (base != BN_MASK2 && 2 <= base && base <= 16) bmachine.ibase = (u_int)base; else warnx("input base must be a number between 2 and 16 " "(inclusive)"); free_number(n); } } static void stackdepth(void) { struct number *n; size_t i; i = stack_size(&bmachine.stack); n = new_number(); bn_check(BN_set_word(n->number, i)); push_number(n); } static void push_scale(void) { struct number *n; struct value *value; u_int scale = 0; value = pop(); if (value != NULL) { switch (value->type) { case BCODE_NONE: return; case BCODE_NUMBER: scale = value->u.num->scale; break; case BCODE_STRING: break; } stack_free_value(value); n = new_number(); bn_check(BN_set_word(n->number, scale)); push_number(n); } } static u_int count_digits(const struct number *n) { struct number *int_part, *fract_part; u_int i; if (BN_is_zero(n->number)) return n->scale ? n->scale : 1; int_part = new_number(); fract_part = new_number(); fract_part->scale = n->scale; split_number(n, int_part->number, fract_part->number); i = 0; while (!BN_is_zero(int_part->number)) { BN_div_word(int_part->number, 10); i++; } free_number(int_part); free_number(fract_part); return (i + n->scale); } static void num_digits(void) { struct number *n = NULL; struct value *value; size_t digits; value = pop(); if (value != NULL) { switch (value->type) { case BCODE_NONE: return; case BCODE_NUMBER: digits = count_digits(value->u.num); n = new_number(); bn_check(BN_set_word(n->number, digits)); break; case BCODE_STRING: digits = strlen(value->u.string); n = new_number(); bn_check(BN_set_word(n->number, digits)); break; } stack_free_value(value); push_number(n); } } static void to_ascii(void) { struct number *n; struct value *value; char str[2]; value = pop(); if (value != NULL) { str[1] = '\0'; switch (value->type) { case BCODE_NONE: return; case BCODE_NUMBER: n = value->u.num; normalize(n, 0); if (BN_num_bits(n->number) > 8) bn_check(BN_mask_bits(n->number, 8)); str[0] = (char)BN_get_word(n->number); break; case BCODE_STRING: str[0] = value->u.string[0]; break; } stack_free_value(value); push_string(bstrdup(str)); } } static int readreg(void) { int ch1, ch2, idx; idx = readch(); if (idx == 0xff && bmachine.extended_regs) { ch1 = readch(); ch2 = readch(); if (ch1 == EOF || ch2 == EOF) { warnx("unexpected eof"); idx = -1; } else idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1; } if (idx < 0 || (unsigned)idx >= bmachine.reg_array_size) { warnx("internal error: reg num = %d", idx); idx = -1; } return (idx); } static void load(void) { struct number *n; struct value *v; struct value copy; int idx; idx = readreg(); if (idx >= 0) { v = stack_tos(&bmachine.reg[idx]); if (v == NULL) { n = new_number(); bn_check(BN_zero(n->number)); push_number(n); } else push(stack_dup_value(v, ©)); } } static void store(void) { struct value *val; int idx; idx = readreg(); if (idx >= 0) { val = pop(); if (val == NULL) { return; } stack_set_tos(&bmachine.reg[idx], val); } } static void load_stack(void) { struct stack *stack; struct value *value; int idx; idx = readreg(); if (idx >= 0) { stack = &bmachine.reg[idx]; value = NULL; if (stack_size(stack) > 0) { value = stack_pop(stack); } if (value != NULL) push(value); else warnx("stack register '%c' (0%o) is empty", idx, idx); } } static void store_stack(void) { struct value *value; int idx; idx = readreg(); if (idx >= 0) { value = pop(); if (value == NULL) return; stack_push(&bmachine.reg[idx], value); } } static void load_array(void) { struct number *inumber, *n; struct stack *stack; struct value *v; struct value copy; u_long idx; int reg; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; idx = get_ulong(inumber); if (BN_is_negative(inumber->number)) warnx("negative idx"); else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) warnx("idx too big"); else { stack = &bmachine.reg[reg]; v = frame_retrieve(stack, idx); if (v == NULL || v->type == BCODE_NONE) { n = new_number(); bn_check(BN_zero(n->number)); push_number(n); } else push(stack_dup_value(v, ©)); } free_number(inumber); } } static void store_array(void) { struct number *inumber; struct value *value; struct stack *stack; u_long idx; int reg; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; value = pop(); if (value == NULL) { free_number(inumber); return; } idx = get_ulong(inumber); if (BN_is_negative(inumber->number)) { warnx("negative idx"); stack_free_value(value); } else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) { warnx("idx too big"); stack_free_value(value); } else { stack = &bmachine.reg[reg]; frame_assign(stack, idx, value); } free_number(inumber); } } static void push_line(void) { push_string(read_string(&bmachine.readstack[bmachine.readsp])); } static void comment(void) { free(readline()); } static void bexec(char *line) { system(line); free(line); } static void badd(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); r->scale = max(a->scale, b->scale); if (r->scale > a->scale) normalize(a, r->scale); else if (r->scale > b->scale) normalize(b, r->scale); bn_check(BN_add(r->number, a->number, b->number)); push_number(r); free_number(a); free_number(b); } static void bsub(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); r->scale = max(a->scale, b->scale); if (r->scale > a->scale) normalize(a, r->scale); else if (r->scale > b->scale) normalize(b, r->scale); bn_check(BN_sub(r->number, b->number, a->number)); push_number(r); free_number(a); free_number(b); } void bmul_number(struct number *r, struct number *a, struct number *b, u_int scale) { BN_CTX *ctx; /* Create copies of the scales, since r might be equal to a or b */ u_int ascale = a->scale; u_int bscale = b->scale; u_int rscale = ascale + bscale; ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_mul(r->number, a->number, b->number, ctx)); BN_CTX_free(ctx); r->scale = rscale; if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) normalize(r, max(scale, max(ascale, bscale))); } static void bmul(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bmul_number(r, a, b, bmachine.scale); push_number(r); free_number(a); free_number(b); } static void bdiv(void) { struct number *a, *b, *r; BN_CTX *ctx; u_int scale; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); r->scale = bmachine.scale; scale = max(a->scale, b->scale); if (BN_is_zero(a->number)) warnx("divide by zero"); else { normalize(a, scale); normalize(b, scale + r->scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_div(r->number, NULL, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(r); free_number(a); free_number(b); } static void bmod(void) { struct number *a, *b, *r; BN_CTX *ctx; u_int scale; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); scale = max(a->scale, b->scale); r->scale = max(b->scale, a->scale + bmachine.scale); if (BN_is_zero(a->number)) warnx("remainder by zero"); else { normalize(a, scale); normalize(b, scale + bmachine.scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_mod(r->number, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(r); free_number(a); free_number(b); } static void bdivmod(void) { struct number *a, *b, *rdiv, *rmod; BN_CTX *ctx; u_int scale; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } rdiv = new_number(); rmod = new_number(); rdiv->scale = bmachine.scale; rmod->scale = max(b->scale, a->scale + bmachine.scale); scale = max(a->scale, b->scale); if (BN_is_zero(a->number)) warnx("divide by zero"); else { normalize(a, scale); normalize(b, scale + bmachine.scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_div(rdiv->number, rmod->number, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(rdiv); push_number(rmod); free_number(a); free_number(b); } static void bexp(void) { struct number *a, *p; struct number *r; bool neg; u_int rscale; p = pop_number(); - if (p == NULL) { + if (p == NULL) return; - } a = pop_number(); if (a == NULL) { push_number(p); return; } if (p->scale != 0) { BIGNUM *i, *f; i = BN_new(); bn_checkp(i); f = BN_new(); bn_checkp(f); split_number(p, i, f); if (!BN_is_zero(f)) warnx("Runtime warning: non-zero fractional part in exponent"); BN_free(i); BN_free(f); } normalize(p, 0); neg = false; if (BN_is_negative(p->number)) { neg = true; negate(p); rscale = bmachine.scale; } else { /* Posix bc says min(a.scale * b, max(a.scale, scale) */ u_long b; u_int m; b = BN_get_word(p->number); m = max(a->scale, bmachine.scale); rscale = a->scale * (u_int)b; if (rscale > m || (a->scale > 0 && (b == BN_MASK2 || b > UINT_MAX))) rscale = m; } if (BN_is_zero(p->number)) { r = new_number(); bn_check(BN_one(r->number)); normalize(r, rscale); } else { u_int ascale, mscale; ascale = a->scale; while (!BN_is_bit_set(p->number, 0)) { ascale *= 2; bmul_number(a, a, a, ascale); bn_check(BN_rshift1(p->number, p->number)); } r = dup_number(a); bn_check(BN_rshift1(p->number, p->number)); mscale = ascale; while (!BN_is_zero(p->number)) { ascale *= 2; bmul_number(a, a, a, ascale); if (BN_is_bit_set(p->number, 0)) { mscale += ascale; bmul_number(r, r, a, mscale); } bn_check(BN_rshift1(p->number, p->number)); } if (neg) { BN_CTX *ctx; BIGNUM *one; one = BN_new(); bn_checkp(one); bn_check(BN_one(one)); ctx = BN_CTX_new(); bn_checkp(ctx); scale_number(one, r->scale + rscale); if (BN_is_zero(r->number)) warnx("divide by zero"); else bn_check(BN_div(r->number, NULL, one, r->number, ctx)); BN_free(one); BN_CTX_free(ctx); r->scale = rscale; } else normalize(r, rscale); } push_number(r); free_number(a); free_number(p); } static bool bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount) { BIGNUM *r; bool ret; r = BN_new(); bn_checkp(r); bn_check(BN_sub(r, x, y)); if (BN_is_one(r)) (*onecount)++; ret = BN_is_zero(r); BN_free(r); return (ret || *onecount > 1); } static void bsqrt(void) { struct number *n, *r; BIGNUM *x, *y; BN_CTX *ctx; u_int onecount, scale; onecount = 0; n = pop_number(); - if (n == NULL) { + if (n == NULL) return; - } if (BN_is_zero(n->number)) { r = new_number(); push_number(r); } else if (BN_is_negative(n->number)) warnx("square root of negative number"); else { scale = max(bmachine.scale, n->scale); normalize(n, 2*scale); x = BN_dup(n->number); bn_checkp(x); bn_check(BN_rshift(x, x, BN_num_bits(x)/2)); y = BN_new(); bn_checkp(y); ctx = BN_CTX_new(); bn_checkp(ctx); for (;;) { bn_checkp(BN_copy(y, x)); bn_check(BN_div(x, NULL, n->number, x, ctx)); bn_check(BN_add(x, x, y)); bn_check(BN_rshift1(x, x)); if (bsqrt_stop(x, y, &onecount)) break; } r = bmalloc(sizeof(*r)); r->scale = scale; r->number = y; BN_free(x); BN_CTX_free(ctx); push_number(r); } free_number(n); } static void not(void) { struct number *a; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } a->scale = 0; bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1)); push_number(a); } static void equal(void) { compare(BCODE_EQUAL); } static void equal_numbers(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bn_check(BN_set_word(r->number, compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0)); push_number(r); } static void less_numbers(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bn_check(BN_set_word(r->number, compare_numbers(BCODE_LESS, a, b) ? 1 : 0)); push_number(r); } static void lesseq_numbers(void) { struct number *a, *b, *r; a = pop_number(); - if (a == NULL) { + if (a == NULL) return; - } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bn_check(BN_set_word(r->number, compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0)); push_number(r); } static void not_equal(void) { compare(BCODE_NOT_EQUAL); } static void less(void) { compare(BCODE_LESS); } static void not_compare(void) { switch (readch()) { case '<': not_less(); break; case '>': not_greater(); break; case '=': not_equal(); break; default: unreadch(); bexec(readline()); break; } } static void not_less(void) { compare(BCODE_NOT_LESS); } static void greater(void) { compare(BCODE_GREATER); } static void not_greater(void) { compare(BCODE_NOT_GREATER); } static bool compare_numbers(enum bcode_compare type, struct number *a, struct number *b) { u_int scale; int cmp; scale = max(a->scale, b->scale); if (scale > a->scale) normalize(a, scale); else if (scale > b->scale) normalize(b, scale); cmp = BN_cmp(a->number, b->number); free_number(a); free_number(b); switch (type) { case BCODE_EQUAL: return (cmp == 0); case BCODE_NOT_EQUAL: return (cmp != 0); case BCODE_LESS: return (cmp < 0); case BCODE_NOT_LESS: return (cmp >= 0); case BCODE_GREATER: return (cmp > 0); case BCODE_NOT_GREATER: return (cmp <= 0); } return (false); } static void compare(enum bcode_compare type) { struct number *a, *b; struct value *v; int idx, elseidx; bool ok; elseidx = NO_ELSE; idx = readreg(); if (readch() == 'e') elseidx = readreg(); else unreadch(); a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } ok = compare_numbers(type, a, b); if (!ok && elseidx != NO_ELSE) idx = elseidx; if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) { v = stack_tos(&bmachine.reg[idx]); if (v == NULL) warnx("register '%c' (0%o) is empty", idx, idx); else { switch(v->type) { case BCODE_NONE: warnx("register '%c' (0%o) is empty", idx, idx); break; case BCODE_NUMBER: warn("eval called with non-string argument"); break; case BCODE_STRING: eval_string(bstrdup(v->u.string)); break; } } } } static void nop(void) { } static void quit(void) { if (bmachine.readsp < 2) exit(0); src_free(); bmachine.readsp--; src_free(); bmachine.readsp--; } static void quitN(void) { struct number *n; u_long i; n = pop_number(); if (n == NULL) return; i = get_ulong(n); free_number(n); if (i == BN_MASK2 || i == 0) warnx("Q command requires a number >= 1"); else if (bmachine.readsp < i) warnx("Q command argument exceeded string execution depth"); else { while (i-- > 0) { src_free(); bmachine.readsp--; } } } static void skipN(void) { struct number *n; u_long i; n = pop_number(); if (n == NULL) return; i = get_ulong(n); if (i == BN_MASK2) warnx("J command requires a number >= 0"); else if (i > 0 && bmachine.readsp < i) warnx("J command argument exceeded string execution depth"); else { while (i-- > 0) { src_free(); bmachine.readsp--; } skip_until_mark(); } } static void skip_until_mark(void) { for (;;) { switch (readch()) { case 'M': return; case EOF: errx(1, "mark not found"); return; case 'l': case 'L': case 's': case 'S': case ':': case ';': case '<': case '>': case '=': readreg(); if (readch() == 'e') readreg(); else unreadch(); break; case '[': free(read_string(&bmachine.readstack[bmachine.readsp])); break; case '!': switch (readch()) { case '<': case '>': case '=': readreg(); if (readch() == 'e') readreg(); else unreadch(); break; default: free(readline()); break; } break; default: break; } } } static void parse_number(void) { unreadch(); push_number(readnumber(&bmachine.readstack[bmachine.readsp], bmachine.ibase)); } static void unknown(void) { int ch = bmachine.readstack[bmachine.readsp].lastchar; warnx("%c (0%o) is unimplemented", ch, ch); } static void eval_string(char *p) { int ch; if (bmachine.readsp > 0) { /* Check for tail call. Do not recurse in that case. */ ch = readch(); if (ch == EOF) { src_free(); src_setstring(&bmachine.readstack[bmachine.readsp], p); return; } else unreadch(); } if (bmachine.readsp == bmachine.readstack_sz - 1) { size_t newsz = bmachine.readstack_sz * 2; struct source *stack; stack = realloc(bmachine.readstack, newsz * sizeof(struct source)); if (stack == NULL) err(1, "recursion too deep"); bmachine.readstack_sz = newsz; bmachine.readstack = stack; } src_setstring(&bmachine.readstack[++bmachine.readsp], p); } static void eval_line(void) { /* Always read from stdin */ struct source in; char *p; clearerr(stdin); src_setstream(&in, stdin); p = (*in.vtable->readline)(&in); eval_string(p); } static void eval_tos(void) { char *p; p = pop_string(); - if (p == NULL) - return; - eval_string(p); + if (p != NULL) + eval_string(p); } void eval(void) { int ch; for (;;) { ch = readch(); if (ch == EOF) { if (bmachine.readsp == 0) return; src_free(); bmachine.readsp--; continue; } #ifdef DEBUGGING fprintf(stderr, "# %c\n", ch); stack_print(stderr, &bmachine.stack, "* ", bmachine.obase); fprintf(stderr, "%zd =>\n", bmachine.readsp); #endif if (0 <= ch && ch < (signed)UCHAR_MAX) (*jump_table[ch])(); else warnx("internal error: opcode %d", ch); #ifdef DEBUGGING stack_print(stderr, &bmachine.stack, "* ", bmachine.obase); fprintf(stderr, "%zd ==\n", bmachine.readsp); #endif } } Index: stable/11/usr.bin/dc/dc.c =================================================================== --- stable/11/usr.bin/dc/dc.c (revision 315133) +++ stable/11/usr.bin/dc/dc.c (revision 315134) @@ -1,140 +1,140 @@ /* $OpenBSD: dc.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $ */ /* * Copyright (c) 2003, Otto Moerbeek * Copyright (c) 2009, Gabor Kovesdan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "extern.h" #define DC_VER "1.3-FreeBSD" static void usage(void); extern char *__progname; static struct source src; static const struct option long_options[] = { {"expression", required_argument, NULL, 'e'}, {"file", required_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'} }; static void usage(void) { fprintf(stderr, "usage: %s [-hVx] [-e expression] [file]\n", __progname); exit(1); } static void procfile(char *fname) { struct stat st; FILE *file; file = fopen(fname, "r"); if (file == NULL) err(1, "cannot open file %s", fname); if (fstat(fileno(file), &st) == -1) err(1, "%s", fname); if (S_ISDIR(st.st_mode)) { errno = EISDIR; err(1, "%s", fname); } src_setstream(&src, file); reset_bmachine(&src); eval(); fclose(file); } int main(int argc, char *argv[]) { int ch; bool extended_regs = false, preproc_done = false; /* accept and ignore a single dash to be 4.4BSD dc(1) compatible */ while ((ch = getopt_long(argc, argv, "e:f:hVx", long_options, NULL)) != -1) { switch (ch) { case 'e': if (!preproc_done) init_bmachine(extended_regs); src_setstring(&src, optarg); reset_bmachine(&src); eval(); preproc_done = true; break; case 'f': if (!preproc_done) init_bmachine(extended_regs); procfile(optarg); preproc_done = true; break; case 'x': extended_regs = true; break; case 'V': fprintf(stderr, "%s (BSD bc) %s\n", __progname, DC_VER); exit(0); break; case '-': break; case 'h': /* FALLTHROUGH */ default: usage(); } } argc -= optind; argv += optind; if (!preproc_done) init_bmachine(extended_regs); - setlinebuf(stdout); - setlinebuf(stderr); + (void)setvbuf(stdout, NULL, _IOLBF, 0); + (void)setvbuf(stderr, NULL, _IOLBF, 0); if (argc > 1) usage(); if (argc == 1) { procfile(argv[0]); preproc_done = true; } if (preproc_done) return (0); src_setstream(&src, stdin); reset_bmachine(&src); eval(); return (0); } Index: stable/11/usr.bin/dc/stack.c =================================================================== --- stable/11/usr.bin/dc/stack.c (revision 315133) +++ stable/11/usr.bin/dc/stack.c (revision 315134) @@ -1,379 +1,372 @@ /* $OpenBSD: stack.c,v 1.12 2014/11/26 15:05:51 otto Exp $ */ /* * Copyright (c) 2003, Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "extern.h" static __inline bool stack_empty(const struct stack *); static void stack_grow(struct stack *); static struct array *array_new(void); static __inline void array_free(struct array *); static struct array *array_dup(const struct array *); static __inline void array_grow(struct array *, size_t); static __inline void array_assign(struct array *, size_t, const struct value *); static __inline struct value *array_retrieve(const struct array *, size_t); void stack_init(struct stack *stack) { stack->size = 0; stack->sp = -1; stack->stack = NULL; } static __inline bool stack_empty(const struct stack *stack) { bool empty = stack->sp == -1; if (empty) warnx("stack empty"); return empty; } /* Clear number or string, but leave value itself */ void stack_free_value(struct value *v) { switch (v->type) { case BCODE_NONE: break; case BCODE_NUMBER: free_number(v->u.num); break; case BCODE_STRING: free(v->u.string); break; } - if (v->array != NULL) { - array_free(v->array); - v->array = NULL; - } + array_free(v->array); + v->array = NULL; } /* Copy number or string content into already allocated target */ struct value * stack_dup_value(const struct value *a, struct value *copy) { copy->type = a->type; switch (a->type) { case BCODE_NONE: break; case BCODE_NUMBER: copy->u.num = dup_number(a->u.num); break; case BCODE_STRING: copy->u.string = strdup(a->u.string); if (copy->u.string == NULL) err(1, NULL); break; } copy->array = a->array == NULL ? NULL : array_dup(a->array); return (copy); } size_t stack_size(const struct stack *stack) { return (stack->sp + 1); } void stack_dup(struct stack *stack) { struct value *value; struct value copy; value = stack_tos(stack); if (value == NULL) { warnx("stack empty"); return; } stack_push(stack, stack_dup_value(value, ©)); } void stack_swap(struct stack *stack) { struct value copy; if (stack->sp < 1) { warnx("stack empty"); return; } copy = stack->stack[stack->sp]; stack->stack[stack->sp] = stack->stack[stack->sp-1]; stack->stack[stack->sp-1] = copy; } static void stack_grow(struct stack *stack) { size_t new_size; if (++stack->sp == stack->size) { new_size = stack->size * 2 + 1; stack->stack = brealloc(stack->stack, new_size * sizeof(*stack->stack)); stack->size = new_size; } } void stack_pushnumber(struct stack *stack, struct number *b) { stack_grow(stack); stack->stack[stack->sp].type = BCODE_NUMBER; stack->stack[stack->sp].u.num = b; stack->stack[stack->sp].array = NULL; } void stack_pushstring(struct stack *stack, char *string) { stack_grow(stack); stack->stack[stack->sp].type = BCODE_STRING; stack->stack[stack->sp].u.string = string; stack->stack[stack->sp].array = NULL; } void stack_push(struct stack *stack, struct value *v) { switch (v->type) { case BCODE_NONE: stack_grow(stack); stack->stack[stack->sp].type = BCODE_NONE; break; case BCODE_NUMBER: stack_pushnumber(stack, v->u.num); break; case BCODE_STRING: stack_pushstring(stack, v->u.string); break; } stack->stack[stack->sp].array = v->array == NULL ? NULL : array_dup(v->array); } struct value * stack_tos(const struct stack *stack) { if (stack->sp == -1) return (NULL); return &stack->stack[stack->sp]; } void stack_set_tos(struct stack *stack, struct value *v) { if (stack->sp == -1) stack_push(stack, v); else { stack_free_value(&stack->stack[stack->sp]); stack->stack[stack->sp] = *v; stack->stack[stack->sp].array = v->array == NULL ? NULL : array_dup(v->array); } } struct value * stack_pop(struct stack *stack) { if (stack_empty(stack)) return (NULL); return &stack->stack[stack->sp--]; } struct number * stack_popnumber(struct stack *stack) { if (stack_empty(stack)) return (NULL); - if (stack->stack[stack->sp].array != NULL) { - array_free(stack->stack[stack->sp].array); - stack->stack[stack->sp].array = NULL; - } + array_free(stack->stack[stack->sp].array); + stack->stack[stack->sp].array = NULL; if (stack->stack[stack->sp].type != BCODE_NUMBER) { warnx("not a number"); /* XXX remove */ return (NULL); } return stack->stack[stack->sp--].u.num; } char * stack_popstring(struct stack *stack) { if (stack_empty(stack)) return (NULL); - if (stack->stack[stack->sp].array != NULL) { - array_free(stack->stack[stack->sp].array); - stack->stack[stack->sp].array = NULL; - } + array_free(stack->stack[stack->sp].array); + stack->stack[stack->sp].array = NULL; if (stack->stack[stack->sp].type != BCODE_STRING) { warnx("not a string"); /* XXX remove */ return (NULL); } return stack->stack[stack->sp--].u.string; } void stack_clear(struct stack *stack) { - while (stack->sp >= 0) { + while (stack->sp >= 0) stack_free_value(&stack->stack[stack->sp--]); - } free(stack->stack); stack_init(stack); } void stack_print(FILE *f, const struct stack *stack, const char *prefix, u_int base) { ssize_t i; for (i = stack->sp; i >= 0; i--) { print_value(f, &stack->stack[i], prefix, base); putc('\n', f); } } static struct array * array_new(void) { struct array *a; a = bmalloc(sizeof(*a)); a->data = NULL; a->size = 0; return a; } static __inline void array_free(struct array *a) { size_t i; if (a == NULL) return; for (i = 0; i < a->size; i++) stack_free_value(&a->data[i]); free(a->data); free(a); } static struct array * array_dup(const struct array *a) { struct array *n; size_t i; if (a == NULL) return (NULL); n = array_new(); array_grow(n, a->size); for (i = 0; i < a->size; i++) stack_dup_value(&a->data[i], &n->data[i]); return (n); } static __inline void array_grow(struct array *array, size_t newsize) { size_t i; array->data = brealloc(array->data, newsize * sizeof(*array->data)); for (i = array->size; i < newsize; i++) { array->data[i].type = BCODE_NONE; array->data[i].array = NULL; } array->size = newsize; } static __inline void array_assign(struct array *array, size_t i, const struct value *v) { if (i >= array->size) array_grow(array, i + 1); stack_free_value(&array->data[i]); array->data[i] = *v; } static __inline struct value * array_retrieve(const struct array *array, size_t i) { if (i >= array->size) return (NULL); return &array->data[i]; } void frame_assign(struct stack *stack, size_t i, const struct value *v) { struct array *a; struct value n; if (stack->sp == -1) { n.type = BCODE_NONE; n.array = NULL; stack_push(stack, &n); } a = stack->stack[stack->sp].array; if (a == NULL) a = stack->stack[stack->sp].array = array_new(); array_assign(a, i, v); } struct value * frame_retrieve(const struct stack *stack, size_t i) { struct array *a; if (stack->sp == -1) return (NULL); a = stack->stack[stack->sp].array; if (a == NULL) a = stack->stack[stack->sp].array = array_new(); return array_retrieve(a, i); } Index: stable/11 =================================================================== --- stable/11 (revision 315133) +++ stable/11 (revision 315134) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r314321