summaryrefslogtreecommitdiff
path: root/dc/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'dc/numeric.c')
-rw-r--r--dc/numeric.c235
1 files changed, 153 insertions, 82 deletions
diff --git a/dc/numeric.c b/dc/numeric.c
index 6086be5..37759de 100644
--- a/dc/numeric.c
+++ b/dc/numeric.c
@@ -1,11 +1,12 @@
/*
* interface dc to the bc numeric routines
*
- * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1997, 1998, 2000, 2005, 2008, 2013, 2017
+ * 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)
+ * the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
@@ -14,11 +15,8 @@
* 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.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
/* This should be the only module that knows the internals of type dc_num */
@@ -26,16 +24,31 @@
* make use of bc's numeric routines.
*/
+/* make all the header files see that these are really the same thing;
+ * this is acceptable because everywhere else dc_number is just referenced
+ * as a pointer-to-incomplete-structure type
+ */
+#define dc_number bc_struct
+
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
-#else
+#endif
+#ifndef UCHAR_MAX
# define UCHAR_MAX ((unsigned char)~0)
#endif
-#include <stdlib.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#else
+ extern int errno;
+#endif
+
#include "number.h"
#include "dc.h"
#include "dc-proto.h"
@@ -56,7 +69,11 @@ static void out_char (int);
int std_only = FALSE;
/* convert an opaque dc_num into a real bc_num */
-#define CastNum(x) ((bc_num)(x))
+/* by a freak accident, these are now no-op mappings,
+ * but leave the notation here in case that changes later
+ * */
+#define CastNum(x) (x)
+#define CastNumPtr(x) (x)
/* add two dc_nums, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
@@ -68,8 +85,8 @@ dc_add DC_DECLARG((a, b, kscale, result))
int kscale ATTRIB((unused)) DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0);
+ bc_init_num(CastNumPtr(result));
+ bc_add(CastNum(a), CastNum(b), CastNumPtr(result), 0);
return DC_SUCCESS;
}
@@ -83,8 +100,8 @@ dc_sub DC_DECLARG((a, b, kscale, result))
int kscale ATTRIB((unused)) DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0);
+ bc_init_num(CastNumPtr(result));
+ bc_sub(CastNum(a), CastNum(b), CastNumPtr(result), 0);
return DC_SUCCESS;
}
@@ -98,8 +115,8 @@ dc_mul DC_DECLARG((a, b, kscale, result))
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
+ bc_init_num(CastNumPtr(result));
+ bc_multiply(CastNum(a), CastNum(b), CastNumPtr(result), kscale);
return DC_SUCCESS;
}
@@ -113,8 +130,8 @@ dc_div DC_DECLARG((a, b, kscale, result))
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
+ bc_init_num(CastNumPtr(result));
+ if (bc_divide(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
fprintf(stderr, "%s: divide by zero\n", progname);
return DC_DOMAIN_ERROR;
}
@@ -133,10 +150,10 @@ dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
dc_num *quotient DC_DECLSEP
dc_num *remainder DC_DECLEND
{
- bc_init_num((bc_num *)quotient);
- bc_init_num((bc_num *)remainder);
+ bc_init_num(CastNumPtr(quotient));
+ bc_init_num(CastNumPtr(remainder));
if (bc_divmod(CastNum(a), CastNum(b),
- (bc_num *)quotient, (bc_num *)remainder, kscale)){
+ CastNumPtr(quotient), CastNumPtr(remainder), kscale)){
fprintf(stderr, "%s: divide by zero\n", progname);
return DC_DOMAIN_ERROR;
}
@@ -153,8 +170,8 @@ dc_rem DC_DECLARG((a, b, kscale, result))
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
+ bc_init_num(CastNumPtr(result));
+ if (bc_modulo(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
fprintf(stderr, "%s: remainder by zero\n", progname);
return DC_DOMAIN_ERROR;
}
@@ -169,9 +186,9 @@ dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
+ bc_init_num(CastNumPtr(result));
if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
- (bc_num *)result, kscale)){
+ CastNumPtr(result), kscale)){
if (bc_is_zero(CastNum(mod)))
fprintf(stderr, "%s: remainder by zero\n", progname);
return DC_DOMAIN_ERROR;
@@ -189,8 +206,8 @@ dc_exp DC_DECLARG((a, b, kscale, result))
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
- bc_init_num((bc_num *)result);
- bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
+ bc_init_num(CastNumPtr(result));
+ bc_raise(CastNum(a), CastNum(b), CastNumPtr(result), kscale);
return DC_SUCCESS;
}
@@ -211,7 +228,7 @@ dc_sqrt DC_DECLARG((value, kscale, result))
bc_free_num(&tmp);
return DC_DOMAIN_ERROR;
}
- *((bc_num *)result) = tmp;
+ *(CastNumPtr(result)) = tmp;
return DC_SUCCESS;
}
@@ -239,6 +256,11 @@ dc_num2int DC_DECLARG((value, discard_p))
long result;
result = bc_num2long(CastNum(value));
+ if (result == 0 && !bc_is_zero(CastNum(value))) {
+ fprintf(stderr, "%s: value overflows simple integer; punting...\n",
+ progname);
+ result = -1; /* more appropriate for dc's purposes */
+ }
if (discard_p == DC_TOSS)
dc_free_num(&value);
return (int)result;
@@ -254,9 +276,9 @@ dc_int2data DC_DECLARG((value))
{
dc_data result;
- bc_init_num((bc_num *)&result.v.number);
- bc_int2num((bc_num *)&result.v.number, value);
- result.dc_type = DC_NUMBER;
+ bc_init_num(CastNumPtr(&result.v.number));
+ bc_int2num(CastNumPtr(&result.v.number), value);
+ result.dc_type = DC_NUMBER;
return result;
}
@@ -346,21 +368,27 @@ dc_getnum DC_DECLARG((input, ibase, readahead))
bc_free_num(&base);
if (readahead)
*readahead = c;
- full_result.v.number = (dc_num)result;
+ *CastNumPtr(&full_result.v.number) = result;
full_result.dc_type = DC_NUMBER;
return full_result;
}
-/* return the "length" of the number */
+/* Return the "length" of the number, ignoring *all* leading zeros,
+ * (including those to the right of the radix point!)
+ */
int
dc_numlen DC_DECLARG((value))
dc_num value DC_DECLEND
{
+ /* XXX warning: unholy coziness with the internals of a bc_num! */
bc_num num = CastNum(value);
+ char *p = num->n_value;
+ int i = num->n_len + num->n_scale;
- /* is this right??? */
- return num->n_len + num->n_scale - (*num->n_value == '\0');
+ while (1<i && *p=='\0')
+ --i, ++p;
+ return i;
}
/* return the scale factor of the passed dc_num
@@ -388,20 +416,16 @@ dc_math_init DC_DECLVOID()
}
/* print out a dc_num in output base obase to stdout;
- * if newline_p is DC_WITHNL, terminate output with a '\n';
* if discard_p is DC_TOSS then deallocate the value after use
*/
void
-dc_out_num DC_DECLARG((value, obase, newline_p, discard_p))
+dc_out_num DC_DECLARG((value, obase, discard_p))
dc_num value DC_DECLSEP
int obase DC_DECLSEP
- dc_newline newline_p DC_DECLSEP
dc_discard discard_p DC_DECLEND
{
out_char('\0'); /* clear the column counter */
bc_out_num(CastNum(value), obase, out_char, 0);
- if (newline_p == DC_WITHNL)
- putchar ('\n');
if (discard_p == DC_TOSS)
dc_free_num(&value);
}
@@ -460,7 +484,7 @@ void
dc_free_num DC_DECLARG((value))
dc_num *value DC_DECLEND
{
- bc_free_num((bc_num *)value);
+ bc_free_num(CastNumPtr(value));
}
/* return a duplicate of the number in the passed value */
@@ -489,18 +513,60 @@ dc_dup_num DC_DECLARG((value))
| 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
+#ifndef HAVE_STRTOL
+/* Maintain some of the error checking of a real strtol() on
+ * ancient systems that lack one, but punting on the niceties
+ * of supporting bases other than 10 and overflow checking.
+ */
+long
+strtol(const char *s, char **end, int base)
+{
+ int sign = 1;
+ long result = 0;
-int out_col = 0;
+ for (;; ++s) {
+ if (*s == '-')
+ sign = -sign;
+ else if (*s != '+' && !isspace(*(const unsigned char *)s))
+ break;
+ }
+ while (isdigit(*(const unsigned char *)s))
+ result = 10*result + (*s++ - '0');
+ *end = s;
+ return result * sign;
+}
+#endif /*!HAVE_STRTOL*/
+
+
+static int out_col = 0;
+static int line_max = -1; /* negative means "need to check environment" */
+#define DEFAULT_LINE_MAX 70
+
+static void
+set_line_max_from_environment(void)
+{
+ const char *env_line_len = getenv("DC_LINE_LENGTH");
+ line_max = DEFAULT_LINE_MAX;
+ errno = 0;
+ if (env_line_len) {
+ char *endptr;
+ long proposed_line_len = strtol(env_line_len, &endptr, 0);
+ line_max = (int)proposed_line_len;
+
+ /* silently enforce sanity */
+ while (isspace(*(const unsigned char *)endptr))
+ ++endptr;
+ if (*endptr || errno || line_max != proposed_line_len
+ || line_max < 0 || line_max == 1)
+ line_max = DEFAULT_LINE_MAX;
+ }
+}
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
@@ -508,24 +574,20 @@ int out_col = 0;
static void
out_char (ch)
- int ch;
+ int ch;
{
-
- if (ch == '\0')
- {
- out_col = 0;
- }
- else
- {
- out_col++;
- if (out_col == 70)
- {
- putchar ('\\');
- putchar ('\n');
- out_col = 1;
+ if (ch == '\0') {
+ out_col = 0;
+ } else {
+ if (line_max < 0)
+ set_line_max_from_environment();
+ if (++out_col >= line_max && line_max != 0) {
+ putchar ('\\');
+ putchar ('\n');
+ out_col = 1;
+ }
+ putchar(ch);
}
- putchar (ch);
- }
}
/* Malloc could not get enough memory. */
@@ -533,10 +595,10 @@ out_char (ch)
void
out_of_memory()
{
- dc_memfail();
+ dc_memfail();
}
-/* Runtime error will print a message and stop the machine. */
+/* Runtime error --- will print a message and stop the machine. */
#ifdef HAVE_STDARG_H
#ifdef __STDC__
@@ -545,25 +607,25 @@ rt_error (char *mesg, ...)
#else
void
rt_error (mesg)
- char *mesg;
+ char *mesg;
#endif
#else
void
rt_error (mesg, va_alist)
- char *mesg;
+ char *mesg;
#endif
{
- va_list args;
+ va_list args;
- fprintf (stderr, "Runtime error: ");
+ fprintf (stderr, "Runtime error: ");
#ifdef HAVE_STDARG_H
- va_start (args, mesg);
+ va_start (args, mesg);
#else
- va_start (args);
+ va_start (args);
#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
- fprintf (stderr, "\n");
+ vfprintf (stderr, mesg, args);
+ va_end (args);
+ fprintf (stderr, "\n");
}
@@ -578,23 +640,32 @@ rt_warn (char *mesg, ...)
#else
void
rt_warn (mesg)
- char *mesg;
+ char *mesg;
#endif
#else
void
rt_warn (mesg, va_alist)
- char *mesg;
+ char *mesg;
#endif
{
- va_list args;
+ va_list args;
- fprintf (stderr, "Runtime warning: ");
+ fprintf (stderr, "Runtime warning: ");
#ifdef HAVE_STDARG_H
- va_start (args, mesg);
+ va_start (args, mesg);
#else
- va_start (args);
+ va_start (args);
#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
- fprintf (stderr, "\n");
+ vfprintf (stderr, mesg, args);
+ va_end (args);
+ fprintf (stderr, "\n");
}
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 4
+ * End:
+ * vi: set ts=4 :
+ */