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.
This commit is contained in:
parent
75930f85df
commit
725bfd8489
|
@ -62,6 +62,43 @@ The following functions provide locale-independent string to number conversions.
|
||||||
|
|
||||||
See the Unix man page :manpage:`strtod(2)` for details.
|
See the Unix man page :manpage:`strtod(2)` for details.
|
||||||
|
|
||||||
|
.. deprecated:: 3.1
|
||||||
|
Use :cfunc:`PyOS_string_to_double` instead.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception)
|
||||||
|
|
||||||
|
Convert a string ``s`` to a :ctype:`double`, raising a Python
|
||||||
|
exception on failure. The set of accepted strings corresponds to
|
||||||
|
the set of strings accepted by Python's :func:`float` constructor,
|
||||||
|
except that ``s`` must not have leading or trailing whitespace.
|
||||||
|
The conversion is independent of the current locale.
|
||||||
|
|
||||||
|
If ``endptr`` is ``NULL``, 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 not ``NULL``, convert as much of the string as
|
||||||
|
possible and set ``*endptr`` to point to the first unconverted
|
||||||
|
character. If no initial segment of the string is the valid
|
||||||
|
representation of a floating-point number, set ``*endptr`` to point
|
||||||
|
to the beginning of the string, raise ValueError, and return
|
||||||
|
``-1.0``.
|
||||||
|
|
||||||
|
If ``s`` represents a value that is too large to store in a float
|
||||||
|
(for example, ``"1e500"`` is such a string on many platforms) then
|
||||||
|
if ``overflow_exception`` is ``NULL`` return ``Py_HUGE_VAL`` (with
|
||||||
|
an appropriate sign) and don't set any exception. Otherwise,
|
||||||
|
``overflow_exception`` must point to a Python exception object;
|
||||||
|
raise that exception and return ``-1.0``. In both cases, set
|
||||||
|
``*endptr`` to point to the first character after the converted value.
|
||||||
|
|
||||||
|
If any other error occurs during the conversion (for example an
|
||||||
|
out-of-memory error), set the appropriate Python exception and
|
||||||
|
return ``-1.0``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
|
||||||
.. cfunction:: char* PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d)
|
.. cfunction:: char* PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d)
|
||||||
|
|
||||||
|
@ -117,6 +154,9 @@ The following functions provide locale-independent string to number conversions.
|
||||||
|
|
||||||
See the Unix man page :manpage:`atof(2)` for details.
|
See the Unix man page :manpage:`atof(2)` for details.
|
||||||
|
|
||||||
|
.. deprecated:: 3.1
|
||||||
|
Use PyOS_string_to_double instead.
|
||||||
|
|
||||||
|
|
||||||
.. cfunction:: char* PyOS_stricmp(char *s1, char *s2)
|
.. cfunction:: char* PyOS_stricmp(char *s1, char *s2)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@ extern "C" {
|
||||||
PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr);
|
PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr);
|
||||||
PyAPI_FUNC(double) PyOS_ascii_atof(const char *str);
|
PyAPI_FUNC(double) PyOS_ascii_atof(const char *str);
|
||||||
PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d);
|
PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d);
|
||||||
|
PyAPI_FUNC(double) PyOS_string_to_double(const char *str,
|
||||||
|
char **endptr,
|
||||||
|
PyObject *overflow_exception);
|
||||||
|
|
||||||
/* The caller is responsible for calling PyMem_Free to free the buffer
|
/* The caller is responsible for calling PyMem_Free to free the buffer
|
||||||
that's is returned. */
|
that's is returned. */
|
||||||
|
|
|
@ -2971,20 +2971,20 @@ load_float(UnpicklerObject *self)
|
||||||
return bad_readline();
|
return bad_readline();
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
d = PyOS_ascii_strtod(s, &endptr);
|
d = PyOS_string_to_double(s, &endptr, PyExc_OverflowError);
|
||||||
|
if (d == -1.0 && PyErr_Occurred())
|
||||||
if ((errno == ERANGE && !(fabs(d) <= 1.0)) ||
|
return -1;
|
||||||
(endptr[0] != '\n') || (endptr[1] != '\0')) {
|
if ((endptr[0] != '\n') || (endptr[1] != '\0')) {
|
||||||
PyErr_SetString(PyExc_ValueError, "could not convert string to float");
|
PyErr_SetString(PyExc_ValueError, "could not convert string to float");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
value = PyFloat_FromDouble(d);
|
||||||
if ((value = PyFloat_FromDouble(d)) == NULL)
|
if (value == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
PDATA_PUSH(self->stack, value, -1);
|
PDATA_PUSH(self->stack, value, -1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
load_binfloat(UnpicklerObject *self)
|
load_binfloat(UnpicklerObject *self)
|
||||||
|
|
|
@ -1045,6 +1045,54 @@ test_with_docstring(PyObject *self)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test PyOS_string_to_double. */
|
||||||
|
static PyObject *
|
||||||
|
test_string_to_double(PyObject *self) {
|
||||||
|
double result;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
#define CHECK_STRING(STR, expected) \
|
||||||
|
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||||
|
if (result == -1.0 && PyErr_Occurred()) \
|
||||||
|
return NULL; \
|
||||||
|
if (result != expected) { \
|
||||||
|
msg = "conversion of " STR " to float failed"; \
|
||||||
|
goto fail; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_INVALID(STR) \
|
||||||
|
result = PyOS_string_to_double(STR, NULL, NULL); \
|
||||||
|
if (result == -1.0 && PyErr_Occurred()) { \
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_ValueError)) \
|
||||||
|
PyErr_Clear(); \
|
||||||
|
else \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
msg = "conversion of " STR " didn't raise ValueError"; \
|
||||||
|
goto fail; \
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_STRING("0.1", 0.1);
|
||||||
|
CHECK_STRING("1.234", 1.234);
|
||||||
|
CHECK_STRING("-1.35", -1.35);
|
||||||
|
CHECK_STRING(".1e01", 1.0);
|
||||||
|
CHECK_STRING("2.e-2", 0.02);
|
||||||
|
|
||||||
|
CHECK_INVALID(" 0.1");
|
||||||
|
CHECK_INVALID("\t\n-3");
|
||||||
|
CHECK_INVALID(".123 ");
|
||||||
|
CHECK_INVALID("3\n");
|
||||||
|
CHECK_INVALID("123abc");
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
fail:
|
||||||
|
return raiseTestError("test_string_to_double", msg);
|
||||||
|
#undef CHECK_STRING
|
||||||
|
#undef CHECK_INVALID
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_GETTIMEOFDAY
|
#ifdef HAVE_GETTIMEOFDAY
|
||||||
/* Profiling of integer performance */
|
/* Profiling of integer performance */
|
||||||
static void print_delta(int test, struct timeval *s, struct timeval *e)
|
static void print_delta(int test, struct timeval *s, struct timeval *e)
|
||||||
|
@ -1223,6 +1271,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
|
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
|
||||||
{"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS},
|
{"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS},
|
||||||
{"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS},
|
{"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS},
|
||||||
|
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
|
||||||
{"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,
|
{"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,
|
||||||
PyDoc_STR("This is a pretty normal docstring.")},
|
PyDoc_STR("This is a pretty normal docstring.")},
|
||||||
|
|
||||||
|
|
|
@ -799,25 +799,26 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* first look for forms starting with <float> */
|
/* first look for forms starting with <float> */
|
||||||
errno = 0;
|
z = PyOS_string_to_double(s, &end, PyExc_OverflowError);
|
||||||
z = PyOS_ascii_strtod(s, &end);
|
if (z == -1.0 && PyErr_Occurred()) {
|
||||||
if (end == s && errno == ENOMEM)
|
if (PyErr_ExceptionMatches(PyExc_ValueError))
|
||||||
return PyErr_NoMemory();
|
PyErr_Clear();
|
||||||
if (errno == ERANGE && fabs(z) >= 1.0)
|
else
|
||||||
goto overflow;
|
return NULL;
|
||||||
|
}
|
||||||
if (end != s) {
|
if (end != s) {
|
||||||
/* all 4 forms starting with <float> land here */
|
/* all 4 forms starting with <float> land here */
|
||||||
s = end;
|
s = end;
|
||||||
if (*s == '+' || *s == '-') {
|
if (*s == '+' || *s == '-') {
|
||||||
/* <float><signed-float>j | <float><sign>j */
|
/* <float><signed-float>j | <float><sign>j */
|
||||||
x = z;
|
x = z;
|
||||||
errno = 0;
|
y = PyOS_string_to_double(s, &end, PyExc_OverflowError);
|
||||||
y = PyOS_ascii_strtod(s, &end);
|
if (y == -1.0 && PyErr_Occurred()) {
|
||||||
if (end == s && errno == ENOMEM)
|
if (PyErr_ExceptionMatches(PyExc_ValueError))
|
||||||
return PyErr_NoMemory();
|
PyErr_Clear();
|
||||||
if (errno == ERANGE && fabs(y) >= 1.0)
|
else
|
||||||
goto overflow;
|
return NULL;
|
||||||
|
}
|
||||||
if (end != s)
|
if (end != s)
|
||||||
/* <float><signed-float>j */
|
/* <float><signed-float>j */
|
||||||
s = end;
|
s = end;
|
||||||
|
@ -877,11 +878,6 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"complex() arg is a malformed string");
|
"complex() arg is a malformed string");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
overflow:
|
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
|
||||||
"complex() arg overflow");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -193,36 +193,20 @@ PyFloat_FromString(PyObject *v)
|
||||||
/* We don't care about overflow or underflow. If the platform
|
/* We don't care about overflow or underflow. If the platform
|
||||||
* supports them, infinities and signed zeroes (on underflow) are
|
* supports them, infinities and signed zeroes (on underflow) are
|
||||||
* fine. */
|
* fine. */
|
||||||
errno = 0;
|
x = PyOS_string_to_double(s, (char **)&end, NULL);
|
||||||
PyFPE_START_PROTECT("strtod", goto error)
|
if (x == -1.0 && PyErr_Occurred())
|
||||||
x = PyOS_ascii_strtod(s, (char **)&end);
|
|
||||||
PyFPE_END_PROTECT(x)
|
|
||||||
if (end == s) {
|
|
||||||
if (errno == ENOMEM)
|
|
||||||
PyErr_NoMemory();
|
|
||||||
else {
|
|
||||||
PyOS_snprintf(buffer, sizeof(buffer),
|
|
||||||
"invalid literal for float(): %.200s", s);
|
|
||||||
PyErr_SetString(PyExc_ValueError, buffer);
|
|
||||||
}
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
/* Since end != s, the platform made *some* kind of sense out
|
|
||||||
of the input. Trust it. */
|
|
||||||
while (*end && isspace(Py_CHARMASK(*end)))
|
while (*end && isspace(Py_CHARMASK(*end)))
|
||||||
end++;
|
end++;
|
||||||
if (end != last) {
|
if (end == last)
|
||||||
if (*end == '\0')
|
result = PyFloat_FromDouble(x);
|
||||||
PyErr_SetString(PyExc_ValueError,
|
else {
|
||||||
"null byte in argument for float()");
|
PyOS_snprintf(buffer, sizeof(buffer),
|
||||||
else {
|
"invalid literal for float(): %.200s", s);
|
||||||
PyOS_snprintf(buffer, sizeof(buffer),
|
PyErr_SetString(PyExc_ValueError, buffer);
|
||||||
"invalid literal for float(): %.200s", s);
|
result = NULL;
|
||||||
PyErr_SetString(PyExc_ValueError, buffer);
|
|
||||||
}
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
result = PyFloat_FromDouble(x);
|
|
||||||
error:
|
error:
|
||||||
if (s_buffer)
|
if (s_buffer)
|
||||||
PyMem_FREE(s_buffer);
|
PyMem_FREE(s_buffer);
|
||||||
|
|
16
Python/ast.c
16
Python/ast.c
|
@ -3162,18 +3162,18 @@ parsenumber(struct compiling *c, const char *s)
|
||||||
#ifndef WITHOUT_COMPLEX
|
#ifndef WITHOUT_COMPLEX
|
||||||
if (imflag) {
|
if (imflag) {
|
||||||
compl.real = 0.;
|
compl.real = 0.;
|
||||||
PyFPE_START_PROTECT("atof", return 0)
|
compl.imag = PyOS_string_to_double(s, (char **)&end, NULL);
|
||||||
compl.imag = PyOS_ascii_atof(s);
|
if (compl.imag == -1.0 && PyErr_Occurred())
|
||||||
PyFPE_END_PROTECT(c)
|
return NULL;
|
||||||
return PyComplex_FromCComplex(compl);
|
return PyComplex_FromCComplex(compl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
PyFPE_START_PROTECT("atof", return 0)
|
dx = PyOS_string_to_double(s, NULL, NULL);
|
||||||
dx = PyOS_ascii_atof(s);
|
if (dx == -1.0 && PyErr_Occurred())
|
||||||
PyFPE_END_PROTECT(dx)
|
return NULL;
|
||||||
return PyFloat_FromDouble(dx);
|
return PyFloat_FromDouble(dx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,9 @@
|
||||||
* that hasn't been MALLOC'ed, private_mem should only be used when k <=
|
* that hasn't been MALLOC'ed, private_mem should only be used when k <=
|
||||||
* Kmax.
|
* 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
|
/* 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 */
|
/* no break */
|
||||||
case 0:
|
case 0:
|
||||||
goto ret0;
|
goto ret0;
|
||||||
|
/* modify original dtoa.c so that it doesn't accept leading whitespace
|
||||||
case '\t':
|
case '\t':
|
||||||
case '\n':
|
case '\n':
|
||||||
case '\v':
|
case '\v':
|
||||||
|
@ -1362,6 +1366,7 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
case '\r':
|
case '\r':
|
||||||
case ' ':
|
case ' ':
|
||||||
continue;
|
continue;
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
goto break2;
|
goto break2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -670,18 +670,17 @@ r_object(RFILE *p)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
double dx;
|
double dx;
|
||||||
|
retval = NULL;
|
||||||
n = r_byte(p);
|
n = r_byte(p);
|
||||||
if (n == EOF || r_string(buf, (int)n, p) != n) {
|
if (n == EOF || r_string(buf, (int)n, p) != n) {
|
||||||
PyErr_SetString(PyExc_EOFError,
|
PyErr_SetString(PyExc_EOFError,
|
||||||
"EOF read where object expected");
|
"EOF read where object expected");
|
||||||
retval = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
retval = NULL;
|
dx = PyOS_string_to_double(buf, NULL, NULL);
|
||||||
PyFPE_START_PROTECT("atof", break)
|
if (dx == -1.0 && PyErr_Occurred())
|
||||||
dx = PyOS_ascii_atof(buf);
|
break;
|
||||||
PyFPE_END_PROTECT(dx)
|
|
||||||
retval = PyFloat_FromDouble(dx);
|
retval = PyFloat_FromDouble(dx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -710,29 +709,27 @@ r_object(RFILE *p)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
Py_complex c;
|
Py_complex c;
|
||||||
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;
|
retval = NULL;
|
||||||
PyFPE_START_PROTECT("atof", break;)
|
|
||||||
c.real = PyOS_ascii_atof(buf);
|
|
||||||
PyFPE_END_PROTECT(c)
|
|
||||||
n = r_byte(p);
|
n = r_byte(p);
|
||||||
if (n == EOF || r_string(buf, (int)n, p) != n) {
|
if (n == EOF || r_string(buf, (int)n, p) != n) {
|
||||||
PyErr_SetString(PyExc_EOFError,
|
PyErr_SetString(PyExc_EOFError,
|
||||||
"EOF read where object expected");
|
"EOF read where object expected");
|
||||||
retval = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
PyFPE_START_PROTECT("atof", break)
|
c.real = PyOS_string_to_double(buf, NULL, NULL);
|
||||||
c.imag = PyOS_ascii_atof(buf);
|
if (c.real == -1.0 && PyErr_Occurred())
|
||||||
PyFPE_END_PROTECT(c)
|
break;
|
||||||
|
n = r_byte(p);
|
||||||
|
if (n == EOF || r_string(buf, (int)n, p) != n) {
|
||||||
|
PyErr_SetString(PyExc_EOFError,
|
||||||
|
"EOF read where object expected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[n] = '\0';
|
||||||
|
c.imag = PyOS_string_to_double(buf, NULL, NULL);
|
||||||
|
if (c.imag == -1.0 && PyErr_Occurred())
|
||||||
|
break;
|
||||||
retval = PyComplex_FromCComplex(c);
|
retval = PyComplex_FromCComplex(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#ifndef PY_NO_SHORT_FLOAT_REPR
|
#ifndef PY_NO_SHORT_FLOAT_REPR
|
||||||
|
|
||||||
double
|
double
|
||||||
PyOS_ascii_strtod(const char *nptr, char **endptr)
|
_PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
{
|
{
|
||||||
double result;
|
double result;
|
||||||
_Py_SET_53BIT_PRECISION_HEADER;
|
_Py_SET_53BIT_PRECISION_HEADER;
|
||||||
|
@ -64,7 +64,7 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double
|
double
|
||||||
PyOS_ascii_strtod(const char *nptr, char **endptr)
|
_PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
{
|
{
|
||||||
char *fail_pos;
|
char *fail_pos;
|
||||||
double val = -1.0;
|
double val = -1.0;
|
||||||
|
@ -92,15 +92,10 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
and underflows */
|
and underflows */
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
/* We process any leading whitespace and the optional sign manually,
|
/* We process the optional sign manually, then pass the remainder to
|
||||||
then pass the remainder to the system strtod. This ensures that
|
the system strtod. This ensures that the result of an underflow
|
||||||
the result of an underflow has the correct sign. (bug #1725) */
|
has the correct sign. (bug #1725) */
|
||||||
|
|
||||||
p = nptr;
|
p = nptr;
|
||||||
/* Skip leading space */
|
|
||||||
while (Py_ISSPACE(*p))
|
|
||||||
p++;
|
|
||||||
|
|
||||||
/* Process leading sign, if present */
|
/* Process leading sign, if present */
|
||||||
if (*p == '-') {
|
if (*p == '-') {
|
||||||
negate = 1;
|
negate = 1;
|
||||||
|
@ -185,8 +180,7 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
copy = (char *)PyMem_MALLOC(end - digits_pos +
|
copy = (char *)PyMem_MALLOC(end - digits_pos +
|
||||||
1 + decimal_point_len);
|
1 + decimal_point_len);
|
||||||
if (copy == NULL) {
|
if (copy == NULL) {
|
||||||
if (endptr)
|
*endptr = (char *)nptr;
|
||||||
*endptr = (char *)nptr;
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -227,27 +221,116 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)
|
||||||
got_val:
|
got_val:
|
||||||
if (negate && fail_pos != nptr)
|
if (negate && fail_pos != nptr)
|
||||||
val = -val;
|
val = -val;
|
||||||
|
*endptr = fail_pos;
|
||||||
if (endptr)
|
|
||||||
*endptr = fail_pos;
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
invalid_string:
|
invalid_string:
|
||||||
if (endptr)
|
*endptr = (char*)nptr;
|
||||||
*endptr = (char*)nptr;
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1.0;
|
return -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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
|
double
|
||||||
PyOS_ascii_atof(const char *nptr)
|
PyOS_ascii_atof(const char *nptr)
|
||||||
{
|
{
|
||||||
return PyOS_ascii_strtod(nptr, NULL);
|
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
|
/* Given a string that may have a decimal point in the current
|
||||||
locale, change it back to a dot. Since the string cannot get
|
locale, change it back to a dot. Since the string cannot get
|
||||||
|
|
Loading…
Reference in New Issue