Skip to content

Commit a37d3f9

Browse files
committed
main: SDL_RunApp now explicitly handles NULL argv in all implementations.
It'll usually replace it with `{ "SDL_app", NULL }`, but things like Win32 can query the OS for the original command line arguments. This allows apps/scripting languages that provide their own entry points to use SDL_RunApp and not have to worry about how to compose an argv array on things like Windows, when SDL was going to do it for them anyhow. Most things won't experience any change with this commit, including apps that that want extra control but originate in a standard main()-style entry point and can just pass the existing argc/argv through to SDL_RunApp. Windows isn't addressed here, since a previous commit already updated it. GDK has a different fix here, but we'll unify that in a later commit. Closes #12676.
1 parent ce5e46c commit a37d3f9

File tree

10 files changed

+83
-56
lines changed

10 files changed

+83
-56
lines changed

include/SDL3/SDL_main.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void);
555555
* using SDL_main (like when using SDL_MAIN_HANDLED). When using this, you do
556556
* *not* need SDL_SetMainReady().
557557
*
558+
* If `argv` is NULL, SDL will provide command line arguments, either by
559+
* querying the OS for them if possible, or supplying a filler array if not.
560+
*
558561
* \param argc the argc parameter from the application's main() function, or 0
559562
* if the platform's main-equivalent has no argc.
560563
* \param argv the argv parameter from the application's main() function, or

src/main/SDL_main_callbacks.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,13 @@ void SDL_QuitMainCallbacks(SDL_AppResult result)
147147
SDL_Quit();
148148
}
149149

150+
void SDL_CheckDefaultArgcArgv(int *argc, char ***argv)
151+
{
152+
if (!argv)
153+
{
154+
static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
155+
static char *argvdummy[2] = { dummyargv0, NULL };
156+
*argc = 1;
157+
*argv = argvdummy;
158+
}
159+
}

src/main/SDL_main_callbacks.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func app
2727
SDL_AppResult SDL_IterateMainCallbacks(bool pump_events);
2828
void SDL_QuitMainCallbacks(SDL_AppResult result);
2929

30+
// (not a callback thing, but convenient to stick this in here.)
31+
// If *_argv is NULL, update *_argc and *_argv to point at a static array of { "SDL_app", NULL }.
32+
void SDL_CheckDefaultArgcArgv(int *_argc, char ***_argv);
33+
3034
#endif // SDL_main_callbacks_h_
3135

3236

src/main/SDL_runapp.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
3. This notice may not be removed or altered from any source distribution.
2020
*/
2121
#include "SDL_internal.h"
22+
#include "SDL_main_callbacks.h"
2223

2324
/* Most platforms that use/need SDL_main have their own SDL_RunApp() implementation.
2425
* If not, you can special case it here by appending || defined(__YOUR_PLATFORM__) */
@@ -27,16 +28,7 @@
2728
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
2829
{
2930
(void)reserved;
30-
31-
if(!argv)
32-
{
33-
// make sure argv isn't NULL, in case some user code doesn't like that
34-
static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
35-
static char *argvdummy[2] = { dummyargv0, NULL };
36-
argc = 1;
37-
argv = argvdummy;
38-
}
39-
31+
SDL_CheckDefaultArgcArgv(&argc, &argv);
4032
return mainFunction(argc, argv);
4133
}
4234

src/main/emscripten/SDL_sysmain_runapp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#ifdef SDL_PLATFORM_EMSCRIPTEN
2424

25+
#include "../SDL_main_callbacks.h"
26+
2527
#include <emscripten/emscripten.h>
2628

2729
EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8");
@@ -35,6 +37,8 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv
3537
{
3638
(void)reserved;
3739

40+
SDL_CheckDefaultArgcArgv(&argc, &argv);
41+
3842
// Move any URL params that start with "SDL_" over to environment
3943
// variables, so the hint system can pick them up, etc, much like a user
4044
// can set them from a shell prompt on a desktop machine. Ignore all

src/main/gdk/SDL_sysmain_runapp.cpp

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -37,53 +37,52 @@ static BOOL OutOfMemory(void)
3737
return FALSE;
3838
}
3939

