SDL: Added basic support for %g snprintf format specifier

From ead4f122e41cf3cc1af1719778da1070cee1d797 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 29 Dec 2022 20:42:07 -0800
Subject: [PATCH] Added basic support for %g snprintf format specifier

---
 src/stdlib/SDL_string.c      | 31 +++++++++++++++++++++++++++++++
 test/testautomation_stdlib.c | 12 ++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index e6464da631a7..047dd572749c 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -1675,6 +1675,29 @@ SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg)
     return length;
 }
 
+static size_t
+SDL_TrimTrailingFractionalZeroes(char *text, size_t start, size_t length)
+{
+    size_t i, j;
+
+    for (i = start; i < length; ++i) {
+        if (text[i] == '.' || text[i] == ',') {
+            for (j = length - 1; j > i; --j) {
+                if (text[j] == '0') {
+                    --length;
+                } else {
+                    break;
+                }
+            }
+            if (j == i) {
+                --length;
+            }
+            break;
+        }
+    }
+    return length;
+}
+
 /* NOLINTNEXTLINE(readability-non-const-parameter) */
 int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
 {
@@ -1856,6 +1879,14 @@ int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *f
                     length += SDL_PrintFloat(TEXT_AND_LEN_ARGS, &info, va_arg(ap, double));
                     done = SDL_TRUE;
                     break;
+                case 'g':
+                {
+                    size_t starting_length = length;
+                    length += SDL_PrintFloat(TEXT_AND_LEN_ARGS, &info, va_arg(ap, double));
+                    length = SDL_TrimTrailingFractionalZeroes(text, starting_length, length);
+                    done = SDL_TRUE;
+                    break;
+                }
                 case 'S':
                 {
                     /* In practice this is used on Windows for WCHAR strings */
diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c
index f818e7a0f458..2d2ed0fdabe4 100644
--- a/test/testautomation_stdlib.c
+++ b/test/testautomation_stdlib.c
@@ -153,6 +153,18 @@ int stdlib_snprintf(void *arg)
     SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text);
     SDLTest_AssertCheck(result == 6, "Check result value, expected: 6, got: %d", result);
 
+    result = SDL_snprintf(text, sizeof(text), "%g", 100.0);
+    expected = "100";
+    SDLTest_AssertPass("Call to SDL_snprintf(\"%%g\", 100.0)");
+    SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text);
+    SDLTest_AssertCheck(result == 3, "Check result value, expected: 3, got: %d", result);
+
+    result = SDL_snprintf(text, sizeof(text), "%g", 100.75);
+    expected = "100.75";
+    SDLTest_AssertPass("Call to SDL_snprintf(\"%%g\", 100.75)");
+    SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text);
+    SDLTest_AssertCheck(result == 6, "Check result value, expected: 6, got: %d", result);
+
     size = 64;
     result = SDL_snprintf(text, sizeof(text), "%zu %s", size, "test");
     expected = "64 test";