usr.bin/bc: remove OpenBSD derived bc and dc commands
Some checks are pending
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, arm64, aarch64) (push) Waiting to run

In 2020, an improved implementation of the bc and dc commands
developed by Gavin D. Howard has been imported into FreeBSD.
It has replaced the OpenBSD-derived versions of these commands
in all currently supported FreeBSD releases.

The OpenBSD versions could still be built using the WITHOUT_GH_BC
option. There have been no reports of problems or unexpected
deviations from the OpenBSD version for some time, therefore
keeping the OpenBSD version is no longer required in FreeBSD.

This commit removes the option to build the OpenBSD version and
corresponding source files from -CURRENT. No MFC is planned, all
currently released FreeBSD versions should retain the build option.

The WITHOUT_GH_BC option is no longer accepted and will cause
make buildworld to fail.

Reviewed by:	des, emaste
Approved by:	des
Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D46876
This commit is contained in:
Stefan Eßer 2024-11-24 22:38:23 +01:00
parent e80419da6c
commit 8ea6c11540
29 changed files with 12 additions and 6335 deletions

View File

@ -51,6 +51,13 @@
# xargs -n1 | sort | uniq -d; # xargs -n1 | sort | uniq -d;
# done # done
# 20241124: library and tests of OpenBSD dc
OLD_FILES+=usr/share/misc/bc.library
OLD_FILES+=usr/tests/usr.bin/dc/Kyuafile
OLD_FILES+=usr/tests/usr.bin/dc/bcode
OLD_FILES+=usr/tests/usr.bin/dc/inout
OLD_DIRS+=usr/tests/usr.bin/dc
# 20241119: rewrite mv tests # 20241119: rewrite mv tests
OLD_FILES+=usr/tests/bin/mv/legacy_test OLD_FILES+=usr/tests/bin/mv/legacy_test

View File

@ -27,6 +27,11 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
world, or to merely disable the most expensive debugging functionality world, or to merely disable the most expensive debugging functionality
at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20241124:
The OpenBSD derived bc and dc implementations and the WITHOUT_GH_BC
option that allowed building them instead of the advanced version
imported more than 4 years ago have been removed.
20241025: 20241025:
The support for the rc_fast_and_loose variable has been removed from The support for the rc_fast_and_loose variable has been removed from
rc.subr(8). Users setting rc_fast_and_loose on their systems are rc.subr(8). Users setting rc_fast_and_loose on their systems are

View File

@ -712,12 +712,6 @@ and
.Xr ftpd 8 . .Xr ftpd 8 .
.It Va WITHOUT_GAMES .It Va WITHOUT_GAMES
Do not build games. Do not build games.
.It Va WITHOUT_GH_BC
Install the traditional FreeBSD
.Xr bc 1
and
.Xr dc 1
programs instead of the enhanced versions.
.It Va WITHOUT_GNU_DIFF .It Va WITHOUT_GNU_DIFF
Do not build GNU Do not build GNU
.Xr diff3 1 ; .Xr diff3 1 ;

View File

@ -101,7 +101,6 @@ __DEFAULT_YES_OPTIONS = \
FREEBSD_UPDATE \ FREEBSD_UPDATE \
FTP \ FTP \
GAMES \ GAMES \
GH_BC \
GNU_DIFF \ GNU_DIFF \
GOOGLETEST \ GOOGLETEST \
GPIO \ GPIO \

View File

@ -2071,14 +2071,6 @@ OLD_FILES+=usr/share/man/man8/strfile.8.gz
OLD_FILES+=usr/share/man/man8/unstr.8.gz OLD_FILES+=usr/share/man/man8/unstr.8.gz
.endif .endif
.if ${MK_GH_BC} == no
OLD_FILES+=usr/share/misc/bc.library
OLD_FILES+=usr/tests/usr.bin/dc/Kyuafile
OLD_FILES+=usr/tests/usr.bin/dc/bcode
OLD_FILES+=usr/tests/usr.bin/dc/inout
OLD_DIRS+=usr/tests/usr.bin/dc
.endif
.if ${MK_GOOGLETEST} == no .if ${MK_GOOGLETEST} == no
OLD_FILES+=usr/include/private/gmock/gmock-actions.h OLD_FILES+=usr/include/private/gmock/gmock-actions.h
OLD_FILES+=usr/include/private/gmock/gmock-cardinalities.h OLD_FILES+=usr/include/private/gmock/gmock-cardinalities.h

View File

@ -1,5 +0,0 @@
Install the traditional FreeBSD
.Xr bc 1
and
.Xr dc 1
programs instead of the enhanced versions.

View File

@ -207,12 +207,7 @@ SUBDIR.${MK_GAMES}+= number
SUBDIR.${MK_GAMES}+= pom SUBDIR.${MK_GAMES}+= pom
SUBDIR.${MK_GAMES}+= primes SUBDIR.${MK_GAMES}+= primes
SUBDIR.${MK_GAMES}+= random SUBDIR.${MK_GAMES}+= random
.if ${MK_GH_BC} == "yes"
SUBDIR+= gh-bc SUBDIR+= gh-bc
.else
SUBDIR.${MK_OPENSSL}+= bc
SUBDIR.${MK_OPENSSL}+= dc
.endif
.if ${MK_GNU_DIFF} == "no" .if ${MK_GNU_DIFF} == "no"
SUBDIR+= diff3 SUBDIR+= diff3
.endif .endif

View File

@ -1,14 +0,0 @@
# $OpenBSD: Makefile,v 1.7 2013/09/19 16:12:00 otto Exp $
PROG= bc
SRCS= bc.y scan.l tty.c
CFLAGS+= -I. -I${.CURDIR}
LIBADD= edit
NO_WMISSING_VARIABLE_DECLARATIONS=
FILES+= bc.library
FILESDIR=${SHAREDIR}/misc
.include <bsd.prog.mk>

View File

@ -1,17 +0,0 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
lib/libedit \
usr.bin/yacc.host \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View File

@ -1,413 +0,0 @@
.\" $OpenBSD: bc.1,v 1.32 2015/11/17 05:45:35 mmcc Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002.
.\" 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 and documentation 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed or owned by Caldera
.\" International, Inc.
.\" 4. Neither the name of Caldera International, Inc. nor the names of other
.\" contributors may be used to endorse or promote products derived from
.\" this software without specific prior written permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
.\"
.Dd November 21, 2015
.Dt BC 1
.Os
.Sh NAME
.Nm bc
.Nd arbitrary-precision arithmetic language and calculator
.Sh SYNOPSIS
.Nm bc
.Op Fl chlv
.Op Fl e Ar expression
.Op Ar file ...
.Sh DESCRIPTION
.Nm
is an interactive processor for a language which resembles
C but provides unlimited precision arithmetic.
It takes input from any expressions on the command line and
any files given, then reads the standard input.
.Pp
Options available:
.Bl -tag -width Ds
.It Fl c
.Nm
is actually a preprocessor for
.Xr dc 1 ,
which it invokes automatically, unless the
.Fl c
.Pq compile only
option is present.
In this case the generated
.Xr dc 1
instructions are sent to the standard output,
instead of being interpreted by a running
.Xr dc 1
process.
.It Fl e Ar expression , Fl Fl expression Ar expression
Evaluate
.Ar expression .
If multiple
.Fl e
options are specified, they are processed in the order given,
separated by newlines.
.It Fl h , Fl Fl help
Prints usage information.
.It Fl l , Fl Fl mathlib
Allow specification of an arbitrary precision math library.
The definitions in the library are available to command line
expressions.
.It Fl v , Fl Fl version
Prints version information.
.El
.Pp
The syntax for
.Nm
programs is as follows:
.Sq L
means letter a-z;
.Sq E
means expression;
.Sq S
means statement.
As a non-portable extension, it is possible to use long names
in addition to single letter names.
A long name is a sequence starting with a lowercase letter
followed by any number of lowercase letters and digits.
The underscore character
.Pq Sq _
counts as a letter.
.Pp
Comments
.Bd -unfilled -offset indent -compact
are enclosed in /* and */
are enclosed in # and the next newline
.Ed
.Pp
The newline is not part of the line comment,
which in itself is a non-portable extension.
.Pp
Names
.Bd -unfilled -offset indent -compact
simple variables: L
array elements: L [ E ]
The words `ibase', `obase', and `scale'
The word `last' or a single dot
.Ed
.Pp
Other operands
.Bd -unfilled -offset indent -compact
arbitrarily long numbers with optional sign and decimal point
( E )
sqrt ( E )
length ( E ) number of significant decimal digits
scale ( E ) number of digits right of decimal point
L ( E , ... , E )
.Ed
.Pp
The sequence
.Sq \e<newline><whitespace>
is ignored within numbers.
.Pp
Operators
.Pp
The following arithmetic and logical operators can be used.
The semantics of the operators is the same as in the C language.
They are listed in order of decreasing precedence.
Operators in the same group have the same precedence.
.Bl -column "= += \-= *= /= %= ^=" "Associativity" "multiply, divide, modulus" -offset indent
.It Sy "Operator" Ta Sy "Associativity" Ta Sy "Description"
.It "++ \-\-" Ta "none" Ta "increment, decrement"
.It "\-" Ta "none" Ta "unary minus"
.It "^" Ta "right" Ta "power"
.It "* / %" Ta "left" Ta "multiply, divide, modulus"
.It "+ \-" Ta "left" Ta "plus, minus"
.It "= += -= *= /= %= ^=" Ta "right" Ta "assignment"
.It "== <= >= != < >" Ta "none" Ta "relational"
.It "!" Ta "none" Ta "boolean not"
.It "&&" Ta "left" Ta "boolean and"
.It "||" Ta "left" Ta "boolean or"
.El
.Pp
Note the following:
.Bl -bullet -offset indent
.It
The relational operators may appear in any expression.
The
.St -p1003.1-2008
standard only allows them in the conditional expression of an
.Sq if ,
.Sq while
or
.Sq for
statement.
.It
The relational operators have a lower precedence than the assignment
operators.
This has the consequence that the expression
.Sy a = b < c
is interpreted as
.Sy (a = b) < c ,
which is probably not what the programmer intended.
.It
In contrast with the C language, the relational operators all have
the same precedence, and are non-associative.
The expression
.Sy a < b < c
will produce a syntax error.
.It
The boolean operators (!, && and ||) are non-portable extensions.
.It
The boolean not
(!) operator has much lower precedence than the same operator in the
C language.
This has the consequence that the expression
.Sy !a < b
is interpreted as
.Sy !(a < b) .
Prudent programmers use parentheses when writing expressions involving
boolean operators.
.El
.Pp
Statements
.Bd -unfilled -offset indent -compact
E
{ S ; ... ; S }
if ( E ) S
if ( E ) S else S
while ( E ) S
for ( E ; E ; E ) S
null statement
break
continue
quit
a string of characters, enclosed in double quotes
print E ,..., E
.Ed
.Pp
A string may contain any character, except double quote.
The if statement with an else branch is a non-portable extension.
All three E's in a for statement may be empty.
This is a non-portable extension.
The continue and print statements are also non-portable extensions.
.Pp
The print statement takes a list of comma-separated expressions.
Each expression in the list is evaluated and the computed
value is printed and assigned to the variable `last'.
No trailing newline is printed.
The expression may also be a string enclosed in double quotes.
Within these strings the following escape sequences may be used:
.Sq \ea
for bell (alert),
.Sq \eb
for backspace,
.Sq \ef
for formfeed,
.Sq \en
for newline,
.Sq \er
for carriage return,
.Sq \et
for tab,
.Sq \eq
for double quote and
.Sq \e\e
for backslash.
Any other character following a backslash will be ignored.
Strings will not be assigned to `last'.
.Pp
Function definitions
.Bd -unfilled -offset indent
define L ( L ,..., L ) {
auto L, ... , L
S; ... S
return ( E )
}
.Ed
.Pp
As a non-portable extension, the opening brace of the define statement
may appear on the next line.
The return statement may also appear in the following forms:
.Bd -unfilled -offset indent
return
return ()
return E
.Ed
.Pp
The first two are equivalent to the statement
.Dq return 0 .
The last form is a non-portable extension.
Not specifying a return statement is equivalent to writing
.Dq return (0) .
.Pp
Functions available in the math library, which is loaded by specifying the
.Fl l
flag on the command line
.Pp
.Bl -tag -width j(n,x) -offset indent -compact
.It s(x)
sine
.It c(x)
cosine
.It e(x)
exponential
.It l(x)
log
.It a(x)
arctangent
.It j(n,x)
Bessel function
.El
.Pp
All function arguments are passed by value.
.Pp
The value of a statement that is an expression is printed
unless the main operator is an assignment.
The value printed is assigned to the special variable `last'.
This is a non-portable extension.
A single dot may be used as a synonym for `last'.
Either semicolons or newlines may separate statements.
Assignment to
.Ar scale
influences the number of digits to be retained on arithmetic
operations in the manner of
.Xr dc 1 .
Assignments to
.Ar ibase
or
.Ar obase
set the input and output number radix respectively.
.Pp
The same letter may be used as an array, a function,
and a simple variable simultaneously.
All variables are global to the program.
`Auto' variables are pushed down during function calls.
When using arrays as function arguments
or defining them as automatic variables,
empty square brackets must follow the array name.
.Pp
For example
.Bd -literal -offset indent
scale = 20
define e(x){
auto a, b, c, i, s
a = 1
b = 1
s = 1
for(i=1; 1==1; i++){
a = a*x
b = b*i
c = a/b
if(c == 0) return(s)
s = s+c
}
}
.Ed
.Pp
defines a function to compute an approximate value of
the exponential function and
.Pp
.Dl for(i=1; i<=10; i++) e(i)
.Pp
prints approximate values of the exponential function of
the first ten integers.
.Bd -literal -offset indent
$ bc -l -e 'scale = 500; 2 * a(2^10000)' -e quit
.Ed
.Pp
prints an approximation of pi.
.Sh COMMAND LINE EDITING
.Nm
supports interactive command line editing, via the
.Xr editline 3
library.
It is enabled by default if input is from a tty.
Previous lines can be recalled and edited with the arrow keys,
and other GNU Emacs-style editing keys may be used as well.
.Pp
The
.Xr editline 3
library is configured with a
.Pa .editrc
file \- refer to
.Xr editrc 5
for more information.
.Sh FILES
.Bl -tag -width /usr/share/misc/bc.library -compact
.It Pa /usr/share/misc/bc.library
math library, read when the
.Fl l
option is specified on the command line.
.El
.Sh COMPATIBILITY
The
.Fl q
and
.Fl Fl quiet
options are no-ops for compatibility with some other implementations of
.Nm
and their use is discouraged.
.Sh SEE ALSO
.Xr dc 1
.Sh STANDARDS
The
.Nm
utility is compliant with the
.St -p1003.1-2008
specification.
.Pp
The flags
.Op Fl ce ,
as well as the parts noted above,
are extensions to that specification.
.Sh HISTORY
The
.Nm
command first appeared in
.At v6 .
A complete rewrite of the
.Nm
command first appeared in
.Ox 3.5 .
.Sh AUTHORS
.An -nosplit
The original version of the
.Nm
command was written by
.An Robert Morris
and
.An Lorinda Cherry .
The current version of the
.Nm
utility was written by
.An Otto Moerbeek .
.Sh BUGS
The
.Ql quit
statement is interpreted when read, not when executed.
.Pp
Some non-portable extensions, as found in the GNU version of the
.Nm
utility are not implemented (yet).

