aboutsummaryrefslogtreecommitdiffstats
path: root/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'node.c')
-rw-r--r--node.c93
1 files changed, 70 insertions, 23 deletions
diff --git a/node.c b/node.c
index 73d3ec41..8dbe68a9 100644
--- a/node.c
+++ b/node.c
@@ -26,15 +26,21 @@
#include "awk.h"
#include "math.h"
+#include "floatmagic.h" /* definition of isnan */
static int is_ieee_magic_val(const char *val);
+static NODE *r_make_number(double x);
static AWKNUM get_ieee_magic_val(const char *val);
extern NODE **fmt_list; /* declared in eval.c */
+NODE *(*make_number)(double) = r_make_number;
+NODE *(*str2number)(NODE *) = r_force_number;
+NODE *(*format_val)(const char *, int, NODE *) = r_format_val;
+int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
/* force_number --- force a value to be numeric */
-AWKNUM
+NODE *
r_force_number(NODE *n)
{
char *cp;
@@ -45,7 +51,7 @@ r_force_number(NODE *n)
extern double strtod();
if (n->flags & NUMCUR)
- return n->numbr;
+ return n;
/* all the conditionals are an attempt to avoid the expensive strtod */
@@ -54,7 +60,7 @@ r_force_number(NODE *n)
n->numbr = 0.0;
if (n->stlen == 0) {
- return 0.0;
+ return n;
}
cp = n->stptr;
@@ -67,14 +73,14 @@ r_force_number(NODE *n)
*/
if (! do_posix) {
if (isalpha((unsigned char) *cp)) {
- return 0.0;
+ return n;
} else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
if (n->flags & MAYBE_NUM)
n->flags &= ~MAYBE_NUM;
n->flags |= NUMBER|NUMCUR;
n->numbr = get_ieee_magic_val(n->stptr);
- return n->numbr;
+ return n;
}
/* else
fall through */
@@ -92,7 +98,7 @@ r_force_number(NODE *n)
/* CANNOT do non-decimal and saw 0x */
|| (! do_non_decimal_data && cp[0] == '0'
&& (cp[1] == 'x' || cp[1] == 'X'))))) {
- return 0.0;
+ return n;
}
if (n->flags & MAYBE_NUM) {
@@ -109,12 +115,12 @@ r_force_number(NODE *n)
if (cp == n->stptr) /* no leading spaces */
n->flags |= NUMINT;
}
- return n->numbr;
+ return n;
}
if (do_non_decimal_data) { /* main.c assures false if do_posix */
errno = 0;
- if (! do_traditional && isnondecimal(cp, TRUE)) {
+ if (! do_traditional && get_numbase(cp, TRUE) != 10) {
n->numbr = nondec2awknum(cp, cpend - cp);
n->flags |= NUMCUR;
ptr = cpend;
@@ -139,7 +145,7 @@ finish:
errno = 0;
}
- return n->numbr;
+ return n;
}
@@ -162,10 +168,10 @@ static const char *values[] = {
};
#define NVAL (sizeof(values)/sizeof(values[0]))
-/* format_val --- format a numeric value based on format */
+/* r_format_val --- format a numeric value based on format */
NODE *
-format_val(const char *format, int index, NODE *s)
+r_format_val(const char *format, int index, NODE *s)
{
char buf[BUFSIZ];
char *sp = buf;
@@ -190,7 +196,8 @@ format_val(const char *format, int index, NODE *s)
/* not an integral value, or out of range */
if ((val = double_to_int(s->numbr)) != s->numbr
- || val <= LONG_MIN || val >= LONG_MAX) {
+ || val <= LONG_MIN || val >= LONG_MAX
+ ) {
/*
* Once upon a time, we just blindly did this:
* sprintf(sp, format, s->numbr);
@@ -201,11 +208,12 @@ format_val(const char *format, int index, NODE *s)
*/
NODE *dummy[2], *r;
- unsigned short oflags;
+ unsigned int oflags;
/* create dummy node for a sole use of format_tree */
dummy[1] = s;
oflags = s->flags;
+
if (val == s->numbr) {
/* integral value, but outside range of %ld, use %.0f */
r = format_tree("%.0f", 4, dummy, 2);
@@ -316,17 +324,17 @@ r_dupnode(NODE *n)
return r;
}
-/* make_number --- allocate a node with defined number */
+/* r_make_number --- allocate a node with defined number */
-NODE *
-make_number(AWKNUM x)
+static NODE *
+r_make_number(double x)
{
NODE *r;
getnode(r);
r->type = Node_val;
r->numbr = x;
- r->valref = 1;
r->flags = MALLOC|NUMBER|NUMCUR;
+ r->valref = 1;
r->stptr = NULL;
r->stlen = 0;
#if MBS_SUPPORT
@@ -336,6 +344,32 @@ make_number(AWKNUM x)
return r;
}
+/* cmp_awknums --- compare two AWKNUMs */
+
+int
+cmp_awknums(const NODE *t1, const NODE *t2)
+{
+ /*
+ * This routine is also used to sort numeric array indices or values.
+ * For the purposes of sorting, NaN is considered greater than
+ * any other value, and all NaN values are considered equivalent and equal.
+ * This isn't in compliance with IEEE standard, but compliance w.r.t. NaN
+ * comparison at the awk level is a different issue, and needs to be dealt
+ * with in the interpreter for each opcode seperately.
+ */
+
+ if (isnan(t1->numbr))
+ return ! isnan(t2->numbr);
+ if (isnan(t2->numbr))
+ return -1;
+ /* don't subtract, in case one or both are infinite */
+ if (t1->numbr == t2->numbr)
+ return 0;
+ if (t1->numbr < t2->numbr)
+ return -1;
+ return 1;
+}
+
/* r_make_str_node --- make a string node */
@@ -437,6 +471,13 @@ r_unref(NODE *tmp)
efree(tmp->stptr);
#endif
+#ifdef HAVE_MPFR
+ if (is_mpg_float(tmp))
+ mpfr_clear(tmp->mpg_numbr);
+ else if (is_mpg_integer(tmp))
+ mpz_clear(tmp->mpg_i);
+#endif
+
free_wstr(tmp);
freenode(tmp);
}
@@ -577,12 +618,14 @@ parse_escape(const char **string_ptr)
}
}
-/* isnondecimal --- return true if number is not a decimal number */
+/* get_numbase --- return the base to use for the number in 's' */
int
-isnondecimal(const char *str, int use_locale)
+get_numbase(const char *s, int use_locale)
{
int dec_point = '.';
+ const char *str = s;
+
#if defined(HAVE_LOCALE_H)
/*
* loc.decimal_point may not have been initialized yet,
@@ -593,11 +636,11 @@ isnondecimal(const char *str, int use_locale)
#endif
if (str[0] != '0')
- return FALSE;
+ return 10;
/* leading 0x or 0X */
if (str[1] == 'x' || str[1] == 'X')
- return TRUE;
+ return 16;
/*
* Numbers with '.', 'e', or 'E' are decimal.
@@ -607,12 +650,16 @@ isnondecimal(const char *str, int use_locale)
*/
for (; *str != '\0'; str++) {
if (*str == 'e' || *str == 'E' || *str == dec_point)
- return FALSE;
+ return 10;
else if (! isdigit((unsigned char) *str))
break;
}
- return TRUE;
+ if (! isdigit((unsigned char) s[1])
+ || s[1] == '8' || s[1] == '9'
+ )
+ return 10;
+ return 8;
}
#if MBS_SUPPORT