Merged revisions 72564 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r72564 | mark.dickinson | 2009-05-11 16:33:08 +0100 (Mon, 11 May 2009) | 2 lines

  Issue #5981: Fix some float.fromhex bugs related to inf and nan handling.
........
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 1074f3d..cd8c14f 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1157,6 +1157,20 @@
 >>> 3.14159.hex()\n\
 '0x1.921f9f01b866ep+1'");
 
+/* Case-insensitive locale-independent string match used for nan and inf
+   detection. t should be lower-case and null-terminated.  Return a nonzero
+   result if the first strlen(t) characters of s match t and 0 otherwise. */
+
+static int
+case_insensitive_match(const char *s, const char *t)
+{
+	while(*t && Py_TOLOWER(*s) == *t) {
+		s++;
+		t++;
+	}
+	return *t ? 0 : 1;
+}
+
 /* Convert a hexadecimal string to a float. */
 
 static PyObject *
@@ -1234,13 +1248,20 @@
 		s++;
 
 	/* infinities and nans */
-	if (PyOS_strnicmp(s, "nan", 4) == 0) {
-		x = Py_NAN;
+	if (*s == 'i' || *s == 'I') {
+		if (!case_insensitive_match(s+1, "nf"))
+			goto parse_error;
+		s += 3;
+		x = Py_HUGE_VAL;
+		if (case_insensitive_match(s, "inity"))
+			s += 5;
 		goto finished;
 	}
-	if (PyOS_strnicmp(s, "inf", 4) == 0 ||
-	    PyOS_strnicmp(s, "infinity", 9) == 0) {
-		x = sign*Py_HUGE_VAL;
+	if (*s == 'n' || *s == 'N') {
+		if (!case_insensitive_match(s+1, "an"))
+			goto parse_error;
+		s += 3;
+		x = Py_NAN;
 		goto finished;
 	}
 
@@ -1293,12 +1314,6 @@
 	else
 		exp = 0;
 
-	/* optional trailing whitespace leading to the end of the string */
-	while (Py_ISSPACE(*s))
-		s++;
-	if (s != s_end)
-		goto parse_error;
-
 /* for 0 <= j < ndigits, HEX_DIGIT(j) gives the jth most significant digit */
 #define HEX_DIGIT(j) hex_from_char(*((j) < fdigits ?		\
 				     coeff_end-(j) :			\
@@ -1312,7 +1327,7 @@
 	while (ndigits > 0 && HEX_DIGIT(ndigits-1) == 0)
 		ndigits--;
 	if (ndigits == 0 || exp < LONG_MIN/2) {
-		x = sign * 0.0;
+		x = 0.0;
 		goto finished;
 	}
 	if (exp > LONG_MAX/2)
@@ -1328,7 +1343,7 @@
 
 	/* catch almost all nonextreme cases of overflow and underflow here */
 	if (top_exp < DBL_MIN_EXP - DBL_MANT_DIG) {
-		x = sign * 0.0;
+		x = 0.0;
 		goto finished;
 	}
 	if (top_exp > DBL_MAX_EXP)
@@ -1343,7 +1358,7 @@
 		/* no rounding required */
 		for (i = ndigits-1; i >= 0; i--)
 			x = 16.0*x + HEX_DIGIT(i);
-		x = sign * ldexp(x, (int)(exp));
+		x = ldexp(x, (int)(exp));
 		goto finished;
 	}
 	/* rounding required.  key_digit is the index of the hex digit
@@ -1377,10 +1392,15 @@
 				goto overflow_error;
 		}
 	}
-	x = sign * ldexp(x, (int)(exp+4*key_digit));
+	x = ldexp(x, (int)(exp+4*key_digit));
 
   finished:
-	result_as_float = Py_BuildValue("(d)", x);
+	/* optional trailing whitespace leading to the end of the string */
+	while (Py_ISSPACE(*s))
+		s++;
+	if (s != s_end)
+		goto parse_error;
+	result_as_float = Py_BuildValue("(d)", sign * x);
 	if (result_as_float == NULL)
 		return NULL;
 	result = PyObject_CallObject(cls, result_as_float);