View File

@ -1,272 +0,0 @@
/* $OpenBSD: bc.library,v 1.4 2012/03/14 07:35:53 otto Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
* 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 and documentation 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed or owned by Caldera
* International, Inc.
* 4. Neither the name of Caldera International, Inc. nor the names of other
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
* INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
*/
/*
*/
scale = 20
define e(x) {
auto a, b, c, d, e, g, t, w, y, r
r = ibase
ibase = A
t = scale
scale = 0
if (x > 0) scale = (0.435*x)/1
scale = scale + t + length(scale + t) + 1
w = 0
if (x < 0) {
x = -x
w = 1
}
y = 0
while (x > 2) {
x = x/2
y = y + 1
}
a = 1
b = 1
c = b
d = 1
e = 1
for (a = 1; 1 == 1; a++) {
b = b*x
c = c*a + b
d = d*a
g = c/d
if (g == e) {
g = g/1
while (y--) {
g = g*g
}
scale = t
ibase = r
if (w == 1) return (1/g)
return (g/1)
}
e = g
}
}
define l(x) {
auto a, b, c, d, e, f, g, u, s, t, r
r = ibase
ibase = A
if (x <= 0) {
a = (1 - 10^scale)
ibase = r
return (a)
}
t = scale
f = 1
if (x < 1) {
s = scale(x)
} else {
s = length(x)-scale(x)
}
scale = 0
a = (2.31*s)/1 /* estimated integer part of the answer */
s = t + length(a) + 2 /* estimated length of the answer */
while (x > 2) {
scale = 0
scale = (length(x) + scale(x))/2 + 1
if (scale < s) scale = s
x = sqrt(x)
f = f*2
}
while (x < .5) {
scale = 0
scale = scale(x)/2 + 1
if (scale < s) scale = s
x = sqrt(x)
f = f*2
}
scale = 0
scale = t + length(f) + length((1.05*(t+length(f))/1)) + 1
u = (x - 1)/(x + 1)
s = u*u
scale = t + 2
b = 2*f
c = b
d = 1
e = 1
for (a = 3; 1 == 1 ; a = a + 2) {
b = b*s
c = c*a + d*b
d = d*a
g = c/d
if (g == e) {
scale = t
ibase = r
return (u*c/d)
}
e = g
}
}
define s(x) {
auto a, b, c, s, t, y, p, n, i, r
r = ibase
ibase = A
t = scale
y = x/.7853
s = t + length(y) - scale(y)
if (s < t) s = t
scale = s
p = a(1)
scale = 0
if (x >= 0) n = (x/(2*p) + 1)/2
if (x < 0) n = (x/(2*p) - 1)/2
x = x - 4*n*p
if (n % 2 != 0) x = -x
scale = t + length(1.2*t) - scale(1.2*t)
y = -x*x
a = x
b = 1
s = x
for (i =3 ; 1 == 1; i = i + 2) {
a = a*y
b = b*i*(i - 1)
c = a/b
if (c == 0) {
scale = t
ibase = r
return (s/1)
}
s = s + c
}
}
define c(x) {
auto t, r
r = ibase
ibase = A
t = scale
scale = scale + 1
x = s(x + 2*a(1))
scale = t
ibase = r
return (x/1)
}
define a(x) {
auto a, b, c, d, e, f, g, s, t, r
if (x == 0) return(0)
r = ibase
ibase = A
if (x == 1) {
if (scale < 52) {
a = .7853981633974483096156608458198757210492923498437764/1
ibase = r
return (a)
}
}
t = scale
f = 1
while (x > .5) {
scale = scale + 1
x = -(1 - sqrt(1. + x*x))/x
f = f*2
}
while (x < -.5) {
scale = scale + 1
x = -(1 - sqrt(1. + x*x))/x
f = f*2
}
s = -x*x
b = f
c = f
d = 1
e = 1
for (a = 3; 1 == 1; a = a + 2) {
b = b*s
c = c*a + d*b
d = d*a
g = c/d
if (g == e) {
ibase = r
scale = t
return (x*c/d)
}
e = g
}
}
define j(n,x) {
auto a, b, c, d, e, g, i, s, k, t, r
r = ibase
ibase = A
t = scale
k = 1.36*x + 1.16*t - n
k = length(k) - scale(k)
if (k > 0) scale = scale + k
s = -x*x/4
if (n < 0) {
n = -n
x = -x
}
a = 1
c = 1
for (i = 1; i <= n; i++) {
a = a*x
c = c*2*i
}
b = a
d = 1
e = 1
for (i = 1; 1; i++) {
a = a*s
b = b*i*(n + i) + a
c = c*i*(n + i)
g = b/c
if (g == e) {
ibase = r
scale = t
return (g/1)
}
e = g
}
}
/* vim: set filetype=bc shiftwidth=8 noexpandtab: */

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
/* $OpenBSD: extern.h,v 1.12 2014/04/17 19:07:14 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <stdbool.h>
#include <stdio.h>
struct lvalue {
ssize_t load;
ssize_t store;
};
int yylex(void);
void yyerror(const char *);
void fatal(const char *);
void abort_line(int);
struct termios;
int gettty(struct termios *);
void tstpcont(int);
unsigned char bc_eof(EditLine *, int);
extern int lineno;
extern int fileindex;
extern int sargc;
extern const char **sargv;
extern const char *filename;
extern bool interactive;
extern EditLine *el;
extern History *hist;
extern HistEvent he;
extern char *cmdexpr;
extern struct termios ttysaved;

View File

@ -1,20 +0,0 @@
/* $OpenBSD: pathnames.h,v 1.1 2003/09/25 19:32:44 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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.
*/
#define _PATH_LIBB "/usr/share/misc/bc.library"
#define _PATH_DC "/usr/bin/dc"

View File

