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