summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin
diff options
context:
space:
mode:
authorsteve <steve@FreeBSD.org>1996-11-04 04:24:33 +0000
committersteve <steve@FreeBSD.org>1996-11-04 04:24:33 +0000
commit70ff03393a156ba7278858a8f8cf05a8c83491c9 (patch)
tree9e720074711c6d935b3da3d22b6e13294832a10f /gnu/usr.bin
parent0be58f23d8dd463dea864d0ad7a6fb8fcb617d73 (diff)
downloadFreeBSD-src-70ff03393a156ba7278858a8f8cf05a8c83491c9.zip
FreeBSD-src-70ff03393a156ba7278858a8f8cf05a8c83491c9.tar.gz
Upgrade to dc version 1.0 which comes bundled with
bc version 1.03.
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/dc/ChangeLog77
-rw-r--r--gnu/usr.bin/dc/Makefile6
-rw-r--r--gnu/usr.bin/dc/NEWS7
-rw-r--r--gnu/usr.bin/dc/README13
-rw-r--r--gnu/usr.bin/dc/dc-array.c105
-rw-r--r--gnu/usr.bin/dc/dc-eval.c569
-rw-r--r--gnu/usr.bin/dc/dc-misc.c224
-rw-r--r--gnu/usr.bin/dc/dc-number.c478
-rw-r--r--gnu/usr.bin/dc/dc-proto.h76
-rw-r--r--gnu/usr.bin/dc/dc-regdef.h38
-rw-r--r--gnu/usr.bin/dc/dc-stack.c367
-rw-r--r--gnu/usr.bin/dc/dc-string.c193
-rw-r--r--gnu/usr.bin/dc/dc-version.h22
-rw-r--r--gnu/usr.bin/dc/dc.1513
-rw-r--r--gnu/usr.bin/dc/dc.c925
-rw-r--r--gnu/usr.bin/dc/dc.h81
-rw-r--r--gnu/usr.bin/dc/decimal.c1235
-rw-r--r--gnu/usr.bin/dc/decimal.h93
-rw-r--r--gnu/usr.bin/dc/doc/dc.texinfo314
19 files changed, 2648 insertions, 2688 deletions
diff --git a/gnu/usr.bin/dc/ChangeLog b/gnu/usr.bin/dc/ChangeLog
deleted file mode 100644
index 09aaf47..0000000
--- a/gnu/usr.bin/dc/ChangeLog
+++ /dev/null
@@ -1,77 +0,0 @@
-Fri May 21 15:02:52 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
-
- * Version 0.2 released.
-
-Fri May 21 11:48:11 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * decimal.c (decimal_rem): Update to match fixes in decimal_div.
-
-Thu May 20 03:12:41 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
-
- * Makefile.in (realclean): Delete dc.info* and configure.
- (DISTFILES): Add `texinfo.tex' and `NEWS'.
- texinfo.tex: New file (symlink to canonical source).
- NEWS: New file.
-
-Wed May 19 11:30:09 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * dc.c (dec_read): Accept only A through F.
-
-Tue May 18 12:35:54 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * dc.c (read_string): New arg STARTC to handle nested brackets.
- (execute): Change calls to read_string.
- (condop): Don't assume result of decimal_compare has abs value <= 1.
- (popmacro): If no macro in progress, exit.
-
-Sun May 2 00:42:47 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * decimal.c (decimal_div): Include in trial_dividend the digit
- at length2 + i - 2, if there is one.
-
-Sat May 1 09:54:35 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * decimal.c (decimal_parse): Don't use digits without recalculation
- if some digit exceeds the radix.
-
- * dc.c (execute): Treat A...F as digits.
- (dec_read): Treat A...F as digits.
-
-Thu Apr 29 14:17:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
-
- * decimal.h (bcopy): Use memcpy, not memmove.
-
- * decimal.c (flush_trailing_digits): Use explicit loop, not bcopy.
-
-Tue Apr 20 17:21:27 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
-
- * dc.c (pushsqrt): `precision' is an argument to `decimal_sqrt', not
- `push'.
-
-Sat Apr 17 15:47:55 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
-
- * All files: Updated GPL version number.
-
- * decimal.c: Include decimal.h and delete duplicate declarations.
-
- * decimal.h [!HAVE_BCOPY]: #define bcopy.
- [!HAVE_BZERO]: #define bzero.
-
-Sun Feb 10 22:06:15 1991 Richard Stallman (rms at mole.ai.mit.edu)
-
- * dc.c (execute): Insert break; in \n case.
-
-Sun Jul 29 17:50:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
-
- * decimal.c (decimal_neg): New function.
-
-Fri Jul 27 04:11:34 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
-
- * bceval.c, bclex.c, bcprint.c, bcsym.c: Declare some functions
- static.
-
-Mon Dec 25 03:01:49 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
-
- * Makefile: add some missing rules.
-
- * decimal.c: change a 'max' to 'MAX'.
diff --git a/gnu/usr.bin/dc/Makefile b/gnu/usr.bin/dc/Makefile
index 57b2ebd..a20cee3 100644
--- a/gnu/usr.bin/dc/Makefile
+++ b/gnu/usr.bin/dc/Makefile
@@ -1,8 +1,10 @@
PROG= dc
-SRCS= dc.c decimal.c
-CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1
+SRCS= dc-array.c dc-eval.c dc-misc.c dc-number.c dc-stack.c dc-string.c number.c
+CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../bc -D_POSIX_SOURCE
DPADD= ${LIBM}
LDADD= -lm
SUBDIR+= doc
+.PATH: ${.CURDIR}/../bc
+
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/dc/NEWS b/gnu/usr.bin/dc/NEWS
deleted file mode 100644
index 6486afb..0000000
--- a/gnu/usr.bin/dc/NEWS
+++ /dev/null
@@ -1,7 +0,0 @@
-Changes between version 0.2 and 0.1:
-
-* You can now have nested square bracket pairs within a string.
-
-* The letters A-F can now be part of a number when the input radix is
-large enough to make them meaningful.
-
diff --git a/gnu/usr.bin/dc/README b/gnu/usr.bin/dc/README
deleted file mode 100644
index c23cc66..0000000
--- a/gnu/usr.bin/dc/README
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a preliminary release of GNU `dc', since people asked for it. GNU
-`bc' (which doesn't rely on a separate `dc') has been available separately
-for a couple of years. Eventually this version of `dc' will be merged with
-the bc package.
-
-See comments in the file decimal.c for some limitations in the arbitrary
-precision library. It's questionable whether it's worth fixing these
-problems since the merged dc will probably use bc's math library instead.
-However, you might want to be aware of known problems.
-
-See the file `INSTALL' for instructions on building and installing dc.
-
-Please report bugs to bug-gnu-utils@prep.ai.mit.edu.
diff --git a/gnu/usr.bin/dc/dc-array.c b/gnu/usr.bin/dc/dc-array.c
new file mode 100644
index 0000000..dd16ed9
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-array.c
@@ -0,0 +1,105 @@
+/*
+ * implement arrays for dc
+ *
+ * Copyright (C) 1994 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 module is the only one that knows what arrays look like. */
+
+#include "config.h"
+
+#include <stdio.h> /* "dc-proto.h" wants this */
+#include <stdlib.h>
+#include "dc.h"
+#include "dc-proto.h"
+#include "dc-regdef.h"
+
+/* what's most useful: quick access or sparse arrays? */
+/* I'll go with sparse arrays for now */
+struct dc_array {
+ int Index;
+ dc_data value;
+ struct dc_array *next;
+};
+typedef struct dc_array dc_array;
+
+/* I can find no reason not to place arrays in their own namespace... */
+static dc_array *dc_array_register[DC_REGCOUNT];
+
+
+/* initialize the arrays to their initial values */
+void
+dc_array_init DC_DECLVOID()
+{
+ int i;
+
+ for (i=0; i<DC_REGCOUNT; ++i)
+ dc_array_register[i] = NULL;
+}
+
+/* store value into array_id[Index] */
+void
+dc_array_set DC_DECLARG((array_id, Index, value))
+ int array_id DC_DECLSEP
+ int Index DC_DECLSEP
+ dc_data value DC_DECLEND
+{
+ dc_array *cur;
+ dc_array *prev=NULL;
+ dc_array *newentry;
+
+ array_id = regmap(array_id);
+ cur = dc_array_register[array_id];
+ while (cur && cur->Index < Index){
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur && cur->Index == Index){
+ if (cur->value.dc_type == DC_NUMBER)
+ dc_free_num(&cur->value.v.number);
+ else if (cur->value.dc_type == DC_STRING)
+ dc_free_str(&cur->value.v.string);
+ else
+ dc_garbage(" in array", array_id);
+ cur->value = value;
+ }else{
+ newentry = dc_malloc(sizeof *newentry);
+ newentry->Index = Index;
+ newentry->value = value;
+ newentry->next = cur;
+ if (prev)
+ prev->next = newentry;
+ else
+ dc_array_register[array_id] = newentry;
+ }
+}
+
+/* retrieve a dup of a value from array_id[Index] */
+/* A zero value is returned if the specified value is unintialized. */
+dc_data
+dc_array_get DC_DECLARG((array_id, Index))
+ int array_id DC_DECLSEP
+ int Index DC_DECLEND
+{
+ dc_array *cur;
+
+ for (cur=dc_array_register[regmap(array_id)]; cur; cur=cur->next)
+ if (cur->Index == Index)
+ return dc_dup(cur->value);
+ return dc_int2data(0);
+}
diff --git a/gnu/usr.bin/dc/dc-eval.c b/gnu/usr.bin/dc/dc-eval.c
new file mode 100644
index 0000000..e368caa
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-eval.c
@@ -0,0 +1,569 @@
+/*
+ * evaluate the dc language, from a FILE* or a string
+ *
+ * Copyright (C) 1994 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 is the only module which knows about the dc input language */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "dc.h"
+#include "dc-proto.h"
+
+typedef enum {
+ DC_OKAY, /* 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
+ */
+ DC_INT, /* caller needs to parse a dc_num from input stream */
+ DC_STR, /* caller needs to parse a dc_str from input stream */
+ DC_SYSTEM, /* caller needs to run a system() on next input line */
+ DC_COMMENT, /* caller needs to skip to the next input line */
+
+ DC_EOF_ERROR /* unexpected end of input; abort current eval */
+} dc_status;
+
+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;
+
+
+/* input_fil and input_str are passed as arguments to dc_getnum */
+
+/* used by the input_* functions: */
+static FILE *input_fil_fp;
+static const char *input_str_string;
+
+/* Since we have a need for two characters of pushback, and
+ * ungetc() only guarantees one, we place the second pushback here
+ */
+static int input_pushback;
+
+/* passed as an argument to dc_getnum */
+static int
+input_fil DC_DECLVOID()
+{
+ if (input_pushback != EOF){
+ int c = input_pushback;
+ input_pushback = EOF;
+ return c;
+ }
+ return getc(input_fil_fp);
+}
+
+/* passed as an argument to dc_getnum */
+static int
+input_str DC_DECLVOID()
+{
+ if (!*input_str_string)
+ return EOF;
+ return *input_str_string++;
+}
+
+
+
+/* takes a string and evals it; frees the string when done */
+/* Wrapper around dc_evalstr to avoid duplicating the free call
+ * at all possible return points.
+ */
+static dc_status
+dc_eval_and_free_str DC_DECLARG((string))
+ dc_data string DC_DECLEND
+{
+ dc_status status;
+
+ status = dc_evalstr(string);
+ if (string.dc_type == DC_STRING)
+ dc_free_str(&string.v.string);
+ return status;
+}
+
+
+/* dc_func does the grunt work of figuring out what each input
+ * character means; used by both dc_evalstr and dc_evalfile
+ *
+ * c -> the "current" input character under consideration
+ * peekc -> the lookahead input character
+ */
+static dc_status
+dc_func DC_DECLARG((c, peekc))
+ int c DC_DECLSEP
+ int peekc DC_DECLEND
+{
+ /* 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
+ * is just one big switch statement.
+ */
+ dc_data datum;
+ int tmpint;
+
+ switch (c){
+ case '_': case '.':
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9': case 'A': case 'B':
+ case 'C': case 'D': case 'E': case 'F':
+ return DC_INT;
+ case ' ':
+ case '\t':
+ case '\n':
+ /* standard command separators */
+ break;
+
+ case '+': /* add top two stack elements */
+ dc_binop(dc_add, dc_scale);
+ break;
+ case '-': /* subtract top two stack elements */
+ dc_binop(dc_sub, dc_scale);
+ break;
+ case '*': /* multiply top two stack elements */
+ dc_binop(dc_mul, dc_scale);
+ break;
+ case '/': /* divide top two stack elements */
+ dc_binop(dc_div, dc_scale);
+ break;
+ case '%':
+ /* take the remainder from division of the top two stack elements */
+ dc_binop(dc_rem, dc_scale);
+ break;
+ case '^': /* exponientiation of the top two stack elements */
+ dc_binop(dc_exp, dc_scale);
+ break;
+ case '<':
+ /* eval register named by peekc if
+ * less-than holds for top two stack elements
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_cmpop() < 0)
+ if (dc_register_get(peekc, &datum) == DC_SUCCESS)
+ if (dc_eval_and_free_str(datum) == DC_QUIT)
+ return DC_QUIT;
+ return DC_EATONE;
+ case '=':
+ /* eval register named by peekc if
+ * equal-to holds for top two stack elements
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_cmpop() == 0)
+ if (dc_register_get(peekc, &datum) == DC_SUCCESS)
+ if (dc_eval_and_free_str(datum) == DC_QUIT)
+ return DC_QUIT;
+ return DC_EATONE;
+ case '>':
+ /* eval register named by peekc if
+ * greater-than holds for top two stack elements
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_cmpop() > 0)
+ if (dc_register_get(peekc, &datum) == DC_SUCCESS)
+ 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);
+ 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;
+ case '!': /* read to newline and call system() on resulting string */
+ return DC_SYSTEM;
+ case '#': /* comment; skip remainder of current line */
+ return DC_COMMENT;
+
+ case 'c': /* clear whole stack */
+ dc_clear_stack();
+ break;
+ case 'd': /* duplicate the datum on the top of stack */
+ if (dc_top_of_stack(&datum) == DC_SUCCESS)
+ dc_push(dc_dup(datum));
+ break;
+ case 'f': /* print list of all stack items */
+ dc_printall(dc_obase);
+ break;
+ case 'i': /* set input base to value on top of stack */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = 0;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) )
+ fprintf(stderr,
+ "%s: input base must be a number \
+between 2 and %d (inclusive)\n",
+ progname, DC_IBASE_MAX);
+ else
+ dc_ibase = tmpint;
+ }
+ break;
+ case 'k': /* set scale to value on top of stack */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = -1;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ if ( ! (tmpint >= 0) )
+ fprintf(stderr,
+ "%s: scale must be a nonnegative number\n",
+ progname);
+ else
+ dc_scale = tmpint;
+ }
+ break;
+ case 'l': /* "load" -- push value on top of register stack named
+ * by peekc onto top of evaluation stack; does not
+ * modify the register stack
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_register_get(peekc, &datum) == DC_SUCCESS)
+ dc_push(datum);
+ return DC_EATONE;
+ case 'o': /* set output base to value on top of stack */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = 0;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ if ( ! (tmpint > 1) )
+ fprintf(stderr,
+ "%s: output base must be a number greater than 1\n",
+ progname);
+ else
+ dc_obase = tmpint;
+ }
+ break;
+ case 'p': /* print the datum on the top of stack */
+ if (dc_top_of_stack(&datum) == DC_SUCCESS)
+ dc_print(datum, dc_obase);
+ break;
+ case 'q': /* quit two levels of evaluation, posibly exiting program */
+ unwind_depth = 2;
+ unwind_noexit = DC_FALSE;
+ return DC_QUIT;
+ case 's': /* "store" -- replace top of register stack named
+ * by peekc with the value popped from the top
+ * of the evaluation stack
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_pop(&datum) == DC_SUCCESS)
+ dc_register_set(peekc, datum);
+ return DC_EATONE;
+ case 'v': /* replace top of stack with its square root */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ dc_num tmpnum;
+ if (datum.dc_type != DC_NUMBER){
+ fprintf(stderr,
+ "%s: square root of nonnumeric attempted\n",
+ progname);
+ }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
+ dc_free_num(&datum.v.number);
+ datum.v.number = tmpnum;
+ dc_push(datum);
+ }
+ }
+ break;
+ case 'x': /* eval the datum popped from top of stack */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ if (datum.dc_type == DC_STRING){
+ if (dc_eval_and_free_str(datum) == DC_QUIT)
+ return DC_QUIT;
+ }else if (datum.dc_type == DC_NUMBER){
+ dc_push(datum);
+ }else{
+ dc_garbage("at top of stack", -1);
+ }
+ }
+ break;
+ case 'z': /* push the current stack depth onto the top of stack */
+ dc_push(dc_int2data(dc_tell_stackdepth()));
+ break;
+
+ case 'I': /* push the current input base onto the stack */
+ dc_push(dc_int2data(dc_ibase));
+ break;
+ case 'K': /* push the current scale onto the stack */
+ dc_push(dc_int2data(dc_scale));
+ break;
+ case 'L': /* pop a value off of register stack named by peekc
+ * and push it onto the evaluation stack
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
+ dc_push(datum);
+ return DC_EATONE;
+ case 'O': /* push the current output base onto the stack */
+ dc_push(dc_int2data(dc_obase));
+ break;
+ case 'P': /* print the value popped off of top-of-stack;
+ * do not add a trailing newline
+ */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ if (datum.dc_type == DC_STRING)
+ dc_out_str(datum.v.string, DC_FALSE, DC_TRUE);
+ else if (datum.dc_type == DC_NUMBER)
+ dc_out_num(datum.v.number, dc_obase, DC_FALSE, DC_TRUE);
+ else
+ dc_garbage("at top of stack", -1);
+ }
+ break;
+ case 'Q': /* quit out of top-of-stack nested evals;
+ * pops value from stack;
+ * does not exit program (stops short if necessary)
+ */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ unwind_depth = 0;
+ unwind_noexit = DC_TRUE;
+ if (datum.dc_type == DC_NUMBER)
+ unwind_depth = dc_num2int(datum.v.number, DC_TRUE);
+ if (unwind_depth > 0)
+ return DC_QUIT;
+ fprintf(stderr,
+ "%s: Q command requires a positive number\n",
+ progname);
+ }
+ break;
+ case 'S': /* pop a value off of the evaluation stack
+ * and push it onto the register stack named by peekc
+ */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_pop(&datum) == DC_SUCCESS)
+ dc_register_push(peekc, datum);
+ return DC_EATONE;
+ case 'X': /* replace the number on top-of-stack with its scale factor */
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = 0;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_tell_scale(datum.v.number, DC_TRUE);
+ dc_push(dc_int2data(tmpint));
+ }
+ break;
+ case 'Z': /* replace the datum on the top-of-stack with its length */
+ if (dc_pop(&datum) == DC_SUCCESS)
+ dc_push(dc_int2data(dc_tell_length(datum, DC_TRUE)));
+ break;
+
+ case ':': /* store into array */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = -1;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ if (dc_pop(&datum) == DC_SUCCESS){
+ if (tmpint < 0)
+ fprintf(stderr,
+ "%s: array index must be a nonnegative integer\n",
+ progname);
+ else
+ dc_array_set(peekc, tmpint, datum);
+ }
+ }
+ return DC_EATONE;
+ case ';': /* retreive from array */
+ if (peekc == EOF)
+ return DC_EOF_ERROR;
+ if (dc_pop(&datum) == DC_SUCCESS){
+ tmpint = -1;
+ if (datum.dc_type == DC_NUMBER)
+ tmpint = dc_num2int(datum.v.number, DC_TRUE);
+ if (tmpint < 0)
+ fprintf(stderr,
+ "%s: array index must be a nonnegative integer\n",
+ progname);
+ else
+ dc_push(dc_array_get(peekc, tmpint));
+ }
+ return DC_EATONE;
+
+ default: /* What did that user mean? */
+ fprintf(stderr, "%s: ", progname);
+ dc_show_id(stdout, c, " unimplemented\n");
+ break;
+ }
+ return DC_OKAY;
+}
+
+
+/* takes a string and evals it */
+static dc_status
+dc_evalstr DC_DECLARG((string))
+ dc_data string DC_DECLEND
+{
+ const char *s;
+ const char *end;
+ const char *p;
+ size_t len;
+ int c;
+ int peekc;
+ int count;
+
+ if (string.dc_type != DC_STRING){
+ fprintf(stderr,
+ "%s: eval called with non-string argument\n",
+ progname);
+ return DC_OKAY;
+ }
+ s = dc_str2charp(string.v.string);
+ end = s + dc_strlen(string.v.string);
+ while (s < end){
+ c = *(const unsigned char *)s++;
+ peekc = EOF;
+ if (s < end)
+ peekc = *(const unsigned char *)s;
+ switch (dc_func(c, peekc)){
+ case DC_OKAY:
+ break;
+ case DC_EATONE:
+ if (peekc != EOF)
+ ++s;
+ break;
+ case DC_QUIT:
+ if (unwind_depth > 0){
+ --unwind_depth;
+ return DC_QUIT;
+ }
+ return DC_OKAY;
+
+ case DC_INT:
+ input_str_string = s - 1;
+ dc_push(dc_getnum(input_str, dc_ibase, &peekc));
+ s = input_str_string;
+ if (peekc != EOF)
+ --s;
+ break;
+ case DC_STR:
+ count = 1;
+ for (p=s; p<end && count>0; ++p)
+ if (*p == ']')
+ --count;
+ else if (*p == '[')
+ ++count;
+ len = p - s;
+ dc_push(dc_makestring(s, len-1));
+ s = p;
+ break;
+ case DC_SYSTEM:
+ s = dc_system(s);
+ case DC_COMMENT:
+ s = memchr(s, '\n', (size_t)(end-s));
+ if (!s)
+ s = end;
+ ++s;
+ break;
+
+ case DC_EOF_ERROR:
+ fprintf(stderr, "%s: unexpected EOS\n", progname);
+ return DC_OKAY;
+ }
+ }
+ return DC_OKAY;
+}
+
+
+/* This is the main function of the whole DC program.
+ * Reads the file described by fp, calls dc_func to do
+ * the dirty work, and takes care of dc_func's shortcomings.
+ */
+int
+dc_evalfile DC_DECLARG((fp))
+ FILE *fp DC_DECLEND
+{
+ int c;
+ int peekc;
+ dc_data datum;
+
+ for (c=getc(fp); c!=EOF; c=peekc){
+ peekc = getc(fp);
+ rescan_stdin = DC_FALSE;
+ switch (dc_func(c, peekc)){
+ case DC_OKAY:
+ if (rescan_stdin == DC_TRUE && fp == stdin)
+ peekc = getc(fp);
+ break;
+ case DC_EATONE:
+ peekc = getc(fp);
+ break;
+ case DC_QUIT:
+ if (unwind_noexit != DC_TRUE)
+ return DC_SUCCESS;
+ fprintf(stderr,
+ "%s: Q command argument exceeded string execution depth\n",
+ progname);
+ if (rescan_stdin == DC_TRUE && fp == stdin)
+ peekc = getc(fp);
+ break;
+
+ case DC_INT:
+ input_fil_fp = fp;
+ input_pushback = c;
+ ungetc(peekc, fp);
+ dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
+ break;
+ case DC_STR:
+ ungetc(peekc, fp);
+ datum = dc_readstring(fp, '[', ']');
+ dc_push(datum);
+ peekc = getc(fp);
+ break;
+ case DC_SYSTEM:
+ ungetc(peekc, fp);
+ datum = dc_readstring(stdin, '\n', '\n');
+ (void)dc_system(dc_str2charp(datum.v.string));
+ dc_free_str(&datum.v.string);
+ peekc = getc(fp);
+ break;
+ case DC_COMMENT:
+ while (peekc!=EOF && peekc!='\n')
+ peekc = getc(fp);
+ if (peekc != EOF)
+ peekc = getc(fp);
+ break;
+
+ case DC_EOF_ERROR:
+ fprintf(stderr, "%s: unexpected EOF\n", progname);
+ return DC_FAIL;
+ }
+ }
+ return DC_SUCCESS;
+}
diff --git a/gnu/usr.bin/dc/dc-misc.c b/gnu/usr.bin/dc/dc-misc.c
new file mode 100644
index 0000000..6443c60
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-misc.c
@@ -0,0 +1,224 @@
+/*
+ * implement the "dc" Desk Calculator language.
+ *
+ * Copyright (C) 1994 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 miscelaneous functions that have no
+ * special knowledge of any private data structures.
+ * They could all be moved to their own separate modules, but
+ * are agglomerated here for convenience.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "dc.h"
+#include "dc-proto.h"
+
+#include "dc-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
+dc_memfail DC_DECLVOID()
+{
+ fprintf(stderr, "%s: out of memory\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+/* malloc or die */
+void *
+dc_malloc DC_DECLARG((len))
+ size_t len DC_DECLEND
+{
+ void *result = malloc(len);
+
+ if (!result)
+ dc_memfail();
+ return result;
+}
+
+
+/* print the id in a human-understandable form
+ * fp is the output stream to place the output on
+ * id is the name of the register (or command) to be printed
+ * suffix is a modifier (such as "stack") to be printed
+ */
+void
+dc_show_id DC_DECLARG((fp, id, suffix))
+ FILE *fp DC_DECLSEP
+ int id DC_DECLSEP
+ const char *suffix DC_DECLEND
+{
+ if (isgraph(id))
+ fprintf(fp, "'%c' (%#o)%s", id, id, suffix);
+ else
+ fprintf(fp, "%#o%s", id, suffix);
+}
+
+
+/* report that corrupt data has been detected;
+ * use the msg and regid (if nonnegative) to give information
+ * about where the garbage was found,
+ *
+ * will abort() so that a debugger might be used to help find
+ * the bug
+ */
+/* If this routine is called, then there is a bug in the code;
+ * i.e. it is _not_ a data or user error
+ */
+void
+dc_garbage DC_DECLARG((msg, regid))
+ const char *msg DC_DECLSEP
+ int regid DC_DECLEND
+{
+ if (regid < 0){
+ fprintf(stderr, "%s: garbage %s\n", progname, msg);
+ }else{
+ fprintf(stderr, "%s:%s register ", progname, msg);
+ dc_show_id(stderr, regid, " is garbage\n");
+ }
+ abort();
+}
+
+
+/* call system() with the passed string;
+ * if the string contains a newline, terminate the string
+ * there before calling system.
+ * Return a pointer to the first unused character in the string
+ * (i.e. past the '\n' if there was one, to the '\0' otherwise).
+ */
+const char *
+dc_system DC_DECLARG((s))
+ const char *s DC_DECLEND
+{
+ const char *p;
+ char *tmpstr;
+ size_t len;
+
+ p = strchr(s, '\n');
+ if (p){
+ len = p - s;
+ tmpstr = dc_malloc(len + 1);
+ strncpy(tmpstr, s, len);
+ tmpstr[len] = '\0';
+ system(tmpstr);
+ free(tmpstr);
+ return p + 1;
+ }
+ system(s);
+ return s + strlen(s);
+}
+
+
+/* print out the indicated value */
+void
+dc_print DC_DECLARG((value, obase))
+ dc_data value DC_DECLSEP
+ int obase DC_DECLEND
+{
+ if (value.dc_type == DC_NUMBER){
+ dc_out_num(value.v.number, obase, DC_TRUE, DC_FALSE);
+ }else if (value.dc_type == DC_STRING){
+ dc_out_str(value.v.string, DC_TRUE, DC_FALSE);
+ }else{
+ dc_garbage("in data being printed", -1);
+ }
+}
+
+/* return a duplicate of the passed value, regardless of type */
+dc_data
+dc_dup DC_DECLARG((value))
+ dc_data value DC_DECLEND
+{
+ if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
+ dc_garbage("in value being duplicated", -1);
+ if (value.dc_type == DC_NUMBER)
+ return dc_dup_num(value.v.number);
+ /*else*/
+ return dc_dup_str(value.v.string);
+}
diff --git a/gnu/usr.bin/dc/dc-number.c b/gnu/usr.bin/dc/dc-number.c
new file mode 100644
index 0000000..8007506
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-number.c
@@ -0,0 +1,478 @@
+/*
+ * interface dc to the bc numeric routines
+ *
+ * Copyright (C) 1994 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 */
+
+#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"
+
+/* 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);
+ 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);
+ 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;
+}
+
+/* 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;
+}
+
+/* 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);
+ }
+ 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);
+ bc_multiply(divisor, base, &divisor, 0);
+ ++decimal;
+ }
+ bc_divide(build, divisor, &build, decimal);
+ bc_add(result, build, &result);
+ }
+ /* Final work. */
+ if (negative)
+ bc_sub(_zero_, result, &result);
+
+ 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 number.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. |
+\---------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+
+#if __STDC__
+# 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 enought memory. */
+
+void
+out_of_memory()
+{
+ dc_memfail();
+}
+
+/* Runtime error will print a message and stop the machine. */
+
+#if __STDC__
+void
+rt_error (char *mesg, ...)
+#else
+void
+rt_error (mesg, va_alist)
+ char *mesg;
+ va_dcl
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#if __STDC__
+ 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. */
+
+#if __STDC__
+void
+rt_warn (char *mesg, ...)
+#else
+void
+rt_warn (mesg, va_alist)
+ char *mesg;
+ va_dcl
+#endif
+{
+ va_list args;
+ char error_mesg [255];
+
+#if __STDC__
+ 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/dc-proto.h b/gnu/usr.bin/dc/dc-proto.h
new file mode 100644
index 0000000..97d7aff
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-proto.h
@@ -0,0 +1,76 @@
+/*
+ * prototypes of all externally visible dc functions
+ *
+ * Copyright (C) 1994 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.
+ */
+
+extern const char *dc_str2charp DC_PROTO((dc_str));
+extern const char *dc_system DC_PROTO((const char *));
+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_clear_stack DC_PROTO((void));
+extern void dc_free_num DC_PROTO((dc_num *));
+extern void dc_free_str DC_PROTO((dc_str *));
+extern void dc_garbage DC_PROTO((const char *, int));
+extern void dc_math_init DC_PROTO((void));
+extern void dc_memfail DC_PROTO((void));
+extern void dc_out_num DC_PROTO((dc_num, int, dc_boolean, dc_boolean));
+extern void dc_out_str DC_PROTO((dc_str, dc_boolean, dc_boolean));
+extern void dc_print DC_PROTO((dc_data, int));
+extern void dc_printall DC_PROTO((int));
+extern void dc_push DC_PROTO((dc_data));
+extern void dc_register_init DC_PROTO((void));
+extern void dc_register_push DC_PROTO((int, dc_data));
+extern void dc_register_set DC_PROTO((int, dc_data));
+extern void dc_show_id DC_PROTO((FILE *, int, const char *));
+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_num2int DC_PROTO((dc_num, dc_boolean));
+extern int dc_numlen DC_PROTO((dc_num));
+extern int dc_pop DC_PROTO((dc_data *));
+extern int dc_register_get DC_PROTO((int, dc_data *));
+extern int dc_register_pop DC_PROTO((int, dc_data *));
+extern int dc_tell_length DC_PROTO((dc_data, dc_boolean));
+extern int dc_tell_scale DC_PROTO((dc_num, dc_boolean));
+extern int dc_tell_stackdepth DC_PROTO((void));
+extern int dc_top_of_stack DC_PROTO((dc_data *));
+
+extern size_t dc_strlen DC_PROTO((dc_str));
+
+extern dc_data dc_array_get DC_PROTO((int, int));
+extern dc_data dc_dup DC_PROTO((dc_data));
+extern dc_data dc_dup_num DC_PROTO((dc_num));
+extern dc_data dc_dup_str DC_PROTO((dc_str));
+extern dc_data dc_getnum DC_PROTO((int (*)(void), int, int *));
+extern dc_data dc_int2data DC_PROTO((int));
+extern dc_data dc_makestring DC_PROTO((const char *, size_t));
+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_exp DC_PROTO((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 *));
+extern int dc_sqrt DC_PROTO((dc_num, int, dc_num *));
diff --git a/gnu/usr.bin/dc/dc-regdef.h b/gnu/usr.bin/dc/dc-regdef.h
new file mode 100644
index 0000000..4142205
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-regdef.h
@@ -0,0 +1,38 @@
+/*
+ * definitions for dc's "register" declarations
+ *
+ * Copyright (C) 1994 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.
+ */
+
+#include <limits.h>
+
+/* determine how many register stacks there are */
+#ifndef DC_REGCOUNT
+# ifndef UCHAR_MAX
+# define DC_REGCOUNT 256
+# else
+# define DC_REGCOUNT (UCHAR_MAX+1)
+# endif
+#endif /* not DC_REGCOUNT */
+
+/* efficiency hack for masking arbritrary integers to 0..(DC_REGCOUNT-1) */
+#if (DC_REGCOUNT & (DC_REGCOUNT-1)) == 0 /* DC_REGCOUNT is power of 2 */
+# define regmap(r) ((r) & (DC_REGCOUNT-1))
+#else
+# define regmap(r) ((r) % DC_REGCOUNT)
+#endif
diff --git a/gnu/usr.bin/dc/dc-stack.c b/gnu/usr.bin/dc/dc-stack.c
new file mode 100644
index 0000000..76e61b3
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-stack.c
@@ -0,0 +1,367 @@
+/*
+ * implement stack functions for dc
+ *
+ * Copyright (C) 1994 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 module is the only one that knows what stacks (both the
+ * regular evaluation stack and the named register stacks)
+ * look like.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dc.h"
+#include "dc-proto.h"
+#include "dc-regdef.h"
+
+/* an oft-used error message: */
+#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname)
+
+
+/* simple linked-list implementaion suffices: */
+struct dc_list {
+ dc_data value;
+ struct dc_list *link;
+};
+typedef struct dc_list dc_list;
+
+/* the anonymous evaluation stack */
+static dc_list *dc_stack=NULL;
+
+/* the named register stacks */
+static dc_list *dc_register[DC_REGCOUNT];
+
+
+/* allocate a new dc_list item */
+static dc_list *
+dc_alloc DC_DECLVOID()
+{
+ dc_list *result;
+
+ result = dc_malloc(sizeof *result);
+ result->value.dc_type = DC_UNINITIALIZED;
+ result->link = NULL;
+ return result;
+}
+
+
+/* check that there are two 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_binop DC_DECLARG((op, kscale))
+ int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
+ int kscale DC_DECLEND
+{
+ dc_data a;
+ dc_data b;
+ dc_data r;
+
+ 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, &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);
+ }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.
+ */
+int
+dc_cmpop DC_DECLVOID()
+{
+ int result;
+ dc_data a;
+ dc_data b;
+
+ if (!dc_stack || !dc_stack->link){
+ Empty_Stack;
+ return 0;
+ }
+ 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 0;
+ }
+ (void)dc_pop(&b);
+ (void)dc_pop(&a);
+ result = dc_compare(b.v.number, a.v.number);
+ dc_free_num(&a.v.number);
+ dc_free_num(&b.v.number);
+ return result;
+}
+
+
+/* initialize the register stacks to their initial values */
+void
+dc_register_init DC_DECLVOID()
+{
+ int i;
+
+ for (i=0; i<DC_REGCOUNT; ++i)
+ dc_register[i] = NULL;
+}
+
+/* clear the evaluation stack */
+void
+dc_clear_stack DC_DECLVOID()
+{
+ dc_list *n;
+ dc_list *t;
+
+ for (n=dc_stack; n; n=t){
+ t = n->link;
+ if (n->value.dc_type == DC_NUMBER)
+ dc_free_num(&n->value.v.number);
+ else if (n->value.dc_type == DC_STRING)
+ dc_free_str(&n->value.v.string);
+ else
+ dc_garbage("in stack", -1);
+ free(n);
+ }
+ dc_stack = NULL;
+}
+
+/* push a value onto the evaluation stack */
+void
+dc_push DC_DECLARG((value))
+ dc_data value DC_DECLEND
+{
+ dc_list *n = dc_alloc();
+
+ if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
+ dc_garbage("in data being pushed", -1);
+ n->value = value;
+ n->link = dc_stack;
+ dc_stack = n;
+}
+
+/* push a value onto the named register stack */
+void
+dc_register_push DC_DECLARG((stackid, value))
+ int stackid DC_DECLSEP
+ dc_data value DC_DECLEND
+{
+ dc_list *n = dc_alloc();
+
+ stackid = regmap(stackid);
+ n->value = value;
+ n->link = dc_register[stackid];
+ dc_register[stackid] = n;
+}
+
+/* set *result to the value on the top of the evaluation stack */
+/* The caller is responsible for duplicating the value if it
+ * is to be maintained as anything more than a transient identity.
+ *
+ * DC_FAIL is returned if the stack is empty (and *result unchanged),
+ * DC_SUCCESS is returned otherwise
+ */
+int
+dc_top_of_stack DC_DECLARG((result))
+ dc_data *result DC_DECLEND
+{
+ if (!dc_stack){
+ Empty_Stack;
+ return DC_FAIL;
+ }
+ if (dc_stack->value.dc_type!=DC_NUMBER
+ && dc_stack->value.dc_type!=DC_STRING)
+ dc_garbage("at top of stack", -1);
+ *result = dc_stack->value;
+ return DC_SUCCESS;
+}
+
+/* set *result to a dup of the value on the top of the named register stack */
+/*
+ * DC_FAIL is returned if the named stack is empty (and *result unchanged),
+ * DC_SUCCESS is returned otherwise
+ */
+int
+dc_register_get DC_DECLARG((regid, result))
+ int regid DC_DECLSEP
+ dc_data *result DC_DECLEND
+{
+ dc_list *r;
+
+ regid = regmap(regid);
+ r = dc_register[regid];
+ if ( ! r ){
+ fprintf(stderr, "%s: register ", progname);
+ dc_show_id(stderr, regid, " is empty\n");
+ return DC_FAIL;
+ }
+ *result = dc_dup(r->value);
+ return DC_SUCCESS;
+}
+
+/* set the top of the named register stack to the indicated value */
+/* If the named stack is empty, craft a stack entry to enter the
+ * value into.
+ */
+void
+dc_register_set DC_DECLARG((regid, value))
+ int regid DC_DECLSEP
+ dc_data value DC_DECLEND
+{
+ dc_list *r;
+
+ regid = regmap(regid);
+ r = dc_register[regid];
+ if ( ! r )
+ dc_register[regid] = dc_alloc();
+ else if (r->value.dc_type == DC_NUMBER)
+ dc_free_num(&r->value.v.number);
+ else if (r->value.dc_type == DC_STRING)
+ dc_free_str(&r->value.v.string);
+ else
+ dc_garbage("", regid);
+ dc_register[regid]->value = value;
+}
+
+/* pop from the evaluation stack
+ *
+ * DC_FAIL is returned if the stack is empty (and *result unchanged),
+ * DC_SUCCESS is returned otherwise
+ */
+int
+dc_pop DC_DECLARG((result))
+ dc_data *result DC_DECLEND
+{
+ dc_list *r;
+
+ r = dc_stack;
+ if (!r){
+ Empty_Stack;
+ return DC_FAIL;
+ }
+ if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
+ dc_garbage("at top of stack", -1);
+ *result = r->value;
+ dc_stack = r->link;
+ free(r);
+ return DC_SUCCESS;
+}
+
+/* pop from the named register stack
+ *
+ * DC_FAIL is returned if the named stack is empty (and *result unchanged),
+ * DC_SUCCESS is returned otherwise
+ */
+int
+dc_register_pop DC_DECLARG((stackid, result))
+ int stackid DC_DECLSEP
+ dc_data *result DC_DECLEND
+{
+ dc_list *r;
+
+ stackid = regmap(stackid);
+ r = dc_register[stackid];
+ if (!r){
+ fprintf(stderr, "%s: stack register ", progname);
+ dc_show_id(stderr, stackid, " is empty\n");
+ return DC_FAIL;
+ }
+ if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
+ dc_garbage(" stack", stackid);
+ *result = r->value;
+ dc_register[stackid] = r->link;
+ free(r);
+ return DC_SUCCESS;
+}
+
+
+/* tell how many entries are currently on the evaluation stack */
+int
+dc_tell_stackdepth DC_DECLVOID()
+{
+ dc_list *n;
+ int depth=0;
+
+ for (n=dc_stack; n; n=n->link)
+ ++depth;
+ return depth;
+}
+
+
+/* return the length of the indicated data value;
+ * if discard_flag is true, the deallocate the value when done
+ *
+ * The definition of a datum's length is deligated to the
+ * appropriate module.
+ */
+int
+dc_tell_length DC_DECLARG((value, discard_flag))
+ dc_data value DC_DECLSEP
+ dc_boolean discard_flag DC_DECLEND
+{
+ int length;
+
+ if (value.dc_type == DC_NUMBER){
+ length = dc_numlen(value.v.number);
+ if (discard_flag == DC_TRUE)
+ dc_free_num(&value.v.number);
+ } else if (value.dc_type == DC_STRING) {
+ length = dc_strlen(value.v.string);
+ if (discard_flag == DC_TRUE)
+ dc_free_str(&value.v.string);
+ } else {
+ dc_garbage("in tell_length", -1);
+ /*NOTREACHED*/
+ length = 0; /*just to suppress spurious compiler warnings*/
+ }
+ return length;
+}
+
+
+
+/* print out all of the values on the evaluation stack */
+void
+dc_printall DC_DECLARG((obase))
+ int obase DC_DECLEND
+{
+ dc_list *n;
+
+ for (n=dc_stack; n; n=n->link)
+ dc_print(n->value, obase);
+}
diff --git a/gnu/usr.bin/dc/dc-string.c b/gnu/usr.bin/dc/dc-string.c
new file mode 100644
index 0000000..262cb03
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-string.c
@@ -0,0 +1,193 @@
+/*
+ * implement string functions for dc
+ *
+ * Copyright (C) 1994 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_string */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "dc.h"
+#include "dc-proto.h"
+
+struct dc_string {
+ char *s_ptr; /* pointer to base of string */
+ size_t s_len; /* length of counted string */
+ int s_refs; /* reference count to cut down on memory use by duplicates */
+};
+
+
+/* return a duplicate of the string 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_str DC_DECLARG((value))
+ dc_str value DC_DECLEND
+{
+ dc_data result;
+
+ ++((struct dc_string *)value)->s_refs;
+ result.v.string = value;
+ result.dc_type = DC_STRING;
+ return result;
+}
+
+/* free an instance of a dc_str value */
+void
+dc_free_str DC_DECLARG((value))
+ dc_str *value DC_DECLEND
+{
+ struct dc_string *string = *value;
+
+ if (--string->s_refs < 1){
+ free(string->s_ptr);
+ free(string);
+ }
+}
+
+/* Output a dc_str value.
+ * Add a trailing newline if "newline" is set.
+ * Free the value after use if discard_flag is set.
+ */
+void
+dc_out_str DC_DECLARG((value, newline, discard_flag))
+ dc_str value DC_DECLSEP
+ dc_boolean newline DC_DECLSEP
+ dc_boolean discard_flag DC_DECLEND
+{
+ struct dc_string *string = value;
+
+ printf("%s", string->s_ptr);
+ if (newline == DC_TRUE)
+ printf("\n");
+ if (discard_flag == DC_TRUE)
+ dc_free_str(&value);
+}
+
+/* make a copy of a string (base s, length len)
+ * into a dc_str value; return a dc_data result
+ * with this value
+ */
+dc_data
+dc_makestring DC_DECLARG((s, len))
+ const char *s DC_DECLSEP
+ size_t len DC_DECLEND
+{
+ dc_data result;
+ struct dc_string *string;
+
+ string = dc_malloc(sizeof *string);
+ string->s_ptr = dc_malloc(len+1);
+ memcpy(string->s_ptr, s, len);
+ string->s_ptr[len] = '\0'; /* nul terminated for those who need it */
+ string->s_len = len;
+ string->s_refs = 1;
+ result.v.string = string;
+ result.dc_type = DC_STRING;
+ return result;
+}
+
+/* read a dc_str value from FILE *fp;
+ * if ldelim == rdelim, then read until a ldelim char or EOF is reached;
+ * if ldelim != rdelim, then read until a matching rdelim for the
+ * (already eaten) first ldelim is read.
+ * Return a dc_data result with the dc_str value as its contents.
+ */
+dc_data
+dc_readstring DC_DECLARG((fp, ldelim, rdelim))
+ FILE *fp DC_DECLSEP
+ int ldelim DC_DECLSEP
+ int rdelim DC_DECLEND
+{
+ static char *line_buf = NULL; /* a buffer to build the string in */
+ static size_t buflen = 0; /* the current size of line_buf */
+ int depth=1;
+ int c;
+ char *p;
+ const char *end;
+
+ if (!line_buf){
+ /* initial buflen should be large enough to handle most cases */
+ buflen = 2016;
+ line_buf = dc_malloc(buflen);
+ }
+ p = line_buf;
+ end = line_buf + buflen;
+ for (;;){
+ c = getc(fp);
+ if (c == EOF)
+ break;
+ else if (c == rdelim && --depth < 1)
+ break;
+ else if (c == ldelim)
+ ++depth;
+ if (p >= end){
+ ptrdiff_t offset = p - line_buf;
+ /* buflen increment should be big enough
+ * to avoid execessive reallocs:
+ */
+ buflen += 2048;
+ line_buf = realloc(line_buf, buflen);
+ if (!line_buf)
+ dc_memfail();
+ p = line_buf + offset;
+ end = line_buf + buflen;
+ }
+ *p++ = c;
+ }
+ return dc_makestring(line_buf, (size_t)(p-line_buf));
+}
+
+/* return the base pointer of the dc_str value;
+ * This function is needed because no one else knows what dc_str
+ * looks like.
+ */
+const char *
+dc_str2charp DC_DECLARG((value))
+ dc_str value DC_DECLEND
+{
+ return ((struct dc_string *)value)->s_ptr;
+}
+
+/* return the length of the dc_str value;
+ * This function is needed because no one else knows what dc_str
+ * looks like, and strlen(dc_str2charp(value)) won't work
+ * if there's an embedded '\0'.
+ */
+size_t
+dc_strlen DC_DECLARG((value))
+ dc_str value DC_DECLEND
+{
+ return ((struct dc_string *)value)->s_len;
+}
+
+
+/* initialize the strings subsystem */
+void
+dc_string_init DC_DECLVOID()
+{
+ /* nothing to do for this implementation */
+}
diff --git a/gnu/usr.bin/dc/dc-version.h b/gnu/usr.bin/dc/dc-version.h
new file mode 100644
index 0000000..917be94
--- /dev/null
+++ b/gnu/usr.bin/dc/dc-version.h
@@ -0,0 +1,22 @@
+/*
+ * dc version number
+ *
+ * Copyright (C) 1994 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.
+ */
+
+#define Version "dc 1.0"
diff --git a/gnu/usr.bin/dc/dc.1 b/gnu/usr.bin/dc/dc.1
index 065baf6..6d8baf5 100644
--- a/gnu/usr.bin/dc/dc.1
+++ b/gnu/usr.bin/dc/dc.1
@@ -1,278 +1,389 @@
-.\" $Id$
-.TH DC 1 "03 Aug 1993" "GNU Project"
-.SH NAME
-dc, An Arbitrary Precision Calculator
-.SH SYNOPSIS
-.B dc
-.SH DESCRIPTION
-.PP
-DC is a reverse-polish desk calculator which supports unlimited
-precision arithmetic. It also allows you to define and call macros.
-Normally DC reads from the standard input; if any command arguments
-are given to it, they are filenames, and DC reads and executes the
-contents of the files before reading from standard input. All output
-is to standard output.
-
-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 DC, type the digits, with an optional decimal
-point. Exponential notation is not supported. To enter a negative
-number, begin the number with `_'. `-' 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.
+.TH DC 1 "07 Apr 1994" "GNU Project"
+.ds dc \fIdc\fP
+.ds Dc \fIDc\fP
+.SH
+NAME
+dc \- an arbitrary precision calculator
+.SH
+SYNOPSIS
+dc
+.SH
+DESCRIPTION
+.PP
+\*(Dc is a reverse-polish desk calculator which supports
+unlimited precision arithmetic.
+It also allows you to define and call macros.
+Normally \*(dc reads from the standard input;
+if any command arguments are given to it, they are filenames,
+and \*(dc reads and executes the contents of the files before reading
+from standard input.
+All normal output is to standard output;
+all error output is to standard error.
+.PP
+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.
+.PP
+To enter a number in
+.IR dc ,
+type the digits with an optional decimal point.
+Exponential notation is not supported.
+To enter a negative number,
+begin the number with ``_''.
+``-'' 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.
.PD
-.SH "Printing Commands"
-.PP
+.SH
+Printing Commands
+.TP
.B p
Prints the value on the top of the stack,
-without altering the stack. A newline is printed
-after the value.
-.PP
+without altering the stack.
+A newline is printed after the value.
+.TP
.B P
-Prints the value on the top of the stack,
-popping it off, and does not print a newline after.
-.PP
+Prints the value on the top of the stack, popping it off,
+and does not print a newline after.
+.TP
.B f
Prints the entire contents of the stack
+.ig
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.
+..
+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.
.PD
-.SH "Arithmetic"
-.PP
+.SH
+Arithmetic
+.TP
.B +
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 pushes the result.
+The precision of the result is determined only
+by the values of the arguments,
and is enough to be exact.
-.PP
+.TP
.B -
-Pops two values, subtracts the first one popped
-from the second one popped, and pushes the result.
-.PP
+Pops two values,
+subtracts the first one popped from the second one popped,
+and pushes the result.
+.TP
.B *
Pops two values, multiplies them, and pushes the result.
The number of fraction digits in the result is controlled
-by the current precision flag (see below) and does not
+by the current precision value (see below) and does not
depend on the values being multiplied.
-.PP
+.TP
.B /
-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 flag.
-.PP
+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.
+.TP
.B %
-Pops two values, computes the remainder of the division
-that the \fB/\fR command would do, and pushes that.
+Pops two values,
+computes the remainder of the division that the
+.B /
+command would do,
+and pushes that.
The division is done with as many fraction digits
-as the precision flag specifies, and the remainder
-is also computed with that many fraction digits.
-.PP
+as the precision value specifies,
+and the remainder is also computed with that many fraction digits.
+.TP
.B ^
-Pops two values and exponentiates, using the first
-value popped as the exponent and the second popped as the base.
+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 flag specifies the number of fraction
+The precision value specifies the number of fraction
digits in the result.
-.PP
+.TP
.B v
-Pops one value, computes its square root, and pushes that.
-The precision flag specifies the number of fraction digits
-in the result.
+Pops one value,
+computes its square root,
+and pushes that.
+The precision value specifies the number of fraction digits in the result.
.PP
-Most arithmetic operations are affected by the "precision flag",
+Most arithmetic operations are affected by the ``precision value'',
which you can set with the
-.BR k
-command. The default precision
-value is zero, which means that all arithmetic except for
+.B k
+command.
+The default precision value is zero,
+which means that all arithmetic except for
addition and subtraction produces integer results.
.PP
The remainder operation
-.BR %
-requires some explanation: applied to
-arguments `a' and `b' it produces `a - (b * (a / b))',
-where `a / b' is computed in the current precision.
-.PP
-.SH "Stack Control"
-.PP
+.B %
+requires some explanation:
+applied to arguments ``a'' and ``b'' it produces ``a - (b * (a / b))'',
+where ``a / b'' is computed in the current precision.
+.SH
+Stack Control
+.TP
.B c
Clears the stack, rendering it empty.
-.PP
+.TP
.B d
Duplicates the value on the top of the stack,
-pushing another copy of it. Thus,
-`4d*p' computes 4 squared and prints it.
-.SH "Registers"
-.PP
-DC provides 128 memory registers, each named by a single
-ASCII character. You can store a number in a register
-and retrieve it later.
-.PP
-.B s\fIr\fR
+pushing another copy of it.
+Thus, ``4d*p'' computes 4 squared and prints it.
+.SH
+Registers
+.PP
+\*(Dc provides 256 memory registers,
+each named by a single character.
+You can store a number or a string in a register and retrieve it later.
+.TP
+.BI s r
Pop the value off the top of the stack and store
-it into register \fIr\fR.
-.PP
-.B l\fIr\fR
-Copy the value in register \fIr\fR and push it onto the stack. This
-does not alter the contents of \fIr\fR.
-.PP
-Each register also contains its own stack. The current
-register value is the top of the register's stack.
-.PP
-.B S\fIr\fR
+it into register
+.IR r .
+.TP
+.BI l r
+Copy the value in register
+.I r
+and push it onto the stack.
+This does not alter the contents of
+.IR r .
+.PP
+Each register also contains its own stack.
+The current register value is the top of the register's stack.
+.TP
+.BI S r
Pop the value off the top of the (main) stack and
-push it onto the stack of register \fIr\fR.
+push it onto the stack of register
+.IR r .
The previous value of the register becomes inaccessible.
-.PP
-.B L\fIr\fR
-Pop the value off the top of register \fIr\fR's stack
-and push it onto the main stack. The previous value
-in register \fIr\fR's stack, if any, is now accessible
-via the
-.BR Ir
+.TP
+.BI L r
+Pop the value off the top of register
+.IR r 's
+stack and push it onto the main stack.
+The previous value
+in register
+.IR r 's
+stack, if any,
+is now accessible via the
+.BI l r
command.
+.ig
.PP
The
-.BR f
-command prints a list of all registers that have contents
-stored in them, together with their contents. Only the
-current contents of each register (the top of its stack)
+.B f
+command prints a list of all registers that have contents stored in them,
+together with their contents.
+Only the current contents of each register
+(the top of its stack)
is printed.
+..
+.SH
+Parameters
.PP
-.SH "Parameters"
-.PP
-DC has three parameters that control its operation: the precision, the
-input radix, and the output radix. The precision specifies the number
+\*(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;
-allnumbers typed in use this radix. The output radix is used
-for printing numbers.
-.PP
-The input and output radices are separate parameters; you can make them
-unequal, which can be useful or confusing. Each radix must be between 2
-and 36 inclusive. The precision must be zero or greater. The precision
-is always measured in decimal digits, regardless of the current input or
-output radix.
-.PP
+all numbers typed in use this radix.
+The output radix is used for printing numbers.
+.PP
+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.
+.TP
.B i
Pops the value off the top of the stack
and uses it to set the input radix.
-.PP
+.TP
.B o
-.PP
+Pops the value off the top of the stack
+and uses it to set the output radix.
+.TP
.B k
-Similarly set the output radix and the precision.
-.PP
+Pops the value off the top of the stack
+and uses it to set the precision.
+.TP
.B I
Pushes the current input radix on the stack.
-.PP
+.TP
.B O
-.PP
+Pushes the current output radix on the stack.
+.TP
.B K
-Similarly push the current output radix and the current precision.
-.PP
-.SH "Strings"
-.PP
-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 DC commands).
-Both registers and the stack can hold strings, and 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;
+Pushes the current precision on the stack.
+.SH
+Strings
+.PP
+\*(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
+\*(dc commands).
+All registers and the stack can hold strings,
+and \*(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
-.BR p
+.B p
command can accept either and prints the object
according to its type.
-.PP
-.B [characters]
+.TP
+.BI [ characters ]
Makes a string containing
-.BR characters
-and pushes it
-on the stack. For example,
-.BR [foo]p
-prints the
-characters \fBfoo\fR (with no newline).
-.PP
+.I characters
+(contained between balanced
+.B [
+and
+.B ]
+characters),
+and pushes it on the stack.
+For example,
+.B [foo]P
+prints the characters
+.B foo
+(with no newline).
+.TP
.B x
Pops a value off the stack and executes it as a macro.
-Normally it should be a string; if it is a number,
+Normally it should be a string;
+if it is a number,
it is simply pushed back onto the stack.
For example,
-.BR [1p]x
+.B [1p]x
executes the macro
-.BR 1p
-which pushes \fB1\fR on the stack and prints \fB1\fR
+.B 1p
+which pushes
+.B 1
+on the stack and prints
+.B 1
on a separate line.
.PP
Macros are most often stored in registers;
-\fB[1p]sa\fR stores a macro to print \fB1\fR into register \fBa\fR,
-and \fBlax\fR invokes the macro.
-.PP
-.B >\fIr\fR
+.B [1p]sa
+stores a macro to print
+.B 1
+into register
+.BR a ,
+and
+.B lax
+invokes this macro.
+.TP
+.BI > r
Pops two values off the stack and compares them
-assuming they are numbers, executing the contents
-of register \fIr\fR as a macro if the original top-of-stack
-is greater. Thus, \fB1 2>a\fR will invoke register \fBa\fR's contents
-and \fB2 1>a\fR will not.
-.PP
-.B <\fIr\fB
-Similar but invokes the macro if the original top-of-stack
-is less.
-.PP
-.B =\fIr\fR
-Similar but invokes the macro if the two numbers popped
-are equal. This can also be validly used to compare two
-strings for equality.
-.PP
+assuming they are numbers,
+executing the contents of register
+.I r
+as a macro if the original top-of-stack
+is greater.
+Thus,
+.B 1 2>a
+will invoke register
+.BR a 's
+contents and
+.B 2 1>a
+will not.
+.TP
+.BI < r
+Similar but invokes the macro if the original top-of-stack is less.
+.TP
+.BI = r
+Similar but invokes the macro if the two numbers popped are equal.
+.ig
+This can also be validly used to compare two strings for equality.
+..
+.TP
.B ?
Reads a line from the terminal and executes it.
This command allows a macro to request input from the user.
-.PP
+.TP
.B q
-During the execution of a macro, this comand
-does not exit DC. Instead, it exits from that
-macro and also from the macro which invoked it (if any).
-.PP
+exits from a 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
+.B q
+command will cause \*(dc to exit.
+.TP
.B Q
Pops a value off the stack and uses it as a count
-of levels of macro execution to be exited. Thus,
-\fB3Q\fR exits three levels.
-.SH "Status Inquiry"
-.PP
+of levels of macro execution to be exited.
+Thus,
+.B 3Q
+exits three levels.
+The
+.B Q
+command will never cause \*(dc to exit.
+.SH
+Status Inquiry
+.TP
.B Z
-Pops a value off the stack, calculates the number of
-digits it has (or number of characters, if it is a string)
+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.
-.PP
+.TP
.B 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 -1.
-.PP
+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
+.\" -1.
+0.
+.TP
.B z
-Pushes the current stack depth; the number of
-objects on the stack before the execution of the \fBz\fR command.
-.PP
-.B I
-Pushes the current value of the input radix.
-.PP
-.B O
-Pushes the current value of the output radix.
-.PP
-.B K
-Pushes the current value of the precision.
-.SH "Notes"
-.PP
-The \fB:\fR and \fB;\fR commands of the Unix DC program are
-not supported, as the documentation does not say what they do.
-The \fB!\fR command is not supported, but will be supported
-as soon as a library for executing a line as a command exists.
-.SH BUGS
+Pushes the current stack depth;
+the number of objects on the stack before the execution of the
+.B z
+command.
+.SH
+Miscellaneous
+.TP
+.B !
+Will run the rest of the line as a system command.
+.TP
+.B #
+Will interpret the rest of the line as a comment.
+.TP
+.BI : r
+Will pop the top two values off of the stack.
+The old second-to-top value will be stored in the array
+.IR r ,
+indexed by the old top-of-stack value.
+.TP
+.BI ; r
+Pops the top-of-stack and uses it as an index into
+the array
+.IR r .
+The selected value is then pushed onto the stack.
+.SH
+NOTES
+.PP
+The array operations
+.B :
+and
+.B ;
+are usually only used by traditional implementations of
+.IR bc .
+(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
Email bug reports to
.BR bug-gnu-utils@prep.ai.mit.edu .
diff --git a/gnu/usr.bin/dc/dc.c b/gnu/usr.bin/dc/dc.c
deleted file mode 100644
index 6dd3083..0000000
--- a/gnu/usr.bin/dc/dc.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * `dc' desk calculator utility.
- *
- * Copyright (C) 1984, 1993 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.
- */
-
-#include <stdio.h>
-#include "decimal.h" /* definitions for our decimal arithmetic package */
-
-FILE *open_file; /* input file now open */
-int file_count; /* Number of input files not yet opened */
-char **next_file; /* Pointer to vector of names of input files left */
-
-struct regstack
- {
- decimal value; /* Saved value of register */
- struct regstack *rest; /* Tail of list */
- };
-
-typedef struct regstack *regstack;
-
-regstack freeregstacks; /* Chain of free regstack structures for fast realloc */
-
-#define DC_MAX_REG 127
-decimal regs[DC_MAX_REG + 1]; /* "registers", with single-character names */
-regstack regstacks[DC_MAX_REG + 1]; /* For each register, a stack of previous values */
-
-int stacktop; /* index of last used element in stack */
-int stacksize; /* Current allocates size of stack */
-decimal *stack; /* Pointer to computation stack */
-
-/* A decimal number can be regarded as a string by
- treating its contents as characters and ignoring the
- position of its decimal point.
- Decimal numbers are marked as strings by having an `after' field of -1
- One use of strings is to execute them as macros.
-*/
-
-#define STRING -1
-
-int macrolevel; /* Current macro nesting; 0 if taking keyboard input */
-int macrostacksize; /* Current allocated size of macrostack and macroindex */
-decimal *macrostack; /* Pointer to macro stack array */
-int *macroindex; /* Pointer to index-within-macro stack array */
- /* Note that an empty macro is popped from the stack
- only when an trying to read a character from it
- or trying to push another macro. */
-
-int ibase; /* Radix for numeric input. */
-int obase; /* Radix for numeric output. */
-int precision; /* Number of digits to keep in multiply and divide. */
-
-char *buffer; /* Address of buffer used for reading numbers */
-int bufsize; /* Current size of buffer (made bigger when nec) */
-
-decimal dec_read ();
-regstack get_regstack ();
-int fetch ();
-int fgetchar ();
-char *concat ();
-void pushsqrt ();
-void condop ();
-void setibase ();
-void setobase ();
-void setprecision ();
-void pushmacro ();
-decimal read_string ();
-void pushlength ();
-void pushscale ();
-void unfetch ();
-void popmacros ();
-void popmacro ();
-void popstack ();
-void print_obj ();
-void print_string ();
-void free_regstack ();
-void pushreg ();
-void execute ();
-void fputchar ();
-void push ();
-void incref ();
-void decref ();
-void binop ();
-
-main (argc, argv, env)
- int argc;
- char **argv, **env;
-{
-
- ibase = 10;
- obase = 10;
- precision = 0;
-
- freeregstacks = 0;
-
- bzero (regs, sizeof regs);
- bzero (regstacks, sizeof regstacks);
-
- bufsize = 40;
- buffer = (char *) xmalloc (40);
-
- stacksize = 40;
- stack = (decimal *) xmalloc (stacksize * sizeof (decimal));
- stacktop = -1;
-
- macrostacksize = 40;
- macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal));
- macroindex = (int *) xmalloc (macrostacksize * sizeof (int));
- macrolevel = 0;
- /* Initialize for reading input files if any */
-
- open_file = 0;
-
- file_count = argc - 1;
- next_file = argv + 1;
-
-
- while (1)
- {
- execute ();
- }
-}
-
-/* Read and execute one command from the current source of input */
-
-void
-execute ()
-{
- int c = fetch ();
-
- if (c < 0) exit (0);
-
- {
- switch (c)
- {
- case '+': /* Arithmetic operators... */
- binop (decimal_add);
- break;
-
- case '-':
- binop (decimal_sub);
- break;
-
- case '*':
- binop (decimal_mul_dc); /* Like decimal_mul but hairy
- way of deciding precision to keep */
- break;
-
- case '/':
- binop (decimal_div);
- break;
-
- case '%':
- binop (decimal_rem);
- break;
-
- case '^':
- binop (decimal_expt);
- break;
-
- case '_': /* Begin a negative decimal constant */
- {
- decimal tem = dec_read (stdin);
- tem->sign = !tem->sign;
- push (tem);
- }
- break;
-
- case '.':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': /* All these begin decimal constants */
- unfetch (c);
- push (dec_read (stdin));
- break;
-
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- unfetch (c);
- push (dec_read (stdin));
- break;
-
- case 'c': /* Clear the stack */
- while (stacktop >= 0)
- decref (stack[stacktop--]);
- break;
-
- case 'd': /* Duplicate top of stack */
- if (stacktop < 0)
- error ("stack empty", 0);
- else push (stack[stacktop]);
- break;
-
- case 'f': /* Describe all registers and stack contents */
- {
- int regno;
- int somereg = 0; /* set to 1 if we print any registers */
- for (regno = 0; regno <= DC_MAX_REG; regno++)
- {
- if (regs[regno])
- {
- printf ("register %c: ", regno);
- print_obj (regs[regno]);
- somereg = 1;
- printf ("\n");
- }
- }
- if (somereg)
- printf ("\n");
- if (stacktop < 0)
- printf ("stack empty\n");
- else
- {
- int i;
- printf ("stack:\n");
- for (i = 0; i <= stacktop; i++)
- {
- print_obj (stack[stacktop - i]);
- printf ("\n");
- }
- }
- }
- break;
-
- case 'i': /* ibase <- top of stack */
- popstack (setibase);
- break;
-
- case 'I': /* Push current ibase */
- push (decimal_from_int (ibase));
- break;
-
- case 'k': /* like i, I but for precision instead of ibase */
- popstack (setprecision);
- break;
-
- case 'K':
- push (decimal_from_int (precision));
- break;
-
- case 'l': /* l<x> load register <x> onto stack */
- {
- int c1 = fetch ();
- if (c1 < 0) exit (0);
- if (c1 > DC_MAX_REG)
- error ("invalid register %c", c1);
- else if (!regs[c1])
- error ("register %c empty", c1);
- else
- push (regs[c1]);
- }
- break;
-
- case 'L': /* L<x> load register <x> to stack, pop <x>'s own stack */
- {
- int c1 = fetch ();
- if (c1 < 0) exit (0);
- if (c1 > DC_MAX_REG)
- error ("invalid register %c", c1);
- else if (!regstacks[c1])
- error ("nothing pushed on register %c", c1);
- else
- {
- regstack r = regstacks[c1];
- if (!regs[c1])
- error ("register %c empty after pop", c1);
- else
- push (regs[c1]);
- regs[c1] = r->value;
- regstacks[c1] = r->rest;
- free_regstack (r);
- }
- }
- break;
-
- case 'o': /* o, O like i, I but for obase instead of ibase */
- popstack (setobase);
- break;
-
- case 'O':
- push (decimal_from_int (obase));
- break;
-
- case 'p': /* Print tos, don't pop, do print newline afterward */
- if (stacktop < 0)
- error ("stack empty", 0);
- else
- {
- print_obj (stack[stacktop]);
- printf ("\n");
- }
- break;
-
- case 'P': /* Print tos, do pop, no newline afterward */
- popstack (print_obj);
- break;
-
- case 'q': /* Exit */
- if (macrolevel)
- { popmacro (); popmacro (); } /* decrease recursion level by 2 */
- else
- exit (0); /* If not in a macro, exit the program. */
-
- break;
-
- case 'Q': /* Tos says how many levels to exit */
- popstack (popmacros);
- break;
-
- case 's': /* s<x> -- Pop stack and set register <x> */
- if (stacktop < 0)
- empty ();
- else
- {
- int c1 = fetch ();
- if (c1 < 0) exit (0);
- if (c1 > DC_MAX_REG)
- error("invalid register %c", c1);
- else
- {
- if (regs[c1]) decref (regs[c1]);
- regs[c1] = stack[stacktop--];
- }
- }
- break;
-
- case 'S': /* S<x> -- pop stack and push as new value of register <x> */
- if (stacktop < 0)
- empty ();
- else
- {
- int c1 = fetch ();
- if (c1 < 0) exit (0);
- if (c1 > DC_MAX_REG)
- error("invalid register %c", c1);
- else
- {
- pushreg (c1);
- regs[c1] = stack[stacktop--];
- }
- }
- break;
-
- case 'v': /* tos gets square root of tos */
- popstack (pushsqrt);
- break;
-
- case 'x': /* pop stack , call as macro */
- popstack (pushmacro);
- break;
-
- case 'X': /* Pop stack, get # fraction digits, push that */
- popstack (pushscale);
- break;
-
- case 'z': /* Compute depth of stack, push that */
- push (decimal_from_int (stacktop + 1));
- break;
-
- case 'Z': /* Pop stack, get # digits, push that */
- popstack (pushlength);
- break;
-
- case '<': /* Conditional: pop two numbers, compare, maybe execute register */
- /* Note: for no obvious reason, the standard Unix `dc'
- considers < to be true if the top of stack is less
- than the next-to-top of stack,
- and vice versa for >.
- This seems backwards to me, but I am preserving compatibility. */
- condop (1);
- break;
-
- case '>':
- condop (-1);
- break;
-
- case '=':
- condop (0);
- break;
-
- case '?': /* Read expression from terminal and execute it */
- /* First ignore any leading newlines */
- {
- int c1;
- while ((c1 = getchar ()) == '\n');
- ungetc (c1, stdin);
- }
- /* Read a line from the terminal and execute it. */
- pushmacro (read_string ('\n', fgetchar, 0));
- break;
-
- case '[': /* Begin string constant */
- push (read_string (']', fetch, '['));
- break;
-
- case ' ':
- case '\n':
- break;
-
- default:
- error ("undefined command %c", c);
- }
- }
-}
-
-/* Functionals for performing arithmetic, etc */
-
-/* Call the function `op', with the top of stack value as argument,
- and then pop the stack.
- If the stack is empty, print a message and do not call `op'. */
-
-void
-popstack (op)
- void (*op) ();
-{
- if (stacktop < 0)
- empty ();
- else
- {
- decimal value = stack[stacktop--];
- op (value);
- decref (value);
- }
-}
-
-/* Call the function `op' with two arguments taken from the stack top,
- then pop those arguments and push the value returned by `op'.
- `op' is assumed to return a decimal number.
- If there are not two values on the stack, print a message
- and do not call `op'. */
-
-void
-binop (op)
- decimal (*op) ();
-{
- if (stacktop < 1)
- error ("stack empty", 0);
- else if (stack[stacktop]->after == STRING || stack[stacktop - 1]->after == STRING)
- error ("operands not both numeric");
- else
- {
- decimal arg2 = stack [stacktop--];
- decimal arg1 = stack [stacktop--];
-
- push (op (arg1, arg2, precision));
-
- decref (arg1);
- decref (arg2);
- }
-}
-
-void
-condop (cond)
- int cond;
-{
- int regno = fetch ();
- if (regno > DC_MAX_REG)
- error ("invalid register %c", regno);
- else if (!regs[regno])
- error ("register %c is empty", regno);
- else if (stacktop < 1)
- empty ();
- else
- {
- decimal arg2 = stack[stacktop--];
- decimal arg1 = stack[stacktop--];
- int relation = decimal_compare (arg1, arg2);
- decref (arg1);
- decref (arg2);
- if (cond == relation
- || (cond < 0 && relation < 0)
- || (cond > 0 && relation > 0))
- pushmacro (regs[regno]);
- }
-}
-
-/* Handle the command input source */
-
-/* Fetch the next command character from a macro or from the terminal */
-
-int
-fetch()
-{
- int c = -1;
-
- while (macrolevel &&
- LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
- popmacro();
- if (macrolevel)
- return macrostack[macrolevel - 1]->contents[macroindex[macrolevel-1]++];
- while (1)
- {
- if (open_file)
- {
- c = getc (open_file);
- if (c >= 0) break;
- fclose (open_file);
- open_file = 0;
- }
- else if (file_count)
- {
- open_file = fopen (*next_file++, "r");
- file_count--;
- if (!open_file)
- perror_with_name (*(next_file - 1));
- }
- else break;
- }
- if (c >= 0) return c;
- return getc (stdin);
-}
-
-/* Unread character c on command input stream, whatever it is */
-
-void
-unfetch (c)
- char c;
-{
- if (macrolevel)
- macroindex[macrolevel-1]--;
- else if (open_file)
- ungetc (c, open_file);
- else
- ungetc (c, stdin);
-}
-
-/* Begin execution of macro m. */
-
-void
-pushmacro (m)
- decimal m;
-{
- while (macrolevel &&
- LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
- popmacro();
- if (m->after == STRING)
- {
- if (macrolevel == macrostacksize)
- {
- macrostacksize *= 2;
- macrostack = (decimal *) xrealloc (macrostack, macrostacksize * sizeof (decimal));
- macroindex = (int *) xrealloc (macroindex, macrostacksize * sizeof (int));
- }
- macroindex[macrolevel] = 0;
- macrostack[macrolevel++] = m;
- incref (m);
- }
- else
- { /* Number supplied as a macro! */
- push (m); /* Its effect wouyld be to push the number. */
- }
-}
-
-/* Pop a specified number of levels of macro execution.
- The number of levels is specified by a decimal number d. */
-
-void
-popmacros (d)
- decimal d;
-{
- int num_pops = decimal_to_int (d);
- int i;
- for (i = 0; i < num_pops; i++)
- popmacro ();
-}
-/* Exit one level of macro execution. */
-
-void
-popmacro ()
-{
- if (!macrolevel)
- exit (0);
- else
- {
- decref (macrostack[--macrolevel]);
- }
-}
-
-void
-push (d)
- decimal d;
-{
- if (stacktop == stacksize - 1)
- stack = (decimal *) xrealloc (stack, (stacksize *= 2) * sizeof (decimal));
-
- incref (d);
-
- stack[++stacktop] = d;
-}
-
-/* Reference counting and storage freeing */
-
-void
-decref (d)
- decimal d;
-{
- if (!--d->refcnt)
- free (d);
-}
-
-void
-incref (d)
- decimal d;
-{
- d->refcnt++;
-}
-
-empty ()
-{
- error ("stack empty", 0);
-}
-
-regstack
-get_regstack ()
-{
- if (freeregstacks)
- {
- regstack r = freeregstacks;
- freeregstacks = r ->rest;
- return r;
- }
- else
- return (regstack) xmalloc (sizeof (struct regstack));
-}
-
-void
-free_regstack (r)
- regstack r;
-{
- r->rest = freeregstacks;
- freeregstacks = r;
-}
-
-void
-pushreg (c)
- char c;
-{
- regstack r = get_regstack ();
-
- r->rest = regstacks[c];
- r->value = regs[c];
- regstacks[c] = r;
- regs[c] = 0;
-}
-
-/* Input of numbers and strings */
-
-/* Return a character read from the terminal. */
-
-fgetchar ()
-{
- return getchar ();
-}
-
-void
-fputchar (c)
- char (c);
-{
- putchar (c);
-}
-
-/* Read text from command input source up to a close-bracket,
- make a string out of it, and return it.
- If STARTC is nonzero, then it and STOPC must balance when nested. */
-
-decimal
-read_string (stopc, inputfn, startc)
- char stopc;
- int (*inputfn) ();
- int startc;
-{
- int c;
- decimal result;
- int i = 0;
- int count = 0;
-
- while (1)
- {
- c = inputfn ();
- if (c < 0 || (c == stopc && count == 0))
- {
- if (count != 0)
- error ("Unmatched `%c'", startc);
- break;
- }
- if (c == stopc)
- count--;
- if (c == startc)
- count++;
- if (i + 1 >= bufsize)
- buffer = (char *) xrealloc (buffer, bufsize *= 2);
- buffer[i++] = c;
- }
- result = make_decimal (i, 0);
- result->after = -1; /* Mark it as a string */
- result->before++; /* but keep the length unchanged */
- bcopy (buffer, result->contents, i);
- return result;
-}
-
-/* Read a number from the current input source */
-
-decimal
-dec_read ()
-{
- int c;
- int i = 0;
-
- while (1)
- {
- c = fetch ();
- if (! ((c >= '0' && c <= '9')
- || (c >= 'A' && c <= 'F')
- || c == '.'))
- break;
- if (i + 1 >= bufsize)
- buffer = (char *) xrealloc (buffer, bufsize *= 2);
- buffer[i++] = c;
- }
- buffer[i++] = 0;
- unfetch (c);
-
- return decimal_parse (buffer, ibase);
-}
-
-/* Output of numbers and strings */
-
-/* Print the contents of obj, either numerically or as a string,
- according to what obj says it is. */
-
-void
-print_obj (obj)
- decimal obj;
-{
- if (obj->after == STRING)
- print_string (obj);
- else
- decimal_print (obj, fputchar, obase);
-}
-
-/* Print the contents of the decimal number `string', treated as a string. */
-
-void
-print_string (string)
- decimal string;
-{
- char *p = string->contents;
- int len = LENGTH (string);
- int i;
-
- for (i = 0; i < len; i++)
- {
- putchar (*p++);
- }
-}
-
-/* Set the input radix from the value of the decimal number d, if valid. */
-
-void
-setibase (d)
- decimal d;
-{
- int value = decimal_to_int (d);
- if (value < 2 || value > 36)
- error ("input radix must be from 2 to 36", 0);
- else
- ibase = value;
-}
-
-/* Set the output radix from the value of the decimal number d, if valid. */
-
-void
-setobase (d)
- decimal d;
-{
- int value = decimal_to_int (d);
- if (value < 2 || value > 36)
- error ("output radix must be from 2 to 36", 0);
- else
- obase = value;
-}
-
-/* Set the precision for mul and div from the value of the decimal number d, if valid. */
-
-void
-setprecision (d)
- decimal d;
-{
- int value = decimal_to_int (d);
- if (value < 0 || value > 30000)
- error ("precision must be nonnegative and < 30000", 0);
- else
- precision = value;
-}
-
-/* Push the number of digits in decimal number d, as a decimal number. */
-
-void
-pushlength (d)
- decimal d;
-{
- push (decimal_from_int (LENGTH (d)));
-}
-
-/* Push the number of fraction digits in d. */
-
-void
-pushscale (d)
- decimal d;
-{
- push (decimal_from_int (d->after));
-}
-
-/* Push the square root of decimal number d. */
-
-void
-pushsqrt (d)
- decimal d;
-{
- push (decimal_sqrt (d, precision));
-}
-
-/* Print error message and exit. */
-
-fatal (s1, s2)
- char *s1, *s2;
-{
- error (s1, s2);
- exit (1);
-}
-
-/* Print error message. `s1' is printf control string, `s2' is arg for it. */
-
-error (s1, s2)
- char *s1, *s2;
-{
- printf ("dc: ");
- printf (s1, s2);
- printf ("\n");
-}
-
-decimal_error (s1, s2)
- char *s1, *s2;
-{
- error (s1, s2);
-}
-
-perror_with_name (name)
- char *name;
-{
- extern int errno, sys_nerr;
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- error (s, name);
-}
-
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-int
-xmalloc (size)
- int size;
-{
- int result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
-}
-
-int
-xrealloc (ptr, size)
- char *ptr;
- int size;
-{
- int result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
-}
diff --git a/gnu/usr.bin/dc/dc.h b/gnu/usr.bin/dc/dc.h
new file mode 100644
index 0000000..7193aea
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.h
@@ -0,0 +1,81 @@
+/*
+ * Header file for dc routines
+ *
+ * Copyright (C) 1994 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.
+ */
+
+#ifndef DC_DEFS_H
+#define DC_DEFS_H
+
+/* 'I' is a command, and bases 17 and 18 are quite
+ * unusual, so we limit ourselves to bases 2 to 16
+ */
+#define DC_IBASE_MAX 16
+
+#define DC_SUCCESS 0
+#define DC_DOMAIN_ERROR 1
+#define DC_FAIL 2 /* generic failure */
+
+
+#ifndef __STDC__
+# define DC_PROTO(x) ()
+# define DC_DECLVOID() ()
+# define DC_DECLARG(arglist) arglist
+# define DC_DECLSEP ;
+# define DC_DECLEND ;
+#else /* __STDC__ */
+# define DC_PROTO(x) x
+# define DC_DECLVOID() (void)
+# define DC_DECLARG(arglist) (
+# define DC_DECLSEP ,
+# define DC_DECLEND )
+#endif /* __STDC__ */
+
+
+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 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;
+
+
+/* except for the two implementation-specific modules, all
+ * dc functions only know of this one generic type of object
+ */
+typedef struct {
+ dc_value_type dc_type; /* discriminant for union */
+ union {
+ dc_num number;
+ dc_str string;
+ } v;
+} dc_data;
+
+
+/* This is dc's only global variable: */
+extern const char *progname; /* basename of program invocation */
+
+#endif /* not DC_DEFS_H */
diff --git a/gnu/usr.bin/dc/decimal.c b/gnu/usr.bin/dc/decimal.c
deleted file mode 100644
index 780de29..0000000
--- a/gnu/usr.bin/dc/decimal.c
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * Arbitrary precision decimal arithmetic.
- *
- * Copyright (C) 1984 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.
- */
-
-/* Some known problems:
-
- Another problem with decimal_div is found when you try to
- divide a number with > scale fraction digits by 1. The
- expected result is simply truncation, but all sorts of things
- happen instead. An example is that the result of .99999998/1
- with scale set to 6 is .000001
-
- There are some problems in the behavior of the decimal package
- related to printing and parsing. The
- printer is weird about very large output radices, tending to want
- to output single ASCII characters for any and all digits (even
- in radices > 127). The UNIX bc approach is to print digit groups
- separated by spaces. There is a rather overwrought workaround in
- the function decputc() in bcmisc.c, but it would be better if
- decimal.c got a fix for this. */
-
-/* For stand-alone testing, compile with -DTEST.
- This DTESTable feature defines a `main' function
- which is a simple loop that accepts input of the form
- number space op space number newline
- where op is +, -, *, /, %, p or r,
- and performs the operation and prints the operands and result.
- `p' means print the first number in the radix spec'd by the second.
- `r' means read the first one in the radix specified by the second
- (and print the result in decimal).
- Divide in this test keeps three fraction digits. */
-
-#include "decimal.h"
-
-#define MAX(a, b) (((a) > (b) ? (a) : (b)))
-
-/* Some constant decimal numbers */
-
-struct decimal decimal_zero = {0, 0, 0, 0, 0};
-
-struct decimal decimal_one = {0, 0, 1, 0, 1};
-
-/*** Assumes RADIX is even ***/
-struct decimal decimal_half = {0, 1, 0, 0, RADIX / 2};
-
-decimal static decimal_add1 (), decimal_sub1 ();
-static void add_scaled ();
-static int subtract_scaled ();
-
-/* Create and return a decimal number that has `before' digits before
- the decimal point and `after' digits after. The digits themselves are
- initialized to zero. */
-
-decimal
-make_decimal (before, after)
- int before, after;
-{
- decimal result;
- if (before >= 1<<16)
- {
- decimal_error ("%d too many decimal digits", before);
- return 0;
- }
- if (after >= 1<<15)
- {
- decimal_error ("%d too many decimal digits", after);
- return 0;
- }
- result = (decimal) malloc (sizeof (struct decimal) + before + after - 1);
- result->sign = 0;
- result->before = before;
- result->after = after;
- result->refcnt = 0;
- bzero (result->contents, before + after);
- return result;
-}
-
-/* Create a copy of the decimal number `b' and return it. */
-
-decimal
-decimal_copy (b)
- decimal b;
-{
- decimal result = make_decimal (b->before, b->after);
- bcopy (b->contents, result->contents, LENGTH(b));
- result->sign = b->sign;
- return result;
-}
-
-/* Copy a decimal number `b' but extend or truncate to exactly
- `digits' fraction digits. */
-
-static decimal
-decimal_copy_1 (b, digits)
- decimal b;
- int digits;
-{
- if (digits > b->after)
- {
- decimal result = make_decimal (b->before, digits);
- bcopy (b->contents, result->contents + (digits - (int) b->after), LENGTH(b));
- return result;
- }
- else
- return decimal_trunc_digits (b, digits);
-}
-
-/* flush specified number `digits' of trailing fraction digits,
- and flush any trailing fraction zero digits exposed after they are gone.
- The number `b' is actually modified; no new storage is allocated.
- That is why this is not global. */
-
-static void
-flush_trailing_digits (b, digits)
- decimal b;
- int digits;
-{
- int flush = digits;
- int maxdig = b->after;
-
- while (flush < maxdig && !b->contents [flush])
- flush++;
-
- if (flush)
- {
- int i;
-
- b->after -= flush;
- for (i = 0; i < LENGTH (b); i++)
- b->contents[i] = b->contents[flush + i];
- }
-
-}
-
-/* Return nonzero integer if the value of decimal number `b' is zero. */
-
-int
-decimal_zerop (b)
- decimal b;
-{
- return !LENGTH(b);
-}
-
-/* Compare two decimal numbers arithmetically.
- The value is < 0 if b1 < b2, > 0 if b1 > b2, 0 if b1 = b2.
- This is the same way that `strcmp' reports the result of comparing
- strings. */
-
-int
-decimal_compare (b1, b2)
- decimal b1, b2;
-{
- int l1, l2;
- char *p1, *p2, *s1, *s2;
- int i;
-
- /* If signs differ, deduce result from the signs */
-
- if (b2->sign && !b1->sign) return 1;
- if (b1->sign && !b2->sign) return -1;
-
- /* If same sign but number of nonfraction digits differs,
- the one with more of them is farther from zero. */
-
- if (b1->before != b2->before)
- if (b1->sign)
- return (int) (b2->before - b1->before);
- else
- return (int) (b1->before - b2->before);
-
- /* Else compare the numbers digit by digit from high end */
- l1 = LENGTH(b1);
- l2 = LENGTH(b2);
- s1 = b1->contents; /* Start of number -- don't back up digit pointer past here */
- s2 = b2->contents;
- p1 = b1->contents + l1; /* Scanning pointer, for fetching digits. */
- p2 = b2->contents + l2;
- for (i = MAX(l1, l2); i >= 0; i--)
- {
- int r = ((p1 != s1) ? *--p1 : 0) - ((p2 != s2) ? *--p2 : 0);
- if (r)
- return b1->sign ? -r : r;
- }
- return 0;
-}
-
-/* Return the number of digits stored in decimal number `b' */
-
-int
-decimal_length (b)
- decimal b;
-{
- return LENGTH(b);
-}
-
-/* Return the number of fraction digits stored in decimal number `b'. */
-
-int
-decimal_after (b)
- decimal b;
-{
- return b->after;
-}
-
-/* Round decimal number `b' to have only `digits' fraction digits.
- Result is rounded to nearest unit in the last remaining digit.
- Return the result, another decimal number. */
-
-decimal
-decimal_round_digits (b, digits)
- decimal b;
- int digits;
-{
- decimal result;
- int old;
-
- if (b->after <= digits) return decimal_copy (b);
-
- if (digits < 0)
- {
- decimal_error ("request to keep negative number of digits %d", digits);
- return decimal_copy (b);
- }
-
- result = make_decimal (b->before + 1, b->after);
- result->sign = b->sign;
- bcopy (b->contents, result->contents, LENGTH(b));
-
- old = result->after;
-
- /* Add .5 * last place to keep, so that we round rather than truncate */
- /* Note this ignores sign of result, so if result is negative
- it is subtracting */
-
- add_scaled (result, DECIMAL_HALF, 1, old - digits - 1);
-
- /* Flush desired digits, and any trailing zeros exposed by them. */
-
- flush_trailing_digits (result, old - digits);
-
- /* Flush leading digits -- always is one, unless was a carry into it */
-
- while (result->before > 0
- && result->contents[LENGTH(result) - 1] == 0)
- result->before--;
-
- return result;
-}
-
-/* Truncate decimal number `b' to have only `digits' fraction digits.
- Any fraction digits in `b' beyond that are dropped and ignored.
- Truncation is toward zero.
- Return the result, another decimal number. */
-
-decimal
-decimal_trunc_digits (b, digits)
- decimal b;
- int digits;
-{
- decimal result = decimal_copy (b);
- int old = result->after;
-
- if (old <= digits) return result;
-
- if (digits < 0)
- {
- decimal_error ("request to keep negative number of digits %d", digits);
- return result;
- }
-
- flush_trailing_digits (result, old - digits);
-
- return result;
-}
-
-/* Return the fractional part of decimal number `b':
- that is, `b' - decimal_trunc_digits (`b') */
-
-decimal
-decimal_fraction (b)
- decimal b;
-{
- decimal result = make_decimal (0, b->after);
- bcopy (b->contents, result->contents, b->after);
- return result;
-}
-
-/* return an integer whose value is that of decimal `b', sans its fraction. */
-
-int
-decimal_to_int (b)
- decimal b;
-{
- int result = 0;
- int i;
- int end = b->after;
-
- for (i = LENGTH(b) - 1; i >= end; i--)
- {
- result *= RADIX;
- result += b->contents[i];
- }
- return result;
-}
-
-/* return a decimal whose value is the integer i. */
-
-decimal
-decimal_from_int (i)
- int i;
-{
- int log, tem;
- decimal result;
-
- for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX);
-
- result = make_decimal (log, 0);
-
- for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX)
- result->contents[log] = tem % RADIX;
-
- if (i < 0) result->sign = 1;
- return result;
-}
-
-/* Return (as an integer) the result of dividing decimal number `b' by
- integer `divisor'.
- This is used in printing decimal numbers in other radices. */
-
-int
-decimal_int_rem (b, divisor)
- decimal b;
- int divisor;
-{
- int len = LENGTH(b);
- int end = b->after;
- int accum = 0;
- int i;
-
- for (i = len - 1; i >= end; i--)
- {
- accum %= divisor;
- accum *= RADIX;
- accum += b->contents[i];
- }
- return accum % divisor;
-}
-
-/* Convert digit `digit' to a character and output it by calling
- `charout' with it as arg. */
-
-static void
-print_digit (digit, charout)
- int digit;
- void (*charout) ();
-{
- if (digit < 10)
- charout ('0' + digit);
- else
- charout ('A' + digit - 10);
-}
-
-/* print decimal number `b' in radix `radix', assuming it is an integer.
- `r' is `radix' expressed as a decimal number. */
-
-static
-decimal_print_1 (b, r, radix, charout)
- decimal b, r;
- int radix;
- void (*charout) ();
-{
- int digit = decimal_int_rem (b, radix);
- decimal rest = decimal_div (b, r, 0);
-
- if (!decimal_zerop (rest))
- decimal_print_1 (rest, r, radix, charout);
-
- print_digit (digit, charout);
-
- free (rest);
-}
-
-/* User entry: print decimal number `b' in radix `radix' (an integer),
- outputting characters by calling `charout'. */
-
-void
-decimal_print (b, charout, radix)
- decimal b;
- void (*charout) ();
- int radix;
-{
- if (b->sign) charout ('-');
-
- if (radix == RADIX)
- {
- /* decimal output => just print the digits, inserting a point in
- the proper place. */
- int i;
- int before = b->before;
- int len = before + b->after;
- for (i = 0; i < len; i++)
- {
- if (i == before) charout ('.');
- /* Broken if RADIX /= 10
- charout ('0' + b->contents [len - 1 - i]); */
- print_digit (b->contents [len - 1 - i], charout);
- }
- if (!len)
- charout ('0');
- }
- else
- {
- /* nonstandard radix: must use multiply and divide to determine the
- digits of the number in that radix. */
-
- int i;
- extern double log10 ();
- /* Compute the number of fraction digits we want to have in the
- new radix. They should contain the same amount of
- information as the decimal digits we have. */
- int nfrac = (b->after / log10 ((double) radix) + .99);
- decimal r = decimal_from_int (radix);
- decimal intpart = decimal_trunc_digits (b, 0);
-
- /* print integer part */
- decimal_print_1 (intpart, r, radix, charout);
- free (intpart);
-
- /* print fraction part */
- if (nfrac)
- {
- decimal tem1, tem2;
- tem1 = decimal_fraction (b);
- charout ('.');
- /* repeatedly multiply by `radix', print integer part as one digit,
- and flush the integer part. */
- for (i = 0; i < nfrac; i++)
- {
- tem2 = decimal_mul (tem1, r);
- free (tem1);
- print_digit (decimal_to_int (tem2), charout);
- tem1 = decimal_fraction (tem2);
- free (tem2);
- }
- free (tem1);
- }
- free (r);
- }
-}
-
-static int
-decode_digit (digitchar)
- char digitchar;
-{
- if ('0' <= digitchar && digitchar <= '9')
- return digitchar - '0';
- if ('a' <= digitchar && digitchar <= 'z')
- return digitchar - 'a' + 10;
- if ('A' <= digitchar && digitchar <= 'Z')
- return digitchar - 'A' + 10;
- return -1;
-}
-
-/* Parse string `s' into a number using radix `radix'
- and return result as a decimal number. */
-
-decimal
-decimal_parse (s, radix)
- char *s;
- int radix;
-{
- int i, len, before = -1;
- char *p;
- char c;
- decimal result;
- int negative = 0;
- int excess_digit = 0;
-
- if (*s == '-')
- {
- s++;
- negative = 1;
- }
-
- /* First scan for valid characters.
- Count total num digits, and count num before the decimal point. */
-
- p = s;
- i = 0;
- while (c = *p++)
- {
- if (c == '.')
- {
- if (before >= 0)
- decimal_error ("two decimal points in %s", s);
- before = i;
- }
- else if (c == '0' && !i && before < 0)
- s++; /* Discard leading zeros */
- else if (decode_digit (c) >= 0)
- {
- i++;
- if (decode_digit (c) > RADIX)
- excess_digit = 1;
- }
- else
- decimal_error ("invalid number %s", s);
- }
-
- len = i;
- if (before < 0) before = i;
-
- p = s;
-
- /* Now parse those digits */
-
- if (radix != RADIX || excess_digit)
- {
- decimal r = decimal_from_int (radix);
- extern double log10 ();
- int digits = (len - before) * log10 ((double) radix) + .99;
- result = decimal_copy (DECIMAL_ZERO);
-
- /* Parse all the digits into an integer, ignoring decimal point,
- by multiplying by `radix'. */
-
- while (i > 0 && (c = *p++))
- {
- if (c != '.')
- {
- decimal newdig = decimal_from_int (decode_digit (c));
- decimal prod = decimal_mul (result, r);
- decimal newresult = decimal_add (newdig, prod);
-
- free (newdig); free (prod); free (result);
- result = newresult;
- i--;
- }
- }
-
- /* Now put decimal point in right place
- by dividing by `radix' once for each digit
- that really should have followed the decimal point. */
-
- for (i = before; i < len; i++)
- {
- decimal newresult = decimal_div (result, r, digits);
- free (result);
- result = newresult;
- }
- free (r);
- }
- else
- {
- /* radix is standard - just copy the digits into a decimal number. */
-
- int tem;
- result = make_decimal (before, len - before);
-
- while (i > 0 && (c = *p++))
- {
- if ((c != '.') &&
- ((tem = decode_digit (c)) >= 0))
- result->contents [--i] = tem;
- }
- }
-
- if (negative) result->sign = 1;
- flush_trailing_digits (result, 0);
- return result;
-}
-
-/* Add b1 and b2, considering their signs */
-
-decimal
-decimal_add (b1, b2)
- decimal b1, b2;
-{
- decimal v;
-
- if (b1->sign != b2->sign)
- v = decimal_sub1 (b1, b2);
- else
- v = decimal_add1 (b1, b2);
- if (b1->sign && !decimal_zerop (v))
- v->sign = !v->sign;
- return v;
-}
-
-/* Add b1 and minus b2, considering their signs */
-
-decimal
-decimal_sub (b1, b2)
- decimal b1, b2;
-{
- decimal v;
-
- if (b1->sign != b2->sign)
- v = decimal_add1 (b1, b2);
- else
- v = decimal_sub1 (b1, b2);
- if (b1->sign && !decimal_zerop (v))
- v->sign = !v->sign;
- return v;
-}
-
-/* Return the negation of b2. */
-
-decimal
-decimal_neg (b2)
- decimal b2;
-{
- decimal v = decimal_copy (b2);
-
- if (!decimal_zerop (v))
- v->sign = !v->sign;
- return v;
-}
-
-/* add magnitudes of b1 and b2, ignoring their signs. */
-
-static decimal
-decimal_add1 (b1, b2)
- decimal b1, b2;
-{
- int before = MAX (b1->before, b2->before);
- int after = MAX (b1->after, b2->after);
-
- int len = before+after+1;
- decimal result = make_decimal (before+1, after);
-
- int i;
- char *s1 = b1->contents;
- char *s2 = b2->contents;
- char *p1 = s1 + b1->after - after;
- char *p2 = s2 + b2->after - after;
- char *e1 = s1 + b1->before + b1->after;
- char *e2 = s2 + b2->before + b2->after;
- char *pr = result->contents;
- int accum = 0;
-
- for (i = 0; i < len; i++, p1++, p2++)
- {
- accum /= RADIX;
- if (p1 >= s1 && p1 < e1) accum += *p1;
- if (p2 >= s2 && p2 < e2) accum += *p2;
- *pr++ = accum % RADIX;
- }
- if (!accum)
- (result->before)--;
-
- flush_trailing_digits (result, 0);
-
- return result;
-}
-
-/* subtract magnitude of b2 from that or b1, returning signed decimal
- number. */
-
-static decimal
-decimal_sub1 (b1, b2)
- decimal b1, b2;
-{
- int before = MAX (b1->before, b2->before);
- int after = MAX (b1->after, b2->after);
-
- int len = before+after;
- decimal result = make_decimal (before, after);
-
- int i;
- char *s1 = b1->contents;
- char *s2 = b2->contents;
- char *p1 = s1 + b1->after - after;
- char *p2 = s2 + b2->after - after;
- char *e1 = s1 + b1->before + b1->after;
- char *e2 = s2 + b2->before + b2->after;
- char *pr = result->contents;
- int accum = 0;
-
- for (i = 0; i < len; i++, p1++, p2++)
- {
- if (p1 >= s1 && p1 < e1) accum += *p1;
- if (p2 >= s2 && p2 < e2) accum -= *p2;
- if (accum < 0 && accum % RADIX)
- *pr = RADIX - (- accum) % RADIX;
- else
- *pr = accum % RADIX;
- accum -= *pr++;
- accum /= RADIX;
- }
-
- /* If result is negative, subtract it from RADIX**length
- so that we get the right digits for sign-magnitude
- rather than RADIX-complement */
-
- if (accum)
- {
- result->sign = 1;
- pr = result->contents;
- accum = 0;
- for (i = 0; i < len; i++)
- {
- accum -= *pr;
- if (accum)
- *pr = accum + RADIX;
- else
- *pr = 0;
- accum -= *pr++;
- accum /= RADIX;
- }
- }
-
- /* flush leading nonfraction zero digits */
-
- while (result->before && *--pr == 0)
- (result->before)--;
-
- flush_trailing_digits (result, 0);
-
- return result;
-}
-
-/* multiply b1 and b2 keeping `digits' fraction digits */
-
-decimal
-decimal_mul_rounded (b1, b2, digits)
- decimal b1, b2;
- int digits;
-{
- decimal tem = decimal_mul (b1, b2);
- decimal result = decimal_round_digits (tem, digits);
- free (tem);
- return result;
-}
-
-/* multiply b1 and b2 keeping the right number of fraction digits
- for the `dc' program with precision = `digits'. */
-
-decimal
-decimal_mul_dc (b1, b2, digits)
- decimal b1, b2;
- int digits;
-{
- decimal tem = decimal_mul (b1, b2);
- decimal result
- = decimal_round_digits (tem, MAX (digits, MAX (b1->after, b2->after)));
- free (tem);
- return result;
-}
-
-/* multiply b1 and b2 as decimal error-free values;
- keep LENGTH(b1) plus LENGTH(b2) significant figures. */
-
-decimal
-decimal_mul (b1, b2)
- decimal b1, b2;
-{
- decimal result = make_decimal (b1->before + b2->before, b1->after + b2->after);
- int i;
- int length2 = LENGTH(b2);
- char *pr;
-
- for (i = 0; i < length2; i++)
- add_scaled (result, b1, b2->contents[i], i);
-
- /* flush leading nonfraction zero digits */
-
- pr = result->contents + LENGTH(result);
- while (result->before && *--pr == 0)
- (result->before)--;
-
- flush_trailing_digits (result, 0); /* flush trailing zeros */
-
- /* Set sign properly */
-
- if (b1->sign != b2->sign && LENGTH(result))
- result->sign = 1;
-
- return result;
-}
-
-/* Modify decimal number `into' by adding `from',
- multiplied by `factor' (which should be nonnegative and less than RADIX)
- and shifted left `scale' digits at the least significant end. */
-
-static void
-add_scaled (into, from, factor, scale)
- decimal into, from;
- int factor, scale;
-{
- char *pf = from->contents;
- char *pi = into->contents + scale;
- int lengthf = LENGTH(from);
- int lengthi = LENGTH(into) - scale;
-
- int accum = 0;
- int i;
-
- for (i = 0; i < lengthi; i++)
- {
- accum /= RADIX;
- if (i < lengthf)
- accum += *pf++ * factor;
- accum += *pi;
- *pi++ = accum % RADIX;
- }
-}
-
-/* Divide decimal number `b1' by `b2', keeping at most `digits'
- fraction digits.
- Returns the result as a decimal number.
-
- When division is not exact, the quotient is truncated toward zero. */
-
-decimal
-decimal_div (b1, b2, digits)
- decimal b1, b2;
- int digits;
-{
- decimal result = make_decimal (MAX(1, (int) (1 + b1->before - b2->before)), digits);
-
- /* b1copy holds what is left of the dividend,
- that is not accounted for by the quotient digits already known */
-
- decimal b1copy = decimal_copy_1 (b1, b2->after + digits);
- int length1 = LENGTH(b1copy);
- int length2 = LENGTH(b2);
- int lengthr = LENGTH(result);
- int i;
-
- /* leading_divisor_digits contains the first two divisor digits, as
- an integer */
-
- int leading_divisor_digits = b2->contents[length2-1]*RADIX;
- if (length2 > 1)
- leading_divisor_digits += b2->contents[length2-2];
-
- if (decimal_zerop (b2))
- {
- decimal_error ("divisor is zero", 0);
- return decimal_copy (DECIMAL_ZERO);
- }
-
-/* if (lengthr <= (length1 - length2))
- abort(); */ /* My reasoning says this cannot happen, I hope */
-
- for (i = length1 - length2; i >= 0; i--)
- {
- /* Guess the next quotient digit (in order of decreasing significance)
- using integer division */
-
- int guess;
- int trial_dividend = b1copy->contents[length2+i-1]*RADIX;
- if (i != length1 - length2)
- trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX;
- if (length2 + i > 1)
- trial_dividend += b1copy->contents[length2+i-2];
-
- guess = trial_dividend / leading_divisor_digits;
-
- /* Remove the quotient times this digit from the dividend left */
- /* We may find that the quotient digit is too large,
- when we consider the entire divisor.
- Then we decrement the quotient digit and add the divisor back in */
-
- if (guess && 0 > subtract_scaled (b1copy, b2, guess, i))
- {
- guess--;
- add_scaled (b1copy, b2, 1, i);
- }
-
- if (guess >= RADIX)
- {
- result->contents[i + 1] += guess / RADIX;
- guess %= RADIX;
- }
- result->contents[i] = guess;
- }
-
- free (b1copy);
-
- result->sign = (b1->sign != b2->sign);
-
- /* flush leading nonfraction zero digits */
-
- {
- char *pr = result->contents + lengthr;
- while (result->before && *--pr == 0)
- (result->before)--;
- }
-
- flush_trailing_digits (result, 0); /* Flush trailing zero fraction digits */
-
- return result;
-}
-
-/* The remainder for the above division.
- Same as `b1' - (`b1' / `b2') * 'b2'.
- Note that the value depends on the number of fraction digits
- that were kept in computing `b1' / `b2';
- the argument `digits' specifies this.
-
- The remainder has the same sign as the dividend.
- The divisor's sign is ignored. */
-
-decimal
-decimal_rem (b1, b2, digits)
- decimal b1, b2;
- int digits;
-{
- decimal b1copy = decimal_copy_1 (b1, b2->after + digits);
- int length1 = LENGTH(b1copy);
- int length2 = LENGTH(b2);
- int i;
-
- int leading_divisor_digits = b2->contents[length2-1]*RADIX;
-
- if (length2 > 1)
- leading_divisor_digits += b2->contents[length2-2];
-
- if (decimal_zerop (b2))
- {
- decimal_error ("divisor is zero", 0);
- return decimal_copy (DECIMAL_ZERO);
- }
-
- /* Do like division, above, but throw away the quotient.
- Keep only the final `rest of dividend', which becomes the remainder. */
-
- for (i = length1 - length2; i >= 0; i--)
- {
- int guess;
- int trial_dividend = b1copy->contents[length2+i-1]*RADIX;
- if (i != length1 - length2)
- trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX;
- if (length2 + i > 1)
- trial_dividend += b1copy->contents[length2+i-2];
-
- guess = trial_dividend / leading_divisor_digits;
-
- if (guess && 0 > subtract_scaled (b1copy, b2, guess, i))
- {
- guess--;
- add_scaled (b1copy, b2, 1, i);
- }
- /* No need to check whether guess exceeds RADIX
- since we are not saving guess. */
- }
-
- /* flush leading nonfraction zero digits */
-
- {
- char *pr = b1copy->contents + length1;
- while (b1copy->before && *--pr == 0)
- (b1copy->before)--;
- }
-
- flush_trailing_digits (b1copy, 0);
- return b1copy;
-}
-
-/* returns negative number if we chose factor too large */
-
-static int
-subtract_scaled (into, from, factor, scale)
- decimal into, from;
- int factor, scale;
-{
- char *pf = from->contents;
- char *pi = into->contents + scale;
- int lengthf = LENGTH(from);
- int lengthi = LENGTH(into) - scale;
- int accum = 0;
- int i;
-
- for (i = 0; i < lengthi && i <= lengthf; i++)
- {
- if (i < lengthf)
- accum -= *pf++ * factor;
- accum += *pi;
- if (accum < 0 && accum % RADIX)
- *pi = RADIX - (- accum) % RADIX;
- else
- *pi = accum % RADIX;
- accum -= *pi++;
- accum /= RADIX;
- }
- return accum;
-}
-
-/* Return the square root of decimal number D, using Newton's method.
- Number of fraction digits returned is max of FRAC_DIGITS
- and D's number of fraction digits. */
-
-decimal
-decimal_sqrt (d, frac_digits)
- decimal d;
- int frac_digits;
-{
- decimal guess;
- int notdone = 1;
-
- if (decimal_zerop (d)) return d;
- if (d->sign)
- {
- decimal_error ("square root argument negative", 0);
- return decimal_copy (DECIMAL_ZERO);
- }
-
- frac_digits = MAX (frac_digits, d->after);
-
- /* Compute an initial guess by taking the square root
- of a nearby power of RADIX. */
-
- if (d->before)
- {
- guess = make_decimal ((d->before + 1) / 2, 0);
- guess->contents[guess->before - 1] = 1;
- }
- else
- {
- /* Arg is less than 1; compute nearest power of RADIX */
- char *p = d->contents + LENGTH(d);
- char *sp = p;
-
- while (!*--p); /* Find most significant nonzero digit */
- if (sp - p == 1)
- {
- /* Arg is bigger than 1/RADIX; use 1 as a guess */
- guess = decimal_copy (DECIMAL_ONE);
- }
- else
- {
- guess = make_decimal (0, (sp - p) / 2);
- guess->contents[0] = 1;
- }
- }
-
- /* Iterate doing guess = (guess + d/guess) / 2 */
-
- while (notdone)
- {
- decimal tem1 = decimal_div (d, guess, frac_digits + 1);
- decimal tem2 = decimal_add (guess, tem1);
- decimal tem3 = decimal_mul_rounded (tem2, DECIMAL_HALF, frac_digits);
- notdone = decimal_compare (guess, tem3);
- free (tem1);
- free (tem2);
- free (guess);
- guess = tem3;
- if (decimal_zerop (guess)) return guess; /* Avoid divide-by-zero */
- }
-
- return guess;
-}
-
-/* Raise decimal number `base' to power of integer part of decimal
- number `expt'.
- This function depends on using radix 10.
- It is too hard to write it to work for any value of RADIX,
- so instead it is simply not available if RADIX is not ten. */
-
-#if !(RADIX - 10)
-
-decimal
-decimal_expt (base, expt, frac_digits)
- decimal base, expt;
- int frac_digits;
-{
- decimal accum = decimal_copy (DECIMAL_ONE);
- decimal basis1 = base;
- int digits = expt->before;
- int dig = 0; /* Expt digit being processed */
-
- if (expt->sign)
- /* If negative power, take reciprocal first thing
- so that fraction digit truncation won't destroy
- what will ultimately be nonfraction digits. */
- basis1 = decimal_div (DECIMAL_ONE, base, frac_digits);
- while (dig < digits)
- {
- decimal basis2, basis4, basis8, basis10;
- int thisdigit = expt->contents[expt->after + dig];
-
- /* Compute factors to multiply in for each bit of this digit */
-
- basis2 = decimal_mul_rounded (basis1, basis1, frac_digits);
- basis4 = decimal_mul_rounded (basis2, basis2, frac_digits);
- basis8 = decimal_mul_rounded (basis4, basis4, frac_digits);
-
- /* Now accumulate the factors this digit value selects */
-
- if (thisdigit & 1)
- {
- decimal accum1 = decimal_mul_rounded (accum, basis1, frac_digits);
- free (accum);
- accum = accum1;
- }
-
- if (thisdigit & 2)
- {
- decimal accum1 = decimal_mul_rounded (accum, basis2, frac_digits);
- free (accum);
- accum = accum1;
- }
-
- if (thisdigit & 4)
- {
- decimal accum1 = decimal_mul_rounded (accum, basis4, frac_digits);
- free (accum);
- accum = accum1;
- }
-
- if (thisdigit & 8)
- {
- decimal accum1 = decimal_mul_rounded (accum, basis8, frac_digits);
- free (accum);
- accum = accum1;
- }
-
- /* If there are further digits, compute the basis1 for the next digit */
-
- if (++dig < digits)
- basis10 = decimal_mul_rounded (basis2, basis8, frac_digits);
-
- /* Free intermediate results */
-
- if (basis1 != base) free (basis1);
- free (basis2);
- free (basis4);
- free (basis8);
- basis1 = basis10;
- }
- return accum;
-}
-#endif
-
-#ifdef TEST
-
-fputchar (c)
- char c;
-{
- putchar (c);
-}
-
-/* Top level that can be used to test the arithmetic functions */
-
-main ()
-{
- char s1[40], s2[40];
- decimal b1, b2, b3;
- char c;
-
- while (1)
- {
- scanf ("%s %c %s", s1, &c, s2);
- b1 = decimal_parse (s1, RADIX);
- b2 = decimal_parse (s2, RADIX);
- switch (c)
- {
- default:
- c = '+';
- case '+':
- b3 = decimal_add (b1, b2);
- break;
- case '*':
- b3 = decimal_mul (b1, b2);
- break;
- case '/':
- b3 = decimal_div (b1, b2, 3);
- break;
- case '%':
- b3 = decimal_rem (b1, b2, 3);
- break;
- case 'p':
- decimal_print (b1, fputchar, RADIX);
- printf (" printed in base %d is ", decimal_to_int (b2));
- decimal_print (b1, fputchar, decimal_to_int (b2));
- printf ("\n");
- continue;
- case 'r':
- printf ("%s read in base %d is ", s1, decimal_to_int (b2));
- decimal_print (decimal_parse (s1, decimal_to_int (b2)), fputchar, RADIX);
- printf ("\n");
- continue;
- }
- decimal_print (b1, fputchar, RADIX);
- printf (" %c ", c);
- decimal_print (b2, fputchar, RADIX);
- printf (" = ");
- decimal_print (b3, fputchar, RADIX);
- printf ("\n");
- }
-}
-
-decimal_error (s1, s2)
- char *s1, *s2;
-{
- printf ("\n");
- printf (s1, s2);
- printf ("\n");
-}
-
-static void
-pbi (b)
- int b;
-{
- decimal_print ((decimal) b, fputchar, RADIX);
-}
-
-static void
-pb (b)
- decimal b;
-{
- decimal_print (b, fputchar, RADIX);
-}
-
-#endif
diff --git a/gnu/usr.bin/dc/decimal.h b/gnu/usr.bin/dc/decimal.h
deleted file mode 100644
index d2cab4d..0000000
--- a/gnu/usr.bin/dc/decimal.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Header file for decimal.c (arbitrary precision decimal arithmetic)
- *
- * Copyright (C) 1984 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.
- */
-
-/* Autoconf stuff */
-#ifndef HAVE_BCOPY
-#undef bcopy
-#define bcopy(s2, s1, n) memcpy (s1, s2, n)
-#endif
-
-#ifndef HAVE_BZERO
-#undef bzero
-#define bzero(b, l) memset (b, 0, l)
-#endif
-
-/* Define the radix to use by default, and for representing the
- numbers internally. This does not need to be decimal; that is just
- the default for it. */
-
-/* Currently, this is required to be even for this program to work. */
-
-#ifndef RADIX
-#define RADIX 10
-#endif
-
-/* The user must define the external function `decimal_error'
- which is called with two arguments to report errors in this package.
- The two arguments may be passed to `printf' to print a message. */
-
-/* Structure that represents a decimal number */
-
-struct decimal
-{
- unsigned int sign: 1; /* One for negative number */
- /* The sign should always be zero for the number 0 */
- int after: 15; /* number of fraction digits */
- unsigned short before; /* number of non-fraction digits */
- unsigned short refcnt; /* number of pointers to this number */
- /* (used by calling program) */
- char contents[1]; /* the digits themselves, least significant first. */
- /* digits are just numbers 0 .. RADIX-1 */
-};
-
-/* There may never be leading nonfraction zeros or trailing fraction
- zeros in a number. They must be removed by all the arithmetic
- functions. Therefore, the number zero always has no digits stored. */
-
-typedef struct decimal *decimal;
-
-/* Decimal numbers are always passed around as pointers.
- All the external entries in this file allocate new numbers
- using `malloc' to store values in.
- They never modify their arguments or any existing numbers. */
-
-/* Return the total number of digits stored in the number `b' */
-#define LENGTH(b) ((b)->before + (b)->after)
-
-/* Some constant decimal numbers */
-
-
-#define DECIMAL_ZERO &decimal_zero
-
-
-#define DECIMAL_ONE &decimal_one
-
-#define DECIMAL_HALF &decimal_half
-
-decimal decimal_add (), decimal_sub (), decimal_mul (), decimal_div ();
-decimal decimal_mul_dc (), decimal_mul_rounded (), decimal_rem ();
-decimal decimal_round_digits (), decimal_trunc_digits ();
-decimal make_decimal (), decimal_copy (), decimal_parse ();
-decimal decimal_sqrt (), decimal_expt ();
-
-void decimal_print ();
-
-/* End of decimal.h */
diff --git a/gnu/usr.bin/dc/doc/dc.texinfo b/gnu/usr.bin/dc/doc/dc.texinfo
index 15b285f..73f687b 100644
--- a/gnu/usr.bin/dc/doc/dc.texinfo
+++ b/gnu/usr.bin/dc/doc/dc.texinfo
@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename dc.info
-@settitle DC, An Arbitrary Precision Calculator
+@settitle dc, an arbitrary precision calculator
@c %**end of header
@c This file has the new style title page commands.
@@ -21,7 +21,7 @@
@syncodeindex tp fn
@ifinfo
-This file documents DC, an arbitrary precision calculator.
+This file documents @sc{dc}, an arbitrary precision calculator.
Published by the Free Software Foundation,
675 Massachusetts Avenue,
@@ -51,15 +51,16 @@ except that this permission notice may be stated in a translation approved
by the Foundation.
@end ifinfo
-@setchapternewpage odd
+@setchapternewpage off
@titlepage
-@title DC, An Arbitrary Precision Calculator
+@title dc, an arbitrary precision calculator
-@author by Richard Stallman
+@author by Ken Pizzini
+@author manual by Richard Stallman
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1984 Free Software Foundation, Inc.
+Copyright @copyright{} 1994 Free Software Foundation, Inc.
@sp 2
Published by the Free Software Foundation, @*
@@ -94,6 +95,7 @@ by the Foundation.
* Parameters:: Parameters
* Strings:: Strings
* Status Inquiry:: Status Inquiry
+* Miscellaneous:: Other commands
* Notes:: Notes
@end menu
@@ -101,27 +103,34 @@ by the Foundation.
@comment node-name, next, previous, up
@chapter Introduction
-DC is a reverse-polish desk calculator which supports unlimited
-precision arithmetic. It also allows you to define and call macros.
-Normally DC reads from the standard input; if any command arguments
-are given to it, they are filenames, and DC reads and executes the
-contents of the files before reading from standard input. All output
-is to standard output.
-
-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 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.
+@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
+before 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 Printing Commands, Arithmetic, Introduction, Top
@chapter Printing Commands
@@ -129,19 +138,19 @@ newlines. These have no meaning as 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.
+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.
+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
-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.
+@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
@@ -149,10 +158,9 @@ what the effect of some command has been.
@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.
+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
@@ -161,41 +169,46 @@ 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 flag (see below) and does not
+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 flag.
+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.
+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 flag specifies, and the remainder
-is also computed with that many fraction digits.
+as the precision value specifies,
+and the remainder is also computed with that many fraction digits.
@item ^
-Pops two values and exponentiates, using the first
-value popped as the exponent and the second popped as the base.
+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 flag specifies the number of fraction
+The precision value specifies the number of fraction
digits in the result.
@item v
Pops one value, computes its square root, and pushes that.
-The precision flag specifies the number of fraction digits
+The precision value specifies the number of fraction digits
in the result.
@end table
-Most arithmetic operations are affected by the "precision flag",
-which you can set with the @samp{k} command. The default precision
-value is zero, which means that all arithmetic except for
+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))},
+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
@@ -207,28 +220,28 @@ Clears the stack, rendering it empty.
@item d
Duplicates the value on the top of the stack,
-pushing another copy of it. Thus,
-`4d*p' computes 4 squared and prints it.
+pushing another copy of it.
+Thus, @samp{4d*p} computes 4 squared and prints it.
@end table
@node Registers, Parameters, Stack Control, Top
@chapter Registers
-DC provides 128 memory registers, each named by a single
-ASCII character. You can store a number in a register
-and retrieve it later.
+@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}.
+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}.
+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.
+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
@@ -237,31 +250,34 @@ 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 `l@var{r}' command.
+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
-
-The @samp{f} command prints a list of all registers that have contents
-stored in them, together with their contents. Only the
-current contents of each register (the top of its stack)
-is printed.
+@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
-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.
+@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.
+@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. Each radix must be between 2
-and 36 inclusive. The precision must be zero or greater. The precision
-is always measured in decimal digits, regardless of the current input or
-output radix.
+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
@@ -269,42 +285,51 @@ Pops the value off the top of the stack
and uses it to set the input radix.
@item o
-@itemx k
-Similarly set the output radix and the precision.
+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
-@itemx K
-Similarly push the current output radix and the current precision.
+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
-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 DC commands).
-Both registers and the stack can hold strings, and 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;
+@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).
+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 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.
+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},
@@ -312,70 +337,89 @@ 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
+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.
+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. This can also be validly used to compare two
-strings for equality.
+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 comand
-does not exit DC. Instead, it exits from that
-macro and also from the macro which invoked it (if any).
+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.
+of levels of macro execution to be exited.
+Thus, @samp{3Q} exits three levels.
@end table
-@node Status Inquiry, Notes, Strings, Top
+@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)
+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 -1.
+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.
+Pushes the current stack depth;
+the number of objects on the stack
+before the execution of the @samp{z} command.
+@end table
-@item I
-Pushes the current value of the input radix.
+@node Miscellaneous, Notes, Status Inquiry, Top
+@chapter Miscellaneous
-@item O
-Pushes the current value of the output radix.
+@table @samp
+@item !
+Will run the rest of the line as a system command.
-@item K
-Pushes the current value of the precision.
+@item #
+Will interpret the rest of the line as a comment.
+
+@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, , Status Inquiry, Top
+@node Notes, , Miscellaneous, Top
@chapter Notes
-The @samp{:} and @samp{;} commands of the Unix DC program are
-not supported, as the documentation does not say what they do.
-The @samp{!} command is not supported, but will be supported
-as soon as a library for executing a line as a command exists.
+The array operations @samp{:} and @samp{;} are usually
+only used by traditional implementations of BC.
+(The GNU BC is self contained and does not need @sc{dc} to run.)
+The comment operator @samp{#} is a new command
+not found in traditional implementations of @sc{dc}.
@contents
@bye
OpenPOWER on IntegriCloud