@ -1,368 +0,0 @@
%{
/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/cdefs.h>
#include <err.h>
#include <errno.h>
#include <histedit.h>
#include <stdbool.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#include "bc.h"
#include "pathnames.h"
int lineno;
bool interactive;
HistEvent he;
EditLine *el;
History *hist;
static char *strbuf = NULL;
static size_t strbuf_sz = 1;
static bool dot_seen;
static int use_el;
static volatile sig_atomic_t skipchars;
static void init_strbuf(void);
static void add_str(const char *);
static int bc_yyinput(char *, int);
#define YY_DECL int yylex(void)
#define YY_NO_INPUT
#undef YY_INPUT
#define YY_INPUT(buf,retval,max) \
(retval = bc_yyinput(buf, max))
%}
%option always-interactive
DIGIT [0-9A-F]
ALPHA [a-z_]
ALPHANUM [a-z_0-9]
%x comment string number
%%
"/*" BEGIN(comment);
<comment>{
"*/" BEGIN(INITIAL);
\n lineno++;
\* ;
[^*\n]+ ;
<<EOF>> fatal("end of file in comment");
}
\" BEGIN(string); init_strbuf();
<string>{
[^"\n\\\[\]]+ add_str(yytext);
\[ add_str("\\[");
\] add_str("\\]");
\\ add_str("\\\\");
\n add_str("\n"); lineno++;
\" BEGIN(INITIAL); yylval.str = strbuf; return STRING;
<<EOF>> fatal("end of file in string");
}
{DIGIT}+ {
BEGIN(number);
dot_seen = false;
init_strbuf();
add_str(yytext);
}
\. {
BEGIN(number);
dot_seen = true;
init_strbuf();
add_str(".");
}
<number>{
{DIGIT}+ add_str(yytext);
\. {
if (dot_seen) {
BEGIN(INITIAL);
yylval.str = strbuf;
unput('.');
return NUMBER;
} else {
dot_seen = true;
add_str(".");
}
}
\\\n[ \t]* lineno++;
[^0-9A-F\.] {
BEGIN(INITIAL);
unput(yytext[0]);
if (strcmp(strbuf, ".") == 0)
return DOT;
else {
yylval.str = strbuf;
return NUMBER;
}
}
}
"auto" return AUTO;
"break" return BREAK;
"continue" return CONTINUE;
"define" return DEFINE;
"else" return ELSE;
"ibase" return IBASE;
"if" return IF;
"last" return DOT;
"for" return FOR;
"length" return LENGTH;
"obase" return OBASE;
"print" return PRINT;
"quit" return QUIT;
"return" return RETURN;
"scale" return SCALE;
"sqrt" return SQRT;
"while" return WHILE;
"^" return EXPONENT;
"*" return MULTIPLY;
"/" return DIVIDE;
"%" return REMAINDER;
"!" return BOOL_NOT;
"&&" return BOOL_AND;
"||" return BOOL_OR;
"+" return PLUS;
"-" return MINUS;
"++" return INCR;
"--" return DECR;
"=" yylval.str = ""; return ASSIGN_OP;
"+=" yylval.str = "+"; return ASSIGN_OP;
"-=" yylval.str = "-"; return ASSIGN_OP;
"*=" yylval.str = "*"; return ASSIGN_OP;
"/=" yylval.str = "/"; return ASSIGN_OP;
"%=" yylval.str = "%"; return ASSIGN_OP;
"^=" yylval.str = "^"; return ASSIGN_OP;
"==" return EQUALS;
"<=" return LESS_EQ;
">=" return GREATER_EQ;
"!=" return UNEQUALS;
"<" return LESS;
">" return GREATER;
"," return COMMA;
";" return SEMICOLON;
"(" return LPAR;
")" return RPAR;
"[" return LBRACKET;
"]" return RBRACKET;
"{" return LBRACE;
"}" return RBRACE;
{ALPHA}{ALPHANUM}* {
/* alloc an extra byte for the type marker */
char *p = malloc(yyleng + 2);
if (p == NULL)
err(1, NULL);
strlcpy(p, yytext, yyleng + 1);
yylval.astr = p;
return LETTER;
}
\\\n lineno++;
\n lineno++; return NEWLINE;
#[^\n]* ;
[ \t] ;
<<EOF>> return QUIT;
. yyerror("illegal character");
%%
static void
init_strbuf(void)
{
if (strbuf == NULL) {
strbuf = malloc(strbuf_sz);
if (strbuf == NULL)
err(1, NULL);
}
strbuf[0] = '\0';
}
static void
add_str(const char *str)
{
size_t arglen;
arglen = strlen(str);
if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
size_t newsize;
char *p;
newsize = strbuf_sz + arglen + 1;
p = realloc(strbuf, newsize);
if (p == NULL) {
free(strbuf);
err(1, NULL);
}
strbuf_sz = newsize;
strbuf = p;
}
strlcat(strbuf, str, strbuf_sz);
}
/* ARGSUSED */
void
abort_line(int sig __unused)
{
static const char str1[] = "[\n]P\n";
static const char str2[] = "[^C\n]P\n";
int save_errno;
const LineInfo *info;
save_errno = errno;
if (use_el) {
write(STDOUT_FILENO, str2, sizeof(str2) - 1);
info = el_line(el);
skipchars = info->lastchar - info->buffer;
} else
write(STDOUT_FILENO, str1, sizeof(str1) - 1);
errno = save_errno;
}
/*
* Avoid the echo of ^D by the default code of editline and take
* into account skipchars to make ^D work when the cursor is at start of
* line after a ^C.
*/
unsigned char
bc_eof(EditLine *e, int ch __unused)
{
const struct lineinfo *info = el_line(e);
if (info->buffer + skipchars == info->cursor &&
info->cursor == info->lastchar)
return (CC_EOF);
else
return (CC_ERROR);
}
int
yywrap(void)
{
static int state;
static YY_BUFFER_STATE buf;
if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
filename = sargv[fileindex++];
yyin = fopen(filename, "r");
lineno = 1;
if (yyin == NULL)
err(1, "cannot open %s", filename);
return (0);
}
if (state == 0 && cmdexpr[0] != '\0') {
buf = yy_scan_string(cmdexpr);
state++;
lineno = 1;
filename = "command line";
return (0);
} else if (state == 1) {
yy_delete_buffer(buf);
free(cmdexpr);
state++;
}
if (yyin != NULL && yyin != stdin)
fclose(yyin);
if (fileindex < sargc) {
filename = sargv[fileindex++];
yyin = fopen(filename, "r");
lineno = 1;
if (yyin == NULL)
err(1, "cannot open %s", filename);
return (0);
} else if (fileindex == sargc) {
fileindex++;
yyin = stdin;
if (interactive) {
signal(SIGINT, abort_line);
signal(SIGTSTP, tstpcont);
}
lineno = 1;
filename = "stdin";
return (0);
}
return (1);
}
static int
bc_yyinput(char *buf, int maxlen)
{
int num;
if (el != NULL)
el_get(el, EL_EDITMODE, &use_el);
if (yyin == stdin && interactive && use_el) {
const char *bp;
sigset_t oset, nset;
if ((bp = el_gets(el, &num)) == NULL || num == 0)
return (0);
sigemptyset(&nset);
sigaddset(&nset, SIGINT);
sigprocmask(SIG_BLOCK, &nset, &oset);
if (skipchars < num) {
bp += skipchars;
num -= skipchars;
}
skipchars = 0;
sigprocmask(SIG_SETMASK, &oset, NULL);
if (num > maxlen) {
el_push(el, bp + maxlen);
num = maxlen;
}
memcpy(buf, bp, num);
history(hist, &he, H_ENTER, bp);
el_get(el, EL_EDITMODE, &use_el);
} else {
int c = '*';
for (num = 0; num < maxlen &&
(c = getc(yyin)) != EOF && c != '\n'; ++num)
buf[num] = (char) c;
if (c == '\n')
buf[num++] = (char) c;
if (c == EOF && ferror(yyin))
YY_FATAL_ERROR( "input in flex scanner failed" );
}
return (num);
}

View File

@ -1,64 +0,0 @@
/* $OpenBSD: tty.c,v 1.3 2015/09/05 09:49:24 jsg Exp $ */
/*
* Copyright (c) 2013, Otto Moerbeek <otto@drijf.net>
*
* 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 <errno.h>
#include <signal.h>
#include <histedit.h>
#include <termios.h>
#include "extern.h"
struct termios ttysaved, ttyedit;
static int
settty(struct termios *t)
{
int ret;
while ((ret = tcsetattr(0, TCSADRAIN, t)) == -1 && errno == EINTR)
continue;
return ret;
}
int
gettty(struct termios *t)
{
int ret;
while ((ret = tcgetattr(0, t)) == -1 && errno == EINTR)
continue;
return ret;
}
/* ARGSUSED */
void
tstpcont(int sig)
{
int save_errno = errno;
if (sig == SIGTSTP) {
signal(SIGCONT, tstpcont);
gettty(&ttyedit);
settty(&ttysaved);
} else {
signal(SIGTSTP, tstpcont);
settty(&ttyedit);
}
signal(sig, SIG_DFL);
kill(0, sig);
errno = save_errno;
}

View File

@ -1,12 +0,0 @@
# $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>

View File

@ -1,18 +0,0 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcapsicum \
lib/libcasper/libcasper \
lib/libcompiler_rt \
secure/lib/libcrypto \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

