From 18c6b0f85db6683f1d0789e800acfdd35da3ce07 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Mon, 13 Jun 2016 18:39:10 -0400 Subject: Fix usage of scalar type flag bits and fix some bugs in numeric conversions and lint checks. --- node.c | 83 +++++++++++++++++++++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 44 deletions(-) (limited to 'node.c') diff --git a/node.c b/node.c index 9227cf2d..7bc48cb9 100644 --- a/node.c +++ b/node.c @@ -45,23 +45,25 @@ r_force_number(NODE *n) { char *cp; char *cpend; - char save; char *ptr; - unsigned int newflags; extern double strtod(); if ((n->flags & NUMCUR) != 0) return n; - /* all the conditionals are an attempt to avoid the expensive strtod */ + /* + * we should always set NUMCUR and clear MAYBE_NUM, and we may possibly + * change STRING to NUMBER of MAYBE_NUM was set and it's a good numeric + * string. + */ - /* Note: only set NUMCUR if we actually convert some digits */ + /* all the conditionals are an attempt to avoid the expensive strtod */ + n->flags |= NUMCUR; n->numbr = 0.0; - if (n->stlen == 0) { - return n; - } + if (n->stlen == 0) + goto badnum; cp = n->stptr; /* @@ -72,20 +74,16 @@ r_force_number(NODE *n) * This also allows hexadecimal floating point. Ugh. */ if (! do_posix) { - if (is_alpha((unsigned char) *cp)) { - return n; - } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) { - if ((n->flags & MAYBE_NUM) != 0) - n->flags &= ~(MAYBE_NUM|STRING); - n->flags |= NUMBER|NUMCUR; + if (is_alpha((unsigned char) *cp)) + goto badnum; + else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) { n->numbr = get_ieee_magic_val(n->stptr); - - return n; + goto goodnum; } /* else fall through */ } - /* else not POSIX, so + /* else POSIX, so fall through */ cpend = cp + n->stlen; @@ -98,52 +96,36 @@ 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 n; + goto badnum; } - if ((n->flags & MAYBE_NUM) != 0) { - newflags = NUMBER; - n->flags &= ~(MAYBE_NUM|STRING); - } else - newflags = 0; - if (cpend - cp == 1) { /* only one character */ if (isdigit((unsigned char) *cp)) { /* it's a digit! */ n->numbr = (AWKNUM)(*cp - '0'); - n->flags |= newflags; - n->flags |= NUMCUR; if (cp == n->stptr) /* no leading spaces */ n->flags |= NUMINT; + goto goodnum; } - return n; + goto badnum; } - if (do_non_decimal_data) { /* main.c assures false if do_posix */ + if (do_non_decimal_data /* main.c assures false if do_posix */ + && ! do_traditional && get_numbase(cp, true) != 10) { errno = 0; - if (! do_traditional && get_numbase(cp, true) != 10) { - n->numbr = nondec2awknum(cp, cpend - cp); - n->flags |= NUMCUR; - ptr = cpend; - goto finish; - } + n->numbr = nondec2awknum(cp, cpend - cp, &ptr); + } else { + errno = 0; + n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); } - errno = 0; - save = *cpend; - *cpend = '\0'; - n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); - /* POSIX says trailing space is OK for NUMBER */ while (isspace((unsigned char) *ptr)) ptr++; - *cpend = save; -finish: if (errno == 0) { - if (ptr == cpend) { - n->flags |= newflags; - n->flags |= NUMCUR; - } + if (ptr == cpend) + goto goodnum; /* else keep the leading numeric value without updating flags */ + /* fall through to badnum*/ } else { errno = 0; /* @@ -152,8 +134,21 @@ finish: * We force the numeric value to 0 in such cases. */ n->numbr = 0; + /* + * Or should we accept it as a NUMBER even though strtod + * threw an error? + */ + /* fall through to badnum*/ } +badnum: + n->flags &= ~MAYBE_NUM; + return n; +goodnum: + if ((n->flags & MAYBE_NUM) != 0) { + n->flags &= ~(MAYBE_NUM|STRING); + n->flags |= NUMBER; + } return n; } -- cgit v1.2.3 From fbe836166a40f0fd19851b2f057ae9632a33d1e7 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Sat, 18 Jun 2016 09:25:12 -0400 Subject: Fix typo in comment. --- node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node.c') diff --git a/node.c b/node.c index 89d889a4..bfa9a35f 100644 --- a/node.c +++ b/node.c @@ -67,7 +67,7 @@ r_force_number(NODE *n) /* * we should always set NUMCUR and clear MAYBE_NUM, and we may possibly - * change STRING to NUMBER of MAYBE_NUM was set and it's a good numeric + * change STRING to NUMBER if MAYBE_NUM was set and it's a good numeric * string. */ -- cgit v1.2.3 From e18ebe10166e2c63f3385666978b678fe6ce67a2 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sun, 26 Jun 2016 18:26:39 +0300 Subject: Minor improvements after Andy's reworking of stuff. --- node.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'node.c') diff --git a/node.c b/node.c index bfa9a35f..39c25dfd 100644 --- a/node.c +++ b/node.c @@ -59,6 +59,7 @@ r_force_number(NODE *n) { char *cp; char *cpend; + char save; char *ptr; extern double strtod(); @@ -66,12 +67,12 @@ r_force_number(NODE *n) return n; /* - * we should always set NUMCUR and clear MAYBE_NUM, and we may possibly + * We should always set NUMCUR and clear MAYBE_NUM, and we may possibly * change STRING to NUMBER if MAYBE_NUM was set and it's a good numeric * string. */ - /* all the conditionals are an attempt to avoid the expensive strtod */ + /* All the conditionals are an attempt to avoid the expensive strtod */ n->flags |= NUMCUR; n->numbr = 0.0; @@ -122,23 +123,27 @@ r_force_number(NODE *n) goto badnum; } + errno = 0; if (do_non_decimal_data /* main.c assures false if do_posix */ && ! do_traditional && get_numbase(cp, true) != 10) { - errno = 0; + /* nondec2awknum() saves and restores the byte after the string itself */ n->numbr = nondec2awknum(cp, cpend - cp, &ptr); } else { - errno = 0; + save = *cpend; + *cpend = '\0'; n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); + *cpend = save; } /* POSIX says trailing space is OK for NUMBER */ while (isspace((unsigned char) *ptr)) ptr++; + if (errno == 0) { if (ptr == cpend) goto goodnum; /* else keep the leading numeric value without updating flags */ - /* fall through to badnum*/ + /* fall through to badnum */ } else { errno = 0; /* @@ -151,7 +156,7 @@ r_force_number(NODE *n) * Or should we accept it as a NUMBER even though strtod * threw an error? */ - /* fall through to badnum*/ + /* fall through to badnum */ } badnum: n->flags &= ~MAYBE_NUM; -- cgit v1.2.3 From a7b4445ceb1d355911a8a367b8db79b225094c43 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Sun, 26 Jun 2016 21:10:25 -0400 Subject: When checking for trailing spaces in numeric strings, avoid running off the end. --- node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node.c') diff --git a/node.c b/node.c index 39c25dfd..58b54561 100644 --- a/node.c +++ b/node.c @@ -136,7 +136,7 @@ r_force_number(NODE *n) } /* POSIX says trailing space is OK for NUMBER */ - while (isspace((unsigned char) *ptr)) + while (ptr < cpend && isspace((unsigned char) *ptr)) ptr++; if (errno == 0) { -- cgit v1.2.3 From e4863f1b6341cbcc4132a8161e000e81092b4d65 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Mon, 27 Jun 2016 19:48:34 -0400 Subject: Protect against an improper call to free in r_format_val. --- node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node.c') diff --git a/node.c b/node.c index 58b54561..2c099bd6 100644 --- a/node.c +++ b/node.c @@ -272,7 +272,7 @@ r_format_val(const char *format, int index, NODE *s) s->flags |= STRING; } } - if (s->stptr != NULL) + if ((s->flags & STRCUR) != 0) efree(s->stptr); emalloc(s->stptr, char *, s->stlen + 1, "format_val"); memcpy(s->stptr, sp, s->stlen + 1); -- cgit v1.2.3 From 2ab2d5f2c468b647615d984cb7953217c63695af Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Wed, 29 Jun 2016 14:25:31 -0400 Subject: Optimize r_force_number and fix obscure bug in get_ieee_magic_val. --- node.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'node.c') diff --git a/node.c b/node.c index 2c099bd6..41dcb2f0 100644 --- a/node.c +++ b/node.c @@ -30,7 +30,7 @@ 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); +static AWKNUM get_ieee_magic_val(char *val); extern NODE **fmt_list; /* declared in eval.c */ NODE *(*make_number)(double) = r_make_number; @@ -77,10 +77,21 @@ r_force_number(NODE *n) n->flags |= NUMCUR; n->numbr = 0.0; - if (n->stlen == 0) - goto badnum; - + /* Trim leading white space, bailing out if there's nothing else */ cp = n->stptr; + cpend = cp + n->stlen; + while (1) { + if (cp == cpend) + goto badnum; + if (!isspace((unsigned char) *cp)) + break; + cp++; + } + /* At this point, we know the string is not entirely white space */ + /* Trim trailing white space */ + while (isspace((unsigned char) cpend[-1])) + cpend--; + /* * 2/2007: * POSIX, by way of severe language lawyering, seems to @@ -91,8 +102,8 @@ r_force_number(NODE *n) if (! do_posix) { if (is_alpha((unsigned char) *cp)) goto badnum; - else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) { - n->numbr = get_ieee_magic_val(n->stptr); + else if (cpend == cp+4 && is_ieee_magic_val(cp)) { + n->numbr = get_ieee_magic_val(cp); goto goodnum; } /* else @@ -101,12 +112,7 @@ r_force_number(NODE *n) /* else POSIX, so fall through */ - cpend = cp + n->stlen; - while (cp < cpend && isspace((unsigned char) *cp)) - cp++; - - if ( cp == cpend /* only spaces, or */ - || (! do_posix /* not POSIXLY paranoid and */ + if ( (! do_posix /* not POSIXLY paranoid and */ && (is_alpha((unsigned char) *cp) /* letter, or */ /* CANNOT do non-decimal and saw 0x */ || (! do_non_decimal_data && is_hex(cp))))) { @@ -116,7 +122,7 @@ r_force_number(NODE *n) if (cpend - cp == 1) { /* only one character */ if (isdigit((unsigned char) *cp)) { /* it's a digit! */ n->numbr = (AWKNUM)(*cp - '0'); - if (cp == n->stptr) /* no leading spaces */ + if (n->stlen == 1) /* no white space */ n->flags |= NUMINT; goto goodnum; } @@ -135,10 +141,6 @@ r_force_number(NODE *n) *cpend = save; } - /* POSIX says trailing space is OK for NUMBER */ - while (ptr < cpend && isspace((unsigned char) *ptr)) - ptr++; - if (errno == 0) { if (ptr == cpend) goto goodnum; @@ -937,14 +939,18 @@ is_ieee_magic_val(const char *val) /* get_ieee_magic_val --- return magic value for string */ static AWKNUM -get_ieee_magic_val(const char *val) +get_ieee_magic_val(char *val) { static bool first = true; static AWKNUM inf; static AWKNUM nan; + char save; char *ptr; + save = val[4]; + val[4] = '\0'; AWKNUM v = strtod(val, &ptr); + val[4] = save; if (val == ptr) { /* Older strtod implementations don't support inf or nan. */ if (first) { -- cgit v1.2.3 From 92b5353bf364897f02003c4116cabe6d48ea17eb Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 30 Jun 2016 09:59:47 -0400 Subject: Use new STFMT_UNUSED define to improve code clarity, and fix some minor stfmt issues. --- node.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'node.c') diff --git a/node.c b/node.c index 41dcb2f0..8c5d0c04 100644 --- a/node.c +++ b/node.c @@ -226,7 +226,7 @@ r_format_val(const char *format, int index, NODE *s) * Once upon a time, we just blindly did this: * sprintf(sp, format, s->numbr); * s->stlen = strlen(sp); - * s->stfmt = (char) index; + * s->stfmt = index; * but that's no good if, e.g., OFMT is %s. So we punt, * and just always format the value ourselves. */ @@ -241,11 +241,11 @@ r_format_val(const char *format, int index, NODE *s) if (val == s->numbr) { /* integral value, but outside range of %ld, use %.0f */ r = format_tree("%.0f", 4, dummy, 2); - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; } else { r = format_tree(format, fmt_list[index]->stlen, dummy, 2); assert(r != NULL); - s->stfmt = (char) index; + s->stfmt = index; } s->flags = oflags; s->stlen = r->stlen; @@ -268,7 +268,7 @@ r_format_val(const char *format, int index, NODE *s) (void) sprintf(sp, "%ld", num); s->stlen = strlen(sp); } - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; if ((s->flags & INTIND) != 0) { s->flags &= ~(INTIND|NUMBER); s->flags |= STRING; @@ -385,7 +385,7 @@ make_str_node(const char *s, size_t len, int flags) r->numbr = 0; r->flags = (MALLOC|STRING|STRCUR); r->valref = 1; - r->stfmt = -1; + r->stfmt = STFMT_UNUSED; r->wstptr = NULL; r->wstlen = 0; -- cgit v1.2.3 From 96d37ecb22d847499fbfab80c62894b64249b8c4 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 30 Jun 2016 10:15:07 -0400 Subject: Improve r_force_number coding style. --- node.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'node.c') diff --git a/node.c b/node.c index 8c5d0c04..bb2fe437 100644 --- a/node.c +++ b/node.c @@ -78,15 +78,13 @@ r_force_number(NODE *n) n->numbr = 0.0; /* Trim leading white space, bailing out if there's nothing else */ - cp = n->stptr; - cpend = cp + n->stlen; - while (1) { - if (cp == cpend) - goto badnum; - if (!isspace((unsigned char) *cp)) - break; - cp++; - } + for (cp = n->stptr, cpend = cp + n->stlen; + cp < cpend && isspace((unsigned char) *cp); cp++) + continue; + + if (cp == cpend) + goto badnum; + /* At this point, we know the string is not entirely white space */ /* Trim trailing white space */ while (isspace((unsigned char) cpend[-1])) -- cgit v1.2.3