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

From 544f2c79824e67b83a619ea1e301ef899fe5b6f4 Mon Sep 17 00:00:00 2001
From: Daniel Gibson <[EMAIL REDACTED]>
Date: Mon, 12 Dec 2022 18:30:05 +0100
Subject: [PATCH] Port ngage to header-only SDL_main + SDL_RunApp()

For some reason, ngage doesn't seem to be handled in any of the
build systems, so I couldn't add SDL_ngage_runapp.cpp to any buildscript
---
 include/SDL3/SDL_main.h             | 10 +++-
 include/SDL3/SDL_main_impl.h        | 21 ++++++--
 src/core/ngage/SDL_ngage_runapp.cpp | 80 +++++++++++++++++++++++++++++
 src/main/ngage/SDL_ngage_main.cpp   | 77 ++-------------------------
 4 files changed, 109 insertions(+), 79 deletions(-)
 create mode 100644 src/core/ngage/SDL_ngage_runapp.cpp

diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index 6abddaa47d06..428cc6ef2d9d 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -110,6 +110,14 @@
 */
 #define SDL_MAIN_AVAILABLE
 
+#elif defined(__NGAGE__)
+
+/*
+   TODO: not sure if it should be SDL_MAIN_NEEDED, in SDL2 ngage had a
+        main implementation, but wasn't mentioned in SDL_main.h
+ */
+#define SDL_MAIN_AVAILABLE
+
 #endif
 #endif /* SDL_MAIN_HANDLED */
 
@@ -272,7 +280,7 @@ 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__) /* TODO: other platforms */
+    || defined(__3DS__) || defined(__NGAGE__) /* TODO: other platforms */
 #include <SDL3/SDL_main_impl.h>
 #elif defined(__WINRT__) /* TODO: other C++ platforms */
 
diff --git a/include/SDL3/SDL_main_impl.h b/include/SDL3/SDL_main_impl.h
index 94166c977a30..b3c056de6ae9 100644
--- a/include/SDL3/SDL_main_impl.h
+++ b/include/SDL3/SDL_main_impl.h
@@ -156,7 +156,22 @@ int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
 }
 
 /* end of WinRT impl */
-#elif defined(__IOS__) || defined(__TVOS__) || defined(__3DS__)
+#elif defined(__NGAGE__)
+
+/* same typedef as in ngage SDKs e32def.h */
+typedef signed int TInt;
+/* TODO: if it turns out that this only works when built as C++,
+         move __NGAGE__ into the C++ section in SDL_main.h */
+TInt E32Main()
+{
+    return SDL_RunApp(0, NULL, SDL_main, NULL);
+}
+
+/* end of __NGAGE__ impl */
+
+/* TODO: remaining platforms */
+
+#else /* platforms that use a standard main() and just call SDL_RunApp(), like iOS and 3DS */
 
 #include <SDL3/begin_code.h>
 
@@ -175,9 +190,7 @@ int main(int argc, char *argv[])
 
 #include <SDL3/close_code.h>
 
-/* end of __IOS__, __3DS__, __TVOS__ impls */
-
-/* TODO: remaining platforms */
+/* end of impls for standard-conforming platforms */
 
 #endif /* __WIN32__ etc */
 
diff --git a/src/core/ngage/SDL_ngage_runapp.cpp b/src/core/ngage/SDL_ngage_runapp.cpp
new file mode 100644
index 000000000000..aaadd965fa56
--- /dev/null
+++ b/src/core/ngage/SDL_ngage_runapp.cpp
@@ -0,0 +1,80 @@
+/*
+   based on SDL_ngage_main.c, originally for SDL 1.2 by Hannu Viitala
+*/
+
+#include "SDL_internal.h"
+
+#ifdef __NGAGE__
+
+#include <e32std.h>
+#include <e32def.h>
+#include <e32svr.h>
+#include <e32base.h>
+#include <estlib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <w32std.h>
+#include <apgtask.h>
+
+
+DECLSPEC int
+SDL_RunApp(int argc_, char* argv_[], SDL_main_func mainFunction, void * reserved)
+{
+    (void)argc_; (void)argv_; (void)reserved;
+    /*  Get the clean-up stack */
+    CTrapCleanup *cleanup = CTrapCleanup::New();
+
+    /* Arrange for multi-threaded operation */
+    SpawnPosixServerThread();
+
+    /* Get args and environment */
+    int argc = 0;
+    char **argv = 0;
+    char **envp = 0;
+
+    __crt0(argc, argv, envp);
+
+    /* Start the application! */
+
+    /* Create stdlib */
+    _REENT;
+
+    /* Set process and thread priority and name */
+
+    RThread currentThread;
+    RProcess thisProcess;
+    TParse exeName;
+    exeName.Set(thisProcess.FileName(), NULL, NULL);
+    currentThread.Rename(exeName.Name());
+    currentThread.SetProcessPriority(EPriorityLow);
+    currentThread.SetPriority(EPriorityMuchLess);
+
+    /* Increase heap size */
+    RHeap *newHeap = NULL;
+    RHeap *oldHeap = NULL;
+    TInt heapSize = 7500000;
+    int ret;
+
+    newHeap = User::ChunkHeap(NULL, heapSize, heapSize, KMinHeapGrowBy);
+
+    if (newHeap == NULL) {
+        ret = 3;
+        goto cleanup;
+    } else {
+        oldHeap = User::SwitchHeap(newHeap);
+        /* Call stdlib main */
+        SDL_SetMainReady();
+        ret = mainFunction(argc, argv);
+    }
+
+cleanup:
+    _cleanup();
+
+    CloseSTDLIB();
+    delete cleanup;
+    return ret;
+}
+
+#endif // __NGAGE__
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/main/ngage/SDL_ngage_main.cpp b/src/main/ngage/SDL_ngage_main.cpp
index ea05a4ee1f48..20480056adf4 100644
--- a/src/main/ngage/SDL_ngage_main.cpp
+++ b/src/main/ngage/SDL_ngage_main.cpp
@@ -1,79 +1,8 @@
 /*
     SDL_ngage_main.c, originally for SDL 1.2 by Hannu Viitala
-*/
-#include <SDL3/SDL.h>
-#include <SDL3/SDL_main.h> /* until this SDL_main impl is converted to header-only.. */
-
-#include <e32std.h>
-#include <e32def.h>
-#include <e32svr.h>
-#include <e32base.h>
-#include <estlib.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <w32std.h>
-#include <apgtask.h>
-
-#ifdef main
-#undef main
-#endif
-
-extern "C" int main(int argc, char *argv[]);
-
-TInt E32Main()
-{
-    /*  Get the clean-up stack */
-    CTrapCleanup *cleanup = CTrapCleanup::New();
-
-    /* Arrange for multi-threaded operation */
-    SpawnPosixServerThread();
-
-    /* Get args and environment */
-    int argc = 0;
-    char **argv = 0;
-    char **envp = 0;
-
-    __crt0(argc, argv, envp);
-
-    /* Start the application! */
 
-    /* Create stdlib */
-    _REENT;
-
-    /* Set process and thread priority and name */
-
-    RThread currentThread;
-    RProcess thisProcess;
-    TParse exeName;
-    exeName.Set(thisProcess.FileName(), NULL, NULL);
-    currentThread.Rename(exeName.Name());
-    currentThread.SetProcessPriority(EPriorityLow);
-    currentThread.SetPriority(EPriorityMuchLess);
-
-    /* Increase heap size */
-    RHeap *newHeap = NULL;
-    RHeap *oldHeap = NULL;
-    TInt heapSize = 7500000;
-    int ret;
-
-    newHeap = User::ChunkHeap(NULL, heapSize, heapSize, KMinHeapGrowBy);
-
-    if (newHeap == NULL) {
-        ret = 3;
-        goto cleanup;
-    } else {
-        oldHeap = User::SwitchHeap(newHeap);
-        /* Call stdlib main */
-        SDL_SetMainReady();
-        ret = SDL_main(argc, argv);
-    }
-
-cleanup:
-    _cleanup();
-
-    CloseSTDLIB();
-    delete cleanup;
-    return ret;
-}
+    empty, moved to SDL_main_impl.h and src/core/ngage/SDL_ngage_runapp.cpp
+    TODO: delete this file
+*/
 
 /* vi: set ts=4 sw=4 expandtab: */