File diff suppressed because it is too large Load Diff

View File

@ -1,103 +0,0 @@
/* $OpenBSD: bcode.h,v 1.7 2012/11/07 11:06:14 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/types.h>
#include <openssl/bn.h>
struct number {
BIGNUM *number;
u_int scale;
};
enum stacktype {
BCODE_NONE,
BCODE_NUMBER,
BCODE_STRING
};
enum bcode_compare {
BCODE_EQUAL,
BCODE_NOT_EQUAL,
BCODE_LESS,
BCODE_NOT_LESS,
BCODE_GREATER,
BCODE_NOT_GREATER
};
struct array;
struct value {
union {
struct number *num;
char *string;
} u;
struct array *array;
enum stacktype type;
};
struct array {
struct value *data;
size_t size;
};
struct stack {
struct value *stack;
ssize_t size;
ssize_t sp;
};
struct source;
struct vtable {
int (*readchar)(struct source *);
void (*unreadchar)(struct source *);
char *(*readline)(struct source *);
void (*free)(struct source *);
};
struct source {
union {
struct {
u_char *buf;
size_t pos;
} string;
FILE *stream;
} u;
struct vtable *vtable;
int lastchar;
};
void init_bmachine(bool);
void reset_bmachine(struct source *);
u_int bmachine_scale(void);
void scale_number(BIGNUM *, int);
void normalize(struct number *, u_int);
void eval(void);
void pn(const char *, const struct number *);
void pbn(const char *, const BIGNUM *);
void negate(struct number *);
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);
}

View File

@ -1,555 +0,0 @@
.\" $OpenBSD: dc.1,v 1.27 2012/08/19 12:07:21 jmc Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002.
.\" 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 and documentation 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed or owned by Caldera
.\" International, Inc.
.\" 4. Neither the name of Caldera International, Inc. nor the names of other
.\" contributors may be used to endorse or promote products derived from
.\" this software without specific prior written permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
.\"
.Dd September 4, 2019
.Dt DC 1
.Os
.Sh NAME
.Nm dc
.Nd desk calculator
.Sh SYNOPSIS
.Nm
.Op Fl hxV
.Op Fl e Ar expression
.Op Fl f Ar filename
.Op Ar filename
.Sh DESCRIPTION
.Nm
is an arbitrary precision arithmetic package.
The overall structure of
.Nm
is
a stacking (reverse Polish) calculator i.e.\&
numbers are stored on a stack.
Adding a number pushes it onto the stack.
Arithmetic operations pop arguments off the stack
and push the results.
See also the
.Xr bc 1
utility, which is a preprocessor for
.Nm
providing infix notation and a C-like syntax
which implements functions and reasonable control
structures for programs.
The options are as follows:
.Bl -tag -width Ds
.It Fl e Ar expr , Fl Fl expression Ar expr
Evaluate
.Ar expression .
If multiple
.Fl e
options are specified, they will be processed in the order given.
.It Fl f Ar filename , Fl Fl file Ar filename
Process the content of the given file before further calculations are done.
If multiple
.Fl f
options are specified, they will be processed in the order given.
.It Fl h , Fl Fl help
Print short usage info.
.It Fl V , Fl Fl version
Print version info.
.It Fl x
Enable extended register mode.
This mode is used by
.Xr bc 1
to allow more than 256 registers.
See
.Sx Registers
for a more detailed description.
.El
.Pp
If neither
.Ar expression
nor
.Ar file
are specified on the command line,
.Nm
reads from the standard input.
Otherwise
.Ar expression
and
.Ar file
are processed and
.Nm
exits.
.Pp
Ordinarily,
.Nm
operates on decimal integers,
but one may specify an input base, output base,
and a number of fractional digits (scale) to be maintained.
Whitespace is ignored, except where it signals the end of a number,
end of a line or when a register name is expected.
The following constructions are recognized:
.Bl -tag -width "number"
.It Va number
The value of the number is pushed on the stack.
A number is an unbroken string of the digits 0\-9 and letters A\-F.
It may be preceded by an underscore
.Pq Sq _
to input a negative number.
A number may contain a single decimal point.
A number may also contain the characters A\-F, with the values 10\-15.
.It Cm "+ - / * % ~ ^"
The
top two values on the stack are added
(+),
subtracted
(\-),
multiplied (*),
divided (/),
remaindered (%),
divided and remaindered (~),
or exponentiated (^).
The two entries are popped off the stack;
the result is pushed on the stack in their place.
Any fractional part of an exponent is ignored.
.Pp
For addition, subtraction, and remainder, the scale of the result is the
maximum of scales of the operands.
For division the scale of the result is defined
by the scale set by the
.Ic k
operation.
For multiplication, the scale is defined by the expression
.Sy min(a+b,max(a,b,scale)) ,
where
.Sy a
and
.Sy b
are the scales of the operands, and
.Sy scale
is the scale defined by the
.Ic k
operation.
For exponentiation with a non-negative exponent, the scale of the result is
.Sy min(a*b,max(scale,a)) ,
where
.Sy a
is the scale of the base, and
.Sy b
is the
.Em value
of the exponent.
If the exponent is negative, the scale of the result is the scale
defined by the
.Ic k
operation.
.Pp
In the case of the division and modulus operator (~),
the resultant quotient is pushed first followed by the remainder.
This is a shorthand for the sequence:
.Bd -literal -offset indent -compact
x y / x y %
.Ed
The division and modulus operator is a non-portable extension.
.It Ic a
Pop the top value from the stack.
If that value is a number, compute the integer part of the number modulo 256.
If the result is zero, push an empty string.
Otherwise push a one character string by interpreting the computed value
as an
.Tn ASCII
character.
.Pp
If the top value is a string, push a string containing the first character
of the original string.
If the original string is empty, an empty string is pushed back.
The
.Ic a
operator is a non-portable extension.
.It Ic c
All values on the stack are popped.
.It Ic d
The top value on the stack is duplicated.
.It Ic e
Equivalent to
.Ic p ,
except that the output is written to the standard error stream.
.It Ic f
All values on the stack are printed, separated by newlines.
.It Ic G
The top two numbers are popped from the stack and compared.
A one is pushed if the top of the stack is equal to the second number
on the stack.
A zero is pushed otherwise.
This is a non-portable extension.
.It Ic I
Pushes the input base on the top of the stack.
.It Ic i
The top value on the stack is popped and used as the
base for further input.
The initial input base is 10.
.It Ic J
Pop the top value from the stack.
The recursion level is popped by that value and, following that,
the input is skipped until the first occurrence of the
.Ic M
operator.
The
.Ic J
operator is a non-portable extension, used by the
.Xr bc 1
command.
.It Ic K
The current scale factor is pushed onto the stack.
.It Ic k
The top of the stack is popped, and that value is used as
a non-negative scale factor:
the appropriate number of places
are printed on output,
and maintained during multiplication, division, and exponentiation.
The interaction of scale factor,
input base, and output base will be reasonable if all are changed
together.
.It Ic L Ns Ar x
Register
.Ar x
is treated as a stack and its top value is popped onto the main stack.
.It Ic l Ns Ar x
The
value in register
.Ar x
is pushed on the stack.
The register
.Ar x
is not altered.
Initially, all registers contain the value zero.
.It Ic M
Mark used by the
.Ic J
operator.
The
.Ic M
operator is a non-portable extensions, used by the
.Xr bc 1
command.
.It Ic N
The top of the stack is replaced by one if the top of the stack
is equal to zero.
If the top of the stack is unequal to zero, it is replaced by zero.
This is a non-portable extension.
.It Ic n
The top value on the stack is popped and printed without a newline.
This is a non-portable extension.
.It Ic O
Pushes the output base on the top of the stack.
.It Ic o
The top value on the stack is popped and used as the
base for further output.
The initial output base is 10.
.It Ic P
The top of the stack is popped.
If the top of the stack is a string, it is printed without a trailing newline.
If the top of the stack is a number, it is interpreted as a
base 256 number, and each digit of this base 256 number is printed as
an
.Tn ASCII
character, without a trailing newline.
.It Ic p
The top value on the stack is printed with a trailing newline.
The top value remains unchanged.
.It Ic Q
The top value on the stack is popped and the string execution level is popped
by that value.
.It Ic q
Exits the program.
If executing a string, the recursion level is
popped by two.
.It Ic R
The top of the stack is removed (popped).
This is a non-portable extension.
.It Ic r
The top two values on the stack are reversed (swapped).
This is a non-portable extension.
.It Ic S Ns Ar x
Register
.Ar x
is treated as a stack.
The top value of the main stack is popped and pushed on it.
.It Ic s Ns Ar x
The
top of the stack is popped and stored into
a register named
.Ar x .
.It Ic v
Replaces the top element on the stack by its square root.
The scale of the result is the maximum of the scale of the argument
and the current value of scale.
.It Ic X
Replaces the number on the top of the stack with its scale factor.
If the top of the stack is a string, replace it with the integer 0.
.It Ic x
Treats the top element of the stack as a character string
and executes it as a string of
.Nm
commands.
.It Ic Z
Replaces the number on the top of the stack with its length.
The length of a string is its number of characters.
The length of a number is its number of digits, not counting the minus sign
and decimal point.
.It Ic z
The stack level is pushed onto the stack.
.It Cm \&[ Ns ... Ns Cm \&]
Puts the bracketed
.Tn ASCII
string onto the top of the stack.
If the string includes brackets, these must be properly balanced.
The backslash character
.Pq Sq \e
may be used as an escape character, making it
possible to include unbalanced brackets in strings.
To include a backslash in a string, use a double backslash.
.It Xo
.Cm < Ns Va x
.Cm > Ns Va x
.Cm = Ns Va x
.Cm !< Ns Va x
.Cm !> Ns Va x
.Cm != Ns Va x
.Xc
The top two elements of the stack are popped and compared.
Register
.Ar x
is executed if they obey the stated
relation.
.It Xo
.Cm < Ns Va x Ns e Ns Va y
.Cm > Ns Va x Ns e Ns Va y
.Cm = Ns Va x Ns e Ns Va y
.Cm !< Ns Va x Ns e Ns Va y
.Cm !> Ns Va x Ns e Ns Va y
.Cm != Ns Va x Ns e Ns Va y
.Xc
These operations are variants of the comparison operations above.
The first register name is followed by the letter
.Sq e
and another register name.
Register
.Ar x
will be executed if the relation is true, and register
.Ar y
will be executed if the relation is false.
This is a non-portable extension.
.It Ic \&(
The top two numbers are popped from the stack and compared.
A one is pushed if the top of the stack is less than the second number
on the stack.
A zero is pushed otherwise.
This is a non-portable extension.
.It Ic {
The top two numbers are popped from the stack and compared.
A one is pushed if the top of stack is less than or equal to the
second number on the stack.
A zero is pushed otherwise.
This is a non-portable extension.
.It Ic \&!
Interprets the rest of the line as a
.Ux
command.
.It Ic \&?
A line of input is taken from the input source (usually the terminal)
and executed.
.It Ic \&: Ns Ar r
Pop two values from the stack.
The second value on the stack is stored into the array
.Ar r
indexed by the top of stack.
.It Ic \&; Ns Ar r
Pop a value from the stack.
The value is used as an index into register
.Ar r .
The value in this register is pushed onto the stack.
.Pp
Array elements initially have the value zero.
Each level of a stacked register has its own array associated with
it.
The command sequence
.Bd -literal -offset indent
[first] 0:a [dummy] Sa [second] 0:a 0;a p La 0;a p
.Ed
.Pp
will print
.Bd -literal -offset indent
second
first
.Ed
.Pp
since the string
.Ql second
is written in an array that is later popped, to reveal the array that
stored
.Ql first .
.It Ic #
Skip the rest of the line.
This is a non-portable extension.
.El
.Ss Registers
Registers have a single character name
.Ar x ,
where
.Ar x
may be any character, including space, tab or any other special character.
If extended register mode is enabled using the
.Fl x
option and the register identifier
.Ar x
has the value 255, the next two characters are interpreted as a
two-byte register index.
The set of standard single character registers and the set of extended
registers do not overlap.
Extended register mode is a non-portable extension.
.Sh EXAMPLES
An example which prints the first ten values of
.Ic n! :
.Bd -literal -offset indent
[la1+dsa*pla10>y]sy
0sa1
lyx
.Ed
.Pp
Independent of the current input base, the command
.Bd -literal -offset indent
Ai
.Ed
.Pp
will reset the input base to decimal 10.
.Sh DIAGNOSTICS
.Bl -diag
.It %c (0%o) is unimplemented
an undefined operation was called.
.It stack empty
for not enough elements on the stack to do what was asked.
.It stack register '%c' (0%o) is empty
for an
.Ar L
operation from a stack register that is empty.
.It Runtime warning: non-zero scale in exponent
for a fractional part of an exponent that is being ignored.
.It divide by zero
for trying to divide by zero.
.It remainder by zero
for trying to take a remainder by zero.
.It square root of negative number
for trying to take the square root of a negative number.
.It index too big
for an array index that is larger than 2048.
.It negative index
for a negative array index.
.It "input base must be a number between 2 and 16"
for trying to set an illegal input base.
.It output base must be a number greater than 1
for trying to set an illegal output base.
.It scale must be a nonnegative number
for trying to set a negative or zero scale.
.It scale too large
for trying to set a scale that is too large.
A scale must be representable as a 32-bit unsigned number.
.It Q command argument exceeded string execution depth
for trying to pop the recursion level more than the current
recursion level.
.It Q command requires a number >= 1
for trying to pop an illegal number of recursion levels.
.It recursion too deep
for too many levels of nested execution.
.Pp
The recursion level is increased by one if the
.Ar x
or
.Ar ?\&
operation or one of the compare operations resulting in the execution
of register is executed.
As an exception, the recursion level is not increased if the operation
is executed as the last command of a string.
For example, the commands
.Bd -literal -offset indent
[lax]sa
1 lax
.Ed
.Pp
will execute an endless loop, while the commands
.Bd -literal -offset indent
[laxp]sa
1 lax
.Ed
.Pp
will terminate because of a too deep recursion level.
.It J command argument exceeded string execution depth
for trying to pop the recursion level more than the current
recursion level.
.It mark not found
for a failed scan for an occurrence of the
.Ic M
operator.
.El
.Sh SEE ALSO
.Xr bc 1
.Pp
.An -nosplit
.An L. L. Cherry ,
.An R. Morris
"DC \- An Interactive Desk Calculator"
.Pa /usr/share/doc/usd/05.dc/ .
.Sh STANDARDS
The arithmetic operations of the
.Nm
utility are expected to conform to the definition listed in the
.Xr bc 1
section of the
.St -p1003.2
specification.
.Sh HISTORY
The
.Nm
command first appeared in
.At v1 .
A complete rewrite of the
.Nm
command using the
.Xr bn 3
big number routines first appeared in
.Ox 3.5 .
.Sh AUTHORS
.An -nosplit
The original version of the
.Nm
command was written by
.An Robert Morris
and
.An Lorinda Cherry .
The current version of the
.Nm
utility was written by
.An Otto Moerbeek .

View File

@ -1,154 +0,0 @@
/* $OpenBSD: dc.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
* Copyright (c) 2009, Gabor Kovesdan <gabor@FreeBSD.org>
*
* 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 <sys/cdefs.h>
#include <sys/stat.h>
#include <capsicum_helpers.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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
procfd(int fd, char *fname) {
struct stat st;
FILE *file;
file = fdopen(fd, "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, fd;
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);
fd = open(optarg, O_RDONLY);
if (fd < 0)
err(1, "cannot open file %s", optarg);
procfd(fd, 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);
(void)setvbuf(stdout, NULL, _IOLBF, 0);
(void)setvbuf(stderr, NULL, _IOLBF, 0);
if (argc > 1)
usage();
if (argc == 1) {
fd = open(argv[0], O_RDONLY);
if (fd < 0)
err(1, "cannot open file %s", argv[0]);
if (caph_limit_stream(fd, CAPH_READ) < 0 ||
caph_limit_stdio() < 0 ||
caph_enter() < 0)
err(1, "capsicum");
procfd(fd, argv[0]);
preproc_done = true;
}
if (preproc_done)
return (0);
if (caph_limit_stdio() < 0 || caph_enter())
err(1, "capsicum");
src_setstream(&src, stdin);
reset_bmachine(&src);
eval();
return (0);
}

View File

@ -1,63 +0,0 @@
/* $OpenBSD: extern.h,v 1.4 2014/12/01 13:13:00 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <stdbool.h>
#include "bcode.h"
/* inout.c */
void src_setstream(struct source *, FILE *);
void src_setstring(struct source *, char *);
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);
void print_ascii(FILE *, const struct number *);
/* 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);
char *bstrdup(const char *p);
void bn_check(int);
void bn_checkp(const void *);
/* stack.c */
void stack_init(struct stack *);
void stack_free_value(struct value *);
struct value *stack_dup_value(const struct value *, struct value *);
void stack_swap(struct stack *);
size_t stack_size(const struct stack *);
void stack_dup(struct stack *);
void stack_pushnumber(struct stack *, struct number *);
void stack_pushstring(struct stack *stack, char *);
void stack_push(struct stack *, struct value *);
void stack_set_tos(struct stack *, struct value *);
struct value *stack_tos(const struct stack *);
struct value *stack_pop(struct stack *);
struct number *stack_popnumber(struct stack *);
char *stack_popstring(struct stack *);
void stack_clear(struct stack *);
void stack_print(FILE *, const struct stack *, const char *,
u_int base);
void frame_assign(struct stack *, size_t, const struct value *);
struct value *frame_retrieve(const struct stack *, size_t);
/* void frame_free(struct stack *); */

