Created
June 27, 2012 09:41
-
-
Save patthoyts/3002978 to your computer and use it in GitHub Desktop.
mysGit git wrapper code to replace git.cmd with an equivalent exe.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* git-wrapper - replace cmd\git.cmd with an executable | |
* | |
* Copyright (C) 2012 Pat Thoyts <patthoyts@users.sourceforge.net> | |
* | |
* Note: Just for fun, this avoids linking to any C run-time with MSVC | |
* Compile: | |
* cl -nologo -W3 -Ox -GS- git-wrapper.c -link -subsystem:console -release | |
* -nodefaultlib -entry:wmain kernel32.lib shlwapi.lib shell32.lib | |
* or: | |
* gcc -Wall -Wwrite-strings -o gw.exe git-wrapper.c -lshell32 -lshlwapi | |
*/ | |
#define STRICT | |
#define WIN32_LEAN_AND_MEAN | |
#define UNICODE | |
#define _UNICODE | |
#define _CRT_SECURE_NO_WARNINGS | |
#include <windows.h> | |
#include <shlwapi.h> | |
#include <shellapi.h> | |
#if _MSC_VER >= 1000 | |
#pragma comment(lib, "shlwapi") | |
#pragma comment(lib, "shell32") | |
#endif | |
#ifdef __GNUC__ | |
#define SecureZeroMemory ZeroMemory | |
#endif | |
static void * | |
xmalloc(size_t len) | |
{ | |
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); | |
} | |
static void | |
xfree(void *p) | |
{ | |
HeapFree(GetProcessHeap(), 0, p); | |
} | |
static int | |
xcsicmp(LPCWSTR a, LPCWSTR b) | |
{ | |
#ifdef __GNUC__ | |
return wcsicmp(a, b); | |
#else | |
return CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, a, -1, b, -1) - 2; | |
#endif | |
} | |
static wchar_t * | |
xcschr(wchar_t *s, wchar_t c) | |
{ | |
while (s && *s) { | |
if (*s == c) return s; | |
++s; | |
} | |
return NULL; | |
} | |
#ifdef __MSC_VER__ | |
int __stdcall wmain(void) | |
#else | |
int main(void) | |
#endif | |
{ | |
int r = 1, wait = 1; | |
WCHAR exepath[MAX_PATH], exe[MAX_PATH]; | |
LPWSTR cmd = NULL, path2 = NULL, exep = exe; | |
UINT codepage = 0; | |
int len; | |
/* get the installation location */ | |
GetModuleFileName(NULL, exepath, MAX_PATH); | |
PathRemoveFileSpec(exepath); | |
PathRemoveFileSpec(exepath); | |
/* set the default exe module */ | |
wcscpy(exe, exepath); | |
PathAppend(exe, L"bin\\git.exe"); | |
/* if not set, set TERM to msys */ | |
if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) { | |
SetEnvironmentVariable(L"TERM", L"msys"); | |
} | |
/* if not set, set PLINK_PROTOCOL to ssh */ | |
if (GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0) == 0) { | |
SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh"); | |
} | |
/* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE% | |
* With roaming profiles: HOMEPATH is the roaming location and | |
* USERPROFILE is the local location | |
*/ | |
if (GetEnvironmentVariable(L"HOME", NULL, 0) == 0) { | |
LPWSTR e = NULL; | |
len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0); | |
if (len == 0) { | |
len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0); | |
if (len != 0) { | |
e = (LPWSTR)xmalloc(len * sizeof(WCHAR)); | |
GetEnvironmentVariable(L"USERPROFILE", e, len); | |
SetEnvironmentVariable(L"HOME", e); | |
xfree(e); | |
} | |
} else { | |
int n; | |
len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0); | |
e = (LPWSTR)xmalloc(sizeof(WCHAR) * (len + 2)); | |
n = GetEnvironmentVariable(L"HOMEDRIVE", e, len); | |
GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n); | |
SetEnvironmentVariable(L"HOME", e); | |
xfree(e); | |
} | |
} | |
/* extend the PATH */ | |
len = GetEnvironmentVariable(L"PATH", NULL, 0); | |
len = sizeof(WCHAR) * (len + 2 * MAX_PATH); | |
path2 = (LPWSTR)xmalloc(len); | |
wcscpy(path2, exepath); | |
PathAppend(path2, L"bin;"); | |
/* should do this only if it exists */ | |
wcscat(path2, exepath); | |
PathAppend(path2, L"mingw\\bin;"); | |
GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)], | |
(len/sizeof(WCHAR))-wcslen(path2)); | |
SetEnvironmentVariable(L"PATH", path2); | |
xfree(path2); | |
/* fix up the command line to call git.exe | |
* We have to be very careful about quoting here so we just | |
* trim off the first argument and replace it leaving the rest | |
* untouched. | |
*/ | |
{ | |
int wargc = 0, gui = 0; | |
LPWSTR cmdline = NULL; | |
LPWSTR *wargv = NULL, p = NULL; | |
cmdline = GetCommandLine(); | |
wargv = CommandLineToArgvW(cmdline, &wargc); | |
cmd = (LPWSTR)xmalloc(sizeof(WCHAR) * (wcslen(cmdline) + MAX_PATH)); | |
if (wargc > 1 && xcsicmp(L"gui", wargv[1]) == 0) { | |
wait = 0; | |
if (wargc > 2 && xcsicmp(L"citool", wargv[2]) == 0) { | |
wait = 1; | |
wcscpy(cmd, L"git.exe"); | |
} else { | |
WCHAR script[MAX_PATH]; | |
gui = 1; | |
wcscat(script, exepath); | |
PathAppend(script, L"libexec\\git-core\\git-gui"); | |
PathQuoteSpaces(script); | |
wcscpy(cmd, L"wish.exe "); | |
wcscat(cmd, script); | |
wcscat(cmd, L" --"); | |
exep = NULL; /* find the module from the commandline */ | |
} | |
} else { | |
wcscpy(cmd, L"git.exe"); | |
} | |
/* find the first space after the initial parameter then append all */ | |
p = xcschr(&cmdline[wcslen(wargv[0])], L' '); | |
if (p && *p) { | |
/* for git gui subcommands, remove the 'gui' word */ | |
if (gui) { | |
while (*p == L' ') ++p; | |
p = xcschr(p, L' '); | |
} | |
if (p && *p) | |
wcscat(cmd, p); | |
} | |
LocalFree(wargv); | |
} | |
/* set the console to ANSI/GUI codepage */ | |
codepage = GetConsoleCP(); | |
SetConsoleCP(GetACP()); | |
{ | |
STARTUPINFO si; | |
PROCESS_INFORMATION pi; | |
SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); | |
SecureZeroMemory(&si, sizeof(STARTUPINFO)); | |
si.cb = sizeof(STARTUPINFO); | |
CreateProcess(exep,/* module: null means use command line */ | |
cmd, /* modified command line */ | |
NULL, /* process handle inheritance */ | |
NULL, /* thread handle inheritance */ | |
TRUE, /* handles inheritable? */ | |
CREATE_UNICODE_ENVIRONMENT, | |
NULL, /* environment: use parent */ | |
NULL, /* starting directory: use parent */ | |
&si, &pi); | |
if (wait) | |
WaitForSingleObject(pi.hProcess, INFINITE); | |
} | |
xfree(cmd); | |
/* reset the console codepage */ | |
SetConsoleCP(codepage); | |
ExitProcess(r); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment