aboutsummaryrefslogtreecommitdiffstats
path: root/parse-xml.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse-xml.c')
-rw-r--r--parse-xml.c150
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;
}