summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorphil <phil@NetBSD.org>1997-04-29 00:34:25 +0000
committerphil <phil@NetBSD.org>1997-04-29 00:34:25 +0000
commitbc4e66aef97f86fd61dc4cd478f6564b0b3857b3 (patch)
tree32b08a693b1a9045e32f00e5b1542f8fc92f24db /gnu
parentf18cfec654719ae1e1ce6725d7b6fd8834919d6a (diff)
Complete import of bc-1.04 by updating dc.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/usr.bin/dc/README.NetBSD18
-rw-r--r--gnu/usr.bin/dc/dc-proto.h9
-rw-r--r--gnu/usr.bin/dc/dc.168
-rw-r--r--gnu/usr.bin/dc/dc.c173
-rw-r--r--gnu/usr.bin/dc/dc.h13
-rw-r--r--gnu/usr.bin/dc/dc.texi497
-rw-r--r--gnu/usr.bin/dc/eval.c113
-rw-r--r--gnu/usr.bin/dc/misc.c80
-rw-r--r--gnu/usr.bin/dc/numeric.c536
-rw-r--r--gnu/usr.bin/dc/stack.c90
-rw-r--r--gnu/usr.bin/dc/string.c13
11 files changed, 1481 insertions, 129 deletions
diff --git a/gnu/usr.bin/dc/README.NetBSD b/gnu/usr.bin/dc/README.NetBSD
index 51823984bcf..5ba67ea3022 100644
--- a/gnu/usr.bin/dc/README.NetBSD
+++ b/gnu/usr.bin/dc/README.NetBSD
@@ -1,11 +1,13 @@
-This is GNU dc. (Taken from the GNU bc 1.03 distribution.)
+This is GNU bc 1.04.
+
+The full distribution of GNU bc-1.04 may be found at any GNU software
+archive. The master copy is at ftp://prep.ai.mit.edu/pub/gnu/bc-1.04.tar.gz.
+
+Not everything included in the full bc-1.04 distribution is included.
+The files included here are only the needed files for building bc on
+NetBSD. Their location in the NetBSD tree are different than in the
+original bc-1.04 source tree.
+
-ALL other files distributed with GNU dc are available in some form in
-/usr/src/gnu/usr.bin/bc. (aka ../bc)
-The files array.c, eval.c, misc.c, stack.c and string.c were renamed from
-their original distribution names as dc-xxxx.c.
-An original distribution of GNU bc/dc can be regenerated from the files
-in the directories bc and dc. (It will require GNU autoconf 2.0 to
-regenerate some files.)
diff --git a/gnu/usr.bin/dc/dc-proto.h b/gnu/usr.bin/dc/dc-proto.h
index 97d7aff4300..5aa9bc79e90 100644
--- a/gnu/usr.bin/dc/dc-proto.h
+++ b/gnu/usr.bin/dc/dc-proto.h
@@ -1,7 +1,7 @@
/*
* prototypes of all externally visible dc functions
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,10 @@ extern void *dc_malloc DC_PROTO((size_t));
extern void dc_array_set DC_PROTO((int, int, dc_data));
extern void dc_array_init DC_PROTO((void));
extern void dc_binop DC_PROTO((int (*)(dc_num, dc_num, int, dc_num *), int));
+extern void dc_binop2 DC_PROTO((int (*)(dc_num, dc_num, int,
+ dc_num *, dc_num *), int));
+extern void dc_triop DC_PROTO((int (*)(dc_num, dc_num, dc_num, int,
+ dc_num *), int));
extern void dc_clear_stack DC_PROTO((void));
extern void dc_free_num DC_PROTO((dc_num *));
extern void dc_free_str DC_PROTO((dc_str *));
@@ -46,6 +50,7 @@ extern void dc_string_init DC_PROTO((void));
extern int dc_cmpop DC_PROTO((void));
extern int dc_compare DC_PROTO((dc_num, dc_num));
extern int dc_evalfile DC_PROTO((FILE *));
+extern int dc_evalstr DC_PROTO((dc_data));
extern int dc_num2int DC_PROTO((dc_num, dc_boolean));
extern int dc_numlen DC_PROTO((dc_num));
extern int dc_pop DC_PROTO((dc_data *));
@@ -69,7 +74,9 @@ extern dc_data dc_readstring DC_PROTO((FILE *, int , int));
extern int dc_add DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_div DC_PROTO((dc_num, dc_num, int, dc_num *));
+extern int dc_divrem DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *));
extern int dc_exp DC_PROTO((dc_num, dc_num, int, dc_num *));
+extern int dc_modexp DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *));
extern int dc_mul DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_rem DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_sub DC_PROTO((dc_num, dc_num, int, dc_num *));
diff --git a/gnu/usr.bin/dc/dc.1 b/gnu/usr.bin/dc/dc.1
index 186d311b264..f64e0f91a81 100644
--- a/gnu/usr.bin/dc/dc.1
+++ b/gnu/usr.bin/dc/dc.1
@@ -1,14 +1,31 @@
-.TH DC 1 "07 Apr 1994" "GNU Project"
+.\"
+.\" dc.1 - the *roff document processor source for the dc manual
+.\"
+.\" This file is part of GNU dc.
+.\" Copyright (C) 1994, 1997 Free Software Foundation, Inc.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License , or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; see the file COPYING. If not, write to
+.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.TH DC 1 "1997-03-25" "GNU Project"
.ds dc \fIdc\fP
.ds Dc \fIDc\fP
-.SH
-NAME
+.SH NAME
dc \- an arbitrary precision calculator
-.SH
-SYNOPSIS
+.SH SYNOPSIS
dc
-.SH
-DESCRIPTION
+.SH DESCRIPTION
.PP
\*(Dc is a reverse-polish desk calculator which supports
unlimited precision arithmetic.
@@ -94,6 +111,15 @@ The division is done with as many fraction digits
as the precision value specifies,
and the remainder is also computed with that many fraction digits.
.TP
+.B ~
+Pops two values,
+divides the second one popped from the first one popped.
+The quotient is pushed first, and the remainder is pushed next.
+The number of fraction digits used in the division
+is specified by the precision value.
+(The sequence \fBSdSn lnld/ LnLd%\fP could also accomplish
+this function, with slightly different error checking.)
+.TP
.B ^
Pops two values and exponentiates,
using the first value popped as the exponent
@@ -102,6 +128,20 @@ The fraction part of the exponent is ignored.
The precision value specifies the number of fraction
digits in the result.
.TP
+.B |
+Pops three values and computes a modular exponentiation.
+The first value popped is used as the reduction modulus;
+this value must be a non-zero number,
+and should be an integer.
+The second popped is used as the exponent;
+this value must be a non-negative number,
+and any fractional part of this exponent will be ignored.
+The third value popped is the base which gets exponentiated.
+The precision value specifies the number of fraction
+digits in the result.
+For small numbers this is like the sequence \fBSm lble^ Lm%\fP,
+but, unlike \fB^\fP, this command will work with arbritrarily large exponents.
+.TP
.B v
Pops one value,
computes its square root,
@@ -131,6 +171,9 @@ Clears the stack, rendering it empty.
Duplicates the value on the top of the stack,
pushing another copy of it.
Thus, ``4d*p'' computes 4 squared and prints it.
+.TP
+.B r
+Reverses the order of (swaps) the top two values on the stack.
.SH
Registers
.PP
@@ -253,6 +296,13 @@ prints the characters
.B foo
(with no newline).
.TP
+.B a
+The top-of-stack is popped.
+If it was a number, then the low-order byte of this number
+is converted into a string and pushed onto the stack.
+Otherwise the top-of-stack was a string,
+and the first character of that string is pushed back.
+.TP
.B x
Pops a value off the stack and executes it as a macro.
Normally it should be a string;
@@ -378,10 +428,6 @@ are usually only used by traditional implementations of
(The GNU
.I bc
is self contained and does not need \*(dc to run.)
-The comment operator
-.B #
-is a new command not found in traditional implementations of
-.IR dc .
.SH
BUGS
.PP
diff --git a/gnu/usr.bin/dc/dc.c b/gnu/usr.bin/dc/dc.c
new file mode 100644
index 00000000000..85da40f3255
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.c
@@ -0,0 +1,173 @@
+/*
+ * implement the "dc" Desk Calculator language.
+ *
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can either send email to this
+ * program's author (see below) or write to: The Free Software Foundation,
+ * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
+ */
+
+/* Written with strong hiding of implementation details
+ * in their own specialized modules.
+ */
+/* This module contains the argument processing/main functions.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif
+#endif
+#include <getopt.h>
+#include "dc.h"
+#include "dc-proto.h"
+
+#include "version.h"
+
+#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
+# define EXIT_FAILURE 1
+#endif
+
+const char *progname; /* basename of program invocation */
+
+/* your generic usage function */
+static void
+usage DC_DECLARG((f))
+ FILE *f DC_DECLEND
+{
+ fprintf(f, "\
+Usage: %s [OPTION] [file ...]\n\
+ -e, --expression=EXPR evaluate expression\n\
+ -f, --file=FILE evaluate contents of file\n\
+ -h, --help display this help and exit\n\
+ -V, --version output version information and exit\n\
+\n\
+Report bugs to @\n\
+", progname);
+}
+
+static void
+show_version DC_DECLVOID()
+{
+ printf("%s\n\n", DC_VERSION);
+ printf("Email bug reports to: bug-gnu-utils@prep.ai.mit.edu .\n");
+ printf("Be sure to include the word ``dc'' \
+somewhere in the ``Subject:'' field.\n");
+}
+
+/* returns a pointer to one past the last occurance of c in s,
+ * or s if c does not occur in s.
+ */
+static char *
+r1bindex DC_DECLARG((s, c))
+ char *s DC_DECLSEP
+ int c DC_DECLEND
+{
+ char *p = strrchr(s, c);
+
+ if (!p)
+ return s;
+ return p + 1;
+}
+
+static void
+try_file(const char *filename) {
+ FILE *input;
+
+ if ( !(input=fopen(filename, "r")) ) {
+ fprintf(stderr, "Could not open file ");
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+ if (dc_evalfile(input))
+ exit(EXIT_FAILURE);
+ fclose(input);
+}
+
+
+int
+main DC_DECLARG((argc, argv))
+ int argc DC_DECLSEP
+ char **argv DC_DECLEND
+{
+ static struct option const long_opts[] = {
+ {"expression", required_argument, NULL, 'e'},
+ {"file", required_argument, NULL, 'f'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+ };
+ int did_eval = 0;
+ int c;
+
+ progname = r1bindex(*argv, '/');
+ dc_math_init();
+ dc_string_init();
+ dc_register_init();
+ dc_array_init();
+
+ while ((c = getopt_long(argc, argv, "hVe:", long_opts, (int *)0)) != EOF) {
+ switch (c) {
+ case 'e':
+ { dc_data string = dc_makestring(optarg, strlen(optarg));
+ if (dc_evalstr(string))
+ return EXIT_SUCCESS;
+ dc_free_str(&string.v.string);
+ did_eval = 1;
+ }
+ break;
+ case 'f':
+ try_file(optarg);
+ did_eval = 1;
+ break;
+ case 'h':
+ usage(stdout);
+ return EXIT_SUCCESS;
+ case 'V':
+ show_version();
+ return EXIT_SUCCESS;
+ default:
+ usage(stderr);
+ return EXIT_FAILURE;
+ }
+ }
+
+ for (; optind < argc; ++optind) {
+ if (strcmp(argv[optind], "-") == 0) {
+ if (dc_evalfile(stdin))
+ return EXIT_FAILURE;
+ } else {
+ try_file(argv[optind]);
+ }
+ did_eval = 1;
+ }
+ if (!did_eval) {
+ /* if no -e commands and no command files, then eval stdin */
+ if (dc_evalfile(stdin))
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/gnu/usr.bin/dc/dc.h b/gnu/usr.bin/dc/dc.h
index 7193aea8967..eeac77b29e2 100644
--- a/gnu/usr.bin/dc/dc.h
+++ b/gnu/usr.bin/dc/dc.h
@@ -1,7 +1,7 @@
/*
* Header file for dc routines
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,14 +53,11 @@ typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
/* type discriminant for dc_data */
typedef enum {DC_UNINITIALIZED, DC_NUMBER, DC_STRING} dc_value_type;
-/* generic pointer for information hiding */
-typedef void *Opaque;
+/* only numeric.c knows what dc_num's *really* look like */
+typedef struct dc_number *dc_num;
-/* only dc-math.c knows what dc_num's *really* look like */
-typedef Opaque dc_num;
-
-/* only dc-string.c knows what dc_str's *really* look like */
-typedef Opaque dc_str;
+/* only string.c knows what dc_str's *really* look like */
+typedef struct dc_string *dc_str;
/* except for the two implementation-specific modules, all
diff --git a/gnu/usr.bin/dc/dc.texi b/gnu/usr.bin/dc/dc.texi
new file mode 100644
index 00000000000..e0ade802b1c
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.texi
@@ -0,0 +1,497 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename dc.info
+@settitle dc, an arbitrary precision calculator
+@c %**end of header
+
+@c This file has the new style title page commands.
+@c Run `makeinfo' rather than `texinfo-format-buffer'.
+
+@c smallbook
+
+@c tex
+@c \overfullrule=0pt
+@c end tex
+
+@c Combine indices.
+@synindex cp fn
+@syncodeindex vr fn
+@syncodeindex ky fn
+@syncodeindex pg fn
+@syncodeindex tp fn
+
+@ifinfo
+This file documents @sc{dc}, an arbitrary precision calculator.
+
+Published by the Free Software Foundation,
+675 Massachusetts Avenue,
+Cambridge, MA 02139 USA
+
+Copyright (C) 1984 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@setchapternewpage off
+
+@titlepage
+@title dc, an arbitrary precision calculator
+
+@author by Ken Pizzini
+@author original manual by Richard Stallman
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1994, 1997 Free Software Foundation, Inc.
+
+@sp 2
+Published by the Free Software Foundation, @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+
+@end titlepage
+@page
+
+@node Top, Introduction, (dir), (dir)
+
+@menu
+* Introduction:: Introduction
+* Invocation:: Invocation
+* Printing Commands:: Printing Commands
+* Arithmetic:: Arithmetic
+* Stack Control:: Stack Control
+* Registers:: Registers
+* Parameters:: Parameters
+* Strings:: Strings
+* Status Inquiry:: Status Inquiry
+* Miscellaneous:: Other commands
+* Notes:: Notes
+@end menu
+
+@node Introduction, Invocation, Top, Top
+@comment node-name, next, previous, up
+@chapter Introduction
+
+@sc{dc} is a reverse-polish desk calculator
+which supports unlimited precision arithmetic.
+It also allows you to define and call macros.
+Normally @sc{dc} reads from the standard input;
+if any command arguments are given to it, they are filenames,
+and @sc{dc} reads and executes the contents of the files
+instead of reading from standard input.
+All normal output is to standard output;
+all error messages are written to standard error.
+
+To exit, use @samp{q}.
+@kbd{C-c} does not exit;
+it is used to abort macros that are looping, etc.
+(Currently this is not true; @kbd{C-c} does exit.)
+
+A reverse-polish calculator stores numbers on a stack.
+Entering a number pushes it on the stack.
+Arithmetic operations pop arguments off the stack and push the results.
+
+To enter a number in @sc{dc}, type the digits,
+with an optional decimal point.
+Exponential notation is not supported.
+To enter a negative number, begin the number with @samp{_}.
+@samp{-} cannot be used for this, as it is a binary operator
+for subtraction instead.
+To enter two numbers in succession,
+separate them with spaces or newlines.
+These have no meaning as commands.
+
+@node Invocation, Printing Commands, Introduction, Top
+@chapter Invocation
+
+@sc{dc} may be invoked with the following command-line options:
+@table @samp
+
+@item -e @var{expr}
+@item --expression=@var{expr}
+Evaluate @var{expr} as @sc{dc} commands.
+
+@item -f @var{file}
+@item --file=@var{file}
+Read and evaluate @sc{dc} commands from @var{file}.
+
+@item -h
+@item --help
+Print a usage message summarizing the command-line options, then exit.
+
+@item -V
+@item --version
+Print the version information for this program, then exit.
+@end table
+
+If any command-line parameters remain after processing the options,
+these parameters are interpreted as additional @var{file}s whose
+contents are read and evaluated.
+A file name of @code{-} refers to the standard input stream.
+If no @code{-e} option was specified, and no files were specified,
+then the standard input will be read for commands to evaluate.
+
+@node Printing Commands, Arithmetic, Invocation, Top
+@chapter Printing Commands
+
+@table @samp
+@item p
+Prints the value on the top of the stack,
+without altering the stack.
+A newline is printed after the value.
+
+@item P
+Prints the value on the top of the stack, popping it off,
+and does not print a newline after.
+
+@item f
+Prints the entire contents of the stack
+@c and the contents of all of the registers,
+without altering anything.
+This is a good command to use if you are lost or want
+to figure out what the effect of some command has been.
+@end table
+
+@node Arithmetic, Stack Control, Printing Commands, Top
+@chapter Arithmetic
+
+@table @samp
+@item +
+Pops two values off the stack, adds them, and pushes the result.
+The precision of the result is determined only
+by the values of the arguments, and is enough to be exact.
+
+@item -
+Pops two values, subtracts the first one popped
+from the second one popped, and pushes the result.
+
+@item *
+Pops two values, multiplies them, and pushes the result.
+The number of fraction digits in the result is controlled
+by the current precision value (see below) and does not
+depend on the values being multiplied.
+
+@item /
+Pops two values, divides the second one popped
+from the first one popped, and pushes the result.
+The number of fraction digits is specified by the precision value.
+
+@item %
+Pops two values,
+computes the remainder of the division that
+the @samp{/} command would do,
+and pushes that.
+The division is done with as many fraction digits
+as the precision value specifies,
+and the remainder is also computed with that many fraction digits.
+
+@item ~
+Pops two values,
+divides the second one popped from the first one popped.
+The quotient is pushed first, and the remainder is pushed next.
+The number of fraction digits used in the division
+is specified by the precision value.
+(The sequence @code{SdSn lnld/ LnLd%} could also accomplish
+this function, with slightly different error checking.)
+(This command is a GNU extension.)
+
+@item ^
+Pops two values and exponentiates,
+using the first value popped as the exponent
+and the second popped as the base.
+The fraction part of the exponent is ignored.
+The precision value specifies the number of fraction
+digits in the result.
+
+@item |
+Pops three values and computes a modular exponentiation.
+The first value popped is used as the reduction modulus;
+this value must be a non-zero number,
+and the result may not be accurate if the modulus
+is not an integer.
+The second popped is used as the exponent;
+this value must be a non-negative number,
+and any fractional part of this exponent will be ignored.
+The third value popped is the base which gets exponentiated.
+The precision value specifies the number of fraction
+digits in the result.
+For small numbers this is like the sequence @code{Sm lble^ Lm%},
+but, unlike @code{^}, this command will work with arbritrarily large exponents.
+
+@item v
+Pops one value, computes its square root, and pushes that.
+The precision value specifies the number of fraction digits
+in the result.
+@end table
+
+Most arithmetic operations are affected by the @emph{precision value},
+which you can set with the @samp{k} command.
+The default precision value is zero,
+which means that all arithmetic except for
+addition and subtraction produces integer results.
+
+The remainder operation (@samp{%}) requires some explanation:
+applied to arguments @samp{a} and @samp{b}
+it produces @samp{a - (b * (a / b))},
+where @samp{a / b} is computed in the current precision.
+
+@node Stack Control, Registers, Arithmetic, Top
+@chapter Stack Control
+
+@table @samp
+@item c
+Clears the stack, rendering it empty.
+
+@item d
+Duplicates the value on the top of the stack,
+pushing another copy of it.
+Thus, @samp{4d*p} computes 4 squared and prints it.
+
+@item r
+Reverses the order of (swaps) the top two values on the stack.
+(This command is a GNU extension.)
+@end table
+
+@node Registers, Parameters, Stack Control, Top
+@chapter Registers
+
+@sc{dc} provides 256 memory registers, each named by a single character.
+You can store a number in a register and retrieve it later.
+
+@table @samp
+@item s@var{r}
+Pop the value off the top of the stack and
+store it into register @var{r}.
+
+@item l@var{r}
+Copy the value in register @var{r},
+and push it onto the stack.
+This does not alter the contents of @var{r}.
+
+Each register also contains its own stack.
+The current register value is the top of the register's stack.
+
+@item S@var{r}
+Pop the value off the top of the (main) stack and
+push it onto the stack of register @var{r}.
+The previous value of the register becomes inaccessible.
+
+@item L@var{r}
+Pop the value off the top of register @var{r}'s stack
+and push it onto the main stack.
+The previous value in register @var{r}'s stack, if any,
+is now accessible via the @samp{l@var{r}} command.
+@end table
+@c
+@c The @samp{f} command prints a list of all registers that have contents
+@c stored in them, together with their contents.
+@c Only the current contents of each register (the top of its stack)
+@c is printed.
+
+@node Parameters, Strings, Registers, Top
+@chapter Parameters
+
+@sc{dc} has three parameters that control its operation:
+the precision, the input radix, and the output radix.
+The precision specifies the number of fraction digits
+to keep in the result of most arithmetic operations.
+The input radix controls the interpretation of numbers typed in;
+@emph{all} numbers typed in use this radix.
+The output radix is used for printing numbers.
+
+The input and output radices are separate parameters;
+you can make them unequal, which can be useful or confusing.
+The input radix must be between 2 and 36 inclusive.
+The output radix must be at least 2.
+The precision must be zero or greater.
+The precision is always measured in decimal digits,
+regardless of the current input or output radix.
+
+@table @samp
+@item i
+Pops the value off the top of the stack
+and uses it to set the input radix.
+
+@item o
+Pops the value off the top of the stack
+and uses it to set the output radix.
+
+@item k
+Pops the value off the top of the stack
+and uses it to set the precision.
+
+@item I
+Pushes the current input radix on the stack.
+
+@item O
+Pushes the current output radix on the stack.
+
+@item K
+Pushes the current precision on the stack.
+
+@end table
+
+@node Strings, Status Inquiry, Parameters, Top
+@chapter Strings
+
+@sc{dc} can operate on strings as well as on numbers.
+The only things you can do with strings are print them
+and execute them as macros
+(which means that the contents of the string are processed as @sc{dc} commands).
+Both registers and the stack can hold strings,
+and @sc{dc} always knows whether any given object is a string or a number.
+Some commands such as arithmetic operations demand numbers
+as arguments and print errors if given strings.
+Other commands can accept either a number or a string;
+for example, the @samp{p} command can accept either and prints the object
+according to its type.
+
+@table @samp
+@item [@var{characters}]
+Makes a string containing @var{characters} and pushes it on the stack.
+For example, @samp{[foo]P} prints the characters @samp{foo}
+(with no newline).
+
+@item a
+The mnemonic for this is somewhat erroneous: asciify.
+The top-of-stack is popped.
+If it was a number, then the low-order byte of this number
+is converted into a string and pushed onto the stack.
+Otherwise the top-of-stack was a string,
+and the first character of that string is pushed back.
+(This command is a GNU extension.)
+
+@item x
+Pops a value off the stack and executes it as a macro.
+Normally it should be a string;
+if it is a number, it is simply pushed back onto the stack.
+For example, @samp{[1p]x} executes the macro @samp{1p},
+which pushes 1 on the stack and prints @samp{1} on a separate line.
+
+Macros are most often stored in registers;
+@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
+and @samp{lax} invokes the macro.
+
+@item >@var{r}
+Pops two values off the stack and compares them
+assuming they are numbers,
+executing the contents of register @var{r} as a macro
+if the original top-of-stack is greater.
+Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
+and @samp{2 1>a} will not.
+
+@item <@var{r}
+Similar but invokes the macro if the original top-of-stack is less.
+
+@item =@var{r}
+Similar but invokes the macro if the two numbers popped are equal.
+@c This can also be validly used to compare two strings for equality.
+
+@item ?
+Reads a line from the terminal and executes it.
+This command allows a macro to request input from the user.
+
+@item q
+During the execution of a macro,
+this command exits from the macro and also from the macro which invoked it.
+If called from the top level,
+or from a macro which was called directly from the top level,
+the @samp{q} command will cause @sc{dc} to exit.
+
+@item Q
+Pops a value off the stack and uses it as a count
+of levels of macro execution to be exited.
+Thus, @samp{3Q} exits three levels.
+@end table
+
+@node Status Inquiry, Miscellaneous, Strings, Top
+@chapter Status Inquiry
+
+@table @samp
+@item Z
+Pops a value off the stack,
+calculates the number of digits it has
+(or number of characters, if it is a string)
+and pushes that number.
+
+@item X
+Pops a value off the stack,
+calculates the number of fraction digits it has,
+and pushes that number.
+For a string, the value pushed is
+@c -1.
+0.
+
+@item z
+Pushes the current stack depth;
+the number of objects on the stack
+before the execution of the @samp{z} command.
+@end table
+
+@node Miscellaneous, Notes, Status Inquiry, Top
+@chapter Miscellaneous
+
+@table @samp
+@item !
+Will run the rest of the line as a system command.
+
+@item #
+Will interpret the rest of the line as a comment.
+(This command is a GNU extension.)
+
+@item :@var{r}
+Will pop the top two values off of the stack.
+The old second-to-top value will be stored in the array @var{r},
+indexed by the old top-of-stack value.
+
+@item ;@var{r}
+Pops the top-of-stack and uses it as an index into
+the array @var{r}.
+The selected value is then pushed onto the stack.
+@end table
+
+@node Notes, , Miscellaneous, Top
+@chapter Notes
+
+The array operations @samp{:} and @samp{;} are usually
+only used by traditional implementations of BC.
+(The GNU implementation of BC is self contained
+and does not need any version of @sc{dc} to run.)
+
+Email bug reports to @code{bug-gnu-utils@@prep.ai.mit.edu}.
+Be sure to include the word ``dc'' somewhere in the ``Subject:'' field.
+
+@contents
+@bye
diff --git a/gnu/usr.bin/dc/eval.c b/gnu/usr.bin/dc/eval.c
index 9fdc3c74a1c..cac4cb1142a 100644
--- a/gnu/usr.bin/dc/eval.c
+++ b/gnu/usr.bin/dc/eval.c
@@ -1,7 +1,7 @@
/*
* evaluate the dc language, from a FILE* or a string
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,12 +39,12 @@
#include "dc-proto.h"
typedef enum {
- DC_OKAY, /* no further intervention needed for this command */
+ DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
DC_EATONE, /* caller needs to eat the lookahead char */
DC_QUIT, /* quit out of unwind_depth levels of evaluation */
/* with the following return values, the caller does not have to
- * fret about rescan_stdin's value
+ * fret about stdin_lookahead's value
*/
DC_INT, /* caller needs to parse a dc_num from input stream */
DC_STR, /* caller needs to parse a dc_str from input stream */
@@ -58,17 +58,17 @@ static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */
static int dc_obase=10; /* output base, 2 <= dc_obase */
static int dc_scale=0; /* scale (see user documentaton) */
-/* forward reference */
-static dc_status dc_evalstr DC_PROTO((dc_data));
-
/* for Quitting evaluations */
static int unwind_depth=0;
/* if true, active Quit will not exit program */
static dc_boolean unwind_noexit=DC_FALSE;
-/* if true, stdin has been mucked with, dc_evalfile() needs to resyncronize */
-static dc_boolean rescan_stdin=DC_FALSE;
+/*
+ * Used to synchronize lookahead on stdin for '?' command.
+ * If set to EOF then lookahead is used up.
+ */
+static int stdin_lookahead=EOF;
/* input_fil and input_str are passed as arguments to dc_getnum */
@@ -109,7 +109,7 @@ input_str DC_DECLVOID()
/* Wrapper around dc_evalstr to avoid duplicating the free call
* at all possible return points.
*/
-static dc_status
+static int
dc_eval_and_free_str DC_DECLARG((string))
dc_data string DC_DECLEND
{
@@ -135,7 +135,7 @@ dc_func DC_DECLARG((c, peekc))
{
/* we occasionally need these for temporary data */
/* Despite the GNU coding standards, it is much easier
- * to have these decared once here, since this function
+ * to have these declared once here, since this function
* is just one big switch statement.
*/
dc_data datum;
@@ -167,9 +167,28 @@ dc_func DC_DECLARG((c, peekc))
dc_binop(dc_div, dc_scale);
break;
case '%':
- /* take the remainder from division of the top two stack elements */
+ /* take the remainder from division of the top two stack elements */
dc_binop(dc_rem, dc_scale);
break;
+ case '~':
+ /* Do division on the top two stack elements. Return the
+ * quotient as next-to-top of stack and the remainder as
+ * top-of-stack.
+ */
+ dc_binop2(dc_divrem, dc_scale);
+ break;
+ case '|':
+ /* Consider the top three elements of the stack as (base, exp, mod),
+ * where mod is top-of-stack, exp is next-to-top, and base is
+ * second-from-top. Mod must be non-zero and exp must be a
+ * non-negative integer. Push the result of raising base to the exp
+ * power, reduced modulo mod. If we had base in register b, exp in
+ * register e, and mod in register m then this is conceptually
+ * equivalent to "lble^lm%", but it is implemented in a more efficient
+ * manner, and can handle arbritrarily large values for exp.
+ */
+ dc_triop(dc_modexp, dc_scale);
+ break;
case '^': /* exponientiation of the top two stack elements */
dc_binop(dc_exp, dc_scale);
break;
@@ -206,13 +225,13 @@ dc_func DC_DECLARG((c, peekc))
if (dc_eval_and_free_str(datum) == DC_QUIT)
return DC_QUIT;
return DC_EATONE;
- case '?': /* read a lnie from standard-input and eval it */
- for (c=peekc; c=='\n'; c=getc(stdin))
- ;
- ungetc(c, stdin);
+ case '?': /* read a line from standard-input and eval it */
+ if (stdin_lookahead != EOF){
+ ungetc(stdin_lookahead, stdin);
+ stdin_lookahead = EOF;
+ }
if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT)
return DC_QUIT;
- rescan_stdin = DC_TRUE;
return DC_OKAY;
case '[': /* read to balancing ']' into a dc_str */
return DC_STR;
@@ -221,6 +240,21 @@ dc_func DC_DECLARG((c, peekc))
case '#': /* comment; skip remainder of current line */
return DC_COMMENT;
+ case 'a': /* Convert top of stack to an ascii character. */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ char tmps;
+ if (datum.dc_type == DC_NUMBER){
+ tmps = (char) dc_num2int(datum.v.number, DC_TRUE);
+ dc_free_num(&datum.v.number);
+ }else if (datum.dc_type == DC_STRING){
+ tmps = *dc_str2charp(datum.v.string);
+ dc_free_str(&datum.v.string);
+ }else{
+ dc_garbage("at top of stack", -1);
+ }
+ dc_push(dc_makestring(&tmps, 1));
+ }
+ break;
case 'c': /* clear whole stack */
dc_clear_stack();
break;
@@ -288,6 +322,17 @@ between 2 and %d (inclusive)\n",
unwind_depth = 2;
unwind_noexit = DC_FALSE;
return DC_QUIT;
+ case 'r': /* rotate (swap) the top two elements on the stack
+ */
+ if (dc_pop(&datum) == DC_SUCCESS) {
+ dc_data datum2;
+ int two_status;
+ two_status = dc_pop(&datum2);
+ dc_push(datum);
+ if (two_status == DC_SUCCESS)
+ dc_push(datum2);
+ }
+ break;
case 's': /* "store" -- replace top of register stack named
* by peekc with the value popped from the top
* of the evaluation stack
@@ -368,10 +413,25 @@ between 2 and %d (inclusive)\n",
if (unwind_depth > 0)
return DC_QUIT;
fprintf(stderr,
- "%s: Q command requires a positive number\n",
+ "%s: Q command requires a number >= 1\n",
progname);
}
break;
+#if 0
+ case 'R': /* pop a value off of the evaluation stack,;
+ * rotate the top
+ remaining stack elements that many
+ * places forward (negative numbers mean rotate
+ * backward).
+ */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = 0;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ dc_stack_rotate(tmpint);
+ }
+ break;
+#endif
case 'S': /* pop a value off of the evaluation stack
* and push it onto the register stack named by peekc
*/
@@ -436,7 +496,7 @@ between 2 and %d (inclusive)\n",
/* takes a string and evals it */
-static dc_status
+int
dc_evalstr DC_DECLARG((string))
dc_data string DC_DECLEND
{
@@ -499,7 +559,8 @@ dc_evalstr DC_DECLARG((string))
s = memchr(s, '\n', (size_t)(end-s));
if (!s)
s = end;
- ++s;
+ else
+ ++s;
break;
case DC_EOF_ERROR:
@@ -523,12 +584,18 @@ dc_evalfile DC_DECLARG((fp))
int peekc;
dc_data datum;
+ stdin_lookahead = EOF;
for (c=getc(fp); c!=EOF; c=peekc){
peekc = getc(fp);
- rescan_stdin = DC_FALSE;
+ /*
+ * The following if() is the only place where ``stdin_lookahead''
+ * might be set to other than EOF:
+ */
+ if (fp == stdin)
+ stdin_lookahead = peekc;
switch (dc_func(c, peekc)){
case DC_OKAY:
- if (rescan_stdin == DC_TRUE && fp == stdin)
+ if (stdin_lookahead != peekc && fp == stdin)
peekc = getc(fp);
break;
case DC_EATONE:
@@ -536,11 +603,11 @@ dc_evalfile DC_DECLARG((fp))
break;
case DC_QUIT:
if (unwind_noexit != DC_TRUE)
- return DC_SUCCESS;
+ return DC_FAIL;
fprintf(stderr,
"%s: Q command argument exceeded string execution depth\n",
progname);
- if (rescan_stdin == DC_TRUE && fp == stdin)
+ if (stdin_lookahead != peekc && fp == stdin)
peekc = getc(fp);
break;
diff --git a/gnu/usr.bin/dc/misc.c b/gnu/usr.bin/dc/misc.c
index a7d3a5ffa37..8c360cacb05 100644
--- a/gnu/usr.bin/dc/misc.c
+++ b/gnu/usr.bin/dc/misc.c
@@ -1,7 +1,7 @@
/*
- * implement the "dc" Desk Calculator language.
+ * misc. functions for the "dc" Desk Calculator language.
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,9 +19,6 @@
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
-/* Written with strong hiding of implementation details
- * in their own specialized modules.
- */
/* This module contains miscelaneous functions that have no
* special knowledge of any private data structures.
* They could all be moved to their own separate modules, but
@@ -47,73 +44,16 @@
# define isgraph isprint
# endif
#endif
+#include <getopt.h>
#include "dc.h"
#include "dc-proto.h"
-#include "dc-version.h"
+#include "version.h"
-#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */
-# define EXIT_SUCCESS 0
-#endif
#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
# define EXIT_FAILURE 1
#endif
-const char *progname; /* basename of program invocation */
-
-/* your generic usage function */
-static void
-usage DC_DECLARG((f))
- FILE *f DC_DECLEND
-{
- fprintf(f, "Usage: %s [OPTION]\n", progname);
- fprintf(f, " --help display this help and exit\n");
- fprintf(f, " --version output version information and exit\n");
-}
-
-/* returns a pointer to one past the last occurance of c in s,
- * or s if c does not occur in s.
- */
-static char *
-r1bindex DC_DECLARG((s, c))
- char *s DC_DECLSEP
- int c DC_DECLEND
-{
- char *p = strrchr(s, c);
-
- if (!p)
- return s;
- return p + 1;
-}
-
-
-int
-main DC_DECLARG((argc, argv))
- int argc DC_DECLSEP
- char **argv DC_DECLEND
-{
- progname = r1bindex(*argv, '/');
- if (argc>1 && strcmp(argv[1], "--version")==0){
- printf("%s\n", Version);
- return EXIT_SUCCESS;
- }else if (argc>1 && strcmp(argv[1], "--help")==0){
- usage(stdout);
- return EXIT_SUCCESS;
- }else if (argc==2 && strcmp(argv[1], "--")==0){
- /*just ignore it*/
- }else if (argc != 1){
- usage(stderr);
- return EXIT_FAILURE;
- }
-
- dc_math_init();
- dc_string_init();
- dc_register_init();
- dc_array_init();
- dc_evalfile(stdin);
- return EXIT_SUCCESS;
-}
-
/* print an "out of memory" diagnostic and exit program */
void
@@ -169,9 +109,9 @@ dc_garbage DC_DECLARG((msg, regid))
const char *msg DC_DECLSEP
int regid DC_DECLEND
{
- if (regid < 0){
+ if (regid < 0) {
fprintf(stderr, "%s: garbage %s\n", progname, msg);
- }else{
+ } else {
fprintf(stderr, "%s:%s register ", progname, msg);
dc_show_id(stderr, regid, " is garbage\n");
}
@@ -194,7 +134,7 @@ dc_system DC_DECLARG((s))
size_t len;
p = strchr(s, '\n');
- if (p){
+ if (p) {
len = p - s;
tmpstr = dc_malloc(len + 1);
strncpy(tmpstr, s, len);
@@ -214,11 +154,11 @@ dc_print DC_DECLARG((value, obase))
dc_data value DC_DECLSEP
int obase DC_DECLEND
{
- if (value.dc_type == DC_NUMBER){
+ if (value.dc_type == DC_NUMBER) {
dc_out_num(value.v.number, obase, DC_TRUE, DC_FALSE);
- }else if (value.dc_type == DC_STRING){
+ } else if (value.dc_type == DC_STRING) {
dc_out_str(value.v.string, DC_TRUE, DC_FALSE);
- }else{
+ } else {
dc_garbage("in data being printed", -1);
}
}
diff --git a/gnu/usr.bin/dc/numeric.c b/gnu/usr.bin/dc/numeric.c
new file mode 100644
index 00000000000..ec1934427df
--- /dev/null
+++ b/gnu/usr.bin/dc/numeric.c
@@ -0,0 +1,536 @@
+/*
+ * interface dc to the bc numeric routines
+ *
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can either send email to this
+ * program's author (see below) or write to: The Free Software Foundation,
+ * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
+ */
+
+/* This should be the only module that knows the internals of type dc_num */
+/* In this particular implementation we just slather out some glue and
+ * make use of bc's numeric routines.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include "bcdefs.h"
+#include "proto.h"
+#include "global.h"
+#include "dc.h"
+#include "dc-proto.h"
+
+/* there is no POSIX standard for dc, so we'll take the GNU definitions */
+int std_only = FALSE;
+
+/* convert an opaque dc_num into a real bc_num */
+#define CastNum(x) ((bc_num)(x))
+
+/* add two dc_nums, place into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_add DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0);
+ return DC_SUCCESS;
+}
+
+/* subtract two dc_nums, place into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_sub DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0);
+ return DC_SUCCESS;
+}
+
+/* multiply two dc_nums, place into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_mul DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
+ return DC_SUCCESS;
+}
+
+/* divide two dc_nums, place into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_div DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
+ fprintf(stderr, "%s: divide by zero\n", progname);
+ return DC_DOMAIN_ERROR;
+ }
+ return DC_SUCCESS;
+}
+
+/* divide two dc_nums, place quotient into *quotient and remainder
+ * into *remainder;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *quotient DC_DECLSEP
+ dc_num *remainder DC_DECLEND
+{
+ init_num((bc_num *)quotient);
+ init_num((bc_num *)remainder);
+ if (bc_divmod(CastNum(a), CastNum(b),
+ (bc_num *)quotient, (bc_num *)remainder, kscale)){
+ fprintf(stderr, "%s: divide by zero\n", progname);
+ return DC_DOMAIN_ERROR;
+ }
+ return DC_SUCCESS;
+}
+
+/* place the reminder of dividing a by b into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_rem DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
+ fprintf(stderr, "%s: remainder by zero\n", progname);
+ return DC_DOMAIN_ERROR;
+ }
+ return DC_SUCCESS;
+}
+
+int
+dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
+ dc_num base DC_DECLSEP
+ dc_num expo DC_DECLSEP
+ dc_num mod DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
+ (bc_num *)result, kscale)){
+ if (is_zero(CastNum(mod)))
+ fprintf(stderr, "%s: remainder by zero\n", progname);
+ return DC_DOMAIN_ERROR;
+ }
+ return DC_SUCCESS;
+}
+
+/* place the result of exponentiationg a by b into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_exp DC_DECLARG((a, b, kscale, result))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ init_num((bc_num *)result);
+ bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
+ return DC_SUCCESS;
+}
+
+/* take the square root of the value, place into *result;
+ * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
+ */
+int
+dc_sqrt DC_DECLARG((value, kscale, result))
+ dc_num value DC_DECLSEP
+ int kscale DC_DECLSEP
+ dc_num *result DC_DECLEND
+{
+ bc_num tmp;
+
+ tmp = copy_num(CastNum(value));
+ if (!bc_sqrt(&tmp, kscale)){
+ fprintf(stderr, "%s: square root of negative number\n", progname);
+ free_num(&tmp);
+ return DC_DOMAIN_ERROR;
+ }
+ *((bc_num *)result) = tmp;
+ return DC_SUCCESS;
+}
+
+/* compare dc_nums a and b;
+ * return a negative value if a < b;
+ * return a positive value if a > b;
+ * return zero value if a == b
+ */
+int
+dc_compare DC_DECLARG((a, b))
+ dc_num a DC_DECLSEP
+ dc_num b DC_DECLEND
+{
+ return bc_compare(CastNum(a), CastNum(b));
+}
+
+/* attempt to convert a dc_num to its corresponding int value
+ * If discard_flag is true then deallocate the value after use.
+ */
+int
+dc_num2int DC_DECLARG((value, discard_flag))
+ dc_num value DC_DECLSEP
+ dc_boolean discard_flag DC_DECLEND
+{
+ long result;
+
+ result = num2long(CastNum(value));
+ if (discard_flag)
+ dc_free_num(&value);
+ return (int)result;
+}
+
+/* convert a C integer value into a dc_num */
+/* For convenience of the caller, package the dc_num
+ * into a dc_data result.
+ */
+dc_data
+dc_int2data DC_DECLARG((value))
+ int value DC_DECLEND
+{
+ dc_data result;
+
+ init_num((bc_num *)&result.v.number);
+ int2num((bc_num *)&result.v.number, value);
+ result.dc_type = DC_NUMBER;
+ return result;
+}
+
+/* get a dc_num from some input stream;
+ * input is a function which knows how to read the desired input stream
+ * ibase is the input base (2<=ibase<=DC_IBASE_MAX)
+ * *readahead will be set to the readahead character consumed while
+ * looking for the end-of-number
+ */
+/* For convenience of the caller, package the dc_num
+ * into a dc_data result.
+ */
+dc_data
+dc_getnum DC_DECLARG((input, ibase, readahead))
+ int (*input) DC_PROTO((void)) DC_DECLSEP
+ int ibase DC_DECLSEP
+ int *readahead DC_DECLEND
+{
+ bc_num base;
+ bc_num result;
+ bc_num build;
+ bc_num tmp;
+ bc_num divisor;
+ dc_data full_result;
+ int negative = 0;
+ int digit;
+ int decimal;
+ int c;
+
+ init_num(&tmp);
+ init_num(&build);
+ init_num(&base);
+ result = copy_num(_zero_);
+ int2num(&base, ibase);
+ c = (*input)();
+ while (isspace(c))
+ c = (*input)();
+ if (c == '_' || c == '-'){
+ negative = c;
+ c = (*input)();
+ }else if (c == '+'){
+ c = (*input)();
+ }
+ while (isspace(c))
+ c = (*input)();
+ for (;;){
+ if (isdigit(c))
+ digit = c - '0';
+ else if ('A' <= c && c <= 'F')
+ digit = 10 + c - 'A';
+ else
+ break;
+ c = (*input)();
+ int2num(&tmp, digit);
+ bc_multiply(result, base, &result, 0);
+ bc_add(result, tmp, &result, 0);
+ }
+ if (c == '.'){
+ free_num(&build);
+ free_num(&tmp);
+ divisor = copy_num(_one_);
+ build = copy_num(_zero_);
+ decimal = 0;
+ for (;;){
+ c = (*input)();
+ if (isdigit(c))
+ digit = c - '0';
+ else if ('A' <= c && c <= 'F')
+ digit = 10 + c - 'A';
+ else
+ break;
+ int2num(&tmp, digit);
+ bc_multiply(build, base, &build, 0);
+ bc_add(build, tmp, &build, 0);
+ bc_multiply(divisor, base, &divisor, 0);
+ ++decimal;
+ }
+ bc_divide(build, divisor, &build, decimal);
+ bc_add(result, build, &result, 0);
+ }
+ /* Final work. */
+ if (negative)
+ bc_sub(_zero_, result, &result, 0);
+
+ free_num(&tmp);
+ free_num(&build);
+ free_num(&base);
+ if (readahead)
+ *readahead = c;
+ full_result.v.number = (dc_num)result;
+ full_result.dc_type = DC_NUMBER;
+ return full_result;
+}
+
+
+/* return the "length" of the number */
+int
+dc_numlen DC_DECLARG((value))
+ dc_num value DC_DECLEND
+{
+ bc_num num = CastNum(value);
+
+ /* is this right??? */
+ return num->n_len + num->n_scale;
+}
+
+/* return the scale factor of the passed dc_num
+ * If discard_flag is true then deallocate the value after use.
+ */
+int
+dc_tell_scale DC_DECLARG((value, discard_flag))
+ dc_num value DC_DECLSEP
+ dc_boolean discard_flag DC_DECLEND
+{
+ int kscale;
+
+ kscale = CastNum(value)->n_scale;
+ if (discard_flag)
+ dc_free_num(&value);
+ return kscale;
+}
+
+
+/* initialize the math subsystem */
+void
+dc_math_init DC_DECLVOID()
+{
+ init_numbers();
+}
+
+/* print out a dc_num in output base obase to stdout;
+ * if newline is true, terminate output with a '\n';
+ * if discard_flag is true then deallocate the value after use
+ */
+void
+dc_out_num DC_DECLARG((value, obase, newline, discard_flag))
+ dc_num value DC_DECLSEP
+ int obase DC_DECLSEP
+ dc_boolean newline DC_DECLSEP
+ dc_boolean discard_flag DC_DECLEND
+{
+ out_num(CastNum(value), obase, out_char);
+ if (newline)
+ out_char('\n');
+ if (discard_flag)
+ dc_free_num(&value);
+}
+
+
+/* deallocate an instance of a dc_num */
+void
+dc_free_num DC_DECLARG((value))
+ dc_num *value DC_DECLEND
+{
+ free_num((bc_num *)value);
+}
+
+/* return a duplicate of the number in the passed value */
+/* The mismatched data types forces the caller to deal with
+ * bad dc_type'd dc_data values, and makes it more convenient
+ * for the caller to not have to do the grunge work of setting
+ * up a dc_type result.
+ */
+dc_data
+dc_dup_num DC_DECLARG((value))
+ dc_num value DC_DECLEND
+{
+ dc_data result;
+
+ ++CastNum(value)->n_refs;
+ result.v.number = value;
+ result.dc_type = DC_NUMBER;
+ return result;
+}
+
+
+
+/*---------------------------------------------------------------------------\
+| The rest of this file consists of stubs for bc routines called by numeric.c|
+| so as to minimize the amount of bc code needed to build dc. |
+| The bulk of the code was just lifted straight out of the bc source. |
+\---------------------------------------------------------------------------*/
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDARG_H
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+
+int out_col = 0;
+
+/* Output routines: Write a character CH to the standard output.
+ It keeps track of the number of characters output and may
+ break the output with a "\<cr>". */
+
+void
+out_char (ch)
+ char ch;
+{
+
+ if (ch == '\n')
+ {
+ out_col = 0;
+ putchar ('\n');
+ }
+ else
+ {
+ out_col++;
+ if (out_col == 70)
+ {
+ putchar ('\\');
+ putchar ('\n');
+ out_col = 1;
+ }
+ putchar (ch);
+ }
+}
+
+/* Malloc could not get enough memory. */
+
+void
+out_of_memory()
+{
+ dc_memfail();
+}
+
+/* Runtime error will print a message and stop the machine. */
+
+#ifdef HAVE_STDARG_H
+#ifdef __STDC__
+void
+rt_error (char *mesg, ...)
+#else
+void
+rt_error (mesg)
+ char *mesg;
+#endif
+#else
+void
+rt_error (mesg, va_alist)
+ char *mesg;
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#ifdef HAVE_STDARG_H
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ vsprintf (error_mesg, mesg, args);
+ va_end (args);
+
+ fprintf (stderr, "Runtime error: %s\n", error_mesg);
+}
+
+
+/* A runtime warning tells of some action taken by the processor that
+ may change the program execution but was not enough of a problem
+ to stop the execution. */
+
+#ifdef HAVE_STDARG_H
+#ifdef __STDC__
+void
+rt_warn (char *mesg, ...)
+#else
+void
+rt_warn (mesg)
+ char *mesg;
+#endif
+#else
+void
+rt_warn (mesg, va_alist)
+ char *mesg;
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#ifdef HAVE_STDARG_H
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ vsprintf (error_mesg, mesg, args);
+ va_end (args);
+
+ fprintf (stderr, "Runtime warning: %s\n", error_mesg);
+}
diff --git a/gnu/usr.bin/dc/stack.c b/gnu/usr.bin/dc/stack.c
index 6e3f9abff9b..c8cd195af35 100644
--- a/gnu/usr.bin/dc/stack.c
+++ b/gnu/usr.bin/dc/stack.c
@@ -1,7 +1,7 @@
/*
* implement stack functions for dc
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -105,6 +105,49 @@ dc_binop DC_DECLARG((op, kscale))
}
/* check that there are two numbers on top of the stack,
+ * then call op with the popped numbers. Construct two dc_data
+ * values from the dc_num's returned by op and push them
+ * on the stack.
+ * If the op call doesn't return DC_SUCCESS, then leave the stack
+ * unmodified.
+ */
+void
+dc_binop2 DC_DECLARG((op, kscale))
+ int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
+ int kscale DC_DECLEND
+{
+ dc_data a;
+ dc_data b;
+ dc_data r1;
+ dc_data r2;
+
+ if (!dc_stack || !dc_stack->link){
+ Empty_Stack;
+ return;
+ }
+ if (dc_stack->value.dc_type!=DC_NUMBER
+ || dc_stack->link->value.dc_type!=DC_NUMBER){
+ fprintf(stderr, "%s: non-numeric value\n", progname);
+ return;
+ }
+ (void)dc_pop(&b);
+ (void)dc_pop(&a);
+ if ((*op)(a.v.number, b.v.number, kscale,
+ &r1.v.number, &r2.v.number) == DC_SUCCESS){
+ r1.dc_type = DC_NUMBER;
+ dc_push(r1);
+ r2.dc_type = DC_NUMBER;
+ dc_push(r2);
+ dc_free_num(&a.v.number);
+ dc_free_num(&b.v.number);
+ }else{
+ /* op failed; restore the stack */
+ dc_push(a);
+ dc_push(b);
+ }
+}
+
+/* check that there are two numbers on top of the stack,
* then call dc_compare with the popped numbers.
* Return negative, zero, or positive based on the ordering
* of the two numbers.
@@ -133,6 +176,51 @@ dc_cmpop DC_DECLVOID()
return result;
}
+/* check that there are three numbers on top of the stack,
+ * then call op with the popped numbers. Construct a dc_data
+ * value from the dc_num returned by op and push it
+ * on the stack.
+ * If the op call doesn't return DC_SUCCESS, then leave the stack
+ * unmodified.
+ */
+void
+dc_triop DC_DECLARG((op, kscale))
+ int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
+ int kscale DC_DECLEND
+{
+ dc_data a;
+ dc_data b;
+ dc_data c;
+ dc_data r;
+
+ if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
+ Empty_Stack;
+ return;
+ }
+ if (dc_stack->value.dc_type!=DC_NUMBER
+ || dc_stack->link->value.dc_type!=DC_NUMBER
+ || dc_stack->link->link->value.dc_type!=DC_NUMBER){
+ fprintf(stderr, "%s: non-numeric value\n", progname);
+ return;
+ }
+ (void)dc_pop(&c);
+ (void)dc_pop(&b);
+ (void)dc_pop(&a);
+ if ((*op)(a.v.number, b.v.number, c.v.number,
+ kscale, &r.v.number) == DC_SUCCESS){
+ r.dc_type = DC_NUMBER;
+ dc_push(r);
+ dc_free_num(&a.v.number);
+ dc_free_num(&b.v.number);
+ dc_free_num(&c.v.number);
+ }else{
+ /* op failed; restore the stack */
+ dc_push(a);
+ dc_push(b);
+ dc_push(c);
+ }
+}
+
/* initialize the register stacks to their initial values */
void
diff --git a/gnu/usr.bin/dc/string.c b/gnu/usr.bin/dc/string.c
index 18cf8ab3628..35bc2630532 100644
--- a/gnu/usr.bin/dc/string.c
+++ b/gnu/usr.bin/dc/string.c
@@ -1,7 +1,7 @@
/*
* implement string functions for dc
*
- * Copyright (C) 1994 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,6 +46,7 @@
#include "dc.h"
#include "dc-proto.h"
+/* here is the completion of the dc_string type: */
struct dc_string {
char *s_ptr; /* pointer to base of string */
size_t s_len; /* length of counted string */
@@ -65,7 +66,7 @@ dc_dup_str DC_DECLARG((value))
{
dc_data result;
- ++((struct dc_string *)value)->s_refs;
+ ++value->s_refs;
result.v.string = value;
result.dc_type = DC_STRING;
return result;
@@ -94,9 +95,7 @@ dc_out_str DC_DECLARG((value, newline, discard_flag))
dc_boolean newline DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
- struct dc_string *string = value;
-
- printf("%s", string->s_ptr);
+ fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
if (newline == DC_TRUE)
printf("\n");
if (discard_flag == DC_TRUE)
@@ -185,7 +184,7 @@ const char *
dc_str2charp DC_DECLARG((value))
dc_str value DC_DECLEND
{
- return ((struct dc_string *)value)->s_ptr;
+ return value->s_ptr;
}
/* return the length of the dc_str value;
@@ -197,7 +196,7 @@ size_t
dc_strlen DC_DECLARG((value))
dc_str value DC_DECLEND
{
- return ((struct dc_string *)value)->s_len;
+ return value->s_len;
}