Created
February 27, 2023 05:04
-
-
Save skeeto/2e3ae0e8623f5ca8ef4adbae9f05449b to your computer and use it in GitHub Desktop.
libtool-compatibility cmd.exe wrapper
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
// 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