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 -}