diff options
Diffstat (limited to 'dc/numeric.c')
-rw-r--r-- | dc/numeric.c | 235 |
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 : + */ |