mirror of
https://github.com/subsurface/subsurface.git
synced 2024-12-11 19:41:30 +00:00
4ee5d08a46
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
120 lines
2.2 KiB
C++
120 lines
2.2 KiB
C++
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Sane helper for 'strtod()'.
|
|
*
|
|
* Sad that we even need this, but the C library version has
|
|
* insane locale behavior, and while the Qt "toDouble()" routines
|
|
* are better in that regard, they don't have an end pointer
|
|
* (having replaced it with the completely idiotic "ok" boolean
|
|
* pointer instead).
|
|
*
|
|
* So if you want the C locale kind of parsing, use the
|
|
* ascii_strtod() function. But if you want a more relaxed
|
|
* "Hey, Europeans are people too, even if they have locales
|
|
* with commas", use general_strtod() instead.
|
|
*/
|
|
#include <ctype.h>
|
|
#include "subsurface-string.h"
|
|
|
|
static double strtod_flags(const char *str, const char **ptr, bool no_comma)
|
|
{
|
|
char c;
|
|
const char *p = str, *ep;
|
|
double val = 0.0;
|
|
double decimal = 1.0;
|
|
bool sign = false, esign = false;
|
|
bool numbers = false, dot = false;
|
|
|
|
/* skip spaces */
|
|
while (isspace(c = *p++))
|
|
/* */;
|
|
|
|
/* optional sign */
|
|
switch (c) {
|
|
case '-':
|
|
sign = true;
|
|
/* fallthrough */
|
|
case '+':
|
|
c = *p++;
|
|
}
|
|
|
|
/* Mantissa */
|
|
for (;; c = *p++) {
|
|
if (c == '.' || (c == ',' && !no_comma)) {
|
|
if (dot)
|
|
goto done;
|
|
dot = true;
|
|
continue;
|
|
}
|
|
if (c >= '0' && c <= '9') {
|
|
numbers = true;
|
|
val = (val * 10) + (c - '0');
|
|
if (dot)
|
|
decimal *= 10;
|
|
continue;
|
|
}
|
|
if (c != 'e' && c != 'E')
|
|
goto done;
|
|
break;
|
|
}
|
|
|
|
if (!numbers)
|
|
goto done;
|
|
|
|
/* Exponent */
|
|
ep = p;
|
|
c = *ep++;
|
|
switch (c) {
|
|
case '-':
|
|
esign = true;
|
|
/* 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)
|
|
decimal *= 10;
|
|
else
|
|
decimal /= 10;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (!numbers)
|
|
goto no_conversion;
|
|
if (ptr)
|
|
*ptr = p - 1;
|
|
return (sign ? -val : val) / decimal;
|
|
|
|
no_conversion:
|
|
if (ptr)
|
|
*ptr = str;
|
|
return 0.0;
|
|
}
|
|
|
|
extern "C" double permissive_strtod(const char *str, const char **ptr)
|
|
{
|
|
return strtod_flags(str, ptr, false);
|
|
}
|
|
|
|
extern "C" double ascii_strtod(const char *str, const char **ptr)
|
|
{
|
|
return strtod_flags(str, ptr, true);
|
|
}
|