diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h index 1e745e80d9623..009cd4ef1a13e 100644 --- a/include/SDL3/SDL_main.h +++ b/include/SDL3/SDL_main.h @@ -555,6 +555,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void); * using SDL_main (like when using SDL_MAIN_HANDLED). When using this, you do * *not* need SDL_SetMainReady(). * + * If `argv` is NULL, SDL will provide command line arguments, either by + * querying the OS for them if possible, or supplying a filler array if not. + * * \param argc the argc parameter from the application's main() function, or 0 * if the platform's main-equivalent has no argc. * \param argv the argv parameter from the application's main() function, or diff --git a/src/main/SDL_main_callbacks.c b/src/main/SDL_main_callbacks.c index 913c9a71cb00c..6c4a67acd7b68 100644 --- a/src/main/SDL_main_callbacks.c +++ b/src/main/SDL_main_callbacks.c @@ -147,3 +147,13 @@ void SDL_QuitMainCallbacks(SDL_AppResult result) SDL_Quit(); } +void SDL_CheckDefaultArgcArgv(int *argc, char ***argv) +{ + if (!argv) + { + static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' }; + static char *argvdummy[2] = { dummyargv0, NULL }; + *argc = 1; + *argv = argvdummy; + } +} diff --git a/src/main/SDL_main_callbacks.h b/src/main/SDL_main_callbacks.h index 1fd3725c259ee..2408414909a9a 100644 --- a/src/main/SDL_main_callbacks.h +++ b/src/main/SDL_main_callbacks.h @@ -27,6 +27,10 @@ SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func app SDL_AppResult SDL_IterateMainCallbacks(bool pump_events); void SDL_QuitMainCallbacks(SDL_AppResult result); +// (not a callback thing, but convenient to stick this in here.) +// If *_argv is NULL, update *_argc and *_argv to point at a static array of { "SDL_app", NULL }. +void SDL_CheckDefaultArgcArgv(int *_argc, char ***_argv); + #endif // SDL_main_callbacks_h_ diff --git a/src/main/SDL_runapp.c b/src/main/SDL_runapp.c index eccdd3fccdcc0..83ac590cb5efc 100644 --- a/src/main/SDL_runapp.c +++ b/src/main/SDL_runapp.c @@ -19,6 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_internal.h" +#include "SDL_main_callbacks.h" /* Most platforms that use/need SDL_main have their own SDL_RunApp() implementation. * If not, you can special case it here by appending || defined(__YOUR_PLATFORM__) */ @@ -27,16 +28,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { (void)reserved; - - if(!argv) - { - // make sure argv isn't NULL, in case some user code doesn't like that - static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' }; - static char *argvdummy[2] = { dummyargv0, NULL }; - argc = 1; - argv = argvdummy; - } - + SDL_CheckDefaultArgcArgv(&argc, &argv); return mainFunction(argc, argv); } diff --git a/src/main/emscripten/SDL_sysmain_runapp.c b/src/main/emscripten/SDL_sysmain_runapp.c index 3b9c0fda89759..92af40db8458f 100644 --- a/src/main/emscripten/SDL_sysmain_runapp.c +++ b/src/main/emscripten/SDL_sysmain_runapp.c @@ -22,6 +22,8 @@ #ifdef SDL_PLATFORM_EMSCRIPTEN +#include "../SDL_main_callbacks.h" + #include EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8"); @@ -35,6 +37,8 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv { (void)reserved; + SDL_CheckDefaultArgcArgv(&argc, &argv); + // Move any URL params that start with "SDL_" over to environment // variables, so the hint system can pick them up, etc, much like a user // can set them from a shell prompt on a desktop machine. Ignore all diff --git a/src/main/gdk/SDL_sysmain_runapp.cpp b/src/main/gdk/SDL_sysmain_runapp.cpp index 5a202259f9d23..c4b4b905c1cf1 100644 --- a/src/main/gdk/SDL_sysmain_runapp.cpp +++ b/src/main/gdk/SDL_sysmain_runapp.cpp @@ -37,53 +37,52 @@ static BOOL OutOfMemory(void) return FALSE; } -/* Gets the arguments with GetCommandLine, converts them to argc and argv - and calls SDL_main */ extern "C" -int SDL_RunApp(int, char **, SDL_main_func mainFunction, void *reserved) +int SDL_RunApp(int _argc, char **_argv, SDL_main_func mainFunction, void *reserved) { - LPWSTR *argvw; - char **argv; - int i, argc, result; - HRESULT hr; - XTaskQueueHandle taskQueue; - - argvw = CommandLineToArgvW(GetCommandLineW(), &argc); - if (argvw == NULL) { - return OutOfMemory(); - } - - /* Note that we need to be careful about how we allocate/free memory here. - * If the application calls SDL_SetMemoryFunctions(), we can't rely on - * SDL_free() to use the same allocator after SDL_main() returns. - */ - - // Parse it into argv and argc - argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv)); - if (argv == NULL) { - return OutOfMemory(); - } - for (i = 0; i < argc; ++i) { - const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL); - if (!utf8size) { // uhoh? - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); - return -1; + char **allocated_argv = NULL; + char **argv = _argv; + int argc = _argc; + + if (!argv) { + // Get the arguments with GetCommandLine, convert them to argc and argv + LPWSTR *argvw = CommandLineToArgvW(GetCommandLineW(), &argc); + if (argvw == NULL) { + return OutOfMemory(); } - argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character. - if (!argv[i]) { + // Note that we need to be careful about how we allocate/free memory here. + // If the application calls SDL_SetMemoryFunctions(), we can't rely on + // SDL_free() to use the same allocator after SDL_main() returns. + + argv = allocated_argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv)); + if (argv == NULL) { return OutOfMemory(); } - - if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh! - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); - return -1; + for (int i = 0; i < argc; ++i) { + const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL); + if (!utf8size) { // uhoh? + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); + return -1; + } + + argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character. + if (!argv[i]) { + return OutOfMemory(); + } + + if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh! + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); + return -1; + } } + argv[argc] = NULL; + LocalFree(argvw); } - argv[i] = NULL; - LocalFree(argvw); - hr = XGameRuntimeInitialize(); + int result = -1; + XTaskQueueHandle taskQueue; + HRESULT hr = XGameRuntimeInitialize(); if (SUCCEEDED(hr) && SDL_GetGDKTaskQueue(&taskQueue)) { Uint32 titleid = 0; @@ -134,14 +133,15 @@ int SDL_RunApp(int, char **, SDL_main_func mainFunction, void *reserved) #else SDL_assert_always(0 && "[GDK] Could not initialize - aborting"); #endif - result = -1; } // Free argv, to avoid memory leak - for (i = 0; i < argc; ++i) { - HeapFree(GetProcessHeap(), 0, argv[i]); + if (allocated_argv) { + for (int i = 0; i < argc; ++i) { + HeapFree(GetProcessHeap(), 0, allocated_argv[i]); + } + HeapFree(GetProcessHeap(), 0, allocated_argv); } - HeapFree(GetProcessHeap(), 0, argv); return result; } diff --git a/src/main/n3ds/SDL_sysmain_runapp.c b/src/main/n3ds/SDL_sysmain_runapp.c index 06e4bf41e0891..4cb6adeb9560b 100644 --- a/src/main/n3ds/SDL_sysmain_runapp.c +++ b/src/main/n3ds/SDL_sysmain_runapp.c @@ -23,11 +23,16 @@ #ifdef SDL_PLATFORM_3DS +#include "../SDL_main_callbacks.h" + #include <3ds.h> int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { int result; + + SDL_CheckDefaultArgcArgv(&argc, &argv); + // init osSetSpeedupEnable(true); romfsInit(); diff --git a/src/main/ps2/SDL_sysmain_runapp.c b/src/main/ps2/SDL_sysmain_runapp.c index 658bce304f12d..e92bc702413ee 100644 --- a/src/main/ps2/SDL_sysmain_runapp.c +++ b/src/main/ps2/SDL_sysmain_runapp.c @@ -25,6 +25,8 @@ // SDL_RunApp() code for PS2 based on SDL_ps2_main.c, fjtrujy@gmail.com +#include "../SDL_main_callbacks.h" + #include #include #include @@ -69,6 +71,8 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv int res; (void)reserved; + SDL_CheckDefaultArgcArgv(&argc, &argv); + prepare_IOP(); init_drivers(); diff --git a/src/main/psp/SDL_sysmain_runapp.c b/src/main/psp/SDL_sysmain_runapp.c index 7f09914b9334e..3b4eb0f8b15d2 100644 --- a/src/main/psp/SDL_sysmain_runapp.c +++ b/src/main/psp/SDL_sysmain_runapp.c @@ -28,6 +28,7 @@ #include #include #include "../../events/SDL_events_c.h" +#include "../SDL_main_callbacks.h" /* If application's main() is redefined as SDL_main, and libSDL_main is linked, then this file will create the standard exit callback, @@ -72,6 +73,9 @@ int sdl_psp_setup_callbacks(void) int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { (void)reserved; + + SDL_CheckDefaultArgcArgv(&argc, &argv); + sdl_psp_setup_callbacks(); SDL_SetMainReady(); diff --git a/src/video/uikit/SDL_uikitappdelegate.m b/src/video/uikit/SDL_uikitappdelegate.m index 2af7165890cef..e6223f1ada371 100644 --- a/src/video/uikit/SDL_uikitappdelegate.m +++ b/src/video/uikit/SDL_uikitappdelegate.m @@ -29,6 +29,7 @@ #import "SDL_uikitwindow.h" #include "../../events/SDL_events_c.h" +#include "../../main/SDL_main_callbacks.h" #ifdef main #undef main @@ -41,7 +42,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved) { - int i; + SDL_CheckDefaultArgcArgv(&argc, &argv); // store arguments /* Note that we need to be careful about how we allocate/free memory here. @@ -51,11 +52,11 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserve forward_main = mainFunction; forward_argc = argc; forward_argv = (char **)malloc((argc + 1) * sizeof(char *)); // This should NOT be SDL_malloc() - for (i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { forward_argv[i] = malloc((strlen(argv[i]) + 1) * sizeof(char)); // This should NOT be SDL_malloc() strcpy(forward_argv[i], argv[i]); } - forward_argv[i] = NULL; + forward_argv[argc] = NULL; // Give over control to run loop, SDLUIKitDelegate will handle most things from here @autoreleasepool { @@ -71,7 +72,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserve } // free the memory we used to hold copies of argc and argv - for (i = 0; i < forward_argc; i++) { + for (int i = 0; i < forward_argc; i++) { free(forward_argv[i]); // This should NOT be SDL_free() } free(forward_argv); // This should NOT be SDL_free()