Issue 5780: Fix test_float failures for legacy style float repr.
diff --git a/Misc/NEWS b/Misc/NEWS
index d4774dd..f0ed225 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -20,14 +20,7 @@
 - Implement PEP 378, Format Specifier for Thousands Separator, for
   floats.
 
-- The repr function switches to exponential notation at 1e16, not 1e17
-  as it did before.  This change applies to both 'short' and legacy
-  float repr styles.  For the new repr style, it avoids misleading
-  output in some cases: an example is repr(2e16+8), which gives
-  '2.000000000000001e+16'; without this change it would have produced
-  '20000000000000010.0' instead.
-
-- Similarly, the str function switches to exponential notation at
+- The str function switches to exponential notation at
   1e11, not 1e12.  This avoids printing 13 significant digits in
   situations where only 12 of them are correct.  Example problem
   value: str(1e11 + 0.5).  (This minor issue has existed in 2.x for a
@@ -44,6 +37,9 @@
   finite float x, repr(x) now outputs a string based on the shortest
   sequence of decimal digits that rounds to x.  Previous behaviour was
   to output 17 significant digits and then strip trailing zeros.
+  Another minor difference is that the new repr switches to
+  exponential notation at 1e16 instead of the previous 1e17; this
+  avoids misleading output in some cases.
 
   There's a new sys attribute sys.float_repr_style, which takes
   the value 'short' to indicate that we're using short float repr,
diff --git a/Python/pystrtod.c b/Python/pystrtod.c
index 9e00823..95fbd89 100644
--- a/Python/pystrtod.c
+++ b/Python/pystrtod.c
@@ -485,6 +485,50 @@
 
 /* The fallback code to use if _Py_dg_dtoa is not available. */
 
+/* Remove trailing zeros after the decimal point from a numeric string; also
+   remove the decimal point if all digits following it are zero.  The numeric
+   string must end in '\0', and should not have any leading or trailing
+   whitespace.  Assumes that the decimal point is '.'. */
+Py_LOCAL_INLINE(void)
+remove_trailing_zeros(char *buffer)
+{
+	char *old_fraction_end, *new_fraction_end, *end, *p;
+
+	p = buffer;
+	if (*p == '-' || *p == '+')
+		/* Skip leading sign, if present */
+		++p;
+	while (isdigit(Py_CHARMASK(*p)))
+		++p;
+
+	/* if there's no decimal point there's nothing to do */
+	if (*p++ != '.')
+		return;
+
+	/* scan any digits after the point */
+	while (isdigit(Py_CHARMASK(*p)))
+		++p;
+	old_fraction_end = p;
+
+	/* scan up to ending '\0' */
+	while (*p != '\0')
+		p++;
+	/* +1 to make sure that we move the null byte as well */
+	end = p+1;
+
+	/* scan back from fraction_end, looking for removable zeros */
+	p = old_fraction_end;
+	while (*(p-1) == '0')
+		--p;
+	/* and remove point if we've got that far */
+	if (*(p-1) == '.')
+		--p;
+	new_fraction_end = p;
+
+	memmove(new_fraction_end, old_fraction_end, end-old_fraction_end);
+}
+
+
 PyAPI_FUNC(char *) PyOS_double_to_string(double val,
                                          char format_code,
                                          int precision,
@@ -498,6 +542,7 @@
 	char *p;
 	int t;
 	int upper = 0;
+	int strip_trailing_zeros = 0;
 
 	/* Validate format_code, and map upper and lower case */
 	switch (format_code) {
@@ -532,8 +577,17 @@
 			PyErr_BadInternalCall();
 			return NULL;
 		}
-		precision = 12;
-		format_code = 'g';
+		/* switch to exponential notation at 1e11, or 1e12 if we're
+		   not adding a .0 */
+		if (fabs(val) >= (flags & Py_DTSF_ADD_DOT_0 ? 1e11 : 1e12)) {
+			precision = 11;
+			format_code = 'e';
+			strip_trailing_zeros = 1;
+		}
+		else {
+			precision = 12;
+			format_code = 'g';
+		}
 		break;
 	default:
 		PyErr_BadInternalCall();
@@ -554,11 +608,14 @@
 		t = Py_DTST_FINITE;
 
 
-		if (flags & Py_DTSF_ADD_DOT_0)
+		if ((flags & Py_DTSF_ADD_DOT_0) && (format_code != 'e'))
 			format_code = 'Z';
 
 		PyOS_snprintf(format, 32, "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code);
 		PyOS_ascii_formatd(buf, sizeof(buf), format, val);
+		/* remove trailing zeros if necessary */
+		if (strip_trailing_zeros)
+			remove_trailing_zeros(buf);
 	}
 
 	len = strlen(buf);
@@ -671,7 +728,7 @@
 	assert(digits_end != NULL && digits_end >= digits);
 	digits_len = digits_end - digits;
 
-	if (digits_len && !isdigit(digits[0])) {
+	if (digits_len && !isdigit(Py_CHARMASK(digits[0]))) {
 		/* Infinities and nans here; adapt Gay's output,
 		   so convert Infinity to inf and NaN to nan, and
 		   ignore sign of nan. Then return. */