aboutsummaryrefslogtreecommitdiffstats
path: root/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'node.c')
-rw-r--r--node.c269
1 files changed, 148 insertions, 121 deletions
diff --git a/node.c b/node.c
index 204a91f9..8d9354f6 100644
--- a/node.c
+++ b/node.c
@@ -26,13 +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;
@@ -43,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 */
@@ -52,7 +60,7 @@ r_force_number(NODE *n)
n->numbr = 0.0;
if (n->stlen == 0) {
- return 0.0;
+ return n;
}
cp = n->stptr;
@@ -65,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 */
@@ -90,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) {
@@ -104,13 +112,15 @@ r_force_number(NODE *n)
n->numbr = (AWKNUM)(*cp - '0');
n->flags |= newflags;
n->flags |= NUMCUR;
+ 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;
@@ -135,7 +145,7 @@ finish:
errno = 0;
}
- return n->numbr;
+ return n;
}
@@ -158,26 +168,14 @@ 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;
double val;
- char *orig, *trans, save;
-
- if (! do_traditional && (s->flags & INTLSTR) != 0) {
- save = s->stptr[s->stlen];
- s->stptr[s->stlen] = '\0';
-
- orig = s->stptr;
- trans = dgettext(TEXTDOMAIN, orig);
-
- s->stptr[s->stlen] = save;
- return make_string(trans, strlen(trans));
- }
/*
* 2/2007: Simplify our lives here. Instead of worrying about
@@ -198,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);
@@ -209,12 +208,12 @@ format_val(const char *format, int index, NODE *s)
*/
NODE *dummy[2], *r;
- unsigned short oflags;
- extern NODE **fmt_list; /* declared in eval.c */
+ 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);
@@ -234,8 +233,7 @@ format_val(const char *format, int index, NODE *s)
goto no_malloc;
} else {
/*
- * integral value
- * force conversion to long only once
+ * integral value; force conversion to long only once.
*/
long num = (long) val;
@@ -247,50 +245,36 @@ format_val(const char *format, int index, NODE *s)
s->stlen = strlen(sp);
}
s->stfmt = -1;
+ if (s->flags & INTIND) {
+ s->flags &= ~(INTIND|NUMBER);
+ s->flags |= STRING;
+ }
}
if (s->stptr != NULL)
efree(s->stptr);
emalloc(s->stptr, char *, s->stlen + 2, "format_val");
- memcpy(s->stptr, sp, s->stlen+1);
+ memcpy(s->stptr, sp, s->stlen + 1);
no_malloc:
s->flags |= STRCUR;
free_wstr(s);
return s;
}
-/* force_string --- force a value to be a string */
+/* r_dupnode --- duplicate a node */
NODE *
-r_force_string(NODE *s)
-{
- if ((s->flags & STRCUR) != 0
- && (s->stfmt == -1 || s->stfmt == CONVFMTidx)
- )
- return s;
- return format_val(CONVFMT, CONVFMTidx, s);
-}
-
-/* dupnode --- duplicate a node */
-
-NODE *
-dupnode(NODE *n)
+r_dupnode(NODE *n)
{
NODE *r;
- if (n->type == Node_ahash) {
- n->ahname_ref++;
- return n;
- }
-
assert(n->type == Node_val);
- if ((n->flags & PERM) != 0)
- return n;
-
+#ifdef GAWKDEBUG
if ((n->flags & MALLOC) != 0) {
n->valref++;
return n;
}
+#endif
getnode(r);
*r = *n;
@@ -308,13 +292,13 @@ dupnode(NODE *n)
#endif /* MBS_SUPPORT */
if ((n->flags & STRCUR) != 0) {
- emalloc(r->stptr, char *, n->stlen + 2, "dupnode");
+ emalloc(r->stptr, char *, n->stlen + 2, "r_dupnode");
memcpy(r->stptr, n->stptr, n->stlen);
r->stptr[n->stlen] = '\0';
#if MBS_SUPPORT
if ((n->flags & WSTRCUR) != 0) {
r->wstlen = n->wstlen;
- emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "dupnode");
+ emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "r_dupnode");
memcpy(r->wstptr, n->wstptr, n->wstlen * sizeof(wchar_t));
r->wstptr[n->wstlen] = L'\0';
r->flags |= WSTRCUR;
@@ -325,35 +309,66 @@ dupnode(NODE *n)
return r;
}
-/* mk_number --- allocate a node with defined number */
+/* r_make_number --- allocate a node with defined number */
-NODE *
-mk_number(AWKNUM x, unsigned int flags)
+static NODE *
+r_make_number(double x)
{
NODE *r;
-
getnode(r);
r->type = Node_val;
r->numbr = x;
+ r->flags = MALLOC|NUMBER|NUMCUR;
r->valref = 1;
- r->flags = flags;
r->stptr = NULL;
r->stlen = 0;
- free_wstr(r);
+#if MBS_SUPPORT
+ r->wstptr = NULL;
+ r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
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;
+}
+
+
/* make_str_node --- make a string node */
NODE *
-r_make_str_node(const char *s, unsigned long len, int flags)
+make_str_node(const char *s, size_t len, int flags)
{
NODE *r;
-
getnode(r);
r->type = Node_val;
r->numbr = 0;
- r->flags = (STRING|STRCUR|MALLOC);
+ r->flags = (MALLOC|STRING|STRCUR);
+ r->valref = 1;
+ r->stfmt = -1;
+
#if MBS_SUPPORT
r->wstptr = NULL;
r->wstlen = 0;
@@ -366,7 +381,7 @@ r_make_str_node(const char *s, unsigned long len, int flags)
memcpy(r->stptr, s, len);
}
r->stptr[len] = '\0';
-
+
if ((flags & SCAN) != 0) { /* scan for escape sequences */
const char *pf;
char *ptm;
@@ -413,68 +428,36 @@ r_make_str_node(const char *s, unsigned long len, int flags)
len = ptm - r->stptr;
erealloc(r->stptr, char *, len + 1, "make_str_node");
r->stptr[len] = '\0';
- r->flags &= ~MALLOC;
- r->flags |= PERM;
}
r->stlen = len;
- r->valref = 1;
- r->stfmt = -1;
return r;
}
-/* more_nodes --- allocate more nodes */
-
-#define NODECHUNK 100
-
-NODE *nextfree = NULL;
-
-NODE *
-more_nodes()
-{
- NODE *np;
-
- /* get more nodes and initialize list */
- emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "more_nodes");
- memset(nextfree, 0, NODECHUNK * sizeof(NODE));
- for (np = nextfree; np <= &nextfree[NODECHUNK - 1]; np++) {
- np->nextp = np + 1;
- }
- --np;
- np->nextp = NULL;
- np = nextfree;
- nextfree = nextfree->nextp;
- return np;
-}
/* unref --- remove reference to a particular node */
void
-unref(NODE *tmp)
+r_unref(NODE *tmp)
{
+#ifdef GAWKDEBUG
if (tmp == NULL)
return;
- if ((tmp->flags & PERM) != 0)
- return;
-
- if (tmp->type == Node_ahash) {
- if (tmp->ahname_ref > 1)
- tmp->ahname_ref--;
- else {
- efree(tmp->ahname_str);
- freenode(tmp);
- }
- return;
- }
-
if ((tmp->flags & MALLOC) != 0) {
if (tmp->valref > 1) {
- tmp->valref--;
+ tmp->valref--;
return;
- }
+ }
if (tmp->flags & STRCUR)
efree(tmp->stptr);
}
+#else
+ if ((tmp->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
+ efree(tmp->stptr);
+#endif
+
+ mpfr_unset(tmp);
+
free_wstr(tmp);
freenode(tmp);
}
@@ -561,10 +544,10 @@ parse_escape(const char **string_ptr)
return i;
case 'x':
if (do_lint) {
- static short warned = FALSE;
+ static bool warned = false;
if (! warned) {
- warned = TRUE;
+ warned = true;
lintwarn(_("POSIX does not allow `\\x' escapes"));
}
}
@@ -600,13 +583,13 @@ parse_escape(const char **string_ptr)
return c;
default:
{
- static short warned[256];
+ static bool warned[256];
unsigned char uc = (unsigned char) c;
/* N.B.: use unsigned char here to avoid Latin-1 problems */
if (! warned[uc]) {
- warned[uc] = TRUE;
+ warned[uc] = true;
warning(_("escape sequence `\\%c' treated as plain `%c'"), uc, uc);
}
@@ -615,12 +598,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, bool use_locale)
{
int dec_point = '.';
+ const char *str = s;
+
#if defined(HAVE_LOCALE_H)
/*
* loc.decimal_point may not have been initialized yet,
@@ -631,11 +616,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.
@@ -645,12 +630,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
@@ -663,7 +652,7 @@ str2wstr(NODE *n, size_t **ptr)
char *sp;
mbstate_t mbs;
wchar_t wc, *wsp;
- static short warned = FALSE;
+ static bool warned = false;
assert((n->flags & (STRING|STRCUR)) != 0);
@@ -746,7 +735,7 @@ str2wstr(NODE *n, size_t **ptr)
memset(& mbs, 0, sizeof(mbs));
/* And warn the user something's wrong */
if (do_lint && ! warned) {
- warned = TRUE;
+ warned = true;
lintwarn(_("Invalid multibyte data detected. There may be a mismatch between your data and your locale."));
}
break;
@@ -820,7 +809,7 @@ wstr2str(NODE *n)
/* free_wstr --- release the wide string part of a node */
void
-free_wstr(NODE *n)
+r_free_wstr(NODE *n)
{
assert(n->type == Node_val);
@@ -927,7 +916,7 @@ is_ieee_magic_val(const char *val)
static AWKNUM
get_ieee_magic_val(const char *val)
{
- static short first = TRUE;
+ static bool first = true;
static AWKNUM inf;
static AWKNUM nan;
@@ -936,7 +925,7 @@ get_ieee_magic_val(const char *val)
if (val == ptr) { /* Older strtod implementations don't support inf or nan. */
if (first) {
- first = FALSE;
+ first = false;
nan = sqrt(-1.0);
inf = -log(0.0);
}
@@ -963,3 +952,41 @@ void init_btowc_cache()
}
}
#endif
+
+#define BLOCKCHUNK 100
+
+BLOCK nextfree[BLOCK_MAX] = {
+ { 0, NULL}, /* invalid */
+ { sizeof(NODE), NULL },
+ { sizeof(BUCKET), NULL },
+};
+
+
+/* more_blocks --- get more blocks of memory and add to the free list;
+ size of a block must be >= sizeof(BLOCK)
+ */
+
+void *
+more_blocks(int id)
+{
+ BLOCK *freep, *np, *next;
+ char *p, *endp;
+ size_t size;
+
+ size = nextfree[id].size;
+
+ emalloc(freep, BLOCK *, BLOCKCHUNK * size, "more_blocks");
+ p = (char *) freep;
+ endp = p + BLOCKCHUNK * size;
+
+ for (np = freep; ; np = next) {
+ next = (BLOCK *) (p += size);
+ if (p >= endp) {
+ np->freep = NULL;
+ break;
+ }
+ np->freep = next;
+ }
+ nextfree[id].freep = freep->freep;
+ return freep;
+}