From 8ea6c115409450ff58a8c6b5e818319d181c6bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20E=C3=9Fer?= Date: Sun, 24 Nov 2024 22:38:23 +0100 Subject: [PATCH] usr.bin/bc: remove OpenBSD derived bc and dc commands 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 --- ObsoleteFiles.inc | 7 + UPDATING | 5 + share/man/man5/src.conf.5 | 6 - share/mk/src.opts.mk | 1 - tools/build/mk/OptionalObsoleteFiles.inc | 8 - tools/build/options/WITHOUT_GH_BC | 5 - usr.bin/Makefile | 5 - usr.bin/bc/Makefile | 14 - usr.bin/bc/Makefile.depend | 17 - usr.bin/bc/bc.1 | 413 ----- usr.bin/bc/bc.library | 272 ---- usr.bin/bc/bc.y | 1214 --------------- usr.bin/bc/extern.h | 46 - usr.bin/bc/pathnames.h | 20 - usr.bin/bc/scan.l | 368 ----- usr.bin/bc/tty.c | 64 - usr.bin/dc/Makefile | 12 - usr.bin/dc/Makefile.depend | 18 - usr.bin/dc/bcode.c | 1773 ---------------------- usr.bin/dc/bcode.h | 103 -- usr.bin/dc/dc.1 | 555 ------- usr.bin/dc/dc.c | 154 -- usr.bin/dc/extern.h | 63 - usr.bin/dc/inout.c | 446 ------ usr.bin/dc/mem.c | 140 -- usr.bin/dc/stack.c | 370 ----- usr.bin/dc/tests/Makefile | 6 - usr.bin/dc/tests/bcode.sh | 142 -- usr.bin/dc/tests/inout.sh | 100 -- 29 files changed, 12 insertions(+), 6335 deletions(-) delete mode 100644 tools/build/options/WITHOUT_GH_BC delete mode 100644 usr.bin/bc/Makefile delete mode 100644 usr.bin/bc/Makefile.depend delete mode 100644 usr.bin/bc/bc.1 delete mode 100644 usr.bin/bc/bc.library delete mode 100644 usr.bin/bc/bc.y delete mode 100644 usr.bin/bc/extern.h delete mode 100644 usr.bin/bc/pathnames.h delete mode 100644 usr.bin/bc/scan.l delete mode 100644 usr.bin/bc/tty.c delete mode 100644 usr.bin/dc/Makefile delete mode 100644 usr.bin/dc/Makefile.depend delete mode 100644 usr.bin/dc/bcode.c delete mode 100644 usr.bin/dc/bcode.h delete mode 100644 usr.bin/dc/dc.1 delete mode 100644 usr.bin/dc/dc.c delete mode 100644 usr.bin/dc/extern.h delete mode 100644 usr.bin/dc/inout.c delete mode 100644 usr.bin/dc/mem.c delete mode 100644 usr.bin/dc/stack.c delete mode 100644 usr.bin/dc/tests/Makefile delete mode 100755 usr.bin/dc/tests/bcode.sh delete mode 100755 usr.bin/dc/tests/inout.sh diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 1378d6b6dcfa..5362ba0e5955 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -51,6 +51,13 @@ # xargs -n1 | sort | uniq -d; # 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 OLD_FILES+=usr/tests/bin/mv/legacy_test diff --git a/UPDATING b/UPDATING index 1fb14a96880b..2a67a65a92ed 100644 --- a/UPDATING +++ b/UPDATING @@ -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 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: 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 diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5 index a1465b0729a3..88df18b3142e 100644 --- a/share/man/man5/src.conf.5 +++ b/share/man/man5/src.conf.5 @@ -712,12 +712,6 @@ and .Xr ftpd 8 . .It Va WITHOUT_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 Do not build GNU .Xr diff3 1 ; diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index f8877153f17f..f3141884cd00 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -101,7 +101,6 @@ __DEFAULT_YES_OPTIONS = \ FREEBSD_UPDATE \ FTP \ GAMES \ - GH_BC \ GNU_DIFF \ GOOGLETEST \ GPIO \ diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index e326155b26a4..864057692566 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -2071,14 +2071,6 @@ OLD_FILES+=usr/share/man/man8/strfile.8.gz OLD_FILES+=usr/share/man/man8/unstr.8.gz .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 OLD_FILES+=usr/include/private/gmock/gmock-actions.h OLD_FILES+=usr/include/private/gmock/gmock-cardinalities.h diff --git a/tools/build/options/WITHOUT_GH_BC b/tools/build/options/WITHOUT_GH_BC deleted file mode 100644 index 2618257ec71d..000000000000 --- a/tools/build/options/WITHOUT_GH_BC +++ /dev/null @@ -1,5 +0,0 @@ -Install the traditional FreeBSD -.Xr bc 1 -and -.Xr dc 1 -programs instead of the enhanced versions. diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 3cd91f8019e3..9baa90aab499 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -207,12 +207,7 @@ SUBDIR.${MK_GAMES}+= number SUBDIR.${MK_GAMES}+= pom SUBDIR.${MK_GAMES}+= primes SUBDIR.${MK_GAMES}+= random -.if ${MK_GH_BC} == "yes" SUBDIR+= gh-bc -.else -SUBDIR.${MK_OPENSSL}+= bc -SUBDIR.${MK_OPENSSL}+= dc -.endif .if ${MK_GNU_DIFF} == "no" SUBDIR+= diff3 .endif diff --git a/usr.bin/bc/Makefile b/usr.bin/bc/Makefile deleted file mode 100644 index 098308b4604b..000000000000 --- a/usr.bin/bc/Makefile +++ /dev/null @@ -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 diff --git a/usr.bin/bc/Makefile.depend b/usr.bin/bc/Makefile.depend deleted file mode 100644 index 7b1781905d71..000000000000 --- a/usr.bin/bc/Makefile.depend +++ /dev/null @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.bin/bc/bc.1 b/usr.bin/bc/bc.1 deleted file mode 100644 index 97bb3bf62c56..000000000000 --- a/usr.bin/bc/bc.1 +++ /dev/null @@ -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 -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). diff --git a/usr.bin/bc/bc.library b/usr.bin/bc/bc.library deleted file mode 100644 index 539de20a7e0c..000000000000 --- a/usr.bin/bc/bc.library +++ /dev/null @@ -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: */ diff --git a/usr.bin/bc/bc.y b/usr.bin/bc/bc.y deleted file mode 100644 index c270330281a8..000000000000 --- a/usr.bin/bc/bc.y +++ /dev/null @@ -1,1214 +0,0 @@ -%{ -/* $OpenBSD: bc.y,v 1.46 2014/10/14 15:35:18 deraadt 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. - */ - -/* - * This implementation of bc(1) uses concepts from the original 4.4 - * BSD bc(1). The code itself is a complete rewrite, based on the - * Posix defined bc(1) grammar. Other differences include type safe - * usage of pointers to build the tree of emitted code, typed yacc - * rule values, dynamic allocation of all data structures and a - * completely rewritten lexical analyzer using lex(1). - * - * Some effort has been made to make sure that the generated code is - * the same as the code generated by the older version, to provide - * easy regression testing. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "extern.h" -#include "pathnames.h" - -#define BC_VER "1.1-FreeBSD" -#define END_NODE ((ssize_t) -1) -#define CONST_STRING ((ssize_t) -2) -#define ALLOC_STRING ((ssize_t) -3) - -extern char *yytext; -extern FILE *yyin; - -struct tree { - union { - char *astr; - const char *cstr; - } u; - ssize_t index; -}; - -int yywrap(void); - -int fileindex; -int sargc; -const char **sargv; -const char *filename; -char *cmdexpr; - -static void grow(void); -static ssize_t cs(const char *); -static ssize_t as(const char *); -static ssize_t node(ssize_t, ...); -static void emit(ssize_t, int); -static void emit_macro(int, ssize_t); -static void free_tree(void); -static ssize_t numnode(int); -static ssize_t lookup(char *, size_t, char); -static ssize_t letter_node(char *); -static ssize_t array_node(char *); -static ssize_t function_node(char *); - -static void add_par(ssize_t); -static void add_local(ssize_t); -static void warning(const char *); -static void init(void); -static void usage(void); -static char *escape(const char *); - -static ssize_t instr_sz = 0; -static struct tree *instructions = NULL; -static ssize_t current = 0; -static int macro_char = '0'; -static int reset_macro_char = '0'; -static int nesting = 0; -static int breakstack[16]; -static int breaksp = 0; -static ssize_t prologue; -static ssize_t epilogue; -static bool st_has_continue; -static char str_table[UCHAR_MAX][2]; -static bool do_fork = true; -static u_short var_count; -static pid_t dc; - -static void sigchld(int); - -extern char *__progname; - -#define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0])) - -/* These values are 4.4BSD bc compatible */ -#define FUNC_CHAR 0x01 -#define ARRAY_CHAR 0xa1 - -/* Skip '\0', [, \ and ] */ -#define ENCODE(c) ((c) < '[' ? (c) : (c) + 3); -#define VAR_BASE (256-4) -#define MAX_VARIABLES (VAR_BASE * VAR_BASE) - -const struct option long_options[] = -{ - {"expression", required_argument, NULL, 'e'}, - {"help", no_argument, NULL, 'h'}, - {"mathlib", no_argument, NULL, 'l'}, - /* compatibility option */ - {"quiet", no_argument, NULL, 'q'}, - {"version", no_argument, NULL, 'v'}, - {NULL, no_argument, NULL, 0} -}; - -%} - -%start program - -%union { - struct lvalue lvalue; - const char *str; - char *astr; - ssize_t node; -} - -%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT -%token NEWLINE -%token LETTER -%token NUMBER STRING -%token DEFINE BREAK QUIT LENGTH -%token RETURN FOR IF WHILE SQRT -%token SCALE IBASE OBASE AUTO -%token CONTINUE ELSE PRINT - -%left BOOL_OR -%left BOOL_AND -%nonassoc BOOL_NOT -%nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER -%right ASSIGN_OP -%left PLUS MINUS -%left MULTIPLY DIVIDE REMAINDER -%right EXPONENT -%nonassoc UMINUS -%nonassoc INCR DECR - -%type named_expression -%type argument_list -%type alloc_macro -%type expression -%type function -%type function_header -%type input_item -%type opt_argument_list -%type opt_expression -%type opt_relational_expression -%type opt_statement -%type print_expression -%type print_expression_list -%type relational_expression -%type return_expression -%type semicolon_list -%type statement -%type statement_list - -%% - -program : /* empty */ - | program input_item - ; - -input_item : semicolon_list NEWLINE - { - emit($1, 0); - macro_char = reset_macro_char; - putchar('\n'); - free_tree(); - st_has_continue = false; - } - | function - { - putchar('\n'); - free_tree(); - st_has_continue = false; - } - | error NEWLINE - { - yyerrok; - } - | error QUIT - { - yyerrok; - } - ; - -semicolon_list : /* empty */ - { - $$ = cs(""); - } - | statement - | semicolon_list SEMICOLON statement - { - $$ = node($1, $3, END_NODE); - } - | semicolon_list SEMICOLON - ; - -statement_list : /* empty */ - { - $$ = cs(""); - } - | statement - | statement_list NEWLINE - | statement_list NEWLINE statement - { - $$ = node($1, $3, END_NODE); - } - | statement_list SEMICOLON - | statement_list SEMICOLON statement - { - $$ = node($1, $3, END_NODE); - } - ; - - -opt_statement : /* empty */ - { - $$ = cs(""); - } - | statement - ; - -statement : expression - { - $$ = node($1, cs("ps."), END_NODE); - } - | named_expression ASSIGN_OP expression - { - if ($2[0] == '\0') - $$ = node($3, cs($2), $1.store, - END_NODE); - else - $$ = node($1.load, $3, cs($2), $1.store, - END_NODE); - } - | STRING - { - $$ = node(cs("["), as($1), - cs("]P"), END_NODE); - } - | BREAK - { - if (breaksp == 0) { - warning("break not in for or while"); - YYERROR; - } else { - $$ = node( - numnode(nesting - - breakstack[breaksp-1]), - cs("Q"), END_NODE); - } - } - | CONTINUE - { - if (breaksp == 0) { - warning("continue not in for or while"); - YYERROR; - } else { - st_has_continue = true; - $$ = node(numnode(nesting - - breakstack[breaksp-1] - 1), - cs("J"), END_NODE); - } - } - | QUIT - { - sigset_t mask; - - putchar('q'); - fflush(stdout); - if (dc) { - sigprocmask(SIG_BLOCK, NULL, &mask); - sigsuspend(&mask); - } else - exit(0); - } - | RETURN return_expression - { - if (nesting == 0) { - warning("return must be in a function"); - YYERROR; - } - $$ = $2; - } - | FOR LPAR alloc_macro opt_expression SEMICOLON - opt_relational_expression SEMICOLON - opt_expression RPAR opt_statement pop_nesting - { - ssize_t n; - - if (st_has_continue) - n = node($10, cs("M"), $8, cs("s."), - $6, $3, END_NODE); - else - n = node($10, $8, cs("s."), $6, $3, - END_NODE); - - emit_macro($3, n); - $$ = node($4, cs("s."), $6, $3, cs(" "), - END_NODE); - } - | IF LPAR alloc_macro pop_nesting relational_expression RPAR - opt_statement - { - emit_macro($3, $7); - $$ = node($5, $3, cs(" "), END_NODE); - } - | IF LPAR alloc_macro pop_nesting relational_expression RPAR - opt_statement ELSE alloc_macro pop_nesting opt_statement - { - emit_macro($3, $7); - emit_macro($9, $11); - $$ = node($5, $3, cs("e"), $9, cs(" "), - END_NODE); - } - | WHILE LPAR alloc_macro relational_expression RPAR - opt_statement pop_nesting - { - ssize_t n; - - if (st_has_continue) - n = node($6, cs("M"), $4, $3, END_NODE); - else - n = node($6, $4, $3, END_NODE); - emit_macro($3, n); - $$ = node($4, $3, cs(" "), END_NODE); - } - | LBRACE statement_list RBRACE - { - $$ = $2; - } - | PRINT print_expression_list - { - $$ = $2; - } - ; - -alloc_macro : /* empty */ - { - $$ = cs(str_table[macro_char]); - macro_char++; - /* Do not use [, \ and ] */ - if (macro_char == '[') - macro_char += 3; - /* skip letters */ - else if (macro_char == 'a') - macro_char = '{'; - else if (macro_char == ARRAY_CHAR) - macro_char += 26; - else if (macro_char == 255) - fatal("program too big"); - if (breaksp == BREAKSTACK_SZ) - fatal("nesting too deep"); - breakstack[breaksp++] = nesting++; - } - ; - -pop_nesting : /* empty */ - { - breaksp--; - } - ; - -function : function_header opt_parameter_list RPAR opt_newline - LBRACE NEWLINE opt_auto_define_list - statement_list RBRACE - { - int n = node(prologue, $8, epilogue, - cs("0"), numnode(nesting), - cs("Q"), END_NODE); - emit_macro($1, n); - reset_macro_char = macro_char; - nesting = 0; - breaksp = 0; - } - ; - -function_header : DEFINE LETTER LPAR - { - $$ = function_node($2); - free($2); - prologue = cs(""); - epilogue = cs(""); - nesting = 1; - breaksp = 0; - breakstack[breaksp] = 0; - } - ; - -opt_newline : /* empty */ - | NEWLINE - ; - -opt_parameter_list - : /* empty */ - | parameter_list - ; - - -parameter_list : LETTER - { - add_par(letter_node($1)); - free($1); - } - | LETTER LBRACKET RBRACKET - { - add_par(array_node($1)); - free($1); - } - | parameter_list COMMA LETTER - { - add_par(letter_node($3)); - free($3); - } - | parameter_list COMMA LETTER LBRACKET RBRACKET - { - add_par(array_node($3)); - free($3); - } - ; - - - -opt_auto_define_list - : /* empty */ - | AUTO define_list NEWLINE - | AUTO define_list SEMICOLON - ; - - -define_list : LETTER - { - add_local(letter_node($1)); - free($1); - } - | LETTER LBRACKET RBRACKET - { - add_local(array_node($1)); - free($1); - } - | define_list COMMA LETTER - { - add_local(letter_node($3)); - free($3); - } - | define_list COMMA LETTER LBRACKET RBRACKET - { - add_local(array_node($3)); - free($3); - } - ; - - -opt_argument_list - : /* empty */ - { - $$ = cs(""); - } - | argument_list - ; - - -argument_list : expression - | argument_list COMMA expression - { - $$ = node($1, $3, END_NODE); - } - | argument_list COMMA LETTER LBRACKET RBRACKET - { - $$ = node($1, cs("l"), array_node($3), - END_NODE); - free($3); - } - ; - -opt_relational_expression - : /* empty */ - { - $$ = cs(" 0 0="); - } - | relational_expression - ; - -relational_expression - : expression EQUALS expression - { - $$ = node($1, $3, cs("="), END_NODE); - } - | expression UNEQUALS expression - { - $$ = node($1, $3, cs("!="), END_NODE); - } - | expression LESS expression - { - $$ = node($1, $3, cs(">"), END_NODE); - } - | expression LESS_EQ expression - { - $$ = node($1, $3, cs("!<"), END_NODE); - } - | expression GREATER expression - { - $$ = node($1, $3, cs("<"), END_NODE); - } - | expression GREATER_EQ expression - { - $$ = node($1, $3, cs("!>"), END_NODE); - } - | expression - { - $$ = node($1, cs(" 0!="), END_NODE); - } - ; - - -return_expression - : /* empty */ - { - $$ = node(cs("0"), epilogue, - numnode(nesting), cs("Q"), END_NODE); - } - | expression - { - $$ = node($1, epilogue, - numnode(nesting), cs("Q"), END_NODE); - } - | LPAR RPAR - { - $$ = node(cs("0"), epilogue, - numnode(nesting), cs("Q"), END_NODE); - } - ; - - -opt_expression : /* empty */ - { - $$ = cs(" 0"); - } - | expression - ; - -expression : named_expression - { - $$ = node($1.load, END_NODE); - } - | DOT { - $$ = node(cs("l."), END_NODE); - } - | NUMBER - { - $$ = node(cs(" "), as($1), END_NODE); - } - | LPAR expression RPAR - { - $$ = $2; - } - | LETTER LPAR opt_argument_list RPAR - { - $$ = node($3, cs("l"), - function_node($1), cs("x"), - END_NODE); - free($1); - } - | MINUS expression %prec UMINUS - { - $$ = node(cs(" 0"), $2, cs("-"), - END_NODE); - } - | expression PLUS expression - { - $$ = node($1, $3, cs("+"), END_NODE); - } - | expression MINUS expression - { - $$ = node($1, $3, cs("-"), END_NODE); - } - | expression MULTIPLY expression - { - $$ = node($1, $3, cs("*"), END_NODE); - } - | expression DIVIDE expression - { - $$ = node($1, $3, cs("/"), END_NODE); - } - | expression REMAINDER expression - { - $$ = node($1, $3, cs("%"), END_NODE); - } - | expression EXPONENT expression - { - $$ = node($1, $3, cs("^"), END_NODE); - } - | INCR named_expression - { - $$ = node($2.load, cs("1+d"), $2.store, - END_NODE); - } - | DECR named_expression - { - $$ = node($2.load, cs("1-d"), - $2.store, END_NODE); - } - | named_expression INCR - { - $$ = node($1.load, cs("d1+"), - $1.store, END_NODE); - } - | named_expression DECR - { - $$ = node($1.load, cs("d1-"), - $1.store, END_NODE); - } - | named_expression ASSIGN_OP expression - { - if ($2[0] == '\0') - $$ = node($3, cs($2), cs("d"), $1.store, - END_NODE); - else - $$ = node($1.load, $3, cs($2), cs("d"), - $1.store, END_NODE); - } - | LENGTH LPAR expression RPAR - { - $$ = node($3, cs("Z"), END_NODE); - } - | SQRT LPAR expression RPAR - { - $$ = node($3, cs("v"), END_NODE); - } - | SCALE LPAR expression RPAR - { - $$ = node($3, cs("X"), END_NODE); - } - | BOOL_NOT expression - { - $$ = node($2, cs("N"), END_NODE); - } - | expression BOOL_AND alloc_macro pop_nesting expression - { - ssize_t n = node(cs("R"), $5, END_NODE); - emit_macro($3, n); - $$ = node($1, cs("d0!="), $3, END_NODE); - } - | expression BOOL_OR alloc_macro pop_nesting expression - { - ssize_t n = node(cs("R"), $5, END_NODE); - emit_macro($3, n); - $$ = node($1, cs("d0="), $3, END_NODE); - } - | expression EQUALS expression - { - $$ = node($1, $3, cs("G"), END_NODE); - } - | expression UNEQUALS expression - { - $$ = node($1, $3, cs("GN"), END_NODE); - } - | expression LESS expression - { - $$ = node($3, $1, cs("("), END_NODE); - } - | expression LESS_EQ expression - { - $$ = node($3, $1, cs("{"), END_NODE); - } - | expression GREATER expression - { - $$ = node($1, $3, cs("("), END_NODE); - } - | expression GREATER_EQ expression - { - $$ = node($1, $3, cs("{"), END_NODE); - } - ; - -named_expression - : LETTER - { - $$.load = node(cs("l"), letter_node($1), - END_NODE); - $$.store = node(cs("s"), letter_node($1), - END_NODE); - free($1); - } - | LETTER LBRACKET expression RBRACKET - { - $$.load = node($3, cs(";"), - array_node($1), END_NODE); - $$.store = node($3, cs(":"), - array_node($1), END_NODE); - free($1); - } - | SCALE - { - $$.load = cs("K"); - $$.store = cs("k"); - } - | IBASE - { - $$.load = cs("I"); - $$.store = cs("i"); - } - | OBASE - { - $$.load = cs("O"); - $$.store = cs("o"); - } - ; - -print_expression_list - : print_expression - | print_expression_list COMMA print_expression - { - $$ = node($1, $3, END_NODE); - } - -print_expression - : expression - { - $$ = node($1, cs("ds.n"), END_NODE); - } - | STRING - { - char *p = escape($1); - $$ = node(cs("["), as(p), cs("]n"), END_NODE); - free(p); - } -%% - - -static void -grow(void) -{ - struct tree *p; - size_t newsize; - - if (current == instr_sz) { - newsize = instr_sz * 2 + 1; - p = reallocarray(instructions, newsize, sizeof(*p)); - if (p == NULL) { - free(instructions); - err(1, NULL); - } - instructions = p; - instr_sz = newsize; - } -} - -static ssize_t -cs(const char *str) -{ - - grow(); - instructions[current].index = CONST_STRING; - instructions[current].u.cstr = str; - return (current++); -} - -static ssize_t -as(const char *str) -{ - - grow(); - instructions[current].index = ALLOC_STRING; - instructions[current].u.astr = strdup(str); - if (instructions[current].u.astr == NULL) - err(1, NULL); - return (current++); -} - -static ssize_t -node(ssize_t arg, ...) -{ - va_list ap; - ssize_t ret; - - va_start(ap, arg); - - ret = current; - grow(); - instructions[current++].index = arg; - - do { - arg = va_arg(ap, ssize_t); - grow(); - instructions[current++].index = arg; - } while (arg != END_NODE); - - va_end(ap); - return (ret); -} - -static void -emit(ssize_t i, int level) -{ - - if (level > 1000) - errx(1, "internal error: tree level > 1000"); - if (instructions[i].index >= 0) { - while (instructions[i].index != END_NODE && - instructions[i].index != i) { - emit(instructions[i].index, level + 1); - i++; - } - } else if (instructions[i].index != END_NODE) - fputs(instructions[i].u.cstr, stdout); -} - -static void -emit_macro(int nodeidx, ssize_t code) -{ - - putchar('['); - emit(code, 0); - printf("]s%s\n", instructions[nodeidx].u.cstr); - nesting--; -} - -static void -free_tree(void) -{ - ssize_t i; - - for (i = 0; i < current; i++) - if (instructions[i].index == ALLOC_STRING) - free(instructions[i].u.astr); - current = 0; -} - -static ssize_t -numnode(int num) -{ - const char *p; - - if (num < 10) - p = str_table['0' + num]; - else if (num < 16) - p = str_table['A' - 10 + num]; - else - errx(1, "internal error: break num > 15"); - return (node(cs(" "), cs(p), END_NODE)); -} - - -static ssize_t -lookup(char * str, size_t len, char type) -{ - ENTRY entry, *found; - u_char *p; - u_short num; - - /* The scanner allocated an extra byte already */ - if (str[len-1] != type) { - str[len] = type; - str[len+1] = '\0'; - } - entry.key = str; - found = hsearch(entry, FIND); - if (found == NULL) { - if (var_count == MAX_VARIABLES) - errx(1, "too many variables"); - p = malloc(4); - if (p == NULL) - err(1, NULL); - num = var_count++; - p[0] = 255; - p[1] = ENCODE(num / VAR_BASE + 1); - p[2] = ENCODE(num % VAR_BASE + 1); - p[3] = '\0'; - - entry.data = (char *)p; - entry.key = strdup(str); - if (entry.key == NULL) - err(1, NULL); - found = hsearch(entry, ENTER); - if (found == NULL) - err(1, NULL); - } - return (cs(found->data)); -} - -static ssize_t -letter_node(char *str) -{ - size_t len; - - len = strlen(str); - if (len == 1 && str[0] != '_') - return (cs(str_table[(int)str[0]])); - else - return (lookup(str, len, 'L')); -} - -static ssize_t -array_node(char *str) -{ - size_t len; - - len = strlen(str); - if (len == 1 && str[0] != '_') - return (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])); - else - return (lookup(str, len, 'A')); -} - -static ssize_t -function_node(char *str) -{ - size_t len; - - len = strlen(str); - if (len == 1 && str[0] != '_') - return (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])); - else - return (lookup(str, len, 'F')); -} - -static void -add_par(ssize_t n) -{ - - prologue = node(cs("S"), n, prologue, END_NODE); - epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); -} - -static void -add_local(ssize_t n) -{ - - prologue = node(cs("0S"), n, prologue, END_NODE); - epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE); -} - -void -yyerror(const char *s) -{ - char *p, *str; - int n; - - if (yyin != NULL && feof(yyin)) - n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF", - __progname, filename, lineno, s); - else if (yytext[0] == '\n') - n = asprintf(&str, - "%s: %s:%d: %s: newline unexpected", - __progname, filename, lineno, s); - else if (isspace((unsigned char)yytext[0]) || - !isprint((unsigned char)yytext[0])) - n = asprintf(&str, - "%s: %s:%d: %s: ascii char 0x%02x unexpected", - __progname, filename, lineno, s, yytext[0] & 0xff); - else - n = asprintf(&str, "%s: %s:%d: %s: %s unexpected", - __progname, filename, lineno, s, yytext); - if (n == -1) - err(1, NULL); - - fputs("c[", stdout); - for (p = str; *p != '\0'; p++) { - if (*p == '[' || *p == ']' || *p =='\\') - putchar('\\'); - putchar(*p); - } - fputs("]ec\n", stdout); - free(str); -} - -void -fatal(const char *s) -{ - - errx(1, "%s:%d: %s", filename, lineno, s); -} - -static void -warning(const char *s) -{ - - warnx("%s:%d: %s", filename, lineno, s); -} - -static void -init(void) -{ - unsigned int i; - - for (i = 0; i < UCHAR_MAX; i++) { - str_table[i][0] = i; - str_table[i][1] = '\0'; - } - if (hcreate(1 << 16) == 0) - err(1, NULL); -} - - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s [-chlv] [-e expression] [file ...]\n", - __progname); - exit(1); -} - -static char * -escape(const char *str) -{ - char *p, *ret; - - ret = malloc(strlen(str) + 1); - if (ret == NULL) - err(1, NULL); - - p = ret; - while (*str != '\0') { - /* - * We get _escaped_ strings here. Single backslashes are - * already converted to double backslashes - */ - if (*str == '\\') { - if (*++str == '\\') { - switch (*++str) { - case 'a': - *p++ = '\a'; - break; - case 'b': - *p++ = '\b'; - break; - case 'f': - *p++ = '\f'; - break; - case 'n': - *p++ = '\n'; - break; - case 'q': - *p++ = '"'; - break; - case 'r': - *p++ = '\r'; - break; - case 't': - *p++ = '\t'; - break; - case '\\': - *p++ = '\\'; - break; - } - str++; - } else { - *p++ = '\\'; - *p++ = *str++; - } - } else - *p++ = *str++; - } - *p = '\0'; - return (ret); -} - -/* ARGSUSED */ -static void -sigchld(int signo __unused) -{ - pid_t pid; - int status, save_errno = errno; - - for (;;) { - pid = waitpid(dc, &status, WCONTINUED | WNOHANG); - if (pid == -1) { - if (errno == EINTR) - continue; - _exit(0); - } else if (pid == 0) - break; - if (WIFEXITED(status) || WIFSIGNALED(status)) - _exit(0); - else - break; - } - errno = save_errno; -} - -static const char * -dummy_prompt(void) -{ - - return (""); -} - -int -main(int argc, char *argv[]) -{ - char *q; - int p[2]; - int ch, i; - - init(); - setvbuf(stdout, NULL, _IOLBF, 0); - - sargv = reallocarray(NULL, argc, sizeof(char *)); - if (sargv == NULL) - err(1, NULL); - - if ((cmdexpr = strdup("")) == NULL) - err(1, NULL); - /* The d debug option is 4.4 BSD bc(1) compatible */ - while ((ch = getopt_long(argc, argv, "cde:hlqv", - long_options, NULL)) != -1) { - switch (ch) { - case 'c': - case 'd': - do_fork = false; - break; - case 'e': - q = cmdexpr; - if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1) - err(1, NULL); - free(q); - break; - case 'h': - usage(); - break; - case 'l': - sargv[sargc++] = _PATH_LIBB; - break; - case 'q': - /* compatibility option */ - break; - case 'v': - fprintf(stderr, "%s (BSD bc) %s\n", __progname, BC_VER); - exit(0); - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && - isatty(STDERR_FILENO); - for (i = 0; i < argc; i++) - sargv[sargc++] = argv[i]; - - if (do_fork) { - if (pipe(p) == -1) - err(1, "cannot create pipe"); - dc = fork(); - if (dc == -1) - err(1, "cannot fork"); - else if (dc != 0) { - signal(SIGCHLD, sigchld); - close(STDOUT_FILENO); - dup(p[1]); - close(p[0]); - close(p[1]); - } else { - close(STDIN_FILENO); - dup(p[0]); - close(p[0]); - close(p[1]); - execl(_PATH_DC, "dc", "-x", (char *)NULL); - err(1, "cannot find dc"); - } - } - if (interactive) { - gettty(&ttysaved); - el = el_init("bc", stdin, stderr, stderr); - hist = history_init(); - history(hist, &he, H_SETSIZE, 100); - el_set(el, EL_HIST, history, hist); - el_set(el, EL_EDITOR, "emacs"); - el_set(el, EL_SIGNAL, 1); - el_set(el, EL_PROMPT, dummy_prompt); - el_set(el, EL_ADDFN, "bc_eof", "", bc_eof); - el_set(el, EL_BIND, "^D", "bc_eof", NULL); - el_source(el, NULL); - } - yywrap(); - return (yyparse()); -} diff --git a/usr.bin/bc/extern.h b/usr.bin/bc/extern.h deleted file mode 100644 index 98adf069f9b1..000000000000 --- a/usr.bin/bc/extern.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $OpenBSD: extern.h,v 1.12 2014/04/17 19:07: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 -#include - -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; diff --git a/usr.bin/bc/pathnames.h b/usr.bin/bc/pathnames.h deleted file mode 100644 index cf1c13a6c702..000000000000 --- a/usr.bin/bc/pathnames.h +++ /dev/null @@ -1,20 +0,0 @@ -/* $OpenBSD: pathnames.h,v 1.1 2003/09/25 19:32:44 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. - */ - -#define _PATH_LIBB "/usr/share/misc/bc.library" -#define _PATH_DC "/usr/bin/dc" diff --git a/usr.bin/bc/scan.l b/usr.bin/bc/scan.l deleted file mode 100644 index 0f57f02e50d5..000000000000 --- a/usr.bin/bc/scan.l +++ /dev/null @@ -1,368 +0,0 @@ -%{ -/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 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 -#include -#include -#include -#include -#include -#include -#include - -#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); -{ - "*/" BEGIN(INITIAL); - \n lineno++; - \* ; - [^*\n]+ ; - <> fatal("end of file in comment"); -} - -\" BEGIN(string); init_strbuf(); -{ - [^"\n\\\[\]]+ add_str(yytext); - \[ add_str("\\["); - \] add_str("\\]"); - \\ add_str("\\\\"); - \n add_str("\n"); lineno++; - \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; - <> 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("."); - } -{ - {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] ; -<> 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); -} - - diff --git a/usr.bin/bc/tty.c b/usr.bin/bc/tty.c deleted file mode 100644 index 3b2a04077040..000000000000 --- a/usr.bin/bc/tty.c +++ /dev/null @@ -1,64 +0,0 @@ -/* $OpenBSD: tty.c,v 1.3 2015/09/05 09:49:24 jsg Exp $ */ - -/* - * Copyright (c) 2013, 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 -#include -#include -#include -#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; -} diff --git a/usr.bin/dc/Makefile b/usr.bin/dc/Makefile deleted file mode 100644 index 377ba30f555f..000000000000 --- a/usr.bin/dc/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $OpenBSD: Makefile,v 1.2 2006/11/26 11:31:09 deraadt Exp $ - -.include - -PROG= dc -SRCS= dc.c bcode.c inout.c mem.c stack.c -LIBADD= crypto - -HAS_TESTS= -SUBDIR.${MK_TESTS}+= tests - -.include diff --git a/usr.bin/dc/Makefile.depend b/usr.bin/dc/Makefile.depend deleted file mode 100644 index 30ac5d62651c..000000000000 --- a/usr.bin/dc/Makefile.depend +++ /dev/null @@ -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 - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/usr.bin/dc/bcode.c b/usr.bin/dc/bcode.c deleted file mode 100644 index 0e34f0399035..000000000000 --- a/usr.bin/dc/bcode.c +++ /dev/null @@ -1,1773 +0,0 @@ -/* $OpenBSD: bcode.c,v 1.46 2014/10/08 03:59:56 doug 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 -#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 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 print_err(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 }, - { 'e', print_err }, - { '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 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) -{ - 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_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); - } -} - -/* Change the scale of n to s. Reducing scale may truncate the mantissa */ -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 -print_err(void) -{ - struct value *value = tos(); - if (value != NULL) { - print_value(stderr, value, "", bmachine.obase); - (void)putc('\n', stderr); - } - 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 != ULONG_MAX && 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 != ULONG_MAX && 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 != ULONG_MAX && 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_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 == ULONG_MAX || 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_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 == ULONG_MAX || 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) - 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) - 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) - 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; - - a = pop_number(); - if (a == NULL) - return; - b = pop_number(); - if (b == NULL) { - push_number(a); - return; - } - - r = div_number(b, a, bmachine.scale); - - 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) - return; - b = pop_number(); - if (b == NULL) { - push_number(a); - return; - } - - r = new_number(); - scale = max(a->scale, b->scale); - r->scale = scale; - - if (BN_is_zero(a->number)) - warnx("remainder by zero"); - else { - normalize(a, scale); - normalize(b, 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, *frac, *quotient, *rdiv, *remainder; - BN_CTX *ctx; - u_int scale; - - a = pop_number(); - if (a == NULL) - return; - b = pop_number(); - if (b == NULL) { - push_number(a); - return; - } - - rdiv = new_number(); - quotient = new_number(); - remainder = new_number(); - scale = max(a->scale, b->scale); - rdiv->scale = 0; - remainder->scale = scale; - quotient->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); - - ctx = BN_CTX_new(); - bn_checkp(ctx); - /* - * Unlike other languages' divmod operations, dc is specified - * to return the remainder and the full quotient, rather than - * the remainder and the floored quotient. bn(3) has no - * function to calculate both. So we'll use BN_div to get the - * remainder and floored quotient, then calculate the full - * quotient from those. - * - * quotient = rdiv + remainder / divisor - */ - bn_check(BN_div(rdiv->number, remainder->number, - b->number, a->number, ctx)); - frac = div_number(remainder, a, bmachine.scale); - normalize(rdiv, bmachine.scale); - normalize(remainder, scale); - bn_check(BN_add(quotient->number, rdiv->number, frac->number)); - free_number(frac); - BN_CTX_free(ctx); - } - push_number(quotient); - push_number(remainder); - free_number(rdiv); - 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) - 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 == ULONG_MAX || - 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) - 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) - 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) - 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) - 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) - 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 == ULONG_MAX || 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 == ULONG_MAX) - 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, bmachine.scale)); -} - -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 = reallocarray(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) - 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 - } -} diff --git a/usr.bin/dc/bcode.h b/usr.bin/dc/bcode.h deleted file mode 100644 index b03f11999a9a..000000000000 --- a/usr.bin/dc/bcode.h +++ /dev/null @@ -1,103 +0,0 @@ -/* $OpenBSD: bcode.h,v 1.7 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 -#include - -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); -} diff --git a/usr.bin/dc/dc.1 b/usr.bin/dc/dc.1 deleted file mode 100644 index 401dd3435127..000000000000 --- a/usr.bin/dc/dc.1 +++ /dev/null @@ -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 . diff --git a/usr.bin/dc/dc.c b/usr.bin/dc/dc.c deleted file mode 100644 index 4f9a55f450bb..000000000000 --- a/usr.bin/dc/dc.c +++ /dev/null @@ -1,154 +0,0 @@ -/* $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 -#include - -#include -#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 -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); -} diff --git a/usr.bin/dc/extern.h b/usr.bin/dc/extern.h deleted file mode 100644 index 86ab2d80dd6f..000000000000 --- a/usr.bin/dc/extern.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $OpenBSD: extern.h,v 1.4 2014/12/01 13:13:00 deraadt 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 -#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 *); */ diff --git a/usr.bin/dc/inout.c b/usr.bin/dc/inout.c deleted file mode 100644 index a91531b2c769..000000000000 --- a/usr.bin/dc/inout.c +++ /dev/null @@ -1,446 +0,0 @@ -/* $OpenBSD: inout.c,v 1.18 2014/12/01 13:13:00 deraadt 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 -#include -#include -#include -#include - -#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("", 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); -} diff --git a/usr.bin/dc/mem.c b/usr.bin/dc/mem.c deleted file mode 100644 index 95c5068f2041..000000000000 --- a/usr.bin/dc/mem.c +++ /dev/null @@ -1,140 +0,0 @@ -/* $OpenBSD: mem.c,v 1.6 2014/12/01 13:13:00 deraadt 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 -#include - -#include -#include -#include -#include - -#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()); -} diff --git a/usr.bin/dc/stack.c b/usr.bin/dc/stack.c deleted file mode 100644 index c4b15dda4a14..000000000000 --- a/usr.bin/dc/stack.c +++ /dev/null @@ -1,370 +0,0 @@ -/* $OpenBSD: stack.c,v 1.13 2014/12/01 13:13:00 deraadt 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 -#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; - } - 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 = 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); -} diff --git a/usr.bin/dc/tests/Makefile b/usr.bin/dc/tests/Makefile deleted file mode 100644 index ac2204e3cba7..000000000000 --- a/usr.bin/dc/tests/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -PACKAGE= tests - -ATF_TESTS_SH= inout -ATF_TESTS_SH+= bcode - -.include diff --git a/usr.bin/dc/tests/bcode.sh b/usr.bin/dc/tests/bcode.sh deleted file mode 100755 index b847ad631655..000000000000 --- a/usr.bin/dc/tests/bcode.sh +++ /dev/null @@ -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 -} diff --git a/usr.bin/dc/tests/inout.sh b/usr.bin/dc/tests/inout.sh deleted file mode 100755 index ef997f642830..000000000000 --- a/usr.bin/dc/tests/inout.sh +++ /dev/null @@ -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 -}