mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +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) */
|
/* 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 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_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_buffer(const char *url, const char *buf, int size, struct dive_table *table, const char **params, char **error);
|
||||||
extern void parse_xml_exit(void);
|
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_cylinder(struct dive *dive, int idx);
|
||||||
extern void remove_weightsystem(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
95
parse-xml.c
95
parse-xml.c
|
@ -263,101 +263,6 @@ enum number_type {
|
||||||
FLOAT
|
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)
|
static enum number_type parse_float(char *buffer, double *res, char **endp)
|
||||||
{
|
{
|
||||||
double val;
|
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 \
|
save-xml.c \
|
||||||
sha1.c \
|
sha1.c \
|
||||||
statistics.c \
|
statistics.c \
|
||||||
|
strtod.c \
|
||||||
subsurfacestartup.c \
|
subsurfacestartup.c \
|
||||||
time.c \
|
time.c \
|
||||||
uemis.c \
|
uemis.c \
|
||||||
|
|
Loading…
Add table
Reference in a new issue