shithub: trueawk

Download patch

ref: 8909e00b57874e5858a210bc3a7e9e56e10eda35
parent: 982a574e3282e0cb650b6e34f694ca191cb73fd4
author: Arnold D. Robbins <arnold@skeeve.com>
date: Fri Dec 18 06:57:48 EST 2020

Inf and NaN values fixed and printing improved. "This time for sure!"

--- a/FIXES
+++ b/FIXES
@@ -25,6 +25,14 @@
 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.
--- /dev/null
+++ b/bugs-fixed/inf-nan-torture.awk
@@ -1,0 +1,4 @@
+{
+	for (i = 1; i <= NF; i++)
+		print i, $i, $i + 0
+}
--- /dev/null
+++ b/bugs-fixed/inf-nan-torture.in
@@ -1,0 +1,1 @@
+-inf -inform inform -nan -nancy nancy -123 0 123 +123 nancy +nancy +nan inform +inform +inf
--- /dev/null
+++ b/bugs-fixed/inf-nan-torture.ok
@@ -1,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
--- a/lib.c
+++ b/lib.c
@@ -784,20 +784,26 @@
 	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;
 	}
@@ -804,26 +810,22 @@
 	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;
 }
--- a/main.c
+++ b/main.c
@@ -22,7 +22,7 @@
 THIS SOFTWARE.
 ****************************************************************/
 
-const char	*version = "version 20201215";
+const char	*version = "version 20201218";
 
 #define DEBUG
 #include <stdio.h>
--- a/tran.c
+++ b/tran.c
@@ -418,10 +418,21 @@
 	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 @@
 	{ \
 		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); \
--