Skip to content

Instantly share code, notes, and snippets.

@patthoyts
Created June 27, 2012 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patthoyts/3002978 to your computer and use it in GitHub Desktop.
Save patthoyts/3002978 to your computer and use it in GitHub Desktop.
mysGit git wrapper code to replace git.cmd with an equivalent exe.
/*
* 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