mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-17 20:16:16 +00:00
Make our 'ascii_strtod()' helper more generic
We'll want to do sane parsing of strings, but the C library makes it hard to handle user input sanely and the Qt toDouble() function interface was designed by a retarded chipmunk. So just extend our existing hacky "ascii_strtod()" to allow a more generic interface. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
5511a0e14e
commit
cb53a78674
4 changed files with 144 additions and 96 deletions
14
dive.h
14
dive.h
|
@ -618,7 +618,6 @@ struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset);
|
|||
/* Check if two dive computer entries are the exact same dive (-1=no/0=maybe/1=yes) */
|
||||
extern int match_one_dc(struct divecomputer *a, struct divecomputer *b);
|
||||
|
||||
extern double ascii_strtod(char *, char **);
|
||||
extern void parse_xml_init(void);
|
||||
extern void parse_xml_buffer(const char *url, const char *buf, int size, struct dive_table *table, const char **params, char **error);
|
||||
extern void parse_xml_exit(void);
|
||||
|
@ -783,6 +782,19 @@ extern bool weightsystems_equal(weightsystem_t *ws1, weightsystem_t *ws2);
|
|||
extern void remove_cylinder(struct dive *dive, int idx);
|
||||
extern void remove_weightsystem(struct dive *dive, int idx);
|
||||
|
||||
/*
|
||||
* String handling.
|
||||
*/
|
||||
#define STRTOD_NO_SIGN 0x01
|
||||
#define STRTOD_NO_DOT 0x02
|
||||
#define STRTOD_NO_COMMA 0x04
|
||||
#define STRTOD_NO_EXPONENT 0x08
|
||||
extern double strtod_flags(char *str, char **ptr, unsigned int flags);
|
||||
|
||||
#define STRTOD_ASCII (STRTOD_NO_COMMA)
|
||||
|
||||
#define ascii_strtod(str,ptr) strtod_flags(str,ptr,STRTOD_ASCII)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
95
parse-xml.c
95
parse-xml.c
|
@ -263,101 +263,6 @@ enum number_type {
|
|||
FLOAT
|
||||
};
|
||||
|
||||
double ascii_strtod(char *str, char **ptr)
|
||||
{
|
||||
char *p = str, c, *ep;
|
||||
double val = 0.0;
|
||||
double decimal = 1.0;
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (ptr)
|
||||
*ptr = p-1;
|
||||
return sign ? -val : val;
|
||||
|
||||
no_conversion:
|
||||
if (ptr)
|
||||
*ptr = str;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static enum number_type parse_float(char *buffer, double *res, char **endp)
|
||||
{
|
||||
double val;
|
||||
|
|
130
strtod.c
Normal file
130
strtod.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Sane helper for 'strtod()'.
|
||||
*
|
||||
* Sad that we even need this, but the C library version has
|
||||
* insane locale behavior, and while the Qt "doDouble()" routines
|
||||
* are better in that regard, they don't have an end pointer
|
||||
* (having replaced it with the completely idiotic "ok" boolean
|
||||
* pointer instead).
|
||||
*
|
||||
* I wonder what drugs people are on sometimes.
|
||||
*
|
||||
* Right now we support the following flags to limit the
|
||||
* parsing some ways:
|
||||
*
|
||||
* STRTOD_NO_SIGN - don't accept signs
|
||||
* STRTOD_NO_DOT - no decimal dots, I'm European
|
||||
* STRTOD_NO_COMMA - no comma, please, I'm C locale
|
||||
* STRTOD_NO_EXPONENT - no exponent parsing, I'm human
|
||||
*
|
||||
* The "negative" flags are so that the common case can just
|
||||
* use a flag value of 0, and only if you have some special
|
||||
* requirements do you need to state those with explicit flags.
|
||||
*
|
||||
* So if you want the C locale kind of parsing, you'd use the
|
||||
* STRTOD_NO_COMMA flag to disallow a decimal comma. But if you
|
||||
* want a more relaxed "Hey, Europeans are people too, even if
|
||||
* they have locales with commas", just pass in a zero flag.
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include "dive.h"
|
||||
|
||||
double strtod_flags(char *str, char **ptr, unsigned int flags)
|
||||
{
|
||||
char *p = str, c, *ep;
|
||||
double val = 0.0;
|
||||
double decimal = 1.0;
|
||||
int sign = 0, esign = 0;
|
||||
int numbers = 0, dot = 0;
|
||||
|
||||
/* skip spaces */
|
||||
while (isspace(c = *p++))
|
||||
/* */;
|
||||
|
||||
/* optional sign */
|
||||
if (!(flags & STRTOD_NO_SIGN)) {
|
||||
switch (c) {
|
||||
case '-':
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mantissa */
|
||||
for (;;c = *p++) {
|
||||
if ((c == '.' && !(flags & STRTOD_NO_DOT)) ||
|
||||
(c == ',' && !(flags & STRTOD_NO_COMMA))) {
|
||||
if (dot)
|
||||
goto done;
|
||||
dot = 1;
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (flags & STRTOD_NO_EXPONENT)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
if (ptr)
|
||||
*ptr = p-1;
|
||||
return sign ? -val : val;
|
||||
|
||||
no_conversion:
|
||||
if (ptr)
|
||||
*ptr = str;
|
||||
return 0.0;
|
||||
}
|
|
@ -98,6 +98,7 @@ SOURCES = \
|
|||
save-xml.c \
|
||||
sha1.c \
|
||||
statistics.c \
|
||||
strtod.c \
|
||||
subsurfacestartup.c \
|
||||
time.c \
|
||||
uemis.c \
|
||||
|
|
Loading…
Add table
Reference in a new issue