SDL: Port PS2 SDL_main to header-only + SDL_RunApp()

From b1b3bd654d73f86abe1f015255f04af8cf9974e7 Mon Sep 17 00:00:00 2001
From: Daniel Gibson <[EMAIL REDACTED]>
Date: Mon, 12 Dec 2022 19:15:09 +0100
Subject: [PATCH] Port PS2 SDL_main to header-only + SDL_RunApp()

---
 CMakeLists.txt              |   3 +
 include/SDL3/SDL_main.h     |  10 +++-
 src/core/ps2/SDL_ps2.c      | 106 ++++++++++++++++++++++++++++++++++++
 src/main/ps2/SDL_ps2_main.c |  89 +-----------------------------
 4 files changed, 119 insertions(+), 89 deletions(-)
 create mode 100644 src/core/ps2/SDL_ps2.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5ab49f6da875..a4ddfdcd67cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2639,6 +2639,9 @@ elseif(PS2)
   file(GLOB PS2_MAIN_SOURCES ${SDL3_SOURCE_DIR}/src/main/ps2/*.c)
   set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${PS2_MAIN_SOURCES})
 
+  file(GLOB PS2_CORE_SOURCES ${SDL3_SOURCE_DIR}/src/core/ps2/*.c)
+  set(SOURCE_FILES ${SOURCE_FILES} ${PS2_CORE_SOURCES})
+
   if(SDL_AUDIO)
     set(SDL_AUDIO_DRIVER_PS2 1)
     file(GLOB PS2_AUDIO_SOURCES ${SDL3_SOURCE_DIR}/src/audio/ps2/*.c)
diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index 428cc6ef2d9d..8a47091af630 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -280,9 +280,12 @@ extern DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
 #if !defined(SDL_MAIN_HANDLED) && !defined(SDL_MAIN_NOIMPL)
 /* include header-only SDL_main implementations */
 #if defined(__WIN32__) || defined(__GDK__) || defined(__IOS__) || defined(__TVOS__) \
-    || defined(__3DS__) || defined(__NGAGE__) /* TODO: other platforms */
+    || defined(__3DS__) || defined(__NGAGE__) || defined(__PS2__)
+
+/* platforms whichs main (-equivalent) can be implemented in plain C */
 #include <SDL3/SDL_main_impl.h>
-#elif defined(__WINRT__) /* TODO: other C++ platforms */
+
+#elif defined(__WINRT__) /* C++ platforms */
 
 #ifdef __cplusplus
 #include <SDL3/SDL_main_impl.h>
@@ -296,7 +299,8 @@ extern DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
 #warning "Note: Your platform needs the SDL_main implementation in a C++ source file. You can keep your main() in plain C and create a fresh .cpp file that only contains #include <SDL3/SDL_main.h>"
 #endif /* __GNUC__ */
 #endif /* __cplusplus */
-#endif /* __WINRT__ etc */
+
+#endif /* C++ platforms like __WINRT__ etc */
 
 #endif /* SDL_MAIN_HANDLED */
 
diff --git a/src/core/ps2/SDL_ps2.c b/src/core/ps2/SDL_ps2.c
new file mode 100644
index 000000000000..7e9bcf8f1a50
--- /dev/null
+++ b/src/core/ps2/SDL_ps2.c
@@ -0,0 +1,106 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_internal.h"
+
+#ifdef __PS2__
+
+/* SDL_RunApp() code for PS2 based on SDL_ps2_main.c, fjtrujy@gmail.com */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <kernel.h>
+#include <sifrpc.h>
+#include <iopcontrol.h>
+#include <sbv_patches.h>
+#include <ps2_fileXio_driver.h>
+#include <ps2_memcard_driver.h>
+#include <ps2_usb_driver.h>
+
+__attribute__((weak)) void reset_IOP()
+{
+    SifInitRpc(0);
+    while (!SifIopReset(NULL, 0)) {
+    }
+    while (!SifIopSync()) {
+    }
+}
+
+static void prepare_IOP()
+{
+    reset_IOP();
+    SifInitRpc(0);
+    sbv_patch_enable_lmb();
+    sbv_patch_disable_prefix_check();
+    sbv_patch_fileio();
+}
+
+static void init_drivers()
+{
+    init_memcard_driver(true);
+    init_usb_driver(true);
+}
+
+static void deinit_drivers()
+{
+    deinit_usb_driver(true);
+    deinit_memcard_driver(true);
+}
+
+static void waitUntilDeviceIsReady(char *path)
+{
+    struct stat buffer;
+    int ret = -1;
+    int retries = 50;
+
+    while (ret != 0 && retries > 0) {
+        ret = stat(path, &buffer);
+        /* Wait until the device is ready */
+        nopdelay();
+
+        retries--;
+    }
+}
+
+DECLSPEC int
+SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
+{
+    int res;
+    char cwd[FILENAME_MAX];
+    (void)reserved;
+
+    prepare_IOP();
+    init_drivers();
+
+    getcwd(cwd, sizeof(cwd));
+    waitUntilDeviceIsReady(cwd);
+
+    res = SDL_main(argc, argv);
+
+    deinit_drivers();
+
+    return res;
+}
+
+#endif /* __PS2__ */
diff --git a/src/main/ps2/SDL_ps2_main.c b/src/main/ps2/SDL_ps2_main.c
index 9e97771cfd4b..1d2bdc1a39c5 100644
--- a/src/main/ps2/SDL_ps2_main.c
+++ b/src/main/ps2/SDL_ps2_main.c
@@ -1,91 +1,8 @@
 /*
     SDL_ps2_main.c, fjtrujy@gmail.com
-*/
-#include <SDL3/SDL.h>
-#include <SDL3/SDL_main.h> /* until this SDL_main impl is converted to header-only.. */
-
-#ifdef __PS2__
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-
-#include <kernel.h>
-#include <sifrpc.h>
-#include <iopcontrol.h>
-#include <sbv_patches.h>
-#include <ps2_fileXio_driver.h>
-#include <ps2_memcard_driver.h>
-#include <ps2_usb_driver.h>
-
-#ifdef main
-#undef main
-#endif
-
-__attribute__((weak)) void reset_IOP()
-{
-    SifInitRpc(0);
-    while (!SifIopReset(NULL, 0)) {
-    }
-    while (!SifIopSync()) {
-    }
-}
-
-static void prepare_IOP()
-{
-    reset_IOP();
-    SifInitRpc(0);
-    sbv_patch_enable_lmb();
-    sbv_patch_disable_prefix_check();
-    sbv_patch_fileio();
-}
-
-static void init_drivers()
-{
-    init_memcard_driver(true);
-    init_usb_driver(true);
-}
-
-static void deinit_drivers()
-{
-    deinit_usb_driver(true);
-    deinit_memcard_driver(true);
-}
-
-static void waitUntilDeviceIsReady(char *path)
-{
-    struct stat buffer;
-    int ret = -1;
-    int retries = 50;
 
-    while (ret != 0 && retries > 0) {
-        ret = stat(path, &buffer);
-        /* Wait until the device is ready */
-        nopdelay();
-
-        retries--;
-    }
-}
-
-int main(int argc, char *argv[])
-{
-    int res;
-    char cwd[FILENAME_MAX];
-
-    prepare_IOP();
-    init_drivers();
-
-    getcwd(cwd, sizeof(cwd));
-    waitUntilDeviceIsReady(cwd);
-
-    res = SDL_main(argc, argv);
-
-    deinit_drivers();
-
-    return res;
-}
-
-#endif /* _PS2 */
+    empty, moved to SDL_RunApp() in src/core/ps2/SDL_ps2.c
+    TODO: remove
+*/
 
 /* vi: set ts=4 sw=4 expandtab: */