40-
/* Gets the arguments with GetCommandLine, converts them to argc and argv
41-
and calls SDL_main */
4240
extern "C"
43-
int SDL_RunApp(int, char **, SDL_main_func mainFunction, void *reserved)
41+
int SDL_RunApp(int _argc, char **_argv, SDL_main_func mainFunction, void *reserved)
4442
{
45-
LPWSTR *argvw;
46-
char **argv;
47-
int i, argc, result;
48-
HRESULT hr;
49-
XTaskQueueHandle taskQueue;
50-
51-
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
52-
if (argvw == NULL) {
53-
return OutOfMemory();
54-
}
55-
56-
/* Note that we need to be careful about how we allocate/free memory here.
57-
* If the application calls SDL_SetMemoryFunctions(), we can't rely on
58-
* SDL_free() to use the same allocator after SDL_main() returns.
59-
*/
60-
61-
// Parse it into argv and argc
62-
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
63-
if (argv == NULL) {
64-
return OutOfMemory();
65-
}
66-
for (i = 0; i < argc; ++i) {
67-
const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
68-
if (!utf8size) { // uhoh?
69-
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
70-
return -1;
43+
char **allocated_argv = NULL;
44+
char **argv = _argv;
45+
int argc = _argc;
46+
47+
if (!argv) {
48+
// Get the arguments with GetCommandLine, convert them to argc and argv
49+
LPWSTR *argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
50+
if (argvw == NULL) {
51+
return OutOfMemory();
7152
}
7253

73-
argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character.
74-
if (!argv[i]) {
54+
// Note that we need to be careful about how we allocate/free memory here.
55+
// If the application calls SDL_SetMemoryFunctions(), we can't rely on
56+
// SDL_free() to use the same allocator after SDL_main() returns.
57+
58+
argv = allocated_argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
59+
if (argv == NULL) {
7560
return OutOfMemory();
7661
}
77-
78-
if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh!
79-
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
80-
return -1;
62+
for (int i = 0; i < argc; ++i) {
63+
const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
64+
if (!utf8size) { // uhoh?
65+
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
66+
return -1;
67+
}
68+
69+
argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character.
70+
if (!argv[i]) {
71+
return OutOfMemory();
72+
}
73+
74+
if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh!
75+
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
76+
return -1;
77+
}
8178
}
79+
argv[argc] = NULL;
80+
LocalFree(argvw);
8281
}
83-
argv[i] = NULL;
84-
LocalFree(argvw);
8582

86-
hr = XGameRuntimeInitialize();
83+
int result = -1;
84+
XTaskQueueHandle taskQueue;
85+
HRESULT hr = XGameRuntimeInitialize();
8786

8887
if (SUCCEEDED(hr) && SDL_GetGDKTaskQueue(&taskQueue)) {
8988
Uint32 titleid = 0;
@@ -134,14 +133,15 @@ int SDL_RunApp(int, char **, SDL_main_func mainFunction, void *reserved)
134133
#else
135134
SDL_assert_always(0 && "[GDK] Could not initialize - aborting");
136135
#endif
137-
result = -1;
138136
}
139137

140138
// Free argv, to avoid memory leak
141-
for (i = 0; i < argc; ++i) {
142-
HeapFree(GetProcessHeap(), 0, argv[i]);
139+
if (allocated_argv) {
140+
for (int i = 0; i < argc; ++i) {
141+
HeapFree(GetProcessHeap(), 0, allocated_argv[i]);
142+
}
143+
HeapFree(GetProcessHeap(), 0, allocated_argv);
143144
}
144-
HeapFree(GetProcessHeap(), 0, argv);
145145

146146
return result;
147147
}

src/main/n3ds/SDL_sysmain_runapp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@
2323

2424
#ifdef SDL_PLATFORM_3DS
2525

26+
#include "../SDL_main_callbacks.h"
27+
2628
#include <3ds.h>
2729

2830
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
2931
{
3032
int result;
33+
34+
SDL_CheckDefaultArgcArgv(&argc, &argv);
35+
3136
// init
3237
osSetSpeedupEnable(true);
3338
romfsInit();

src/main/ps2/SDL_sysmain_runapp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
// SDL_RunApp() code for PS2 based on SDL_ps2_main.c, fjtrujy@gmail.com
2727

28+
#include "../SDL_main_callbacks.h"
29+
2830
#include <sys/types.h>
2931
#include <sys/stat.h>
3032
#include <unistd.h>
@@ -69,6 +71,8 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv
6971
int res;
7072
(void)reserved;
7173

74+
SDL_CheckDefaultArgcArgv(&argc, &argv);
75+
7276
prepare_IOP();
7377
init_drivers();
7478

src/main/psp/SDL_sysmain_runapp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <pspkernel.h>
2929
#include <pspthreadman.h>
3030
#include "../../events/SDL_events_c.h"
31+
#include "../SDL_main_callbacks.h"
3132

3233
/* If application's main() is redefined as SDL_main, and libSDL_main is
3334
linked, then this file will create the standard exit callback,
@@ -72,6 +73,9 @@ int sdl_psp_setup_callbacks(void)
7273
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved)
7374
{
7475
(void)reserved;
76+
77+
SDL_CheckDefaultArgcArgv(&argc, &argv);
78+
7579
sdl_psp_setup_callbacks();
7680

7781
SDL_SetMainReady();

src/video/uikit/SDL_uikitappdelegate.m

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#import "SDL_uikitwindow.h"
3030

3131
#include "../../events/SDL_events_c.h"
32+
#include "../../main/SDL_main_callbacks.h"
3233

3334
#ifdef main
3435
#undef main
@@ -41,7 +42,7 @@
4142

4243
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved)
4344
{
44-
int i;
45+
SDL_CheckDefaultArgcArgv(&argc, &argv);
4546

4647
// store arguments
4748
/* 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
5152
forward_main = mainFunction;
5253
forward_argc = argc;
5354
forward_argv = (char **)malloc((argc + 1) * sizeof(char *)); // This should NOT be SDL_malloc()
54-
for (i = 0; i < argc; i++) {
55+
for (int i = 0; i < argc; i++) {
5556
forward_argv[i] = malloc((strlen(argv[i]) + 1) * sizeof(char)); // This should NOT be SDL_malloc()
5657
strcpy(forward_argv[i], argv[i]);
5758
}
58-
forward_argv[i] = NULL;
59+
forward_argv[argc] = NULL;
5960

6061
// Give over control to run loop, SDLUIKitDelegate will handle most things from here
6162
@autoreleasepool {
@@ -71,7 +72,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserve
7172
}
7273

7374
// free the memory we used to hold copies of argc and argv
74-
for (i = 0; i < forward_argc; i++) {
75+
for (int i = 0; i < forward_argc; i++) {
7576
free(forward_argv[i]); // This should NOT be SDL_free()
7677
}
7778
free(forward_argv); // This should NOT be SDL_free()

0 commit comments

Comments
 (0)