SDL-mirror/src/main/windows/SDL_windows_main.c
Sam Lantinga 198b2d497f Fixed bug 4692 - Command line parsing
Galadrim

As I have seen, SDL implements its own command line parser for Windows in SDL_windows_main.c. Unfortunately, it doesn't seem to allow command line arguments with trailing backslashes if quoting is required.

Usually, when you write an application that gets command line arguments passed as argc and argv, the parsing is done by parse_cmdline. The Windows API also provides the function CommandLineToArgvW, so an application can parse itself if only the command line string is provided. Both functions behave almost identically according to their documentation. If the argument "\\" (including the quotes) is passed, they both turn it into a single backslash.

The SDL command line parser on the other hand doesn't recognize the second quote character as the closing character in this example and therefore includes it in the parsed argument. The parser does not count the number of backslashes preceding a quote. It always treats a quote as escaped if a backslash is in front of it. Therefore, it should be impossible to quote and escape an argument correctly, if it has a trailing backslash and contains characters that require quoting.

Of course, each application is allowed to implement its own parsing rules, so SDL is free to do so. But the problem I see is that there are arguments, that are impossible to be passed to the parser correctly, as I described above. Is there a reason, why SDL does not simply use CommandLineToArgvW instead of implementing its own parser?

Here are some links that show that correct argument parsing, as it is usually done in Windows, is quite complicated:

https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw

http://www.windowsinspired.com/how-a-windows-programs-splits-its-command-line-into-individual-arguments/
2019-07-31 09:11:20 -07:00

109 lines
2.3 KiB
C

/*
SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98
The WinMain function -- calls your program's main() function
*/
#include "SDL_config.h"
#ifdef __WIN32__
/* Include this so we define UNICODE properly */
#include "../../core/windows/SDL_windows.h"
#include <shellapi.h> /* CommandLineToArgvW() */
/* Include the SDL main definition header */
#include "SDL.h"
#include "SDL_main.h"
#ifdef main
# undef main
#endif /* main */
#define WIN_WStringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
/* Pop up an out of memory message, returns to Windows */
static BOOL
OutOfMemory(void)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
return FALSE;
}
#if defined(_MSC_VER)
/* The VC++ compiler needs main/wmain defined */
# define console_ansi_main main
# if UNICODE
# define console_wmain wmain
# endif
#endif
/* Gets the arguments with GetCommandLine, converts them to argc and argv
and calls SDL_main */
static int
main_getcmdline(void)
{
LPWSTR *argvw;
char **argv;
int i, argc;
int result;
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
if (argvw == NULL) {
return OutOfMemory();
}
/* Parse it into argv and argc */
argv = (char **)SDL_calloc(argc + 1, sizeof(*argv));
if (!argv) {
return OutOfMemory();
}
for (i = 0; i < argc; ++i) {
argv[i] = WIN_WStringToUTF8(argvw[i]);
if (!argv[i]) {
return OutOfMemory();
}
}
argv[i] = NULL;
LocalFree(argvw);
SDL_SetMainReady();
/* Run the application main() code */
result = SDL_main(argc, argv);
/* Free argv, to avoid memory leak */
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
SDL_free(argv);
return result;
}
/* This is where execution begins [console apps, ansi] */
int
console_ansi_main(int argc, char *argv[])
{
return main_getcmdline();
}
#if UNICODE
/* This is where execution begins [console apps, unicode] */
int
console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
{
return main_getcmdline();
}
#endif
/* This is where execution begins [windowed apps] */
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
return main_getcmdline();
}
#endif /* __WIN32__ */
/* vi: set ts=4 sw=4 expandtab: */