Fix starting git-gui through git-wrapper.
[msysgit.git] / src / git-wrapper / git-wrapper.c
blob06184420080a1062a05c9ca31d37c99c3e7097ff
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>
15 #ifdef __MSC_VER__
16 int __stdcall wmain(void)
17 #else
18 int main(void)
19 #endif
21 int r = 1, wait = 1;
22 WCHAR exepath[MAX_PATH], exe[MAX_PATH];
23 LPWSTR cmd = NULL, path2 = NULL, exep = exe;
24 UINT codepage = 0;
25 int len;
27 /* get the installation location */
28 GetModuleFileName(NULL, exepath, MAX_PATH);
29 PathRemoveFileSpec(exepath);
30 PathRemoveFileSpec(exepath);
32 /* set the default exe module */
33 wcscpy(exe, exepath);
34 PathAppend(exe, L"bin\\git.exe");
36 /* if not set, set TERM to msys */
37 if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) {
38 SetEnvironmentVariable(L"TERM", L"msys");
41 /* if not set, set PLINK_PROTOCOL to ssh */
42 if (GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0) == 0) {
43 SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh");
46 /* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
47 * With roaming profiles: HOMEPATH is the roaming location and
48 * USERPROFILE is the local location
50 if (GetEnvironmentVariable(L"HOME", NULL, 0) == 0) {
51 LPWSTR e = NULL;
52 len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0);
53 if (len == 0) {
54 len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0);
55 if (len != 0) {
56 e = (LPWSTR)malloc(len * sizeof(WCHAR));
57 GetEnvironmentVariable(L"USERPROFILE", e, len);
58 SetEnvironmentVariable(L"HOME", e);
59 free(e);
61 } else {
62 int n;
63 len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0);
64 e = (LPWSTR)malloc(sizeof(WCHAR) * (len + 2));
65 n = GetEnvironmentVariable(L"HOMEDRIVE", e, len);
66 GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n);
67 SetEnvironmentVariable(L"HOME", e);
68 free(e);
72 /* extend the PATH */
73 len = GetEnvironmentVariable(L"PATH", NULL, 0);
74 len = sizeof(WCHAR) * (len + 2 * MAX_PATH);
75 path2 = (LPWSTR)malloc(len);
76 wcscpy(path2, exepath);
77 PathAppend(path2, L"bin;");
78 /* should do this only if it exists */
79 wcscat(path2, exepath);
80 PathAppend(path2, L"mingw\\bin;");
81 GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)],
82 (len/sizeof(WCHAR))-wcslen(path2));
83 SetEnvironmentVariable(L"PATH", path2);
84 free(path2);
87 /* fix up the command line to call git.exe
88 * We have to be very careful about quoting here so we just
89 * trim off the first argument and replace it leaving the rest
90 * untouched.
93 int wargc = 0, gui = 0;
94 LPWSTR cmdline = NULL;
95 LPWSTR *wargv = NULL, p = NULL;
96 cmdline = GetCommandLine();
97 wargv = CommandLineToArgvW(cmdline, &wargc);
98 cmd = (LPWSTR)malloc(sizeof(WCHAR) * (wcslen(cmdline) + MAX_PATH));
99 if (wargc > 1 && wcsicmp(L"gui", wargv[1]) == 0) {
100 wait = 0;
101 if (wargc > 2 && wcsicmp(L"citool", wargv[2]) == 0) {
102 wait = 1;
103 wcscpy(cmd, L"git.exe");
104 } else {
105 WCHAR script[MAX_PATH];
106 gui = 1;
107 wcscpy(script, exepath);
108 PathAppend(script, L"libexec\\git-core\\git-gui");
109 PathQuoteSpaces(script);
110 wcscpy(cmd, L"wish.exe ");
111 wcscat(cmd, script);
112 wcscat(cmd, L" --");
113 exep = NULL; /* find the module from the commandline */
115 } else {
116 wcscpy(cmd, L"git.exe");
118 /* find the first space after the initial parameter then append all */
119 p = wcschr(&cmdline[wcslen(wargv[0])], L' ');
120 if (p && *p) {
121 /* for git gui subcommands, remove the 'gui' word */
122 if (gui) {
123 while (*p == L' ') ++p;
124 p = wcschr(p, L' ');
126 if (p && *p)
127 wcscat(cmd, p);
129 LocalFree(wargv);
132 /* set the console to ANSI/GUI codepage */
133 codepage = GetConsoleCP();
134 SetConsoleCP(GetACP());
137 STARTUPINFO si;
138 PROCESS_INFORMATION pi;
139 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
140 ZeroMemory(&si, sizeof(STARTUPINFO));
141 si.cb = sizeof(STARTUPINFO);
142 CreateProcess(exep,/* module: null means use command line */
143 cmd, /* modified command line */
144 NULL, /* process handle inheritance */
145 NULL, /* thread handle inheritance */
146 TRUE, /* handles inheritable? */
147 CREATE_UNICODE_ENVIRONMENT,
148 NULL, /* environment: use parent */
149 NULL, /* starting directory: use parent */
150 &si, &pi);
151 if (wait)
152 WaitForSingleObject(pi.hProcess, INFINITE);
155 free(cmd);
157 /* reset the console codepage */
158 SetConsoleCP(codepage);
159 ExitProcess(r);