diff options
Diffstat (limited to 'node.c')
-rw-r--r-- | node.c | 269 |
1 files changed, 148 insertions, 121 deletions
@@ -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; +} |