diff -r 1d9f730717b8 Objects/complexobject.c --- a/Objects/complexobject.c Wed Dec 31 05:08:55 2008 +0100 +++ b/Objects/complexobject.c Wed Dec 31 16:36:18 2008 +0900 @@ -861,21 +861,113 @@ {0}, }; +/* + * Parse sign in string s, and put the result in sign + * + * Return the string at position just after the sign if successfull, NULL + * otherwise + */ +static const char* +parse_sign(const char *s, int *sign) +{ + *sign = 1; + + switch (*s) { + case '-': + *sign = -1; + /* Fallthrough */ + case '+': + s++; + if (*s=='\0'||*s=='+'||*s=='-'||*s==')'|| + isspace(Py_CHARMASK(*s))) { + return NULL; + } + break; + default: + break; + } + + return s; +} + +/* + * Parse one part (imaginary or real) of a complex number. Assumes the string + * starts right at the beginning of the number (number including sign). + * + * Return the string at position just after the number if successfull, NULL + * otherwise, and the value into val + * + * ebuf is a buffer for error: if an error happened, ebuf may contain some + * informations about it. ebuf is not touched otherwise. ebuflen is the max number + * of bytes which can be written to ebuf (including '\0'). + * + * Handle nan and inf + */ +static const char* +parse_part(const char* s, double *val, char *ebuf, size_t ebuflen) +{ + int digit_or_dot = 0; + const char *ret; + char *end; + int sign; + + ret = parse_sign(s, &sign); + if (ret == NULL) { + goto parse_error; + } + s = ret; + + if (isspace(Py_CHARMASK(*s))) { + goto parse_error; + } else if (PyOS_strnicmp(s, "inf", 3) == 0) { + s += 3; + if (PyOS_strnicmp(s, "inite", 5) == 0) { + s += 5; + } + *val = sign * Py_HUGE_VAL; + } else if (PyOS_strnicmp(s, "nan", 3) == 0) { + s += 3; + *val = Py_NAN; + } else { + /* Parse 'normal number' */ + digit_or_dot = + (*s=='.' || isdigit(Py_CHARMASK(*s))); + if (!digit_or_dot) { + goto parse_error; + } + errno = 0; + PyFPE_START_PROTECT("strtod", goto parse_error) + *val = PyOS_ascii_strtod(s, &end) ; + PyFPE_END_PROTECT(*val) + if (errno != 0) { + PyOS_snprintf(ebuf, ebuflen, + "float() out of range: %.150s", s); + goto parse_error; + } + *val *= sign; + + s=end; + } + + return s; + +parse_error: + return NULL; +} + static PyObject * complex_subtype_from_string(PyTypeObject *type, PyObject *v) { - const char *s, *start; - char *end; - double x=0.0, y=0.0, z; - int got_re=0, got_im=0, got_bracket=0, done=0; - int digit_or_dot; - int sw_error=0; - int sign; + const char *s, *start, *ret; + double x, y, z; + int got_bracket=0; char buffer[256]; /* For errors */ #ifdef Py_USING_UNICODE char s_buffer[256]; #endif Py_ssize_t len; + + buffer[0] = '\0'; if (PyString_Check(v)) { s = PyString_AS_STRING(v); @@ -920,120 +1012,66 @@ s++; } - z = -1.0; - sign = 1; - do { + /* Parse first number */ + ret = parse_part(s, &z, buffer, sizeof(buffer)); + if (ret == NULL) { + goto parse_error; + } + s = ret; - switch (*s) { + if (*s == 'j' || *s == 'J') { + x = 0; + y = z; + s += 1; + } else { + x = z; - case '\0': - if (s-start != len) { - PyErr_SetString( - PyExc_ValueError, - "complex() arg contains a null byte"); - return NULL; - } - if(!done) sw_error=1; - break; + if (*s != '\0') { + /* Parse 2nd number */ - case ')': - if (!got_bracket || !(got_re || got_im)) { - sw_error=1; - break; - } - got_bracket=0; - done=1; - s++; - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (*s) sw_error=1; - break; + ret = parse_part(s, &z, buffer, sizeof(buffer)); + if (ret == NULL) { + goto parse_error; + } + s = ret; - case '-': - sign = -1; - /* Fallthrough */ - case '+': - if (done) sw_error=1; - s++; - if ( *s=='\0'||*s=='+'||*s=='-'||*s==')'|| - isspace(Py_CHARMASK(*s)) ) sw_error=1; - break; + /* Check it was an imaginary number */ + if (*s == 'j' || *s == 'J') { + s += 1; + } else { + goto parse_error; + } + y = z; + } else { + y = 0; + } + } - case 'J': - case 'j': - if (got_im || done) { - sw_error = 1; - break; - } - if (z<0.0) { - y=sign; - } - else{ - y=sign*z; - } - got_im=1; - s++; - if (*s!='+' && *s!='-' ) - done=1; - break; + if (*s == ')') { + if (!got_bracket) { + goto parse_error; + } + s += 1; + } + /* Got ( without ) */ + else if (got_bracket) { + goto parse_error; + } - default: - if (isspace(Py_CHARMASK(*s))) { - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (*s && *s != ')') - sw_error=1; - else - done = 1; - break; - } - digit_or_dot = - (*s=='.' || isdigit(Py_CHARMASK(*s))); - if (done||!digit_or_dot) { - sw_error=1; - break; - } - errno = 0; - PyFPE_START_PROTECT("strtod", return 0) - z = PyOS_ascii_strtod(s, &end) ; - PyFPE_END_PROTECT(z) - if (errno != 0) { - PyOS_snprintf(buffer, sizeof(buffer), - "float() out of range: %.150s", s); - PyErr_SetString( - PyExc_ValueError, - buffer); - return NULL; - } - s=end; - if (*s=='J' || *s=='j') { - - break; - } - if (got_re) { - sw_error=1; - break; - } - - /* accept a real part */ - x=sign*z; - got_re=1; - if (got_im) done=1; - z = -1.0; - sign = 1; - break; - - } /* end of switch */ - - } while (s - start < len && !sw_error); - - if (sw_error || got_bracket) { - PyErr_SetString(PyExc_ValueError, - "complex() arg is a malformed string"); - return NULL; - } + if (*s != '\0') { + goto parse_error; + } return complex_subtype_from_doubles(type, x, y); + +parse_error: + if (buffer[0] != '\0') { + PyErr_SetString(PyExc_ValueError, buffer); + } else { + PyErr_SetString(PyExc_ValueError, + "complex() arg is a malformed string"); + } + return NULL; } static PyObject *