View File

@ -1,446 +0,0 @@
/* $OpenBSD: inout.c,v 1.18 2014/12/01 13:13:00 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/cdefs.h>
#include <openssl/ssl.h>
#include <ctype.h>
#include <err.h>
#include <string.h>
#include "extern.h"
#define MAX_CHARS_PER_LINE 68
static int lastchar;
static int charcount;
static int src_getcharstream(struct source *);
static void src_ungetcharstream(struct source *);
static char *src_getlinestream(struct source *);
static int src_getcharstring(struct source *);
static void src_ungetcharstring(struct source *);
static char *src_getlinestring(struct source *);
static void src_freestring(struct source *);
static void flushwrap(FILE *);
static void putcharwrap(FILE *, int);
static void printwrap(FILE *, const char *);
static char *get_digit(u_long, int, u_int);
static struct vtable stream_vtable = {
src_getcharstream,
src_ungetcharstream,
src_getlinestream,
NULL
};
static struct vtable string_vtable = {
src_getcharstring,
src_ungetcharstring,
src_getlinestring,
src_freestring
};
void
src_setstream(struct source *src, FILE *stream)
{
src->u.stream = stream;
src->vtable = &stream_vtable;
}
void
src_setstring(struct source *src, char *p)
{
src->u.string.buf = (u_char *)p;
src->u.string.pos = 0;
src->vtable = &string_vtable;
}
static int
src_getcharstream(struct source *src)
{
return (src->lastchar = getc(src->u.stream));
}
static void
src_ungetcharstream(struct source *src)
{
ungetc(src->lastchar, src->u.stream);
}
static char *
src_getlinestream(struct source *src)
{
char buf[BUFSIZ];
if (fgets(buf, BUFSIZ, src->u.stream) == NULL)
return (bstrdup(""));
return bstrdup(buf);
}
static int
src_getcharstring(struct source *src)
{
src->lastchar = src->u.string.buf[src->u.string.pos];
if (src->lastchar == '\0')
return (EOF);
else {
src->u.string.pos++;
return (src->lastchar);
}
}
static void
src_ungetcharstring(struct source *src)
{
if (src->u.string.pos > 0) {
if (src->lastchar != '\0')
--src->u.string.pos;
}
}
static char *
src_getlinestring(struct source *src)
{
char buf[BUFSIZ];
int i, ch;
i = 0;
while (i < BUFSIZ-1) {
ch = src_getcharstring(src);
if (ch == EOF)
break;
buf[i++] = ch;
if (ch == '\n')
break;
}
buf[i] = '\0';
return (bstrdup(buf));
}
static void
src_freestring(struct source *src)
{
free(src->u.string.buf);
}
static void
flushwrap(FILE *f)
{
if (lastchar != -1)
putc(lastchar, f);
}
static void
putcharwrap(FILE *f, int ch)
{
if (charcount >= MAX_CHARS_PER_LINE) {
charcount = 0;
fputs("\\\n", f);
}
if (lastchar != -1) {
charcount++;
putc(lastchar, f);
}
lastchar = ch;
}
static void
printwrap(FILE *f, const char *p)
{
char *q;
char buf[12];
q = buf;
strlcpy(buf, p, sizeof(buf));
while (*q)
putcharwrap(f, *q++);
}
struct number *
readnumber(struct source *src, u_int base, u_int bscale)
{
struct number *n;
BN_ULONG v;
int ch;
u_int iscale = 0;
bool dot = false, sign = false;
n = new_number();
BN_zero(n->number);
while ((ch = (*src->vtable->readchar)(src)) != EOF) {
if ('0' <= ch && ch <= '9')
v = ch - '0';
else if ('A' <= ch && ch <= 'F')
v = ch - 'A' + 10;
else if (ch == '_') {
sign = true;
continue;
} else if (ch == '.') {
if (dot)
break;
dot = true;
continue;
} else {
(*src->vtable->unreadchar)(src);
break;
}
if (dot)
iscale++;
bn_check(BN_mul_word(n->number, base));
bn_check(BN_add_word(n->number, v));
}
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_zero(base_n);
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);
return (n);
}
char *
read_string(struct source *src)
{
char *p;
int count, ch, i, new_sz, sz;
bool escape;
escape = false;
count = 1;
i = 0;
sz = 15;
p = bmalloc(sz + 1);
while ((ch = (*src->vtable->readchar)(src)) != EOF) {
if (!escape) {
if (ch == '[')
count++;
else if (ch == ']')
count--;
if (count == 0)
break;
}
if (ch == '\\' && !escape)
escape = true;
else {
escape = false;
if (i == sz) {
new_sz = sz * 2;
p = breallocarray(p, 1, new_sz + 1);
sz = new_sz;
}
p[i++] = ch;
}
}
p[i] = '\0';
return (p);
}
static char *
get_digit(u_long num, int digits, u_int base)
{
char *p;
if (base <= 16) {
p = bmalloc(2);
p[0] = num >= 10 ? num + 'A' - 10 : num + '0';
p[1] = '\0';
} else {
if (asprintf(&p, "%0*lu", digits, num) == -1)
err(1, NULL);
}
return (p);
}
void
printnumber(FILE *f, const struct number *b, u_int base)
{
struct number *fract_part, *int_part;
struct stack stack;
char *p;
char buf[11];
size_t sz;
unsigned int i;
int digits;
charcount = 0;
lastchar = -1;
if (BN_is_zero(b->number))
putcharwrap(f, '0');
int_part = new_number();
fract_part = new_number();
fract_part->scale = b->scale;
if (base <= 16)
digits = 1;
else {
digits = snprintf(buf, sizeof(buf), "%u", base-1);
}
split_number(b, int_part->number, fract_part->number);
i = 0;
stack_init(&stack);
while (!BN_is_zero(int_part->number)) {
BN_ULONG rem = BN_div_word(int_part->number, base);
stack_pushstring(&stack, get_digit(rem, digits, base));
i++;
}
sz = i;
if (BN_is_negative(b->number))
putcharwrap(f, '-');
for (i = 0; i < sz; i++) {
p = stack_popstring(&stack);
if (base > 16)
putcharwrap(f, ' ');
printwrap(f, p);
free(p);
}
stack_clear(&stack);
if (b->scale > 0) {
struct number *num_base;
BIGNUM *mult, *stop;
putcharwrap(f, '.');
num_base = new_number();
bn_check(BN_set_word(num_base->number, base));
mult = BN_new();
bn_checkp(mult);
bn_check(BN_one(mult));
stop = BN_new();
bn_checkp(stop);
bn_check(BN_one(stop));
scale_number(stop, b->scale);
i = 0;
while (BN_cmp(mult, stop) < 0) {
u_long rem;
if (i && base > 16)
putcharwrap(f, ' ');
i = 1;
bmul_number(fract_part, fract_part, num_base,
bmachine_scale());
split_number(fract_part, int_part->number, NULL);
rem = BN_get_word(int_part->number);
p = get_digit(rem, digits, base);
int_part->scale = 0;
normalize(int_part, fract_part->scale);
bn_check(BN_sub(fract_part->number, fract_part->number,
int_part->number));
printwrap(f, p);
free(p);
bn_check(BN_mul_word(mult, base));
}
free_number(num_base);
BN_free(mult);
BN_free(stop);
}
flushwrap(f);
free_number(int_part);
free_number(fract_part);
}
void
print_value(FILE *f, const struct value *value, const char *prefix, u_int base)
{
fputs(prefix, f);
switch (value->type) {
case BCODE_NONE:
if (value->array != NULL)
fputs("<array>", f);
break;
case BCODE_NUMBER:
printnumber(f, value->u.num, base);
break;
case BCODE_STRING:
fputs(value->u.string, f);
break;
}
}
void
print_ascii(FILE *f, const struct number *n)
{
BIGNUM *v;
int ch, i, numbits;
v = BN_dup(n->number);
bn_checkp(v);
if (BN_is_negative(v))
BN_set_negative(v, 0);
numbits = BN_num_bytes(v) * 8;
while (numbits > 0) {
ch = 0;
for (i = 0; i < 8; i++)
ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i);
putc(ch, f);
numbits -= 8;
}
BN_free(v);
}

View File

@ -1,140 +0,0 @@
/* $OpenBSD: mem.c,v 1.6 2014/12/01 13:13:00 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/cdefs.h>
#include <openssl/err.h>
#include <err.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "extern.h"
struct number *
new_number(void)
{
struct number *n;
n = bmalloc(sizeof(*n));
n->scale = 0;
n->number = BN_new();
if (n->number == NULL)
err(1, NULL);
return (n);
}
void
free_number(struct number *n)
{
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 *
dup_number(const struct number *a)
{
struct number *n;
n = bmalloc(sizeof(*n));
n->scale = a->scale;
n->number = BN_dup(a->number);
bn_checkp(n->number);
return (n);
}
void *
bmalloc(size_t sz)
{
void *p;
p = malloc(sz);
if (p == NULL)
err(1, NULL);
return (p);
}
void *
breallocarray(void *p, size_t nmemb, size_t size)
{
void *q;
q = reallocarray(p, nmemb, size);
if (q == NULL)
err(1, NULL);
return (q);
}
char *
bstrdup(const char *p)
{
char *q;
q = strdup(p);
if (q == NULL)
err(1, NULL);
return (q);
}
void
bn_check(int x) \
{
if (x == 0)
err(1, "big number failure %lx", ERR_get_error());
}
void
bn_checkp(const void *p) \
{
if (p == NULL)
err(1, "allocation failure %lx", ERR_get_error());
}

View File

@ -1,370 +0,0 @@
/* $OpenBSD: stack.c,v 1.13 2014/12/01 13:13:00 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/cdefs.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#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;
}
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, &copy));
}
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 = breallocarray(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);
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);
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)
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 = breallocarray(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);
}

View File

@ -1,6 +0,0 @@
PACKAGE= tests
ATF_TESTS_SH= inout
ATF_TESTS_SH+= bcode
.include <bsd.test.mk>

View File

@ -1,142 +0,0 @@
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2017 Alan Somers
#
# 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.
#
atf_test_case bmod
bmod_head()
{
atf_set "descr" "Tests the remainder % operator"
}
bmod_body()
{
cat > input.dc << EOF
0 3 % p # basic usage
1 3 % p
2 3 % p
3 3 % p
4 3 % p
_1 3 % p # negative dividends work like a remainder, not a modulo
1 _3 % p # negative divisors use the divisor's absolute value
1k # fractional remainders
5 3 % p
6 5 % p
5.4 3 % p
_.1 3 % p
1.1 _3 % p
1 .3 % p
EOF
dc input.dc > output.txt
cat > expect.txt << EOF
0
1
2
0
1
-1
1
2
1
2.4
-.1
1.1
.1
EOF
atf_check cmp expect.txt output.txt
}
atf_test_case bmod_by_zero
bmod_by_zero_head()
{
atf_set "descr" "remaindering by zero should print a warning"
}
bmod_by_zero_body()
{
atf_check -e match:"remainder by zero" dc -e '1 0 %'
}
atf_test_case bdivmod
bdivmod_head()
{
atf_set "descr" "Tests the divide and modulo ~ operator"
}
bdivmod_body()
{
cat > input.dc << EOF
0 3 ~ n32Pp # basic usage
1 3 ~ n32Pp
2 3 ~ n32Pp
3 3 ~ n32Pp
4 3 ~ n32Pp
_1 3 ~ n32Pp # negative dividends work like a remainder, not a modulo
_4 3 ~ n32Pp # sign of quotient and divisor must agree
1 _3 ~ n32Pp # negative divisors use the divisor's absolute value
1k # fractional remainders
5 3 ~ n32Pp
6 5 ~ n32Pp
5.4 3 ~ n32Pp
_.1 3 ~ n32Pp
1.1 _3 ~ n32Pp
1 .3 ~ n32Pp
4k
.01 .003 ~ n32Pp # divmod quotient always has scale=0
EOF
dc input.dc > output.txt
cat > expect.txt << EOF
0 0
1 0
2 0
0 1
1 1
-1 0
-1 -1
1 0
2 1.6
1 1.2
2.4 1.8
-.1 0.0
1.1 -.3
.1 3.3
.001 3.3333
EOF
atf_check cmp expect.txt output.txt
}
atf_test_case bdivmod_by_zero
bdivmod_by_zero_head()
{
atf_set "descr" "divmodding by zero should print a warning"
}
bdivmod_by_zero_body()
{
atf_check -e match:"divide by zero" dc -e '1 0 ~'
}
atf_init_test_cases()
{
atf_add_test_case bmod
atf_add_test_case bmod_by_zero
atf_add_test_case bdivmod
atf_add_test_case bdivmod_by_zero
}

View File

@ -1,100 +0,0 @@
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2017 Alan Somers
#
# 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.
#
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
}