Module: wine Branch: master Commit: c7d2b1d5ccd9d2c1df317e03ea4ae35941c169a8 URL: http://source.winehq.org/git/wine.git/?a=commit;h=c7d2b1d5ccd9d2c1df317e03ea...
Author: Sergey Guralnik serhio@etersoft.ru Date: Tue Apr 9 14:15:01 2013 +0300
extrac32: Use own parser for command line.
---
programs/extrac32/extrac32.c | 102 +++++++++++++++++++++++++++++++++++++++++- 1 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/programs/extrac32/extrac32.c b/programs/extrac32/extrac32.c index addd732..111d2a7 100644 --- a/programs/extrac32/extrac32.c +++ b/programs/extrac32/extrac32.c @@ -82,6 +82,98 @@ static void copy_file(LPCWSTR source, LPCWSTR destination) CopyFileW(source, destination, FALSE); }
+static LPWSTR *get_extrac_args(LPWSTR cmdline, int *pargc) +{ + enum {OUTSIDE_ARG, INSIDE_ARG, INSIDE_QUOTED_ARG} state; + LPWSTR str; + int argc; + LPWSTR *argv; + int max_argc = 16; + BOOL new_arg; + + WINE_TRACE("cmdline: %s\n", wine_dbgstr_w(cmdline)); + str = HeapAlloc(GetProcessHeap(), 0, (strlenW(cmdline) + 1) * sizeof(WCHAR)); + if(!str) return NULL; + strcpyW(str, cmdline); + argv = HeapAlloc(GetProcessHeap(), 0, (max_argc + 1) * sizeof(LPWSTR)); + if(!argv) + { + HeapFree(GetProcessHeap(), 0, str); + return NULL; + } + + /* Split command line to separate arg-strings and fill argv */ + state = OUTSIDE_ARG; + argc = 0; + while(*str) + { + new_arg = FALSE; + /* Check character */ + if(isspaceW(*str)) /* white space */ + { + if(state == INSIDE_ARG) + { + state = OUTSIDE_ARG; + *str = 0; + } + } + else if(*str == '"') /* double quote */ + switch(state) + { + case INSIDE_QUOTED_ARG: + state = OUTSIDE_ARG; + *str = 0; + break; + case INSIDE_ARG: + *str = 0; + /* Fall through */ + case OUTSIDE_ARG: + if(!*++str) continue; + state = INSIDE_QUOTED_ARG; + new_arg = TRUE; + break; + } + else /* regular character */ + if(state == OUTSIDE_ARG) + { + state = INSIDE_ARG; + new_arg = TRUE; + } + + /* Add new argv entry, if need */ + if(new_arg) + { + if(argc >= max_argc - 1) + { + /* Realloc argv here because there always should be + at least one reserved cell for terminating NULL */ + max_argc *= 2; + argv = HeapReAlloc(GetProcessHeap(), 0, argv, + (max_argc + 1) * sizeof(LPWSTR)); + if(!argv) + { + HeapFree(GetProcessHeap(), 0, str); + return NULL; + } + } + argv[argc++] = str; + } + + str++; + } + + argv[argc] = NULL; + *pargc = argc; + + if(TRACE_ON(extrac32)) + { + int i; + for(i = 0; i < argc; i++) + WINE_TRACE("arg %d: %s\n", i, wine_dbgstr_w(argv[i])); + } + return argv; +} + int PASCAL wWinMain(HINSTANCE hInstance, HINSTANCE prev, LPWSTR cmdline, int show) { LPWSTR *argv; @@ -93,11 +185,17 @@ int PASCAL wWinMain(HINSTANCE hInstance, HINSTANCE prev, LPWSTR cmdline, int sho LPCWSTR cabfile = NULL;
path[0] = 0; - argv = CommandLineToArgvW(cmdline, &argc); + + /* Do not use CommandLineToArgvW() or __wgetmainargs() to parse + * command line for this program. It should treat each quote as argument + * delimiter. This doesn't match with behavior of mentioned functions. + * Do not use args provided by wmain() for the same reason. + */ + argv = get_extrac_args(cmdline, &argc);
if(!argv) { - WINE_ERR("Bad command line arguments\n"); + WINE_ERR("Command line parsing failed\n"); return 0; }