diff --git a/core/import-cobalt.cpp b/core/import-cobalt.cpp index d79a9a35e..e0fcefa8e 100644 --- a/core/import-cobalt.cpp +++ b/core/import-cobalt.cpp @@ -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; diff --git a/core/import-divinglog.cpp b/core/import-divinglog.cpp index 8b4230721..545c26c31 100644 --- a/core/import-divinglog.cpp +++ b/core/import-divinglog.cpp @@ -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; diff --git a/core/import-shearwater.cpp b/core/import-shearwater.cpp index 07c3a6a8f..f9924e67d 100644 --- a/core/import-shearwater.cpp +++ b/core/import-shearwater.cpp @@ -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]); diff --git a/core/import-suunto.cpp b/core/import-suunto.cpp index 0ed7dc396..3b65c954f 100644 --- a/core/import-suunto.cpp +++ b/core/import-suunto.cpp @@ -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]) diff --git a/core/parse-xml.cpp b/core/parse-xml.cpp index f8554d66b..8988d9602 100644 --- a/core/parse-xml.cpp +++ b/core/parse-xml.cpp @@ -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); } } diff --git a/core/qthelper.cpp b/core/qthelper.cpp index 758a2d082..a094efca4 100644 --- a/core/qthelper.cpp +++ b/core/qthelper.cpp @@ -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); diff --git a/core/strtod.c b/core/strtod.c index 74720783c..39abfb7a7 100644 --- a/core/strtod.c +++ b/core/strtod.c @@ -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 #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); +} diff --git a/core/subsurface-string.h b/core/subsurface-string.h index 59a50d8c0..c46cf2a5a 100644 --- a/core/subsurface-string.h +++ b/core/subsurface-string.h @@ -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 }