Skip to content

Commit 9e7db49

Browse files
committed
Add Git for Windows' wrapper executable
On Windows, Git is faced by the challenge that it has to set up certain environment variables before running Git under special circumstances such as when Git is called directly from cmd.exe (i.e. outside any Bash environment). This source code was taken from msysGit's commit 74a198d: https://github.com/msysgit/msysgit/blob/74a198d/src/git-wrapper/git-wrapper.c Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 8c01ab4 commit 9e7db49

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

compat/win32/git-wrapper.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* git-wrapper - replace cmd\git.cmd with an executable
3+
*
4+
* Copyright (C) 2012 Pat Thoyts <[email protected]>
5+
*/
6+
7+
#define STRICT
8+
#define WIN32_LEAN_AND_MEAN
9+
#define UNICODE
10+
#define _UNICODE
11+
#include <windows.h>
12+
#include <shlwapi.h>
13+
#include <shellapi.h>
14+
#include <stdio.h>
15+
16+
static void
17+
PrintError(LPCWSTR wszPrefix, DWORD dwError)
18+
{
19+
LPWSTR lpsz = NULL;
20+
DWORD cch = 0;
21+
22+
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
23+
| FORMAT_MESSAGE_FROM_SYSTEM
24+
| FORMAT_MESSAGE_IGNORE_INSERTS,
25+
NULL, dwError, LANG_NEUTRAL,
26+
(LPTSTR)&lpsz, 0, NULL);
27+
if (cch < 1) {
28+
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
29+
| FORMAT_MESSAGE_FROM_STRING
30+
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
31+
L"Code 0x%1!08x!",
32+
0, LANG_NEUTRAL, (LPTSTR)&lpsz, 0,
33+
(va_list*)&dwError);
34+
}
35+
fwprintf(stderr, L"%s: %s", wszPrefix, lpsz);
36+
LocalFree((HLOCAL)lpsz);
37+
}
38+
39+
int
40+
main(void)
41+
{
42+
int r = 1, wait = 1;
43+
WCHAR exepath[MAX_PATH], exe[MAX_PATH];
44+
LPWSTR cmd = NULL, path2 = NULL, exep = exe;
45+
UINT codepage = 0;
46+
int len;
47+
48+
/* get the installation location */
49+
GetModuleFileName(NULL, exepath, MAX_PATH);
50+
PathRemoveFileSpec(exepath);
51+
PathRemoveFileSpec(exepath);
52+
53+
/* set the default exe module */
54+
wcscpy(exe, exepath);
55+
PathAppend(exe, L"bin\\git.exe");
56+
57+
/* if not set, set TERM to msys */
58+
if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) {
59+
SetEnvironmentVariable(L"TERM", L"msys");
60+
}
61+
62+
/* if not set, set PLINK_PROTOCOL to ssh */
63+
if (GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0) == 0) {
64+
SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh");
65+
}
66+
67+
/* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
68+
* With roaming profiles: HOMEPATH is the roaming location and
69+
* USERPROFILE is the local location
70+
*/
71+
if (GetEnvironmentVariable(L"HOME", NULL, 0) == 0) {
72+
LPWSTR e = NULL;
73+
len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0);
74+
if (len == 0) {
75+
len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0);
76+
if (len != 0) {
77+
e = (LPWSTR)malloc(len * sizeof(WCHAR));
78+
GetEnvironmentVariable(L"USERPROFILE", e, len);
79+
SetEnvironmentVariable(L"HOME", e);
80+
free(e);
81+
}
82+
} else {
83+
int n;
84+
len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0);
85+
e = (LPWSTR)malloc(sizeof(WCHAR) * (len + 2));
86+
n = GetEnvironmentVariable(L"HOMEDRIVE", e, len);
87+
GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n);
88+
SetEnvironmentVariable(L"HOME", e);
89+
free(e);
90+
}
91+
}
92+
93+
/* extend the PATH */
94+
len = GetEnvironmentVariable(L"PATH", NULL, 0);
95+
len = sizeof(WCHAR) * (len + 2 * MAX_PATH);
96+
path2 = (LPWSTR)malloc(len);
97+
wcscpy(path2, exepath);
98+
PathAppend(path2, L"bin;");
99+
/* should do this only if it exists */
100+
wcscat(path2, exepath);
101+
PathAppend(path2, L"mingw\\bin;");
102+
GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)],
103+
(len/sizeof(WCHAR))-wcslen(path2));
104+
SetEnvironmentVariable(L"PATH", path2);
105+
free(path2);
106+
107+
108+
/* fix up the command line to call git.exe
109+
* We have to be very careful about quoting here so we just
110+
* trim off the first argument and replace it leaving the rest
111+
* untouched.
112+
*/
113+
{
114+
int wargc = 0, gui = 0;
115+
LPWSTR cmdline = NULL;
116+
LPWSTR *wargv = NULL, p = NULL;
117+
cmdline = GetCommandLine();
118+
wargv = CommandLineToArgvW(cmdline, &wargc);
119+
cmd = (LPWSTR)malloc(sizeof(WCHAR) * (wcslen(cmdline) + MAX_PATH));
120+
if (wargc > 1 && wcsicmp(L"gui", wargv[1]) == 0) {
121+
wait = 0;
122+
if (wargc > 2 && wcsicmp(L"citool", wargv[2]) == 0) {
123+
wait = 1;
124+
wcscpy(cmd, L"git.exe");
125+
} else {
126+
WCHAR script[MAX_PATH];
127+
gui = 1;
128+
wcscpy(script, exepath);
129+
PathAppend(script, L"libexec\\git-core\\git-gui");
130+
PathQuoteSpaces(script);
131+
wcscpy(cmd, L"wish.exe ");
132+
wcscat(cmd, script);
133+
wcscat(cmd, L" --");
134+
exep = NULL; /* find the module from the commandline */
135+
}
136+
} else {
137+
wcscpy(cmd, L"git.exe");
138+
}
139+
/* find the first space after the initial parameter then append all */
140+
p = wcschr(&cmdline[wcslen(wargv[0])], L' ');
141+
if (p && *p) {
142+
/* for git gui subcommands, remove the 'gui' word */
143+
if (gui) {
144+
while (*p == L' ') ++p;
145+
p = wcschr(p, L' ');
146+
}
147+
if (p && *p)
148+
wcscat(cmd, p);
149+
}
150+
LocalFree(wargv);
151+
}
152+
153+
/* set the console to ANSI/GUI codepage */
154+
codepage = GetConsoleCP();
155+
SetConsoleCP(GetACP());
156+
157+
{
158+
STARTUPINFO si;
159+
PROCESS_INFORMATION pi;
160+
BOOL br = FALSE;
161+
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
162+
ZeroMemory(&si, sizeof(STARTUPINFO));
163+
si.cb = sizeof(STARTUPINFO);
164+
br = CreateProcess(exep,/* module: null means use command line */
165+
cmd, /* modified command line */
166+
NULL, /* process handle inheritance */
167+
NULL, /* thread handle inheritance */
168+
TRUE, /* handles inheritable? */
169+
CREATE_UNICODE_ENVIRONMENT,
170+
NULL, /* environment: use parent */
171+
NULL, /* starting directory: use parent */
172+
&si, &pi);
173+
if (br) {
174+
if (wait)
175+
WaitForSingleObject(pi.hProcess, INFINITE);
176+
if (!GetExitCodeProcess(pi.hProcess, (DWORD *)&r))
177+
PrintError(L"error reading exit code", GetLastError());
178+
CloseHandle(pi.hProcess);
179+
} else {
180+
PrintError(L"error launching git", GetLastError());
181+
r = 1;
182+
}
183+
}
184+
185+
free(cmd);
186+
187+
/* reset the console codepage */
188+
SetConsoleCP(codepage);
189+
ExitProcess(r);
190+
}
191+
192+
/*
193+
* Local variables:
194+
* mode: c
195+
* indent-tabs-mode: nil
196+
* c-basic-offset: 4
197+
* tab-width: 4
198+
* End:
199+
*/

0 commit comments

Comments
 (0)