diff options
Diffstat (limited to 'parse-xml.c')
-rw-r--r-- | parse-xml.c | 150 |
1 files changed, 78 insertions, 72 deletions
diff --git a/parse-xml.c b/parse-xml.c index b301aefec..edb30e112 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -239,88 +239,94 @@ enum number_type { double ascii_strtod(char *str, char **ptr) { - char *p; - - if (ptr == (char **)0) - return atof (str); - - p = str; - - while (isspace (*p)) - ++p; - - if (*p == '+' || *p == '-') - ++p; - - /* INF or INFINITY. */ - if ((p[0] == 'i' || p[0] == 'I') - && (p[1] == 'n' || p[1] == 'N') - && (p[2] == 'f' || p[2] == 'F')) - { - if ((p[3] == 'i' || p[3] == 'I') - && (p[4] == 'n' || p[4] == 'N') - && (p[5] == 'i' || p[5] == 'I') - && (p[6] == 't' || p[6] == 'T') - && (p[7] == 'y' || p[7] == 'Y')) - { - *ptr = p + 7; - return atof (str); + char *p = str, c, *ep; + double val = 0.0; + double decimal; + int sign = 0, esign = 0; + int numbers = 0, dot = 0; + + /* skip spaces */ + while (isspace(c = *p++)) + /* */; + + /* optional sign */ + switch (c) { + case '-': + sign = 1; + /* fallthrough */ + case '+': + c = *p++; + } + + /* Mantissa */ + for (;;c = *p++) { + if (c == '.') { + if (dot) + goto done; + dot = 1; + decimal = 1.0; + continue; } - else - { - *ptr = p + 3; - return atof (str); + if (c >= '0' && c <= '9') { + numbers++; + if (dot) { + decimal /= 10; + val += (c - '0') * decimal; + } else { + val = (val * 10) + (c - '0'); + } + continue; } + if (c != 'e' && c != 'E') + goto done; + break; } - /* NAN or NAN(foo). */ - if ((p[0] == 'n' || p[0] == 'N') - && (p[1] == 'a' || p[1] == 'A') - && (p[2] == 'n' || p[2] == 'N')) - { - p += 3; - if (*p == '(') - { - ++p; - while (*p != '\0' && *p != ')') - ++p; - if (*p == ')') - ++p; - } - *ptr = p; - return atof (str); + if (!numbers) + goto done; + + /* Exponent */ + ep = p; + c = *ep++; + switch (c) { + case '-': + esign = 1; + /* fallthrough */ + case '+': + c = *ep++; } - /* digits, with 0 or 1 periods in it. */ - if (isdigit (*p) || *p == '.') - { - int got_dot = 0; - while (isdigit (*p) || (!got_dot && *p == '.')) - { - if (*p == '.') - got_dot = 1; - ++p; + if (c >= '0' && c <= '9') { + p = ep; + int exponent = c - '0'; + + for (;;) { + c = *p++; + if (c < '0' || c > '9') + break; + exponent *= 10; + exponent += c - '0'; } - /* Exponent. */ - if (*p == 'e' || *p == 'E') - { - int i; - i = 1; - if (p[i] == '+' || p[i] == '-') - ++i; - if (isdigit (p[i])) - { - while (isdigit (p[i])) - ++i; - *ptr = p + i; - return atof (str); - } + /* We're not going to bother playing games */ + if (exponent > 308) + exponent = 308; + + while (exponent-- > 0) { + if (esign) + val /= 10; + else + val *= 10; } - *ptr = p; - return atof (str); } - /* Didn't find any digits. Doesn't look like a number. */ + +done: + if (!numbers) + goto no_conversion; + *ptr = p-1; + return sign ? -val : val; + +no_conversion: *ptr = str; return 0.0; } |