summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2013-10-07 08:57:27 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-10-07 09:26:08 -0700
commit8ba5423e65b59163080c5ccee8e40d0c5e5a42b6 (patch)
treec32e2a693a88e0fdd6bd0ecd29195564208936e2
parent79f907eb277227c2d386c1474985391d3d65009d (diff)
downloadsubsurface-8ba5423e65b59163080c5ccee8e40d0c5e5a42b6.tar.gz
ascii_strtod that actually does what we need
Dirk's ascii_strtod was blindly copied from other GPL code and didn't do what was the main purpose (i.e. ignore the locale and still accept the numbers we have in our data files). This implementation does *not* care about INF/NaN, and it does *not* try to handle some strange conditions (overflow/underflow), and I do *not* guarantee that it doesn't have rounding issues. That said, for our native format, we never print odd FP numbers anyway (since we use fixed-point integer arithmetic), and while we *do* care about exponents for some of the odder import formats (I remember seeing them in jdivelog output), we don't care about the crazy cases. So rather than worry about getting the edge cases right for the max double exponents (around +-308), it just says "screw you" and gives you something close enough. So what it *does* try to do is handle the actual parsing right, and get the right answer for all the reasonable cases. Works-For-Me(tm). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-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;
}