diff --git a/FIXES b/FIXES index 0add0eb..20b4bd8 100644 --- a/FIXES +++ b/FIXES @@ -25,6 +25,14 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the AWK book was sent to the printers in August, 1987. +December 18, 2020: + Fix problems converting inf and NaN values in lib.c:is_valid_number. + Enhance number to string conversion to do the right thing for + NaN and inf values. Things are now pretty much the same as in + gawk. (Found a gawk bug while we're at it.) Added a torture + test for these values. Thanks to Arnold Robbins. Allows closing + of PR #101. + December 15, 2020: Merge PR #99, which gets the right header for strcasecmp. Thanks to GitHub user michaelforney. diff --git a/bugs-fixed/inf-nan-torture.awk b/bugs-fixed/inf-nan-torture.awk new file mode 100644 index 0000000..8d145f2 --- /dev/null +++ b/bugs-fixed/inf-nan-torture.awk @@ -0,0 +1,4 @@ +{ + for (i = 1; i <= NF; i++) + print i, $i, $i + 0 +} diff --git a/bugs-fixed/inf-nan-torture.in b/bugs-fixed/inf-nan-torture.in new file mode 100644 index 0000000..45dfdc8 --- /dev/null +++ b/bugs-fixed/inf-nan-torture.in @@ -0,0 +1 @@ +-inf -inform inform -nan -nancy nancy -123 0 123 +123 nancy +nancy +nan inform +inform +inf diff --git a/bugs-fixed/inf-nan-torture.ok b/bugs-fixed/inf-nan-torture.ok new file mode 100644 index 0000000..40d3194 --- /dev/null +++ b/bugs-fixed/inf-nan-torture.ok @@ -0,0 +1,16 @@ +1 -inf -inf +2 -inform 0 +3 inform 0 +4 -nan -nan +5 -nancy 0 +6 nancy 0 +7 -123 -123 +8 0 0 +9 123 123 +10 +123 123 +11 nancy 0 +12 +nancy 0 +13 +nan +nan +14 inform 0 +15 +inform 0 +16 +inf +inf diff --git a/lib.c b/lib.c index c200114..e8310a9 100644 --- a/lib.c +++ b/lib.c @@ -784,46 +784,48 @@ bool is_valid_number(const char *s, bool trailing_stuff_ok, double r; char *ep; bool retval = false; + bool is_nan = false; + bool is_inf = false; if (no_trailing) *no_trailing = false; - while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') + while (isspace(*s)) s++; - if (s[0] == '0' && tolower(s[1]) == 'x') // no hex floating point, sorry + // no hex floating point, sorry + if (s[0] == '0' && tolower(s[1]) == 'x') return false; // allow +nan, -nan, +inf, -inf, any other letter, no if (s[0] == '+' || s[0] == '-') { - if (strcasecmp(s+1, "nan") == 0 || strcasecmp(s+1, "inf") == 0) - return true; + is_nan = (strncasecmp(s+1, "nan", 3) == 0); + is_inf = (strncasecmp(s+1, "inf", 3) == 0); + if ((is_nan || is_inf) + && (isspace(s[4]) || s[4] == '\0')) + goto convert; else if (! isdigit(s[1]) && s[1] != '.') return false; } else if (! isdigit(s[0]) && s[0] != '.') return false; +convert: errno = 0; r = strtod(s, &ep); - if (ep == s || r == HUGE_VAL || errno == ERANGE) + if (ep == s || errno == ERANGE) return false; + if (isnan(r) && s[0] == '-' && signbit(r) == 0) + r = -r; + if (result != NULL) *result = r; - /* - * check for trailing stuff - * allow \r as well. windows files aren't going to go away. - */ - while (*ep == ' ' || *ep == '\t' || *ep == '\n' || *ep == '\r') - ep++; + retval = (isspace(*ep) || *ep == '\0' || trailing_stuff_ok); - if (no_trailing) + if (no_trailing != NULL) *no_trailing = (*ep == '\0'); - // return true if found the end, or trailing stuff is allowed - retval = (*ep == '\0') || trailing_stuff_ok; - return retval; } diff --git a/main.c b/main.c index 22e52f6..5970cb4 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ -const char *version = "version 20201215"; +const char *version = "version 20201218"; #define DEBUG #include diff --git a/tran.c b/tran.c index 0ce45db..add9d85 100644 --- a/tran.c +++ b/tran.c @@ -418,10 +418,21 @@ Awkfloat getfval(Cell *vp) /* get float val of a Cell */ return(vp->fval); } +static char *get_inf_nan(double d) +{ + if (isinf(d)) { + return (d < 0 ? "-inf" : "+inf"); + } else if (isnan(d)) { + return (signbit(d) != 0 ? "-nan" : "+nan"); + } else + return NULL; +} + static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ { char s[256]; double dtemp; + char *p; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); @@ -458,7 +469,9 @@ static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cel { \ if (freeable(vp)) \ xfree(vp->sval); \ - if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ + if ((p = get_inf_nan(vp->fval)) != NULL) \ + strcpy(s, p); \ + else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ snprintf(s, sizeof (s), "%.30g", vp->fval); \ else \ snprintf(s, sizeof (s), *fmt, vp->fval); \