mirror of
https://github.com/subsurface/subsurface.git
synced 2024-12-05 00:21:29 +00:00
core: simplify custom strtod() interface
The strtod_flags() function allowed for fine control of how to parse strings. However, only two different modes were actually used: ascii mode ("C" locale) and permissive mode (accept "," and "." as decimal separator). The former had already its own function name (ascii_strtod). Make the latter a separatge function as well (permissive_strtod) and remove all the flags rigmarole. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
fa178ddb9b
commit
b6cabdf023
8 changed files with 57 additions and 73 deletions
|
@ -29,7 +29,7 @@ static int cobalt_profile_sample(void *param, int, char **data, char **)
|
|||
if (data[1])
|
||||
state->cur_sample->depth.mm = atoi(data[1]);
|
||||
if (data[2])
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0));
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(permissive_strtod(data[2], NULL)) : F_to_mkelvin(permissive_strtod(data[2], NULL));
|
||||
sample_end(state);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -284,7 +284,7 @@ static int divinglog_dive(void *param, int, char **data, char **)
|
|||
utf8_string(data[4], &state->cur_dive->notes);
|
||||
|
||||
if (data[5])
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[5], NULL, 0) * 1000);
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[5], NULL) * 1000);
|
||||
|
||||
if (data[6])
|
||||
state->cur_dive->dc.duration.seconds = atoi(data[6]) * 60;
|
||||
|
|
|
@ -23,8 +23,8 @@ static int shearwater_cylinders(void *param, int, char **data, char **)
|
|||
struct parser_state *state = (struct parser_state *)param;
|
||||
cylinder_t *cyl;
|
||||
|
||||
int o2 = lrint(strtod_flags(data[0], NULL, 0) * 1000);
|
||||
int he = lrint(strtod_flags(data[1], NULL, 0) * 1000);
|
||||
int o2 = lrint(permissive_strtod(data[0], NULL) * 1000);
|
||||
int he = lrint(permissive_strtod(data[1], NULL) * 1000);
|
||||
|
||||
/* Shearwater allows entering only 99%, not 100%
|
||||
* so assume 99% to be pure oxygen */
|
||||
|
@ -50,8 +50,8 @@ static int shearwater_changes(void *param, int columns, char **data, char **)
|
|||
if (!data[0] || !data[1] || !data[2]) {
|
||||
return 2;
|
||||
}
|
||||
int o2 = lrint(strtod_flags(data[1], NULL, 0) * 1000);
|
||||
int he = lrint(strtod_flags(data[2], NULL, 0) * 1000);
|
||||
int o2 = lrint(permissive_strtod(data[1], NULL) * 1000);
|
||||
int he = lrint(permissive_strtod(data[2], NULL) * 1000);
|
||||
|
||||
/* Shearwater allows entering only 99%, not 100%
|
||||
* so assume 99% to be pure oxygen */
|
||||
|
@ -101,11 +101,11 @@ static int shearwater_profile_sample(void *param, int, char **data, char **)
|
|||
|
||||
|
||||
if (data[1])
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0));
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(permissive_strtod(data[1], NULL) * 1000) : feet_to_mm(permissive_strtod(data[1], NULL));
|
||||
if (data[2])
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0));
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(permissive_strtod(data[2], NULL)) : F_to_mkelvin(permissive_strtod(data[2], NULL));
|
||||
if (data[3]) {
|
||||
state->cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000);
|
||||
state->cur_sample->setpoint.mbar = lrint(permissive_strtod(data[3], NULL) * 1000);
|
||||
}
|
||||
if (data[4])
|
||||
state->cur_sample->ndl.seconds = atoi(data[4]) * 60;
|
||||
|
@ -161,11 +161,11 @@ static int shearwater_ai_profile_sample(void *param, int, char **data, char **)
|
|||
state->cur_sample->time.seconds = atoi(data[0]);
|
||||
|
||||
if (data[1])
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0));
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(permissive_strtod(data[1], NULL) * 1000) : feet_to_mm(permissive_strtod(data[1], NULL));
|
||||
if (data[2])
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0));
|
||||
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(permissive_strtod(data[2], NULL)) : F_to_mkelvin(permissive_strtod(data[2], NULL));
|
||||
if (data[3]) {
|
||||
state->cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000);
|
||||
state->cur_sample->setpoint.mbar = lrint(permissive_strtod(data[3], NULL) * 1000);
|
||||
}
|
||||
if (data[4])
|
||||
state->cur_sample->ndl.seconds = atoi(data[4]) * 60;
|
||||
|
@ -250,7 +250,7 @@ static int shearwater_dive(void *param, int, char **data, char **)
|
|||
|
||||
/* TODO: verify that metric calculation is correct */
|
||||
if (data[6])
|
||||
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(strtod_flags(data[6], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[6], NULL, 0));
|
||||
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
|
||||
|
||||
if (data[7])
|
||||
state->cur_dive->dc.duration.seconds = atoi(data[7]) * 60;
|
||||
|
@ -380,7 +380,7 @@ static int shearwater_cloud_dive(void *param, int, char **data, char **)
|
|||
|
||||
/* TODO: verify that metric calculation is correct */
|
||||
if (data[6])
|
||||
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(strtod_flags(data[6], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[6], NULL, 0));
|
||||
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
|
||||
|
||||
if (data[7])
|
||||
state->cur_dive->dc.duration.seconds = atoi(data[7]);
|
||||
|
|
|
@ -208,7 +208,7 @@ static int dm4_dive(void *param, int, char **data, char **)
|
|||
settings_end(state);
|
||||
|
||||
if (data[6])
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000);
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
|
||||
if (data[8])
|
||||
state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
|
||||
if (data[9])
|
||||
|
@ -227,7 +227,7 @@ static int dm4_dive(void *param, int, char **data, char **)
|
|||
if (data[11] && atoi(data[11]) > 0)
|
||||
cyl->end.mbar = (atoi(data[11]));
|
||||
if (data[12])
|
||||
cyl->type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000);
|
||||
cyl->type.size.mliter = lrint((permissive_strtod(data[12], NULL)) * 1000);
|
||||
if (data[13])
|
||||
cyl->type.workingpressure.mbar = (atoi(data[13]));
|
||||
if (data[20])
|
||||
|
@ -314,10 +314,10 @@ static int dm5_cylinders(void *param, int, char **data, char **)
|
|||
/* DM5 shows tank size of 12 liters when the actual
|
||||
* value is 0 (and using metric units). So we just use
|
||||
* the same 12 liters when size is not available */
|
||||
if (strtod_flags(data[6], NULL, 0) == 0.0 && cyl->start.mbar)
|
||||
if (permissive_strtod(data[6], NULL) == 0.0 && cyl->start.mbar)
|
||||
cyl->type.size.mliter = 12000;
|
||||
else
|
||||
cyl->type.size.mliter = lrint((strtod_flags(data[6], NULL, 0)) * 1000);
|
||||
cyl->type.size.mliter = lrint((permissive_strtod(data[6], NULL)) * 1000);
|
||||
}
|
||||
if (data[2])
|
||||
cyl->gasmix.o2.permille = atoi(data[2]) * 10;
|
||||
|
@ -336,12 +336,12 @@ static int dm5_gaschange(void *param, int, char **data, char **)
|
|||
state->cur_event.time.seconds = atoi(data[0]);
|
||||
if (data[1]) {
|
||||
strcpy(state->cur_event.name, "gaschange");
|
||||
state->cur_event.value = lrint(strtod_flags(data[1], NULL, 0));
|
||||
state->cur_event.value = lrint(permissive_strtod(data[1], NULL));
|
||||
}
|
||||
|
||||
/* He part of the mix */
|
||||
if (data[2])
|
||||
state->cur_event.value += lrint(strtod_flags(data[2], NULL, 0)) << 16;
|
||||
state->cur_event.value += lrint(permissive_strtod(data[2], NULL)) << 16;
|
||||
event_end(state);
|
||||
|
||||
return 0;
|
||||
|
@ -389,7 +389,7 @@ static int dm5_dive(void *param, int, char **data, char **)
|
|||
settings_end(state);
|
||||
|
||||
if (data[6])
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000);
|
||||
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
|
||||
if (data[8])
|
||||
state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
|
||||
if (data[9])
|
||||
|
|
|
@ -168,7 +168,7 @@ static enum number_type parse_float(const char *buffer, double &res, const char
|
|||
first_time = false;
|
||||
}
|
||||
/* Try again in permissive mode*/
|
||||
val = strtod_flags(buffer, &endp, 0);
|
||||
val = permissive_strtod(buffer, &endp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1240,7 +1240,7 @@ QStringList stringToList(const QString &s)
|
|||
weight_t string_to_weight(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
double value = strtod_flags(str, &end, 0);
|
||||
double value = permissive_strtod(str, &end);
|
||||
QString rest = QString(end).trimmed();
|
||||
QString local_kg = gettextFromC::tr("kg");
|
||||
QString local_lbs = gettextFromC::tr("lbs");
|
||||
|
@ -1264,7 +1264,7 @@ lbs:
|
|||
depth_t string_to_depth(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
double value = strtod_flags(str, &end, 0);
|
||||
double value = permissive_strtod(str, &end);
|
||||
QString rest = QString(end).trimmed();
|
||||
QString local_ft = gettextFromC::tr("ft");
|
||||
QString local_m = gettextFromC::tr("m");
|
||||
|
@ -1289,7 +1289,7 @@ ft:
|
|||
pressure_t string_to_pressure(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
double value = strtod_flags(str, &end, 0);
|
||||
double value = permissive_strtod(str, &end);
|
||||
QString rest = QString(end).trimmed();
|
||||
QString local_psi = gettextFromC::tr("psi");
|
||||
QString local_bar = gettextFromC::tr("bar");
|
||||
|
@ -1312,7 +1312,7 @@ psi:
|
|||
volume_t string_to_volume(const char *str, pressure_t workp)
|
||||
{
|
||||
const char *end;
|
||||
double value = strtod_flags(str, &end, 0);
|
||||
double value = permissive_strtod(str, &end);
|
||||
QString rest = QString(end).trimmed();
|
||||
QString local_l = gettextFromC::tr("l");
|
||||
QString local_cuft = gettextFromC::tr("cuft");
|
||||
|
@ -1343,7 +1343,7 @@ l:
|
|||
fraction_t string_to_fraction(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
double value = strtod_flags(str, &end, 0);
|
||||
double value = permissive_strtod(str, &end);
|
||||
fraction_t fraction;
|
||||
|
||||
fraction.permille = lrint(value * 10);
|
||||
|
|
|
@ -3,68 +3,51 @@
|
|||
* 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
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
* 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"
|
||||
|
||||
double strtod_flags(const char *str, const char **ptr, unsigned int flags)
|
||||
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;
|
||||
int sign = 0, esign = 0;
|
||||
int numbers = 0, dot = 0;
|
||||
bool sign = false, esign = false;
|
||||
bool numbers = false, dot = false;
|
||||
|
||||
/* skip spaces */
|
||||
while (isspace(c = *p++))
|
||||
/* */;
|
||||
|
||||
/* optional sign */
|
||||
if (!(flags & STRTOD_NO_SIGN)) {
|
||||
switch (c) {
|
||||
case '-':
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *p++;
|
||||
}
|
||||
switch (c) {
|
||||
case '-':
|
||||
sign = true;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *p++;
|
||||
}
|
||||
|
||||
/* Mantissa */
|
||||
for (;; c = *p++) {
|
||||
if ((c == '.' && !(flags & STRTOD_NO_DOT)) ||
|
||||
(c == ',' && !(flags & STRTOD_NO_COMMA))) {
|
||||
if (c == '.' || (c == ',' && !no_comma)) {
|
||||
if (dot)
|
||||
goto done;
|
||||
dot = 1;
|
||||
dot = true;
|
||||
continue;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
numbers++;
|
||||
numbers = true;
|
||||
val = (val * 10) + (c - '0');
|
||||
if (dot)
|
||||
decimal *= 10;
|
||||
|
@ -72,8 +55,6 @@ double strtod_flags(const char *str, const char **ptr, unsigned int flags)
|
|||
}
|
||||
if (c != 'e' && c != 'E')
|
||||
goto done;
|
||||
if (flags & STRTOD_NO_EXPONENT)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -85,7 +66,7 @@ double strtod_flags(const char *str, const char **ptr, unsigned int flags)
|
|||
c = *ep++;
|
||||
switch (c) {
|
||||
case '-':
|
||||
esign = 1;
|
||||
esign = true;
|
||||
/* fallthrough */
|
||||
case '+':
|
||||
c = *ep++;
|
||||
|
@ -127,3 +108,13 @@ no_conversion:
|
|||
*ptr = str;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double permissive_strtod(const char *str, const char **ptr)
|
||||
{
|
||||
return strtod_flags(str, ptr, false);
|
||||
}
|
||||
|
||||
double ascii_strtod(const char *str, const char **ptr)
|
||||
{
|
||||
return strtod_flags(str, ptr, true);
|
||||
}
|
||||
|
|
|
@ -52,15 +52,8 @@ static inline char *copy_string(const char *s)
|
|||
return (s && *s) ? strdup(s) : NULL;
|
||||
}
|
||||
|
||||
#define STRTOD_NO_SIGN 0x01
|
||||
#define STRTOD_NO_DOT 0x02
|
||||
#define STRTOD_NO_COMMA 0x04
|
||||
#define STRTOD_NO_EXPONENT 0x08
|
||||
extern double strtod_flags(const char *str, const char **ptr, unsigned int flags);
|
||||
|
||||
#define STRTOD_ASCII (STRTOD_NO_COMMA)
|
||||
|
||||
#define ascii_strtod(str, ptr) strtod_flags(str, ptr, STRTOD_ASCII)
|
||||
extern double permissive_strtod(const char *str, const char **ptr);
|
||||
extern double ascii_strtod(const char *str, const char **ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue