Module: wine Branch: master Commit: 036f4dca3c7f9ee8964bb4ae0c4bcd106a347c7b URL: https://source.winehq.org/git/wine.git/?a=commit;h=036f4dca3c7f9ee8964bb4ae0... Author: Alexandre Julliard <julliard(a)winehq.org> Date: Wed Apr 8 15:09:00 2020 +0200 winecrt0: Rebuild the argv array instead of getting it from libwine. Signed-off-by: Alexandre Julliard <julliard(a)winehq.org> --- dlls/winecrt0/exe_entry.c | 78 +++++++++++++++++++++++++++++++++++----------- dlls/winecrt0/exe_wentry.c | 68 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 21 deletions(-) diff --git a/dlls/winecrt0/exe_entry.c b/dlls/winecrt0/exe_entry.c index 9ae45f9f04..803d56e10e 100644 --- a/dlls/winecrt0/exe_entry.c +++ b/dlls/winecrt0/exe_entry.c @@ -25,43 +25,83 @@ #include <stdarg.h> #include "windef.h" #include "winbase.h" -#include "winnls.h" #include "winternl.h" -#include "wine/library.h" #include "crt0_private.h" extern int __cdecl main( int argc, char *argv[] ); -static char **build_argv( WCHAR **wargv ) +static char **build_argv( const char *src, int *ret_argc ) { - int argc; - char *p, **argv; - DWORD total = 0; - - for (argc = 0; wargv[argc]; argc++) - total += WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, NULL, 0, NULL, NULL ); + char **argv, *arg, *dst; + int argc, in_quotes = 0, bcount = 0, len = strlen(src) + 1; - argv = HeapAlloc( GetProcessHeap(), 0, total + (argc + 1) * sizeof(*argv) ); - p = (char *)(argv + argc + 1); - for (argc = 0; wargv[argc]; argc++) + argc = 2 + len / 2; + argv = HeapAlloc( GetProcessHeap(), 0, argc * sizeof(*argv) + len ); + arg = dst = (char *)(argv + argc); + argc = 0; + while (*src) { - DWORD reslen = WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, p, total, NULL, NULL ); - argv[argc] = p; - p += reslen; - total -= reslen; + if ((*src == ' ' || *src == '\t') && !in_quotes) + { + /* skip the remaining spaces */ + while (*src == ' ' || *src == '\t') src++; + if (!*src) break; + /* close the argument and copy it */ + *dst++ = 0; + argv[argc++] = arg; + /* start with a new argument */ + arg = dst; + bcount = 0; + } + else if (*src == '\\') + { + *dst++ = *src++; + bcount++; + } + else if (*src == '"') + { + if ((bcount & 1) == 0) + { + /* Preceded by an even number of '\', this is half that + * number of '\', plus a '"' which we discard. + */ + dst -= bcount / 2; + src++; + if (in_quotes && *src == '"') *dst++ = *src++; + else in_quotes = !in_quotes; + } + else + { + /* Preceded by an odd number of '\', this is half that + * number of '\' followed by a '"' + */ + dst -= bcount / 2 + 1; + *dst++ = *src++; + } + bcount = 0; + } + else /* a regular character */ + { + *dst++ = *src++; + bcount = 0; + } } + *dst = 0; + argv[argc++] = arg; argv[argc] = NULL; + *ret_argc = argc; return argv; } DWORD WINAPI DECLSPEC_HIDDEN __wine_spec_exe_entry( PEB *peb ) { + int argc; BOOL needs_init = (__wine_spec_init_state != CONSTRUCTORS_DONE); - char **argv = build_argv( __wine_main_wargv ); + char **argv = build_argv( GetCommandLineA(), &argc ); DWORD ret; - if (needs_init) _init( __wine_main_argc, argv, NULL ); - ret = main( __wine_main_argc, argv ); + if (needs_init) _init( argc, argv, NULL ); + ret = main( argc, argv ); if (needs_init) _fini(); ExitProcess( ret ); } diff --git a/dlls/winecrt0/exe_wentry.c b/dlls/winecrt0/exe_wentry.c index b889e5a102..b01bfd6210 100644 --- a/dlls/winecrt0/exe_wentry.c +++ b/dlls/winecrt0/exe_wentry.c @@ -26,18 +26,82 @@ #include "windef.h" #include "winbase.h" #include "winternl.h" -#include "wine/library.h" #include "crt0_private.h" extern int __cdecl wmain( int argc, WCHAR *argv[] ); +static WCHAR **build_argv( const WCHAR *src, int *ret_argc ) +{ + WCHAR **argv, *arg, *dst; + int argc, in_quotes = 0, bcount = 0, len = lstrlenW(src) + 1; + + argc = 2 + len / 2; + argv = HeapAlloc( GetProcessHeap(), 0, argc * sizeof(*argv) + len * sizeof(WCHAR) ); + arg = dst = (WCHAR *)(argv + argc); + argc = 0; + while (*src) + { + if ((*src == ' ' || *src == '\t') && !in_quotes) + { + /* skip the remaining spaces */ + while (*src == ' ' || *src == '\t') src++; + if (!*src) break; + /* close the argument and copy it */ + *dst++ = 0; + argv[argc++] = arg; + /* start with a new argument */ + arg = dst; + bcount = 0; + } + else if (*src == '\\') + { + *dst++ = *src++; + bcount++; + } + else if (*src == '"') + { + if ((bcount & 1) == 0) + { + /* Preceded by an even number of '\', this is half that + * number of '\', plus a '"' which we discard. + */ + dst -= bcount / 2; + src++; + if (in_quotes && *src == '"') *dst++ = *src++; + else in_quotes = !in_quotes; + } + else + { + /* Preceded by an odd number of '\', this is half that + * number of '\' followed by a '"' + */ + dst -= bcount / 2 + 1; + *dst++ = *src++; + } + bcount = 0; + } + else /* a regular character */ + { + *dst++ = *src++; + bcount = 0; + } + } + *dst = 0; + argv[argc++] = arg; + argv[argc] = NULL; + *ret_argc = argc; + return argv; +} + DWORD WINAPI DECLSPEC_HIDDEN __wine_spec_exe_wentry( PEB *peb ) { + int argc; BOOL needs_init = (__wine_spec_init_state != CONSTRUCTORS_DONE); + WCHAR **argv = build_argv( GetCommandLineW(), &argc ); DWORD ret; if (needs_init) _init( 0, NULL, NULL ); - ret = wmain( __wine_main_argc, __wine_main_wargv ); + ret = wmain( argc, argv ); if (needs_init) _fini(); ExitProcess( ret ); }