diff options
Diffstat (limited to 'Python/pystrtod.c')
-rw-r--r-- | Python/pystrtod.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/Python/pystrtod.c b/Python/pystrtod.c index 209c908..64d0c52 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -370,6 +370,72 @@ PyOS_string_to_double(const char *s, return result; } +/* Remove underscores that follow the underscore placement rule from + the string and then call the `innerfunc` function on the result. + It should return a new object or NULL on exception. + + `what` is used for the error message emitted when underscores are detected + that don't follow the rule. `arg` is an opaque pointer passed to the inner + function. + + This is used to implement underscore-agnostic conversion for floats + and complex numbers. +*/ +PyObject * +_Py_string_to_number_with_underscores( + const char *s, Py_ssize_t orig_len, const char *what, PyObject *obj, void *arg, + PyObject *(*innerfunc)(const char *, Py_ssize_t, void *)) +{ + char prev; + const char *p, *last; + char *dup, *end; + PyObject *result; + + if (strchr(s, '_') == NULL) { + return innerfunc(s, orig_len, arg); + } + + dup = PyMem_Malloc(orig_len + 1); + end = dup; + prev = '\0'; + last = s + orig_len; + for (p = s; *p; p++) { + if (*p == '_') { + /* Underscores are only allowed after digits. */ + if (!(prev >= '0' && prev <= '9')) { + goto error; + } + } + else { + *end++ = *p; + /* Underscores are only allowed before digits. */ + if (prev == '_' && !(*p >= '0' && *p <= '9')) { + goto error; + } + } + prev = *p; + } + /* Underscores are not allowed at the end. */ + if (prev == '_') { + goto error; + } + /* No embedded NULs allowed. */ + if (p != last) { + goto error; + } + *end = '\0'; + result = innerfunc(dup, end - dup, arg); + PyMem_Free(dup); + return result; + + error: + PyMem_Free(dup); + PyErr_Format(PyExc_ValueError, + "could not convert string to %s: " + "%R", what, obj); + return NULL; +} + #ifdef PY_NO_SHORT_FLOAT_REPR /* Given a string that may have a decimal point in the current @@ -881,12 +947,12 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val, #define OFS_E 2 /* The lengths of these are known to the code below, so don't change them */ -static char *lc_float_strings[] = { +static const char * const lc_float_strings[] = { "inf", "nan", "e", }; -static char *uc_float_strings[] = { +static const char * const uc_float_strings[] = { "INF", "NAN", "E", @@ -925,7 +991,8 @@ static char * format_float_short(double d, char format_code, int mode, int precision, int always_add_sign, int add_dot_0_if_integer, - int use_alt_formatting, char **float_strings, int *type) + int use_alt_formatting, const char * const *float_strings, + int *type) { char *buf = NULL; char *p = NULL; @@ -1176,7 +1243,7 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val, int flags, int *type) { - char **float_strings = lc_float_strings; + const char * const *float_strings = lc_float_strings; int mode; /* Validate format_code, and map upper and lower case. Compute the |