foxygit / doom Log in
commit 2435843ccd797d6bd70fa41872b92657cf6e98dc
Author:     Fabian Greffrath <fabian@greffrath.com>
AuthorDate: Fri Mar 11 17:04:48 2022 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Fri Mar 11 17:04:48 2022 +0100

    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
---
 src/m_config.c | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/src/m_config.c b/src/m_config.c
index adb11e45..1d043970 100644
--- 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 @@ static void SetVariable(default_t *def, const char *value)
             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;
     }
 }