ref: 2435843ccd797d6bd70fa41872b92657cf6e98dc
parent: 9546b2f0392a606bb6220671741525ba40480685
author: Fabian Greffrath <fabian@greffrath.com>
date: Fri Mar 11 12:04:48 EST 2022
convert first non-digit to locale's decimal in float value parsing (#1390) * convert first non-digit to locale's decimal in float value parsing Different locales use different characters as decimal separators. Since the currently used locale isn't always under our own control (c.f. https://github.com/fabiangreffrath/crispy-doom/issues/620) this commit makes sure to translate the first non-digit character in a string that is going to get parsed as a float value into the current locale's decimal separator. Fixes https://github.com/fabiangreffrath/crispy-doom/issues/758. * let minus pass * add elaborative comment to the hack * skip sign indicators * be more explicit about skipping sign indicators
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -24,6 +24,7 @@
#include <ctype.h>
#include <errno.h>
#include <assert.h>
+#include <locale.h>
#include "SDL_filesystem.h"
@@ -1993,7 +1994,41 @@
break;
case DEFAULT_FLOAT:
- *def->location.f = (float) atof(value);
+ {
+ // Different locales use different decimal separators.
+ // However, the choice of the current locale isn't always
+ // under our own control. If the atof() function fails to
+ // parse the string representing the floating point number
+ // using the current locale's decimal separator, it will
+ // return 0, resulting in silent sound effects. To
+ // mitigate this, we replace the first non-digit,
+ // non-minus character in the string with the current
+ // locale's decimal separator before passing it to atof().
+ struct lconv *lc = localeconv();
+ char dec, *str;
+ int i = 0;
+
+ dec = lc->decimal_point[0];
+ str = M_StringDuplicate(value);
+
+ // Skip sign indicators.
+ if (str[i] == '-' || str[i] == '+')
+ {
+ i++;
+ }
+
+ for ( ; str[i] != '\0'; i++)
+ {
+ if (!isdigit(str[i]))
+ {
+ str[i] = dec;
+ break;
+ }
+ }
+
+ *def->location.f = (float) atof(str);
+ free(str);
+ }
break;
}
}