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

This commit is contained in:
Arnold D. Robbins 2020-12-18 11:57:48 +02:00
parent 982a574e32
commit 8909e00b57
7 changed files with 61 additions and 17 deletions

8
FIXES
View File

@ -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.

View File

@ -0,0 +1,4 @@
{
for (i = 1; i <= NF; i++)
print i, $i, $i + 0
}

View File

@ -0,0 +1 @@
-inf -inform inform -nan -nancy nancy -123 0 123 +123 nancy +nancy +nan inform +inform +inf

View File

@ -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

32
lib.c
View File

@ -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;
}

2
main.c
View File

@ -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 <stdio.h>

15
tran.c
View File

@ -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); \