shell prompt should not beep and only show MSYSTEM when non-standard.
[msysgit.git] / src / git-wrapper / git-wrapper.c
blobe4ee5905205a414ad7abf525909fc08d94050dee
1 /*
2 * git-wrapper - replace cmd\git.cmd with an executable
4 * Copyright (C) 2012 Pat Thoyts <patthoyts@users.sourceforge.net>
5 */
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>
16 static void
17 PrintError(LPCWSTR wszPrefix, DWORD dwError)
19 LPWSTR lpsz = NULL;
20 DWORD cch = 0;
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);
35 fwprintf(stderr, L"%s: %s", wszPrefix, lpsz);
36 LocalFree((HLOCAL)lpsz);
39 int
40 main(void)
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;
48 /* get the installation location */
49 GetModuleFileName(NULL, exepath, MAX_PATH);
50 PathRemoveFileSpec(exepath);
51 PathRemoveFileSpec(exepath);
53 /* set the default exe module */
54 wcscpy(exe, exepath);
55 PathAppend(exe, L"bin\\git.exe");
57 /* if not set, set TERM to msys */
58 if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) {
59 SetEnvironmentVariable(L"TERM", L"msys");
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");
67 /* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
68 * With roaming profiles: HOMEPATH is the roaming location and
69 * USERPROFILE is the local location
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);
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);
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);
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.
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 */
136 } else {
137 wcscpy(cmd, L"git.exe");
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' ');
147 if (p && *p)
148 wcscat(cmd, p);
150 LocalFree(wargv);
153 /* set the console to ANSI/GUI codepage */
154 codepage = GetConsoleCP();
155 SetConsoleCP(GetACP());
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;
185 free(cmd);
187 /* reset the console codepage */
188 SetConsoleCP(codepage);
189 ExitProcess(r);
193 * Local variables:
194 * mode: c
195 * indent-tabs-mode: nil
196 * c-basic-offset: 4
197 * tab-width: 4
198 * End: