Skip to content

Instantly share code, notes, and snippets.

@skeeto
Created February 27, 2023 05:04
Show Gist options
  • Save skeeto/2e3ae0e8623f5ca8ef4adbae9f05449b to your computer and use it in GitHub Desktop.
Save skeeto/2e3ae0e8623f5ca8ef4adbae9f05449b to your computer and use it in GitHub Desktop.
libtool-compatibility cmd.exe wrapper
// libtool-compatibility cmd.exe wrapper
// Converts libtool's Cygwin-style "cmd //c ..." to "cmd /c ..."
// $ cc -nostartfiles -o cmd.exe cmd.c
// This is free and unencumbered software released into the public domain.
#define MAX_PATH 260
#define COUNTOF(a) (int)(sizeof(a) / sizeof(0[a]))
#define FATAL "cmd.exe (fake): CreateProcessW() failed\n"
#define CMDEXE "\\cmd.exe"
typedef unsigned short char16_t;
typedef struct {
int cb;
void *a, *b, *c;
int d, e, f, g, h, i, j, k;
short l, m;
void *n, *o, *p, *q;
} StartupInfo;
typedef struct {
void *process;
void *thread;
int pid;
int tid;
} ProcessInformation;
int CreateProcessW(
void *, void *, void *, void *, int, int, void *, void *, void *, void *
) __attribute((dllimport,stdcall));
char16_t *GetCommandLineW(void)
__attribute((dllimport,stdcall));
int GetExitCodeProcess(void *, int *)
__attribute((dllimport,stdcall));
void *GetStdHandle(int)
__attribute((dllimport,stdcall));
int GetSystemDirectoryW(void *, int)
__attribute((dllimport,stdcall));
int WaitForSingleObject(void *, int)
__attribute((dllimport,stdcall));
int WriteFile(void *, void *, int, int *, void *)
__attribute((dllimport,stdcall));
// Find the end of argv[0].
static char16_t *findargs(char16_t *s)
{
if (s[0] == '"') {
for (s++;; s++) { // quoted argv[0]
switch (*s) {
case 0: return s;
case '"': return s + 1;
}
}
} else {
for (;; s++) { // unquoted argv[0]
switch (*s) {
case 0:
case '\t':
case ' ': return s;
}
}
}
}
static int space(char16_t c)
{
return c==' ' || c=='\t';
}
static char16_t *skipspace(char16_t *s)
{
for (;space(*s); s++) {}
return s;
}
static int targetmatch(char16_t *s)
{
return s[0]=='/' && s[1]=='/' && s[2]=='c' && (!s[3] || space(s[3]));
}
#if __i386
__attribute((force_align_arg_pointer))
#endif
__attribute((externally_visible))
int mainCRTStartup(void)
{
// Locate the real cmd.exe
char16_t cmdexe[MAX_PATH+COUNTOF(CMDEXE)];
int len = GetSystemDirectoryW(cmdexe, MAX_PATH);
for (int i = 0; i < COUNTOF(CMDEXE); i++) {
cmdexe[len++] = CMDEXE[i];
}
// Chop argv[0] so that it's a harmless empty string, then stomp the
// first '/' in "//c" into a space if present.
char16_t *cmdline = findargs(GetCommandLineW());
char16_t *argv1 = skipspace(cmdline);
if (targetmatch(argv1)) {
*argv1 = ' ';
}
StartupInfo si = {0};
si.cb = sizeof(si);
ProcessInformation pi;
if (!CreateProcessW(cmdexe, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi)) {
int dummy;
WriteFile(GetStdHandle(-12), FATAL, COUNTOF(FATAL)-1, &dummy, 0);
return -1;
}
int ret;
WaitForSingleObject(pi.process, -1);
GetExitCodeProcess(pi.process, &ret);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment