summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2009-05-03 20:33:40 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2009-05-03 20:33:40 (GMT)
commit725bfd8489e444aedd8dfd686a27ffc308657155 (patch)
tree99d4e0cc2953794a67a5cff491e1897723a119ff /Python
parent75930f85df76472686a8c4eb587a2a70562f61fe (diff)
downloadcpython-725bfd8489e444aedd8dfd686a27ffc308657155.zip
cpython-725bfd8489e444aedd8dfd686a27ffc308657155.tar.gz
cpython-725bfd8489e444aedd8dfd686a27ffc308657155.tar.bz2
Issue #5914: Add new C-API function PyOS_string_to_double, to complement
PyOS_double_to_string, and deprecate PyOS_ascii_strtod and PyOS_ascii_atof.
Diffstat (limited to 'Python')
-rw-r--r--Python/ast.c16
-rw-r--r--Python/dtoa.c5
-rw-r--r--Python/marshal.c25
-rw-r--r--Python/pystrtod.c117
4 files changed, 124 insertions, 39 deletions
diff --git a/Python/ast.c b/Python/ast.c
index b08cf9b..1c79359 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -3162,18 +3162,18 @@ parsenumber(struct compiling *c, const char *s)
#ifndef WITHOUT_COMPLEX
if (imflag) {
compl.real = 0.;
- PyFPE_START_PROTECT("atof", return 0)
- compl.imag = PyOS_ascii_atof(s);
- PyFPE_END_PROTECT(c)
- return PyComplex_FromCComplex(compl);
+ compl.imag = PyOS_string_to_double(s, (char **)&end, NULL);
+ if (compl.imag == -1.0 && PyErr_Occurred())
+ return NULL;
+ return PyComplex_FromCComplex(compl);
}
else
#endif
{
- PyFPE_START_PROTECT("atof", return 0)
- dx = PyOS_ascii_atof(s);
- PyFPE_END_PROTECT(dx)
- return PyFloat_FromDouble(dx);
+ dx = PyOS_string_to_double(s, NULL, NULL);
+ if (dx == -1.0 && PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble(dx);
}
}
diff --git a/Python/dtoa.c b/Python/dtoa.c
index 1d96304..82434bc 100644
--- a/Python/dtoa.c
+++ b/Python/dtoa.c
@@ -61,6 +61,9 @@
* that hasn't been MALLOC'ed, private_mem should only be used when k <=
* Kmax.
*
+ * 7. _Py_dg_strtod has been modified so that it doesn't accept strings with
+ * leading whitespace.
+ *
***************************************************************/
/* Please send bug reports for the original dtoa.c code to David M. Gay (dmg
@@ -1355,6 +1358,7 @@ _Py_dg_strtod(const char *s00, char **se)
/* no break */
case 0:
goto ret0;
+ /* modify original dtoa.c so that it doesn't accept leading whitespace
case '\t':
case '\n':
case '\v':
@@ -1362,6 +1366,7 @@ _Py_dg_strtod(const char *s00, char **se)
case '\r':
case ' ':
continue;
+ */
default:
goto break2;
}
diff --git a/Python/marshal.c b/Python/marshal.c
index 4ad873e..4e9c129 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -670,18 +670,17 @@ r_object(RFILE *p)
{
char buf[256];
double dx;
+ retval = NULL;
n = r_byte(p);
if (n == EOF || r_string(buf, (int)n, p) != n) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
- retval = NULL;
break;
}
buf[n] = '\0';
- retval = NULL;
- PyFPE_START_PROTECT("atof", break)
- dx = PyOS_ascii_atof(buf);
- PyFPE_END_PROTECT(dx)
+ dx = PyOS_string_to_double(buf, NULL, NULL);
+ if (dx == -1.0 && PyErr_Occurred())
+ break;
retval = PyFloat_FromDouble(dx);
break;
}
@@ -710,29 +709,27 @@ r_object(RFILE *p)
{
char buf[256];
Py_complex c;
+ retval = NULL;
n = r_byte(p);
if (n == EOF || r_string(buf, (int)n, p) != n) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
- retval = NULL;
break;
}
buf[n] = '\0';
- retval = NULL;
- PyFPE_START_PROTECT("atof", break;)
- c.real = PyOS_ascii_atof(buf);
- PyFPE_END_PROTECT(c)
+ c.real = PyOS_string_to_double(buf, NULL, NULL);
+ if (c.real == -1.0 && PyErr_Occurred())
+ break;
n = r_byte(p);
if (n == EOF || r_string(buf, (int)n, p) != n) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
- retval = NULL;
break;
}
buf[n] = '\0';
- PyFPE_START_PROTECT("atof", break)
- c.imag = PyOS_ascii_atof(buf);
- PyFPE_END_PROTECT(c)
+ c.imag = PyOS_string_to_double(buf, NULL, NULL);
+ if (c.imag == -1.0 && PyErr_Occurred())
+ break;
retval = PyComplex_FromCComplex(c);
break;
}
diff --git a/Python/pystrtod.c b/Python/pystrtod.c
index 1040610..66242d8 100644
--- a/Python/pystrtod.c
+++ b/Python/pystrtod.c
@@ -35,7 +35,7 @@
#ifndef PY_NO_SHORT_FLOAT_REPR
double
-PyOS_ascii_strtod(const char *nptr, char **endptr)
+_PyOS_ascii_strtod(const char *nptr, char **endptr)
{
double result;
_Py_SET_53BIT_PRECISION_HEADER;
@@ -64,7 +64,7 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
*/
double
-PyOS_ascii_strtod(const char *nptr, char **endptr)
+_PyOS_ascii_strtod(const char *nptr, char **endptr)
{
char *fail_pos;
double val = -1.0;
@@ -92,15 +92,10 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
and underflows */
errno = 0;
- /* We process any leading whitespace and the optional sign manually,
- then pass the remainder to the system strtod. This ensures that
- the result of an underflow has the correct sign. (bug #1725) */
-
+ /* We process the optional sign manually, then pass the remainder to
+ the system strtod. This ensures that the result of an underflow
+ has the correct sign. (bug #1725) */
p = nptr;
- /* Skip leading space */
- while (Py_ISSPACE(*p))
- p++;
-
/* Process leading sign, if present */
if (*p == '-') {
negate = 1;
@@ -185,8 +180,7 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
copy = (char *)PyMem_MALLOC(end - digits_pos +
1 + decimal_point_len);
if (copy == NULL) {
- if (endptr)
- *endptr = (char *)nptr;
+ *endptr = (char *)nptr;
errno = ENOMEM;
return val;
}
@@ -227,27 +221,116 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
got_val:
if (negate && fail_pos != nptr)
val = -val;
-
- if (endptr)
- *endptr = fail_pos;
+ *endptr = fail_pos;
return val;
invalid_string:
- if (endptr)
- *endptr = (char*)nptr;
+ *endptr = (char*)nptr;
errno = EINVAL;
return -1.0;
}
#endif
+/* PyOS_ascii_strtod is DEPRECATED in Python 3.1 */
+
+double
+PyOS_ascii_strtod(const char *nptr, char **endptr)
+{
+ char *fail_pos;
+ const char *p;
+ double x;
+
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "PyOS_ascii_strtod and PyOS_ascii_atof are "
+ "deprecated. Use PyOS_string_to_double "
+ "instead.", 1) < 0)
+ return -1.0;
+
+ /* _PyOS_ascii_strtod already does everything that we want,
+ except that it doesn't parse leading whitespace */
+ p = nptr;
+ while (Py_ISSPACE(*p))
+ p++;
+ x = _PyOS_ascii_strtod(p, &fail_pos);
+ if (fail_pos == p)
+ fail_pos = (char *)nptr;
+ if (endptr)
+ *endptr = (char *)fail_pos;
+ return x;
+}
+
+/* PyOS_ascii_strtod is DEPRECATED in Python 3.1 */
+
double
PyOS_ascii_atof(const char *nptr)
{
return PyOS_ascii_strtod(nptr, NULL);
}
+/* PyOS_string_to_double is the recommended replacement for the deprecated
+ PyOS_ascii_strtod and PyOS_ascii_atof functions. It converts a
+ null-terminated byte string s (interpreted as a string of ASCII characters)
+ to a float. The string should not have leading or trailing whitespace (in
+ contrast, PyOS_ascii_strtod allows leading whitespace but not trailing
+ whitespace). The conversion is independent of the current locale.
+
+ If endptr is NULL, try to convert the whole string. Raise ValueError and
+ return -1.0 if the string is not a valid representation of a floating-point
+ number.
+
+ If endptr is non-NULL, try to convert as much of the string as possible.
+ If no initial segment of the string is the valid representation of a
+ floating-point number then *endptr is set to point to the beginning of the
+ string, -1.0 is returned and again ValueError is raised.
+
+ On overflow (e.g., when trying to convert '1e500' on an IEEE 754 machine),
+ if overflow_exception is NULL then +-Py_HUGE_VAL is returned, and no Python
+ exception is raised. Otherwise, overflow_exception should point to a
+ a Python exception, this exception will be raised, -1.0 will be returned,
+ and *endptr will point just past the end of the converted value.
+
+ If any other failure occurs (for example lack of memory), -1.0 is returned
+ and the appropriate Python exception will have been set.
+*/
+
+double
+PyOS_string_to_double(const char *s,
+ char **endptr,
+ PyObject *overflow_exception)
+{
+ double x, result=-1.0;
+ char *fail_pos;
+
+ errno = 0;
+ PyFPE_START_PROTECT("PyOS_string_to_double", return -1.0)
+ x = _PyOS_ascii_strtod(s, &fail_pos);
+ PyFPE_END_PROTECT(x)
+
+ if (errno == ENOMEM) {
+ PyErr_NoMemory();
+ fail_pos = (char *)s;
+ }
+ else if (!endptr && (fail_pos == s || *fail_pos != '\0'))
+ PyErr_Format(PyExc_ValueError,
+ "could not convert string to float: "
+ "%.200s", s);
+ else if (fail_pos == s)
+ PyErr_Format(PyExc_ValueError,
+ "could not convert string to float: "
+ "%.200s", s);
+ else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception)
+ PyErr_Format(overflow_exception,
+ "value too large to convert to float: "
+ "%.200s", s);
+ else
+ result = x;
+
+ if (endptr != NULL)
+ *endptr = fail_pos;
+ return result;
+}
/* Given a string that may have a decimal point in the current
locale, change it back to a dot. Since the string cannot get