From 0de2fde5500f77adad7fb685f416d7d9d599d4d1 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 8 Oct 2003 22:38:52 +0000 Subject: [PATCH] Moved build_command_line back to kernel and make it handle Unicode properly. --- dlls/kernel/process.c | 175 ++++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/env.c | 173 ----------------------------------------- 2 files changed, 170 insertions(+), 178 deletions(-) diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c index d97c8efd49d..3f3d8317706 100644 --- a/dlls/kernel/process.c +++ b/dlls/kernel/process.c @@ -121,9 +121,6 @@ static const WCHAR comW[] = {'c','o','m',0}; static const WCHAR batW[] = {'b','a','t',0}; static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0}; -/* dlls/ntdll/env.c */ -extern BOOL build_command_line( char **argv ); - extern void SHELL_LoadRegistry(void); extern void VERSION_Init( const WCHAR *appname ); extern void MODULE_InitLoadPath(void); @@ -423,6 +420,173 @@ static BOOL build_initial_environment(void) } +/*********************************************************************** + * set_library_argv + * + * Set the Wine library argc/argv global variables. + */ +static void set_library_argv( char **argv ) +{ + int argc; + WCHAR *p; + WCHAR **wargv; + DWORD total = 0; + + for (argc = 0; argv[argc]; argc++) + total += MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, NULL, 0 ); + + wargv = RtlAllocateHeap( GetProcessHeap(), 0, + total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) ); + p = (WCHAR *)(wargv + argc + 1); + for (argc = 0; argv[argc]; argc++) + { + DWORD reslen = MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, p, total ); + wargv[argc] = p; + p += reslen; + total -= reslen; + } + wargv[argc] = NULL; + + __wine_main_argc = argc; + __wine_main_argv = argv; + __wine_main_wargv = wargv; +} + + +/*********************************************************************** + * build_command_line + * + * Build the command line of a process from the argv array. + * + * Note that it does NOT necessarily include the file name. + * Sometimes we don't even have any command line options at all. + * + * We must quote and escape characters so that the argv array can be rebuilt + * from the command line: + * - spaces and tabs must be quoted + * 'a b' -> '"a b"' + * - quotes must be escaped + * '"' -> '\"' + * - if '\'s are followed by a '"', they must be doubled and followed by '\"', + * resulting in an odd number of '\' followed by a '"' + * '\"' -> '\\\"' + * '\\"' -> '\\\\\"' + * - '\'s that are not followed by a '"' can be left as is + * 'a\b' == 'a\b' + * 'a\\b' == 'a\\b' + */ +static BOOL build_command_line( WCHAR **argv ) +{ + int len; + WCHAR **arg; + LPWSTR p; + RTL_USER_PROCESS_PARAMETERS* rupp = NtCurrentTeb()->Peb->ProcessParameters; + + if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */ + + len = 0; + for (arg = argv; *arg; arg++) + { + int has_space,bcount; + WCHAR* a; + + has_space=0; + bcount=0; + a=*arg; + if( !*a ) has_space=1; + while (*a!='\0') { + if (*a=='\\') { + bcount++; + } else { + if (*a==' ' || *a=='\t') { + has_space=1; + } else if (*a=='"') { + /* doubling of '\' preceeding a '"', + * plus escaping of said '"' + */ + len+=2*bcount+1; + } + bcount=0; + } + a++; + } + len+=(a-*arg)+1 /* for the separating space */; + if (has_space) + len+=2; /* for the quotes */ + } + + if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return FALSE; + + p = rupp->CommandLine.Buffer; + rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR); + rupp->CommandLine.MaximumLength = len * sizeof(WCHAR); + for (arg = argv; *arg; arg++) + { + int has_space,has_quote; + WCHAR* a; + + /* Check for quotes and spaces in this argument */ + has_space=has_quote=0; + a=*arg; + if( !*a ) has_space=1; + while (*a!='\0') { + if (*a==' ' || *a=='\t') { + has_space=1; + if (has_quote) + break; + } else if (*a=='"') { + has_quote=1; + if (has_space) + break; + } + a++; + } + + /* Now transfer it to the command line */ + if (has_space) + *p++='"'; + if (has_quote) { + int bcount; + WCHAR* a; + + bcount=0; + a=*arg; + while (*a!='\0') { + if (*a=='\\') { + *p++=*a; + bcount++; + } else { + if (*a=='"') { + int i; + + /* Double all the '\\' preceeding this '"', plus one */ + for (i=0;i<=bcount;i++) + *p++='\\'; + *p++='"'; + } else { + *p++=*a; + } + bcount=0; + } + a++; + } + } else { + WCHAR* x = *arg; + while ((*p=*x++)) p++; + } + if (has_space) + *p++='"'; + *p++=' '; + } + if (p > rupp->CommandLine.Buffer) + p--; /* remove last space */ + *p = '\0'; + + return TRUE; +} + + /* make sure the unicode string doesn't point beyond the end pointer */ static inline void fix_unicode_string( UNICODE_STRING *str, char *end_ptr ) { @@ -741,7 +905,7 @@ void __wine_process_init( int argc, char *argv[] ) if (DOSFS_GetFullName( main_exe_name, TRUE, &full_name ) && wine_dlopen( full_name.long_name, RTLD_NOW, error, sizeof(error) )) { - static const WCHAR soW[] = {'s','o',0}; + static const WCHAR soW[] = {'.','s','o',0}; if ((p = strrchrW( main_exe_name, '.' )) && !strcmpW( p, soW )) { *p = 0; @@ -758,7 +922,8 @@ void __wine_process_init( int argc, char *argv[] ) found: /* build command line */ - if (!build_command_line( argv )) goto error; + set_library_argv( argv ); + if (!build_command_line( __wine_main_wargv )) goto error; /* create 32-bit module for main exe */ if (!(current_process.module = BUILTIN32_LoadExeModule( current_process.module, CreateFileW ))) diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c index 9097d696507..997d1ab761b 100644 --- a/dlls/ntdll/env.c +++ b/dlls/ntdll/env.c @@ -479,176 +479,3 @@ void WINAPI RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS *params ) ULONG size = 0; NtFreeVirtualMemory( NtCurrentProcess(), &ptr, &size, MEM_RELEASE ); } - - -/*********************************************************************** - * set_library_argv - * - * Set the Wine library argc/argv global variables. - */ -static void set_library_argv( char **argv ) -{ - int argc; - WCHAR *p; - WCHAR **wargv; - DWORD total = 0, len, reslen; - - for (argc = 0; argv[argc]; argc++) - { - len = strlen(argv[argc]) + 1; - RtlMultiByteToUnicodeN(NULL, 0, &reslen, argv[argc], len); - total += reslen; - } - wargv = RtlAllocateHeap( ntdll_get_process_heap(), 0, - total + (argc + 1) * sizeof(*wargv) ); - p = (WCHAR *)(wargv + argc + 1); - for (argc = 0; argv[argc]; argc++) - { - len = strlen(argv[argc]) + 1; - RtlMultiByteToUnicodeN(p, total, &reslen, argv[argc], len); - wargv[argc] = p; - p += reslen / sizeof(WCHAR); - total -= reslen; - } - wargv[argc] = NULL; - - __wine_main_argc = argc; - __wine_main_argv = argv; - __wine_main_wargv = wargv; -} - -/*********************************************************************** - * build_command_line - * - * Build the command line of a process from the argv array. - * - * Note that it does NOT necessarily include the file name. - * Sometimes we don't even have any command line options at all. - * - * We must quote and escape characters so that the argv array can be rebuilt - * from the command line: - * - spaces and tabs must be quoted - * 'a b' -> '"a b"' - * - quotes must be escaped - * '"' -> '\"' - * - if '\'s are followed by a '"', they must be doubled and followed by '\"', - * resulting in an odd number of '\' followed by a '"' - * '\"' -> '\\\"' - * '\\"' -> '\\\\\"' - * - '\'s that are not followed by a '"' can be left as is - * 'a\b' == 'a\b' - * 'a\\b' == 'a\\b' - */ -BOOL build_command_line( char **argv ) -{ - int len; - char **arg; - LPWSTR p; - RTL_USER_PROCESS_PARAMETERS* rupp; - - set_library_argv( argv ); - - rupp = ntdll_get_process_pmts(); - if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */ - - len = 0; - for (arg = argv; *arg; arg++) - { - int has_space,bcount; - char* a; - - has_space=0; - bcount=0; - a=*arg; - if( !*a ) has_space=1; - while (*a!='\0') { - if (*a=='\\') { - bcount++; - } else { - if (*a==' ' || *a=='\t') { - has_space=1; - } else if (*a=='"') { - /* doubling of '\' preceeding a '"', - * plus escaping of said '"' - */ - len+=2*bcount+1; - } - bcount=0; - } - a++; - } - len+=(a-*arg)+1 /* for the separating space */; - if (has_space) - len+=2; /* for the quotes */ - } - - if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len * sizeof(WCHAR)))) - return FALSE; - - p = rupp->CommandLine.Buffer; - rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR); - rupp->CommandLine.MaximumLength = len * sizeof(WCHAR); - for (arg = argv; *arg; arg++) - { - int has_space,has_quote; - char* a; - - /* Check for quotes and spaces in this argument */ - has_space=has_quote=0; - a=*arg; - if( !*a ) has_space=1; - while (*a!='\0') { - if (*a==' ' || *a=='\t') { - has_space=1; - if (has_quote) - break; - } else if (*a=='"') { - has_quote=1; - if (has_space) - break; - } - a++; - } - - /* Now transfer it to the command line */ - if (has_space) - *p++='"'; - if (has_quote) { - int bcount; - char* a; - - bcount=0; - a=*arg; - while (*a!='\0') { - if (*a=='\\') { - *p++=*a; - bcount++; - } else { - if (*a=='"') { - int i; - - /* Double all the '\\' preceeding this '"', plus one */ - for (i=0;i<=bcount;i++) - *p++='\\'; - *p++='"'; - } else { - *p++=*a; - } - bcount=0; - } - a++; - } - } else { - char* x = *arg; - while ((*p=*x++)) p++; - } - if (has_space) - *p++='"'; - *p++=' '; - } - if (p > rupp->CommandLine.Buffer) - p--; /* remove last space */ - *p = '\0'; - - return TRUE; -}