From 156f4a1f0a7d3b65d1257c60fff2a9f7d6c6d8b4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 May 2015 15:19:04 +0200 Subject: [PATCH 1/4] git wrapper: refactor extraction of 1st arg into its own function This will be reused by the upcoming `--command=` option. Signed-off-by: Johannes Schindelin --- compat/win32/git-wrapper.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/compat/win32/git-wrapper.c b/compat/win32/git-wrapper.c index 1e214af2a4..1ca8a8a95b 100644 --- a/compat/win32/git-wrapper.c +++ b/compat/win32/git-wrapper.c @@ -188,6 +188,26 @@ static int strip_prefix(LPWSTR str, int *len, LPCWSTR prefix) return 0; } +static void extract_first_arg(LPWSTR command_line, LPWSTR exepath, LPWSTR buf) +{ + LPWSTR *wargv; + int wargc; + + wargv = CommandLineToArgvW(command_line, &wargc); + if (wargc < 1) { + fwprintf(stderr, L"Invalid command-line: '%s'\n", command_line); + exit(1); + } + if (*wargv[0] == L'\\' || + (isalpha(*wargv[0]) && wargv[0][1] == L':')) + wcscpy(buf, wargv[0]); + else { + wcscpy(buf, exepath); + PathAppend(buf, wargv[0]); + } + LocalFree(wargv); +} + static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, LPWSTR *prefix_args, int *prefix_args_len, int *is_git_command, LPWSTR *working_directory, int *full_path, @@ -268,20 +288,7 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, atat[env_len - 1] = save; } - /* parse first argument */ - wargv = CommandLineToArgvW(buf, &wargc); - if (wargc < 1) { - fwprintf(stderr, L"Invalid command-line: '%s'\n", buf); - exit(1); - } - if (*wargv[0] == L'\\' || - (isalpha(*wargv[0]) && wargv[0][1] == L':')) - wcscpy(exep, wargv[0]); - else { - wcscpy(exep, exepath); - PathAppend(exep, wargv[0]); - } - LocalFree(wargv); + extract_first_arg(buf, exepath, exep); if (_waccess(exep, 0) != -1) break; From 3f8cce86d473dcd13cff94b672984501358437f0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 May 2015 15:19:04 +0200 Subject: [PATCH 2/4] git wrapper: refactor @@VAR@@ expansion into its own function We will enhance the function in the next commit to support @@VAR@@ expansion in the upcoming `--command=` option. Signed-off-by: Johannes Schindelin --- compat/win32/git-wrapper.c | 78 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/compat/win32/git-wrapper.c b/compat/win32/git-wrapper.c index 1ca8a8a95b..08daea1d60 100644 --- a/compat/win32/git-wrapper.c +++ b/compat/win32/git-wrapper.c @@ -208,6 +208,44 @@ static void extract_first_arg(LPWSTR command_line, LPWSTR exepath, LPWSTR buf) LocalFree(wargv); } +static LPWSTR expand_variables(LPWSTR buf, size_t alloc) +{ + size_t len = wcslen(buf); + + for (;;) { + LPWSTR atat = wcsstr(buf, L"@@"), atat2; + WCHAR save; + int env_len, delta; + + if (!atat) + break; + + atat2 = wcsstr(atat + 2, L"@@"); + if (!atat2) + break; + + *atat2 = L'\0'; + env_len = GetEnvironmentVariable(atat + 2, NULL, 0); + delta = env_len - 1 - (atat2 + 2 - atat); + if (len + delta >= alloc) { + fwprintf(stderr, + L"Substituting '%s' results in too " + L"large a command-line\n", atat + 2); + exit(1); + } + if (delta) + memmove(atat2 + 2 + delta, atat2 + 2, + sizeof(WCHAR) * (len + 1 + - (atat2 + 2 - buf))); + len += delta; + save = atat[env_len - 1]; + GetEnvironmentVariable(atat + 2, atat, env_len); + atat[env_len - 1] = save; + } + + return buf; +} + static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, LPWSTR *prefix_args, int *prefix_args_len, int *is_git_command, LPWSTR *working_directory, int *full_path, @@ -218,6 +256,7 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, #define BUFSIZE 65536 static WCHAR buf[BUFSIZE]; + LPWSTR buf2 = buf; int len; for (id = 0; ; id++) { @@ -257,48 +296,19 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, if (!id) SetEnvironmentVariable(L"EXEPATH", exepath); - for (;;) { - LPWSTR atat = wcsstr(buf, L"@@"), atat2; - WCHAR save; - int env_len, delta; + buf2 = expand_variables(buf, BUFSIZE); - if (!atat) - break; - - atat2 = wcsstr(atat + 2, L"@@"); - if (!atat2) - break; - - *atat2 = L'\0'; - env_len = GetEnvironmentVariable(atat + 2, NULL, 0); - delta = env_len - 1 - (atat2 + 2 - atat); - if (len + delta >= BUFSIZE) { - fwprintf(stderr, - L"Substituting '%s' results in too " - L"large a command-line\n", atat + 2); - exit(1); - } - if (delta) - memmove(atat2 + 2 + delta, atat2 + 2, - sizeof(WCHAR) * (len + 1 - - (atat2 + 2 - buf))); - len += delta; - save = atat[env_len - 1]; - GetEnvironmentVariable(atat + 2, atat, env_len); - atat[env_len - 1] = save; - } - - extract_first_arg(buf, exepath, exep); + extract_first_arg(buf2, exepath, exep); if (_waccess(exep, 0) != -1) break; fwprintf(stderr, L"Skipping command-line '%s'\n('%s' not found)\n", - buf, exep); + buf2, exep); } - *prefix_args = buf; - *prefix_args_len = wcslen(buf); + *prefix_args = buf2; + *prefix_args_len = wcslen(buf2); *is_git_command = 0; *working_directory = (LPWSTR) 1; From 4e86a184941bfde6529742fc0fd9674d977e0a68 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 May 2015 15:26:15 +0200 Subject: [PATCH 3/4] git wrapper: auto-grow buffer in expand_variables() Signed-off-by: Johannes Schindelin --- compat/win32/git-wrapper.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/compat/win32/git-wrapper.c b/compat/win32/git-wrapper.c index 08daea1d60..603525eb7a 100644 --- a/compat/win32/git-wrapper.c +++ b/compat/win32/git-wrapper.c @@ -208,8 +208,11 @@ static void extract_first_arg(LPWSTR command_line, LPWSTR exepath, LPWSTR buf) LocalFree(wargv); } -static LPWSTR expand_variables(LPWSTR buf, size_t alloc) +#define alloc_nr(x) (((x)+16)*3/2) + +static LPWSTR expand_variables(LPWSTR buffer, size_t alloc) { + LPWSTR buf = buffer; size_t len = wcslen(buf); for (;;) { @@ -228,10 +231,27 @@ static LPWSTR expand_variables(LPWSTR buf, size_t alloc) env_len = GetEnvironmentVariable(atat + 2, NULL, 0); delta = env_len - 1 - (atat2 + 2 - atat); if (len + delta >= alloc) { - fwprintf(stderr, - L"Substituting '%s' results in too " - L"large a command-line\n", atat + 2); - exit(1); + LPWSTR buf2; + alloc = alloc_nr(alloc); + if (alloc <= len + delta) + alloc = len + delta + 1; + if (buf != buffer) + buf2 = realloc(buf, sizeof(WCHAR) * alloc); + else { + buf2 = malloc(sizeof(WCHAR) * alloc); + if (buf2) + memcpy(buf2, buf, sizeof(WCHAR) + * (len + 1)); + } + if (!buf2) { + fwprintf(stderr, + L"Substituting '%s' results in too " + L"large a command-line\n", atat + 2); + exit(1); + } + atat += buf2 - buf; + atat2 += buf2 - buf; + buf = buf2; } if (delta) memmove(atat2 + 2 + delta, atat2 + 2, From e0eccfa2b0661e2e41453c9b2bd133f666cee398 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 May 2015 15:04:48 +0200 Subject: [PATCH 4/4] git-wrapper: allow overriding the command to spawn via command-line args By embedding string resources into the Git wrapper executable, it can be configured to execute custom commands (after setting up the environment in the way required for Git for Windows to work properly). This feature is used e.g. for `git-bash.exe` which launches a Bash in the configured terminal window. Here, we introduce command-line options to override those string resources. That way, a user can call `git-bash.exe` (which is a copy of the Git wrapper with `usr\bin\bash.exe --login -i` embedded as string resource) with command-line options that will override what command is run. ConEmu, for example, might want to call ...\git-bash.exe --needs-console --no-hide --minimal-search-path ^ --command=usr\\bin\\bash.exe --login -i In particular, the following options are supported now: --command=:: Executes `` instead of the embedded string resource --[no-]minimal-search-path:: Ensures that only `/cmd/` is added to the `PATH` instead of `/mingw??/bin` and `/usr/bin/`, or not --[no-]needs-console:: Ensures that there is a Win32 console associated with the spawned process, or not --[no-]hide:: Hides the console window, or not Helped-by: Eli Young Signed-off-by: Johannes Schindelin --- compat/win32/git-wrapper.c | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/compat/win32/git-wrapper.c b/compat/win32/git-wrapper.c index 603525eb7a..396a4eec24 100644 --- a/compat/win32/git-wrapper.c +++ b/compat/win32/git-wrapper.c @@ -271,7 +271,7 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, int *is_git_command, LPWSTR *working_directory, int *full_path, int *skip_arguments, int *allocate_console, int *show_console) { - int id, minimal_search_path, needs_a_console, no_hide, wargc; + int i, id, minimal_search_path, needs_a_console, no_hide, wargc; LPWSTR *wargv; #define BUFSIZE 65536 @@ -333,15 +333,41 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, *is_git_command = 0; *working_directory = (LPWSTR) 1; wargv = CommandLineToArgvW(GetCommandLine(), &wargc); - if (wargc > 1) { - if (!wcscmp(L"--no-cd", wargv[1])) { + for (i = 1; i < wargc; i++) { + if (!wcscmp(L"--no-cd", wargv[i])) *working_directory = NULL; - *skip_arguments = 1; - } - else if (!wcsncmp(L"--cd=", wargv[1], 5)) { - *working_directory = wcsdup(wargv[1] + 5); - *skip_arguments = 1; + else if (!wcsncmp(L"--cd=", wargv[i], 5)) + *working_directory = wcsdup(wargv[i] + 5); + else if (!wcscmp(L"--minimal-search-path", wargv[i])) + minimal_search_path = 1; + else if (!wcscmp(L"--no-minimal-search-path", wargv[i])) + minimal_search_path = 0; + else if (!wcscmp(L"--needs-console", wargv[i])) + needs_a_console = 1; + else if (!wcscmp(L"--no-needs-console", wargv[i])) + needs_a_console = 0; + else if (!wcscmp(L"--hide", wargv[i])) + no_hide = 0; + else if (!wcscmp(L"--no-hide", wargv[i])) + no_hide = 1; + else if (!wcsncmp(L"--command=", wargv[i], 10)) { + LPWSTR expanded; + + wargv[i] += 10; + expanded = expand_variables(wargv[i], wcslen(wargv[i])); + if (expanded == wargv[i]) + expanded = wcsdup(expanded); + + extract_first_arg(expanded, exepath, exep); + + *prefix_args = expanded; + *prefix_args_len = wcslen(*prefix_args); + *skip_arguments = i; + break; } + else + break; + *skip_arguments = i; } if (minimal_search_path) *full_path = 0;