Page MenuHomeFreeBSD

D13336.id.diff
No OneTemporary

D13336.id.diff

Index: head/etc/mtree/BSD.tests.dist
===================================================================
--- head/etc/mtree/BSD.tests.dist
+++ head/etc/mtree/BSD.tests.dist
@@ -654,6 +654,8 @@
..
cut
..
+ dc
+ ..
diff
..
dirname
Index: head/usr.bin/dc/Makefile
===================================================================
--- head/usr.bin/dc/Makefile
+++ head/usr.bin/dc/Makefile
@@ -1,8 +1,13 @@
# $FreeBSD$
# $OpenBSD: Makefile,v 1.2 2006/11/26 11:31:09 deraadt Exp $
+.include <src.opts.mk>
+
PROG= dc
SRCS= dc.c bcode.c inout.c mem.c stack.c
LIBADD= crypto
+
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
.include <bsd.prog.mk>
Index: head/usr.bin/dc/bcode.h
===================================================================
--- head/usr.bin/dc/bcode.h
+++ head/usr.bin/dc/bcode.h
@@ -95,3 +95,10 @@
void split_number(const struct number *, BIGNUM *, BIGNUM *);
void bmul_number(struct number *, struct number *,
struct number *, u_int scale);
+
+static __inline u_int
+max(u_int a, u_int b)
+{
+
+ return (a > b ? a : b);
+}
Index: head/usr.bin/dc/bcode.c
===================================================================
--- head/usr.bin/dc/bcode.c
+++ head/usr.bin/dc/bcode.c
@@ -58,7 +58,6 @@
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 *);
@@ -326,18 +325,12 @@
#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
};
+/* Multiply n by 10^s */
void
scale_number(BIGNUM *n, int s)
{
@@ -411,6 +404,7 @@
}
}
+/* Change the scale of n to s. Reducing scale may truncate the mantissa */
void
normalize(struct number *n, u_int s)
{
@@ -1067,8 +1061,6 @@
bdiv(void)
{
struct number *a, *b, *r;
- BN_CTX *ctx;
- u_int scale;
a = pop_number();
if (a == NULL)
@@ -1079,21 +1071,8 @@
return;
}
- r = new_number();
- r->scale = bmachine.scale;
- scale = max(a->scale, b->scale);
+ r = div_number(b, a, bmachine.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);
@@ -1681,7 +1660,7 @@
unreadch();
push_number(readnumber(&bmachine.readstack[bmachine.readsp],
- bmachine.ibase));
+ bmachine.ibase, bmachine.scale));
}
static void
Index: head/usr.bin/dc/extern.h
===================================================================
--- head/usr.bin/dc/extern.h
+++ head/usr.bin/dc/extern.h
@@ -24,7 +24,7 @@
/* inout.c */
void src_setstream(struct source *, FILE *);
void src_setstring(struct source *, char *);
-struct number *readnumber(struct source *, u_int);
+struct number *readnumber(struct source *, u_int, u_int);
void printnumber(FILE *, const struct number *, u_int);
char *read_string(struct source *);
void print_value(FILE *, const struct value *, const char *, u_int);
@@ -33,6 +33,7 @@
/* mem.c */
struct number *new_number(void);
void free_number(struct number *);
+struct number *div_number(struct number *, struct number *, u_int scale);
struct number *dup_number(const struct number *);
void *bmalloc(size_t);
void *breallocarray(void *, size_t, size_t);
Index: head/usr.bin/dc/inout.c
===================================================================
--- head/usr.bin/dc/inout.c
+++ head/usr.bin/dc/inout.c
@@ -183,12 +183,12 @@
}
struct number *
-readnumber(struct source *src, u_int base)
+readnumber(struct source *src, u_int base, u_int bscale)
{
struct number *n;
BN_ULONG v;
- u_int i;
int ch;
+ u_int iscale = 0;
bool dot = false, sign = false;
n = new_number();
@@ -213,15 +213,48 @@
break;
}
if (dot)
- n->scale++;
+ iscale++;
bn_check(BN_mul_word(n->number, base));
bn_check(BN_add_word(n->number, v));
}
- if (base != 10) {
- scale_number(n->number, n->scale);
- for (i = 0; i < n->scale; i++)
- BN_div_word(n->number, base);
+ if (base == 10) {
+ n->scale = iscale;
+ } else {
+ /* At this point, the desired result is n->number / base^iscale*/
+ struct number *quotient, *divisor, *_n;
+ BIGNUM *base_n, *exponent;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ base_n = BN_new();
+ exponent = BN_new();
+ divisor = new_number();
+ bn_check(BN_zero(base_n));
+ bn_check(BN_zero(exponent));
+
+ bn_check(BN_add_word(base_n, base));
+ bn_check(BN_add_word(exponent, iscale));
+ bn_check(BN_exp(divisor->number, base_n, exponent, ctx));
+ divisor->scale = 0;
+ quotient = div_number(n, divisor, bscale);
+ _n = n;
+ n = quotient;
+
+ /*
+ * Trim off trailing zeros to yield the smallest scale without
+ * loss of accuracy
+ */
+ while ( n->scale > 0 &&
+ BN_mod_word(n->number, 10) == 0) {
+ normalize(n, n->scale - 1);
+ }
+
+ free_number(_n);
+ free_number(divisor);
+ BN_CTX_free(ctx);
+ BN_free(base_n);
+ BN_free(exponent);
}
if (sign)
negate(n);
Index: head/usr.bin/dc/mem.c
===================================================================
--- head/usr.bin/dc/mem.c
+++ head/usr.bin/dc/mem.c
@@ -22,6 +22,7 @@
#include <openssl/err.h>
#include <err.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -46,6 +47,37 @@
BN_free(n->number);
free(n);
+}
+
+/*
+ * Divide dividend by divisor, returning the result. Retain bscale places of
+ * precision.
+ * The result must be freed when no longer in use
+ */
+struct number *
+div_number(struct number *dividend, struct number *divisor, u_int bscale)
+{
+ struct number *quotient;
+ BN_CTX *ctx;
+ u_int scale;
+
+ quotient = new_number();
+ quotient->scale = bscale;
+ scale = max(divisor->scale, dividend->scale);
+
+ if (BN_is_zero(divisor->number))
+ warnx("divide by zero");
+ else {
+ normalize(divisor, scale);
+ normalize(dividend, scale + quotient->scale);
+
+ ctx = BN_CTX_new();
+ bn_checkp(ctx);
+ bn_check(BN_div(quotient->number, NULL, dividend->number,
+ divisor->number, ctx));
+ BN_CTX_free(ctx);
+ }
+ return (quotient);
}
struct number *
Index: head/usr.bin/dc/tests/Makefile
===================================================================
--- head/usr.bin/dc/tests/Makefile
+++ head/usr.bin/dc/tests/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+ATF_TESTS_SH= inout
+
+.include <bsd.test.mk>
Index: head/usr.bin/dc/tests/inout.sh
===================================================================
--- head/usr.bin/dc/tests/inout.sh
+++ head/usr.bin/dc/tests/inout.sh
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2017 Alan Somers
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+atf_test_case base16_input
+base16_input_head()
+{
+ atf_set "descr" "Input hexadecimal numbers"
+}
+base16_input_body()
+{
+ cat > input.dc << EOF
+4k # set scale to 4 decimal places
+16i # switch to base 16
+0 p
+10 p
+1 p
+1. p # The '.' should have no effect
+1.0 p # Unlike with decimal, should not change the result's scale
+.8 p # Can input fractions
+# Check that we can input fractions that need more scale in base 10 than in 16
+# See PR 206230
+.1 p
+.10 p # Result should be .0625, with scale=4
+.01 p # Result should be truncated to scale=4
+8k # Increase scale to 8 places
+.01 p # Result should be exact again
+0.1 p # Leading zeros are ignored
+00.1 p # Leading zeros are ignored
+EOF
+dc input.dc > output.txt
+cat > expect.txt << EOF
+0
+16
+1
+1
+1
+.5
+.0625
+.0625
+.0039
+.00390625
+.0625
+.0625
+EOF
+ atf_check cmp expect.txt output.txt
+}
+
+atf_test_case base3_input
+base3_input_head()
+{
+ atf_set "descr" "Input ternary numbers"
+}
+base3_input_body()
+{
+ cat > input.dc << EOF
+4k # 4 digits of precision
+3i # Base 3 input
+0 p
+1 p
+10 p
+.1 p # Repeating fractions get truncated
+EOF
+dc input.dc > output.txt
+cat > expect.txt << EOF
+0
+1
+3
+.3333
+EOF
+ atf_check cmp expect.txt output.txt
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case base16_input
+ atf_add_test_case base3_input
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 25, 6:02 PM (2 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32136433
Default Alt Text
D13336.id.diff (9 KB)

Event Timeline