aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Moore <alm@FreeBSD.org>1993-07-31 01:10:24 +0000
committerAndrew Moore <alm@FreeBSD.org>1993-07-31 01:10:24 +0000
commite20f62775f48640f6c537aef81ac966633eb081e (patch)
treeda0dc629176f09b8598440f7bd7bc300683235ac
parent6eefa612a977ece8f5e118392b27413260cb6996 (diff)
downloadsrc-e20f62775f48640f6c537aef81ac966633eb081e.tar.gz
src-e20f62775f48640f6c537aef81ac966633eb081e.zip
adding GNU dc ("desk calculator")
Notes
Notes: svn path=/cvs2svn/branches/unlabeled-1.1.1/; revision=220
-rw-r--r--gnu/usr.bin/dc/COPYING339
-rw-r--r--gnu/usr.bin/dc/ChangeLog77
-rw-r--r--gnu/usr.bin/dc/Makefile7
-rw-r--r--gnu/usr.bin/dc/NEWS7
-rw-r--r--gnu/usr.bin/dc/README13
-rw-r--r--gnu/usr.bin/dc/dc.c909
-rw-r--r--gnu/usr.bin/dc/dc.info330
-rw-r--r--gnu/usr.bin/dc/dc.texinfo381
-rw-r--r--gnu/usr.bin/dc/decimal.c1235
-rw-r--r--gnu/usr.bin/dc/decimal.h93
10 files changed, 3391 insertions, 0 deletions
diff --git a/gnu/usr.bin/dc/COPYING b/gnu/usr.bin/dc/COPYING
new file mode 100644
index 000000000000..e77696ae8ddf
--- /dev/null
+++ b/gnu/usr.bin/dc/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/dc/ChangeLog b/gnu/usr.bin/dc/ChangeLog
new file mode 100644
index 000000000000..09aaf4706884
--- /dev/null
+++ b/gnu/usr.bin/dc/ChangeLog
@@ -0,0 +1,77 @@
+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
new file mode 100644
index 000000000000..d786bc80544d
--- /dev/null
+++ b/gnu/usr.bin/dc/Makefile
@@ -0,0 +1,7 @@
+PROG= dc
+CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1
+SRCS= dc.c decimal.c
+DPADD= ${LIBM}
+LDADD= -lm
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/dc/NEWS b/gnu/usr.bin/dc/NEWS
new file mode 100644
index 000000000000..6486afb3ec86
--- /dev/null
+++ b/gnu/usr.bin/dc/NEWS
@@ -0,0 +1,7 @@
+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
new file mode 100644
index 000000000000..c23cc6699202
--- /dev/null
+++ b/gnu/usr.bin/dc/README
@@ -0,0 +1,13 @@
+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.c b/gnu/usr.bin/dc/dc.c
new file mode 100644
index 000000000000..933b24b916cd
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.c
@@ -0,0 +1,909 @@
+/*
+ * `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 */
+
+decimal regs[128]; /* "registers", with single-character names */
+regstack regstacks[128]; /* 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 < 128; 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 */
+ {
+ char c1 = fetch ();
+ if (c1 < 0) exit (0);
+ 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 */
+ {
+ char c1 = fetch ();
+ if (c1 < 0) exit (0);
+ 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 (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);
+ 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 (!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;
+ extern char *sys_errlist[];
+ 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.info b/gnu/usr.bin/dc/dc.info
new file mode 100644
index 000000000000..a30fea9f5555
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.info
@@ -0,0 +1,330 @@
+This is Info file dc.info, produced by Makeinfo-1.52 from the input
+file dc.texinfo.
+
+ This file documents DC, an arbitrary precision calculator.
+
+ Published by the Free Software Foundation, 675 Massachusetts Avenue,
+Cambridge, MA 02139 USA
+
+ Copyright (C) 1984 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir)
+
+* Menu:
+
+* Introduction:: Introduction
+* Printing Commands:: Printing Commands
+* Arithmetic:: Arithmetic
+* Stack Control:: Stack Control
+* Registers:: Registers
+* Parameters:: Parameters
+* Strings:: Strings
+* Status Inquiry:: Status Inquiry
+* Notes:: Notes
+
+
+File: dc.info, Node: Introduction, Next: Printing Commands, Prev: Top, Up: Top
+
+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 `q'. `C-c' does not exit; it is used to abort macros
+that are looping, etc. (Currently this is not true; `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 `_'. `-' 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.
+
+
+File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Introduction, Up: Top
+
+Printing Commands
+*****************
+
+`p'
+ Prints the value on the top of the stack, without altering the
+ stack. A newline is printed after the value.
+
+`P'
+ Prints the value on the top of the stack, popping it off, and does
+ not print a newline after.
+
+`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.
+
+
+File: dc.info, Node: Arithmetic, Next: Stack Control, Prev: Printing Commands, Up: Top
+
+Arithmetic
+**********
+
+`+'
+ 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, subtracts the first one popped from the second
+ one popped, and pushes the result.
+
+`*'
+ 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 depend on the
+ values being multiplied.
+
+`/'
+ 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, computes the remainder of the division that the
+ `/' 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.
+
+`^'
+ 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 digits in the result.
+
+`v'
+ Pops one value, computes its square root, and pushes that. The
+ precision flag specifies the number of fraction digits in the
+ result.
+
+ Most arithmetic operations are affected by the "precision flag",
+which you can set with the `k' command. The default precision value is
+zero, which means that all arithmetic except for addition and
+subtraction produces integer results.
+
+ The remainder operation (`%') requires some explanation: applied to
+arguments `a' and `b' it produces `a - (b * (a / b))', where `a / b' is
+computed in the current precision.
+
+
+File: dc.info, Node: Stack Control, Next: Registers, Prev: Arithmetic, Up: Top
+
+Stack Control
+*************
+
+`c'
+ Clears the stack, rendering it empty.
+
+`d'
+ Duplicates the value on the top of the stack, pushing another copy
+ of it. Thus, `4d*p' computes 4 squared and prints it.
+
+
+File: dc.info, Node: Registers, Next: Parameters, Prev: Stack Control, Up: Top
+
+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.
+
+`sR'
+ Pop the value off the top of the stack and store it into register
+ R.
+
+`lR'
+ Copy the value in register R, and push it onto the stack. This
+ does not alter the contents of R.
+
+ Each register also contains its own stack. The current register
+ value is the top of the register's stack.
+
+`SR'
+ Pop the value off the top of the (main) stack and push it onto the
+ stack of register R. The previous value of the register becomes
+ inaccessible.
+
+`LR'
+ Pop the value off the top of register R's stack and push it onto
+ the main stack. The previous value in register R's stack, if any,
+ is now accessible via the `lR' command.
+
+ The `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.
+
+
+File: dc.info, Node: Parameters, Next: Strings, Prev: Registers, Up: Top
+
+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. The input radix controls the interpretation of numbers
+typed in; *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.
+
+`i'
+ Pops the value off the top of the stack and uses it to set the
+ input radix.
+
+`o'
+`k'
+ Similarly set the output radix and the precision.
+
+`I'
+ Pushes the current input radix on the stack.
+
+`O'
+`K'
+ Similarly push the current output radix and the current precision.
+
+
+File: dc.info, Node: Strings, Next: Status Inquiry, Prev: Parameters, Up: Top
+
+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;
+for example, the `p' command can accept either and prints the object
+according to its type.
+
+`[CHARACTERS]'
+ Makes a string containing CHARACTERS and pushes it on the stack.
+ For example, `[foo]P' prints the characters `foo' (with no
+ newline).
+
+`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, `[1p]x' executes the macro `1p',
+ which pushes 1 on the stack and prints `1' on a separate line.
+
+ Macros are most often stored in registers; `[1p]sa' stores a macro
+ to print `1' into register `a', and `lax' invokes the macro.
+
+`>R'
+ Pops two values off the stack and compares them assuming they are
+ numbers, executing the contents of register R as a macro if the
+ original top-of-stack is greater. Thus, `1 2>a' will invoke
+ register `a''s contents and `2 1>a' will not.
+
+`<R'
+ Similar but invokes the macro if the original top-of-stack is less.
+
+`=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.
+
+`?'
+ Reads a line from the terminal and executes it. This command
+ allows a macro to request input from the user.
+
+`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).
+
+`Q'
+ Pops a value off the stack and uses it as a count of levels of
+ macro execution to be exited. Thus, `3Q' exits three levels.
+
+
+File: dc.info, Node: Status Inquiry, Next: Notes, Prev: Strings, Up: Top
+
+Status Inquiry
+**************
+
+`Z'
+ Pops a value off the stack, calculates the number of digits it has
+ (or number of characters, if it is a string) and pushes that
+ number.
+
+`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.
+
+`z'
+ Pushes the current stack depth; the number of objects on the stack
+ before the execution of the `z' command.
+
+`I'
+ Pushes the current value of the input radix.
+
+`O'
+ Pushes the current value of the output radix.
+
+`K'
+ Pushes the current value of the precision.
+
+
+File: dc.info, Node: Notes, Prev: Status Inquiry, Up: Top
+
+Notes
+*****
+
+ The `:' and `;' commands of the Unix DC program are not supported,
+as the documentation does not say what they do. The `!' command is not
+supported, but will be supported as soon as a library for executing a
+line as a command exists.
+
+
+
+Tag Table:
+Node: Top960
+Node: Introduction1440
+Node: Printing Commands2603
+Node: Arithmetic3211
+Node: Stack Control5168
+Node: Registers5468
+Node: Parameters6586
+Node: Strings7659
+Node: Status Inquiry9857
+Node: Notes10571
+
+End Tag Table
diff --git a/gnu/usr.bin/dc/dc.texinfo b/gnu/usr.bin/dc/dc.texinfo
new file mode 100644
index 000000000000..15b285fbd579
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.texinfo
@@ -0,0 +1,381 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename dc.info
+@settitle DC, An Arbitrary Precision Calculator
+@c %**end of header
+
+@c This file has the new style title page commands.
+@c Run `makeinfo' rather than `texinfo-format-buffer'.
+
+@c smallbook
+
+@c tex
+@c \overfullrule=0pt
+@c end tex
+
+@c Combine indices.
+@synindex cp fn
+@syncodeindex vr fn
+@syncodeindex ky fn
+@syncodeindex pg fn
+@syncodeindex tp fn
+
+@ifinfo
+This file documents DC, an arbitrary precision calculator.
+
+Published by the Free Software Foundation,
+675 Massachusetts Avenue,
+Cambridge, MA 02139 USA
+
+Copyright (C) 1984 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@setchapternewpage odd
+
+@titlepage
+@title DC, An Arbitrary Precision Calculator
+
+@author by Richard Stallman
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1984 Free Software Foundation, Inc.
+
+@sp 2
+Published by the Free Software Foundation, @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+
+@end titlepage
+@page
+
+@node Top, Introduction, (dir), (dir)
+
+@menu
+* Introduction:: Introduction
+* Printing Commands:: Printing Commands
+* Arithmetic:: Arithmetic
+* Stack Control:: Stack Control
+* Registers:: Registers
+* Parameters:: Parameters
+* Strings:: Strings
+* Status Inquiry:: Status Inquiry
+* Notes:: Notes
+@end menu
+
+@node Introduction, Printing Commands, Top, Top
+@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.
+
+@node Printing Commands, Arithmetic, Introduction, Top
+@chapter Printing Commands
+
+@table @samp
+@item p
+Prints the value on the top of the stack,
+without altering the stack. A newline is printed
+after the value.
+
+@item P
+Prints the value on the top of the stack,
+popping it off, and does not print a newline after.
+
+@item f
+Prints the entire contents of the stack
+and the contents of all of the registers,
+without altering anything. This is a good command
+to use if you are lost or want to figure out
+what the effect of some command has been.
+@end table
+
+@node Arithmetic, Stack Control, Printing Commands, Top
+@chapter Arithmetic
+
+@table @samp
+@item +
+Pops two values off the stack, adds them,
+and pushes the result. The precision of the result
+is determined only by the values of the arguments,
+and is enough to be exact.
+
+@item -
+Pops two values, subtracts the first one popped
+from the second one popped, and pushes the result.
+
+@item *
+Pops two values, multiplies them, and pushes the result.
+The number of fraction digits in the result is controlled
+by the current precision flag (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.
+
+@item %
+Pops two values, computes the remainder of the division
+that the @samp{/} command would do, and pushes that.
+The division is done with as many fraction digits
+as the precision flag 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.
+The fraction part of the exponent is ignored.
+The precision flag 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
+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
+addition and subtraction produces integer results.
+
+The remainder operation (@samp{%}) requires some explanation: applied to
+arguments @samp{a} and @samp{b} it produces @samp{a - (b * (a / b))},
+where @samp{a / b} is computed in the current precision.
+
+@node Stack Control, Registers, Arithmetic, Top
+@chapter Stack Control
+
+@table @samp
+@item c
+Clears the stack, rendering it empty.
+
+@item d
+Duplicates the value on the top of the stack,
+pushing another copy of it. Thus,
+`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.
+
+@table @samp
+@item s@var{r}
+Pop the value off the top of the stack and store
+it into register @var{r}.
+
+@item l@var{r}
+Copy the value in register @var{r}, and push it onto
+the stack. This does not alter the contents of @var{r}.
+
+Each register also contains its own stack. The current
+register value is the top of the register's stack.
+
+@item S@var{r}
+Pop the value off the top of the (main) stack and
+push it onto the stack of register @var{r}.
+The previous value of the register becomes inaccessible.
+
+@item L@var{r}
+Pop the value off the top of register @var{r}'s stack
+and push it onto the main stack. The previous value
+in register @var{r}'s stack, if any, is now accessible
+via the `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.
+
+@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.
+The input radix controls the interpretation of numbers typed in;
+@emph{all} numbers typed in use this radix. The output radix is used
+for printing numbers.
+
+The input and output radices are separate parameters; you can make them
+unequal, which can be useful or confusing. 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.
+
+@table @samp
+@item i
+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.
+
+@item I
+Pushes the current input radix on the stack.
+
+@item O
+@itemx K
+Similarly push the current output radix and the current precision.
+@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;
+for example, the @samp{p} command can accept either and prints the object
+according to its type.
+
+@table @samp
+@item [@var{characters}]
+Makes a string containing @var{characters} and pushes it
+on the stack. For example, @samp{[foo]P} prints the
+characters @samp{foo} (with no newline).
+
+@item x
+Pops a value off the stack and executes it as a macro.
+Normally it should be a string; if it is a number,
+it is simply pushed back onto the stack.
+For example, @samp{[1p]x} executes the macro @samp{1p}, which
+pushes 1 on the stack and prints @samp{1} on a separate line.
+
+Macros are most often stored in registers;
+@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
+and @samp{lax} invokes the macro.
+
+@item >@var{r}
+Pops two values off the stack and compares them
+assuming they are numbers, executing the contents
+of register @var{r} as a macro if the original top-of-stack
+is greater. Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
+and @samp{2 1>a} will not.
+
+@item <@var{r}
+Similar but invokes the macro if the original top-of-stack
+is less.
+
+@item =@var{r}
+Similar but invokes the macro if the two numbers popped
+are equal. 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).
+
+@item Q
+Pops a value off the stack and uses it as a count
+of levels of macro execution to be exited. Thus,
+@samp{3Q} exits three levels.
+@end table
+
+@node Status Inquiry, Notes, Strings, Top
+@chapter Status Inquiry
+
+@table @samp
+@item Z
+Pops a value off the stack, calculates the number of
+digits it has (or number of characters, if it is a string)
+and pushes that number.
+
+@item X
+Pops a value off the stack, calculates the number of
+fraction digits it has, and pushes that number.
+For a string, the value pushed is -1.
+
+@item z
+Pushes the current stack depth; the number of
+objects on the stack before the execution of the @samp{z} command.
+
+@item I
+Pushes the current value of the input radix.
+
+@item O
+Pushes the current value of the output radix.
+
+@item K
+Pushes the current value of the precision.
+@end table
+
+@node Notes, , Status Inquiry, 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.
+
+@contents
+@bye
diff --git a/gnu/usr.bin/dc/decimal.c b/gnu/usr.bin/dc/decimal.c
new file mode 100644
index 000000000000..1fb95c18aa14
--- /dev/null
+++ b/gnu/usr.bin/dc/decimal.c
@@ -0,0 +1,1235 @@
+/*
+ * 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_round_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
new file mode 100644
index 000000000000..2b41158166a2
--- /dev/null
+++ b/gnu/usr.bin/dc/decimal.h
@@ -0,0 +1,93 @@
+/*
+ * 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 make_decimal (), decimal_copy (), decimal_parse ();
+decimal decimal_sqrt (), decimal_expt ();
+
+void decimal_print ();
+
+/* End of decimal.h */