SDL: SDL_Log: avoid sending text to the debug stream twice

From 125ce7137987ec91b931b4fb97d9c3c7af88c377 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Wed, 7 Aug 2024 23:49:02 +0200
Subject: [PATCH] SDL_Log: avoid sending text to the debug stream twice

When debugging a GUI application in Visual Studio,
text printed with fprintf(stderr) will also be sent to the debug stream.

When buiding SDL with SDL_LIBC=ON, this patch makes logging skip
OutputDebugString and rely on fprintf(stderr) to send the text to
the debugger.
---
 src/SDL_log.c | 47 +++++++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/src/SDL_log.c b/src/SDL_log.c
index 2b2680f5fdef7..000c90e642105 100644
--- a/src/SDL_log.c
+++ b/src/SDL_log.c
@@ -510,9 +510,14 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_S
     }
 }
 
-#if defined(SDL_PLATFORM_WIN32) && !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
-/* Flag tracking the attachment of the console: 0=unattached, 1=attached to a console, 2=attached to a file, -1=error */
-static int consoleAttached = 0;
+#if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
+enum {
+    CONSOLE_UNATTACHED = 0,
+    CONSOLE_ATTACHED_CONSOLE = 1,
+    CONSOLE_ATTACHED_FILE = 2,
+    CONSOLE_ATTACHED_MSVC = 3,
+    CONSOLE_ATTACHED_ERROR = -1,
+} consoleAttached = CONSOLE_UNATTACHED;
 
 /* Handle to stderr output of console. */
 static HANDLE stderrHandle = NULL;
@@ -530,58 +535,68 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
         LPTSTR tstr;
         SDL_bool isstack;
 
-#if !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
+#if !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
         BOOL attachResult;
         DWORD attachError;
-        DWORD charsWritten;
         DWORD consoleMode;
+#if !defined(HAVE_STDIO_H)
+        DWORD charsWritten;
+#endif
 
         /* Maybe attach console and get stderr handle */
-        if (consoleAttached == 0) {
+        if (consoleAttached == CONSOLE_UNATTACHED) {
             attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
             if (!attachResult) {
                 attachError = GetLastError();
                 if (attachError == ERROR_INVALID_HANDLE) {
                     /* This is expected when running from Visual Studio */
                     /*OutputDebugString(TEXT("Parent process has no console\r\n"));*/
-                    consoleAttached = -1;
+                    consoleAttached = CONSOLE_ATTACHED_MSVC;
                 } else if (attachError == ERROR_GEN_FAILURE) {
                     OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
-                    consoleAttached = -1;
+                    consoleAttached = CONSOLE_ATTACHED_ERROR;
                 } else if (attachError == ERROR_ACCESS_DENIED) {
                     /* Already attached */
-                    consoleAttached = 1;
+                    consoleAttached = CONSOLE_ATTACHED_CONSOLE;
                 } else {
                     OutputDebugString(TEXT("Error attaching console\r\n"));
-                    consoleAttached = -1;
+                    consoleAttached = CONSOLE_ATTACHED_ERROR;
                 }
             } else {
                 /* Newly attached */
-                consoleAttached = 1;
+                consoleAttached = CONSOLE_ATTACHED_CONSOLE;
             }
 
-            if (consoleAttached == 1) {
+            if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
                 stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
 
                 if (GetConsoleMode(stderrHandle, &consoleMode) == 0) {
                     /* WriteConsole fails if the output is redirected to a file. Must use WriteFile instead. */
-                    consoleAttached = 2;
+                    consoleAttached = CONSOLE_ATTACHED_FILE;
                 }
             }
         }
 #endif /* !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK) */
-
         length = SDL_strlen(SDL_GetLogPriorityPrefix(priority)) + SDL_strlen(message) + 1 + 1 + 1;
         output = SDL_small_alloc(char, length, &isstack);
         (void)SDL_snprintf(output, length, "%s%s\r\n", SDL_GetLogPriorityPrefix(priority), message);
         tstr = WIN_UTF8ToString(output);
 
+
+#if defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
+        /* When running in MSVC and using stdio, rely on forwarding of stderr to the debug stream */
+        if (consoleAttached != CONSOLE_ATTACHED_MSVC) {
+            /* Output to debugger */
+            OutputDebugString(tstr);
+        }
+#else
         /* Output to debugger */
         OutputDebugString(tstr);
+#endif
 
 #if !defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINRT) && !defined(SDL_PLATFORM_GDK)
         /* Screen output to stderr, if console was attached. */
-        if (consoleAttached == 1) {
+        if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
             if (!WriteConsole(stderrHandle, tstr, (DWORD)SDL_tcslen(tstr), &charsWritten, NULL)) {
                 OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
                 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
@@ -589,7 +604,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
                 }
             }
 
-        } else if (consoleAttached == 2) {
+        } else if (consoleAttached == CONSOLE_ATTACHED_FILE) {
             if (!WriteFile(stderrHandle, output, (DWORD)SDL_strlen(output), &charsWritten, NULL)) {
                 OutputDebugString(TEXT("Error calling WriteFile\r\n"));
             }