| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 75930f8 commit 725bfd8
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,6 +62,43 @@ The following functions provide locale-independent string to number conversions. | |||
| 62 | 62 | ||
| 63 | 63 | See the Unix man page :manpage:`strtod(2)` for details. | |
| 64 | 64 | ||
| 65 | + .. deprecated:: 3.1 | ||
| 66 | + Use :cfunc:`PyOS_string_to_double` instead. | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + .. cfunction:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) | ||
| 70 | + | ||
| 71 | + Convert a string ``s`` to a :ctype:`double`, raising a Python | ||
| 72 | + exception on failure. The set of accepted strings corresponds to | ||
| 73 | + the set of strings accepted by Python's :func:`float` constructor, | ||
| 74 | + except that ``s`` must not have leading or trailing whitespace. | ||
| 75 | + The conversion is independent of the current locale. | ||
| 76 | + | ||
| 77 | + If ``endptr`` is ``NULL``, convert the whole string. Raise | ||
| 78 | + ValueError and return ``-1.0`` if the string is not a valid | ||
| 79 | + representation of a floating-point number. | ||
| 80 | + | ||
| 81 | + If endptr is not ``NULL``, convert as much of the string as | ||
| 82 | + possible and set ``*endptr`` to point to the first unconverted | ||
| 83 | + character. If no initial segment of the string is the valid | ||
| 84 | + representation of a floating-point number, set ``*endptr`` to point | ||
| 85 | + to the beginning of the string, raise ValueError, and return | ||
| 86 | + ``-1.0``. | ||
| 87 | + | ||
| 88 | + If ``s`` represents a value that is too large to store in a float | ||
| 89 | + (for example, ``"1e500"`` is such a string on many platforms) then | ||
| 90 | + if ``overflow_exception`` is ``NULL`` return ``Py_HUGE_VAL`` (with | ||
| 91 | + an appropriate sign) and don't set any exception. Otherwise, | ||
| 92 | + ``overflow_exception`` must point to a Python exception object; | ||
| 93 | + raise that exception and return ``-1.0``. In both cases, set | ||
| 94 | + ``*endptr`` to point to the first character after the converted value. | ||
| 95 | + | ||
| 96 | + If any other error occurs during the conversion (for example an | ||
| 97 | + out-of-memory error), set the appropriate Python exception and | ||
| 98 | + return ``-1.0``. | ||
| 99 | + | ||
| 100 | + .. versionadded:: 3.1 | ||
| 101 | + | ||
| 65 | 102 | ||
| 66 | 103 | .. cfunction:: char* PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d) | |
| 67 | 104 | ||
@@ -117,6 +154,9 @@ The following functions provide locale-independent string to number conversions. | |||
| 117 | 154 | ||
| 118 | 155 | See the Unix man page :manpage:`atof(2)` for details. | |
| 119 | 156 | ||
| 157 | + .. deprecated:: 3.1 | ||
| 158 | + Use PyOS_string_to_double instead. | ||
| 159 | + | ||
| 120 | 160 | ||
| 121 | 161 | .. cfunction:: char* PyOS_stricmp(char *s1, char *s2) | |
| 122 | 162 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,9 @@ extern "C" { | |||
| 9 | 9 | PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr); | |
| 10 | 10 | PyAPI_FUNC(double) PyOS_ascii_atof(const char *str); | |
| 11 | 11 | PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d); | |
| 12 | + PyAPI_FUNC(double) PyOS_string_to_double(const char *str, | ||
| 13 | + char **endptr, | ||
| 14 | + PyObject *overflow_exception); | ||
| 12 | 15 | ||
| 13 | 16 | /* The caller is responsible for calling PyMem_Free to free the buffer | |
| 14 | 17 | that's is returned. */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2971,20 +2971,20 @@ load_float(UnpicklerObject *self) | |||
| 2971 | 2971 | return bad_readline(); | |
| 2972 | 2972 | ||
| 2973 | 2973 | errno = 0; | |
| 2974 | - d = PyOS_ascii_strtod(s, &endptr); | ||
| 2975 | - | ||
| 2976 | - if ((errno == ERANGE && !(fabs(d) <= 1.0)) || | ||
| 2977 | - (endptr[0] != '\n') || (endptr[1] != '\0')) { | ||
| 2974 | + d = PyOS_string_to_double(s, &endptr, PyExc_OverflowError); | ||
| 2975 | + if (d == -1.0 && PyErr_Occurred()) | ||
| 2976 | + return -1; | ||
| 2977 | + if ((endptr[0] != '\n') || (endptr[1] != '\0')) { | ||
| 2978 | 2978 | PyErr_SetString(PyExc_ValueError, "could not convert string to float"); | |
| 2979 | 2979 | return -1; | |
| 2980 | 2980 | } | |
| 2981 | - | ||
| 2982 | - if ((value = PyFloat_FromDouble(d)) == NULL) | ||
| 2981 | + value = PyFloat_FromDouble(d); | ||
| 2982 | + if (value == NULL) | ||
| 2983 | 2983 | return -1; | |
| 2984 | 2984 | ||
| 2985 | 2985 | PDATA_PUSH(self->stack, value, -1); | |
| 2986 | 2986 | return 0; | |
| 2987 | - } | ||
| 2987 | + } | ||
| 2988 | 2988 | ||
| 2989 | 2989 | static int | |
| 2990 | 2990 | load_binfloat(UnpicklerObject *self) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1045,6 +1045,54 @@ test_with_docstring(PyObject *self) | |||
| 1045 | 1045 | Py_RETURN_NONE; | |
| 1046 | 1046 | } | |
| 1047 | 1047 | ||
| 1048 | + /* Test PyOS_string_to_double. */ | ||
| 1049 | + static PyObject * | ||
| 1050 | + test_string_to_double(PyObject *self) { | ||
| 1051 | + double result; | ||
| 1052 | + char *msg; | ||
| 1053 | + | ||
| 1054 | + #define CHECK_STRING(STR, expected) \ | ||
| 1055 | + result = PyOS_string_to_double(STR, NULL, NULL); \ | ||
| 1056 | + if (result == -1.0 && PyErr_Occurred()) \ | ||
| 1057 | + return NULL; \ | ||
| 1058 | + if (result != expected) { \ | ||
| 1059 | + msg = "conversion of " STR " to float failed"; \ | ||
| 1060 | + goto fail; \ | ||
| 1061 | + } | ||
| 1062 | + | ||
| 1063 | + #define CHECK_INVALID(STR) \ | ||
| 1064 | + result = PyOS_string_to_double(STR, NULL, NULL); \ | ||
| 1065 | + if (result == -1.0 && PyErr_Occurred()) { \ | ||
| 1066 | + if (PyErr_ExceptionMatches(PyExc_ValueError)) \ | ||
| 1067 | + PyErr_Clear(); \ | ||
| 1068 | + else \ | ||
| 1069 | + return NULL; \ | ||
| 1070 | + } \ | ||
| 1071 | + else { \ | ||
| 1072 | + msg = "conversion of " STR " didn't raise ValueError"; \ | ||
| 1073 | + goto fail; \ | ||
| 1074 | + } | ||
| 1075 | + | ||
| 1076 | + CHECK_STRING("0.1", 0.1); | ||
| 1077 | + CHECK_STRING("1.234", 1.234); | ||
| 1078 | + CHECK_STRING("-1.35", -1.35); | ||
| 1079 | + CHECK_STRING(".1e01", 1.0); | ||
| 1080 | + CHECK_STRING("2.e-2", 0.02); | ||
| 1081 | + | ||
| 1082 | + CHECK_INVALID(" 0.1"); | ||
| 1083 | + CHECK_INVALID("\t\n-3"); | ||
| 1084 | + CHECK_INVALID(".123 "); | ||
| 1085 | + CHECK_INVALID("3\n"); | ||
| 1086 | + CHECK_INVALID("123abc"); | ||
| 1087 | + | ||
| 1088 | + Py_RETURN_NONE; | ||
| 1089 | + fail: | ||
| 1090 | + return raiseTestError("test_string_to_double", msg); | ||
| 1091 | + #undef CHECK_STRING | ||
| 1092 | + #undef CHECK_INVALID | ||
| 1093 | + } | ||
| 1094 | + | ||
| 1095 | + | ||
| 1048 | 1096 | #ifdef HAVE_GETTIMEOFDAY | |
| 1049 | 1097 | /* Profiling of integer performance */ | |
| 1050 | 1098 | static void print_delta(int test, struct timeval *s, struct timeval *e) | |
@@ -1223,6 +1271,7 @@ static PyMethodDef TestMethods[] = { | |||
| 1223 | 1271 | {"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS}, | |
| 1224 | 1272 | {"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS}, | |
| 1225 | 1273 | {"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS}, | |
| 1274 | + {"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS}, | ||
| 1226 | 1275 | {"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS, | |
| 1227 | 1276 | PyDoc_STR("This is a pretty normal docstring.")}, | |
| 1228 | 1277 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -799,25 +799,26 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) | |||
| 799 | 799 | */ | |
| 800 | 800 | ||
| 801 | 801 | /* first look for forms starting with <float> */ | |
| 802 | - errno = 0; | ||
| 803 | - z = PyOS_ascii_strtod(s, &end); | ||
| 804 | - if (end == s && errno == ENOMEM) | ||
| 805 | - return PyErr_NoMemory(); | ||
| 806 | - if (errno == ERANGE && fabs(z) >= 1.0) | ||
| 807 | - goto overflow; | ||
| 808 | - | ||
| 802 | + z = PyOS_string_to_double(s, &end, PyExc_OverflowError); | ||
| 803 | + if (z == -1.0 && PyErr_Occurred()) { | ||
| 804 | + if (PyErr_ExceptionMatches(PyExc_ValueError)) | ||
| 805 | + PyErr_Clear(); | ||
| 806 | + else | ||
| 807 | + return NULL; | ||
| 808 | + } | ||
| 809 | 809 | if (end != s) { | |
| 810 | 810 | /* all 4 forms starting with <float> land here */ | |
| 811 | 811 | s = end; | |
| 812 | 812 | if (*s == '+' || *s == '-') { | |
| 813 | 813 | /* <float><signed-float>j | <float><sign>j */ | |
| 814 | 814 | x = z; | |
| 815 | - errno = 0; | ||
| 816 | - y = PyOS_ascii_strtod(s, &end); | ||
| 817 | - if (end == s && errno == ENOMEM) | ||
| 818 | - return PyErr_NoMemory(); | ||
| 819 | - if (errno == ERANGE && fabs(y) >= 1.0) | ||
| 820 | - goto overflow; | ||
| 815 | + y = PyOS_string_to_double(s, &end, PyExc_OverflowError); | ||
| 816 | + if (y == -1.0 && PyErr_Occurred()) { | ||
| 817 | + if (PyErr_ExceptionMatches(PyExc_ValueError)) | ||
| 818 | + PyErr_Clear(); | ||
| 819 | + else | ||
| 820 | + return NULL; | ||
| 821 | + } | ||
| 821 | 822 | if (end != s) | |
| 822 | 823 | /* <float><signed-float>j */ | |
| 823 | 824 | s = end; | |
@@ -877,11 +878,6 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) | |||
| 877 | 878 | PyErr_SetString(PyExc_ValueError, | |
| 878 | 879 | "complex() arg is a malformed string"); | |
| 879 | 880 | return NULL; | |
| 880 | - | ||
| 881 | - overflow: | ||
| 882 | - PyErr_SetString(PyExc_OverflowError, | ||
| 883 | - "complex() arg overflow"); | ||
| 884 | - return NULL; | ||
| 885 | 881 | } | |
| 886 | 882 | ||
| 887 | 883 | static PyObject * | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -193,36 +193,20 @@ PyFloat_FromString(PyObject *v) | |||
| 193 | 193 | /* We don't care about overflow or underflow. If the platform | |
| 194 | 194 | * supports them, infinities and signed zeroes (on underflow) are | |
| 195 | 195 | * fine. */ | |
| 196 | - errno = 0; | ||
| 197 | - PyFPE_START_PROTECT("strtod", goto error) | ||
| 198 | - x = PyOS_ascii_strtod(s, (char **)&end); | ||
| 199 | - PyFPE_END_PROTECT(x) | ||
| 200 | - if (end == s) { | ||
| 201 | - if (errno == ENOMEM) | ||
| 202 | - PyErr_NoMemory(); | ||
| 203 | - else { | ||
| 204 | - PyOS_snprintf(buffer, sizeof(buffer), | ||
| 205 | - "invalid literal for float(): %.200s", s); | ||
| 206 | - PyErr_SetString(PyExc_ValueError, buffer); | ||
| 207 | - } | ||
| 196 | + x = PyOS_string_to_double(s, (char **)&end, NULL); | ||
| 197 | + if (x == -1.0 && PyErr_Occurred()) | ||
| 208 | 198 | goto error; | |
| 209 | - } | ||
| 210 | - /* Since end != s, the platform made *some* kind of sense out | ||
| 211 | - of the input. Trust it. */ | ||
| 212 | 199 | while (*end && isspace(Py_CHARMASK(*end))) | |
| 213 | 200 | end++; | |
| 214 | - if (end != last) { | ||
| 215 | - if (*end == '\0') | ||
| 216 | - PyErr_SetString(PyExc_ValueError, | ||
| 217 | - "null byte in argument for float()"); | ||
| 218 | - else { | ||
| 219 | - PyOS_snprintf(buffer, sizeof(buffer), | ||
| 220 | - "invalid literal for float(): %.200s", s); | ||
| 221 | - PyErr_SetString(PyExc_ValueError, buffer); | ||
| 222 | - } | ||
| 223 | - goto error; | ||
| 201 | + if (end == last) | ||
| 202 | + result = PyFloat_FromDouble(x); | ||
| 203 | + else { | ||
| 204 | + PyOS_snprintf(buffer, sizeof(buffer), | ||
| 205 | + "invalid literal for float(): %.200s", s); | ||
| 206 | + PyErr_SetString(PyExc_ValueError, buffer); | ||
| 207 | + result = NULL; | ||
| 224 | 208 | } | |
| 225 | - result = PyFloat_FromDouble(x); | ||
| 209 | + | ||
| 226 | 210 | error: | |
| 227 | 211 | if (s_buffer) | |
| 228 | 212 | PyMem_FREE(s_buffer); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3162,18 +3162,18 @@ parsenumber(struct compiling *c, const char *s) | |||
| 3162 | 3162 | #ifndef WITHOUT_COMPLEX | |
| 3163 | 3163 | if (imflag) { | |
| 3164 | 3164 | compl.real = 0.; | |
| 3165 | - PyFPE_START_PROTECT("atof", return 0) | ||
| 3166 | - compl.imag = PyOS_ascii_atof(s); | ||
| 3167 | - PyFPE_END_PROTECT(c) | ||
| 3168 | - return PyComplex_FromCComplex(compl); | ||
| 3165 | + compl.imag = PyOS_string_to_double(s, (char **)&end, NULL); | ||
| 3166 | + if (compl.imag == -1.0 && PyErr_Occurred()) | ||
| 3167 | + return NULL; | ||
| 3168 | + return PyComplex_FromCComplex(compl); | ||
| 3169 | 3169 | } | |
| 3170 | 3170 | else | |
| 3171 | 3171 | #endif | |
| 3172 | 3172 | { | |
| 3173 | - PyFPE_START_PROTECT("atof", return 0) | ||
| 3174 | - dx = PyOS_ascii_atof(s); | ||
| 3175 | - PyFPE_END_PROTECT(dx) | ||
| 3176 | - return PyFloat_FromDouble(dx); | ||
| 3173 | + dx = PyOS_string_to_double(s, NULL, NULL); | ||
| 3174 | + if (dx == -1.0 && PyErr_Occurred()) | ||
| 3175 | + return NULL; | ||
| 3176 | + return PyFloat_FromDouble(dx); | ||
| 3177 | 3177 | } | |
| 3178 | 3178 | } | |
| 3179 | 3179 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,6 +61,9 @@ | |||
| 61 | 61 | * that hasn't been MALLOC'ed, private_mem should only be used when k <= | |
| 62 | 62 | * Kmax. | |
| 63 | 63 | * | |
| 64 | + * 7. _Py_dg_strtod has been modified so that it doesn't accept strings with | ||
| 65 | + * leading whitespace. | ||
| 66 | + * | ||
| 64 | 67 | ***************************************************************/ | |
| 65 | 68 | ||
| 66 | 69 | /* Please send bug reports for the original dtoa.c code to David M. Gay (dmg | |
@@ -1355,13 +1358,15 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1355 | 1358 | /* no break */ | |
| 1356 | 1359 | case 0: | |
| 1357 | 1360 | goto ret0; | |
| 1361 | + /* modify original dtoa.c so that it doesn't accept leading whitespace | ||
| 1358 | 1362 | case '\t': | |
| 1359 | 1363 | case '\n': | |
| 1360 | 1364 | case '\v': | |
| 1361 | 1365 | case '\f': | |
| 1362 | 1366 | case '\r': | |
| 1363 | 1367 | case ' ': | |
| 1364 | 1368 | continue; | |
| 1369 | + */ | ||
| 1365 | 1370 | default: | |
| 1366 | 1371 | goto break2; | |
| 1367 | 1372 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -670,18 +670,17 @@ r_object(RFILE *p) | |||
| 670 | 670 | { | |
| 671 | 671 | char buf[256]; | |
| 672 | 672 | double dx; | |
| 673 | + retval = NULL; | ||
| 673 | 674 | n = r_byte(p); | |
| 674 | 675 | if (n == EOF || r_string(buf, (int)n, p) != n) { | |
| 675 | 676 | PyErr_SetString(PyExc_EOFError, | |
| 676 | 677 | "EOF read where object expected"); | |
| 677 | - retval = NULL; | ||
| 678 | 678 | break; | |
| 679 | 679 | } | |
| 680 | 680 | buf[n] = '\0'; | |
| 681 | - retval = NULL; | ||
| 682 | - PyFPE_START_PROTECT("atof", break) | ||
| 683 | - dx = PyOS_ascii_atof(buf); | ||
| 684 | - PyFPE_END_PROTECT(dx) | ||
| 681 | + dx = PyOS_string_to_double(buf, NULL, NULL); | ||
| 682 | + if (dx == -1.0 && PyErr_Occurred()) | ||
| 683 | + break; | ||
| 685 | 684 | retval = PyFloat_FromDouble(dx); | |
| 686 | 685 | break; | |
| 687 | 686 | } | |
@@ -710,29 +709,27 @@ r_object(RFILE *p) | |||
| 710 | 709 | { | |
| 711 | 710 | char buf[256]; | |
| 712 | 711 | Py_complex c; | |
| 712 | + retval = NULL; | ||
| 713 | 713 | n = r_byte(p); | |
| 714 | 714 | if (n == EOF || r_string(buf, (int)n, p) != n) { | |
| 715 | 715 | PyErr_SetString(PyExc_EOFError, | |
| 716 | 716 | "EOF read where object expected"); | |
| 717 | - retval = NULL; | ||
| 718 | 717 | break; | |
| 719 | 718 | } | |
| 720 | 719 | buf[n] = '\0'; | |
| 721 | - retval = NULL; | ||
| 722 | - PyFPE_START_PROTECT("atof", break;) | ||
| 723 | - c.real = PyOS_ascii_atof(buf); | ||
| 724 | - PyFPE_END_PROTECT(c) | ||
| 720 | + c.real = PyOS_string_to_double(buf, NULL, NULL); | ||
| 721 | + if (c.real == -1.0 && PyErr_Occurred()) | ||
| 722 | + break; | ||
| 725 | 723 | n = r_byte(p); | |
| 726 | 724 | if (n == EOF || r_string(buf, (int)n, p) != n) { | |
| 727 | 725 | PyErr_SetString(PyExc_EOFError, | |
| 728 | 726 | "EOF read where object expected"); | |
| 729 | - retval = NULL; | ||
| 730 | 727 | break; | |
| 731 | 728 | } | |
| 732 | 729 | buf[n] = '\0'; | |
| 733 | - PyFPE_START_PROTECT("atof", break) | ||
| 734 | - c.imag = PyOS_ascii_atof(buf); | ||
| 735 | - PyFPE_END_PROTECT(c) | ||
| 730 | + c.imag = PyOS_string_to_double(buf, NULL, NULL); | ||
| 731 | + if (c.imag == -1.0 && PyErr_Occurred()) | ||
| 732 | + break; | ||
| 736 | 733 | retval = PyComplex_FromCComplex(c); | |
| 737 | 734 | break; | |
| 738 | 735 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments