SDL: PortNintendo 3DS SDL_main to header-only + SDL_N3DSRunApp()

From 1de559248e2f3f0a9520ee4d86d4753b0e00abc8 Mon Sep 17 00:00:00 2001
From: Daniel Gibson <[EMAIL REDACTED]>
Date: Mon, 12 Dec 2022 04:38:06 +0100
Subject: [PATCH] PortNintendo 3DS SDL_main to header-only + SDL_N3DSRunApp()

and move the #undef main and #define main SDL_main to the start/end of
SDL_main_impl.h instead of repeating it in every platform implementation

Thanks to SDL_N3DSRunApp we don't need the #include <3ds.h> in
SDL_main_impl.h - that caused conflicts with testthread.c, because both
have (different) ThreadFunc typedefs.
---
 CMakeLists.txt                    |  3 ++
 include/SDL3/SDL_main.h           | 19 +++++++++++-
 include/SDL3/SDL_main_impl.h      | 43 ++++++++++++++++++---------
 src/core/n3ds/SDL_n3ds.c          | 49 +++++++++++++++++++++++++++++++
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  3 ++
 src/main/n3ds/SDL_n3ds_main.c     | 41 ++------------------------
 7 files changed, 106 insertions(+), 53 deletions(-)
 create mode 100644 src/core/n3ds/SDL_n3ds.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94c29f7a141a..7d6e3d620fd9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2688,6 +2688,9 @@ elseif(N3DS)
   file(GLOB N3DS_MAIN_SOURCES ${SDL3_SOURCE_DIR}/src/main/n3ds/*.c)
   set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${N3DS_MAIN_SOURCES})
 
+  file(GLOB N3DS_CORE_SOURCES ${SDL3_SOURCE_DIR}/src/core/n3ds/*.c)
+  list(APPEND SOURCE_FILES ${N3DS_CORE_SOURCES})
+
   if(SDL_AUDIO)
     set(SDL_AUDIO_DRIVER_N3DS 1)
     file(GLOB N3DS_AUDIO_SOURCES ${SDL3_SOURCE_DIR}/src/audio/n3ds/*.c)
diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index f22903cacafa..fffa78a49925 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -278,6 +278,22 @@ extern DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
 
 #endif /* __GDK__ */
 
+#ifdef __3DS__
+
+/**
+ * Initializes and launches an SDL application.
+ *
+ * \param argc The argc parameter from the application's main() function
+ * \param argv The argv parameter from the application's main() function
+ * \param mainFunction The SDL app's C-style main(), an SDL_main_func
+ * \return the return value from mainFunction
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC int SDLCALL SDL_N3DSRunApp(int argc, char *argv[], SDL_main_func mainFunction);
+
+#endif /* __3DS__ */
+
 #ifdef __cplusplus
 }
 #endif
@@ -286,7 +302,8 @@ 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__) /* TODO: other platforms */
+#if defined(__WIN32__) || defined(__GDK__) || defined(__IOS__) || defined(__TVOS__) \
+    || defined(__3DS__) /* 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 11acf2e859e0..79d6e0b19db6 100644
--- a/include/SDL3/SDL_main_impl.h
+++ b/include/SDL3/SDL_main_impl.h
@@ -35,6 +35,12 @@
    and main() is implemented in plain C */
 #if !defined(SDL_MAIN_HANDLED) && !defined(SDL_MAIN_NOIMPL)
 
+/* the implementations below must be able to use the implement real main(), nothing renamed
+   (the user's main() will be renamed to SDL_main so it can be called from here) */
+#ifdef main
+#  undef main
+#endif /* main */
+
 #if defined(__WIN32__) || defined(__GDK__)
 
 /* these defines/typedefs are needed for the WinMain() definition */
@@ -42,10 +48,6 @@
 #define WINAPI __stdcall
 #endif
 
-#ifdef main
-#  undef main
-#endif /* main */
-
 #include <SDL3/begin_code.h>
 
 #ifdef __cplusplus
@@ -102,9 +104,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
 
 #include <SDL3/close_code.h>
 
-/* rename users main() function to SDL_main() so it can be called from the wrapper above */
-#define main    SDL_main
-
 /* end of __WIN32__ and __GDK__ impls */
 #elif defined(__WINRT__)
 
@@ -163,10 +162,6 @@ int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
 /* end of WinRT impl */
 #elif defined(__IOS__) || defined(__TVOS__)
 
-#ifdef main
-#  undef main
-#endif /* main */
-
 #include <SDL3/begin_code.h>
 
 #ifdef __cplusplus
@@ -184,15 +179,35 @@ int main(int argc, char *argv[])
 
 #include <SDL3/close_code.h>
 
-/* rename users main() function to SDL_main() so it can be called from the wrapper above */
-#define main    SDL_main
-
 /* end of __IOS__ and __TVOS__ impls */
+#elif defined(__3DS__)
+
+#include <SDL3/begin_code.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int main(int argc, char *argv[])
+{
+    return SDL_N3DSRunApp(argc, argv, SDL_main);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include <SDL3/close_code.h>
+
+/* end of __3DS__ impl */
 
 /* TODO: remaining platforms */
 
 #endif /* __WIN32__ etc */
 
+/* rename users main() function to SDL_main() so it can be called from the wrappers above */
+#define main    SDL_main
+
 #endif /* SDL_MAIN_HANDLED */
 
 #endif /* SDL_main_windows_h_ */
diff --git a/src/core/n3ds/SDL_n3ds.c b/src/core/n3ds/SDL_n3ds.c
new file mode 100644
index 000000000000..1b8727a98cd7
--- /dev/null
+++ b/src/core/n3ds/SDL_n3ds.c
@@ -0,0 +1,49 @@
+/*
+  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 __3DS__
+
+#include <3ds.h>
+
+DECLSPEC int
+SDL_N3DSRunApp(int argc, char *argv[], SDL_main_func mainFunction)
+{
+    int result;
+    /* init */
+    osSetSpeedupEnable(true);
+    romfsInit();
+
+    SDL_SetMainReady();
+    result = mainFunction(argc, argv);
+
+    /* quit */
+    romfsExit();
+
+    return result;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 44575201c149..7b6817933586 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -886,3 +886,4 @@
 #define SDL_GetEventState SDL_GetEventState_REAL
 #define SDL_GetRenderDriver SDL_GetRenderDriver_REAL
 #define SDL_Win32RunApp SDL_Win32RunApp_REAL
+#define SDL_N3DSRunApp SDL_N3DSRunApp_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index dd7707b50bd5..f402bd11409c 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -964,3 +964,6 @@ SDL_DYNAPI_PROC(const char*,SDL_GetRenderDriver,(int a),(a),return)
 #if defined(__WIN32__)
 SDL_DYNAPI_PROC(int,SDL_Win32RunApp,(SDL_main_func a, void *b),(a,b),return)
 #endif
+#if defined(__3DS__)
+SDL_DYNAPI_PROC(int,SDL_N3DSRunApp,(int a, char *b[], SDL_main_func c),(a,b,c),return)
+#endif
diff --git a/src/main/n3ds/SDL_n3ds_main.c b/src/main/n3ds/SDL_n3ds_main.c
index 03034290c305..87573bdc9b90 100644
--- a/src/main/n3ds/SDL_n3ds_main.c
+++ b/src/main/n3ds/SDL_n3ds_main.c
@@ -17,44 +17,9 @@
   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 <SDL3/SDL.h>
-#include <SDL3/SDL_main.h> /* until this SDL_main impl is converted to header-only.. */
-
-#ifdef __3DS__
-
-#include <3ds.h>
-
-#ifdef main
-#undef main
-#endif
-
-SDL_FORCE_INLINE void N3DS_Init(void);
-SDL_FORCE_INLINE void N3DS_Quit(void);
 
-int main(int argc, char *argv[])
-{
-    int result;
-    N3DS_Init();
-    SDL_SetMainReady();
-    result = SDL_main(argc, argv);
-    N3DS_Quit();
-    return result;
-}
-
-SDL_FORCE_INLINE void
-N3DS_Init(void)
-{
-    osSetSpeedupEnable(true);
-    romfsInit();
-}
-
-SDL_FORCE_INLINE void
-N3DS_Quit(void)
-{
-    romfsExit();
-}
-
-#endif /* __3DS__ */
+   Nothing to do here, the code moved into SDL_main_impl.h
+    TODO: remove this file
+*/
 
 /* vi: set sts=4 ts=4 sw=4 expandtab: */