mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
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>
This commit is contained in:
parent
79f907eb27
commit
8ba5423e65
1 changed files with 80 additions and 74 deletions
154
parse-xml.c
154
parse-xml.c
|
@ -239,88 +239,94 @@ enum number_type {
|
|||
|
||||
double ascii_strtod(char *str, char **ptr)
|
||||
{
|
||||
char *p;
|
||||
char *p = str, c, *ep;
|
||||
double val = 0.0;
|
||||
double decimal;
|
||||
int sign = 0, esign = 0;
|
||||
int numbers = 0, dot = 0;
|
||||
|
||||
if (ptr == (char **)0)
|
||||
return atof (str);
|
||||
/* skip spaces */
|
||||
while (isspace(c = *p++))
|
||||
/* */;
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = p + 3;
|
||||
return atof (str);
|
||||
}
|
||||
/* optional sign */
|
||||
switch (c) {
|
||||
case '-':
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *p++;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Mantissa */
|
||||
for (;;c = *p++) {
|
||||
if (c == '.') {
|
||||
if (dot)
|
||||
goto done;
|
||||
dot = 1;
|
||||
decimal = 1.0;
|
||||
continue;
|
||||
}
|
||||
*ptr = p;
|
||||
return atof (str);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (c >= '0' && c <= '9') {
|
||||
numbers++;
|
||||
if (dot) {
|
||||
decimal /= 10;
|
||||
val += (c - '0') * decimal;
|
||||
} else {
|
||||
val = (val * 10) + (c - '0');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*ptr = p;
|
||||
return atof (str);
|
||||
if (c != 'e' && c != 'E')
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
/* Didn't find any digits. Doesn't look like a number. */
|
||||
|
||||
if (!numbers)
|
||||
goto done;
|
||||
|
||||
/* Exponent */
|
||||
ep = p;
|
||||
c = *ep++;
|
||||
switch (c) {
|
||||
case '-':
|
||||
esign = 1;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *ep++;
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
/* We're not going to bother playing games */
|
||||
if (exponent > 308)
|
||||
exponent = 308;
|
||||
|
||||
while (exponent-- > 0) {
|
||||
if (esign)
|
||||
val /= 10;
|
||||
else
|
||||
val *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (!numbers)
|
||||
goto no_conversion;
|
||||
*ptr = p-1;
|
||||
return sign ? -val : val;
|
||||
|
||||
no_conversion:
|
||||
*ptr = str;
|
||||
return 0.0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue