Rewrite the LCC process spawning code on Windows, to handle file names containing spaces
This commit is contained in:
parent
f03a012087
commit
787bdba0ec
|
|
@ -221,64 +221,81 @@ char *basename(char *name) {
|
|||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
|
||||
static char *escapeDoubleQuotes(const char *string) {
|
||||
int stringLength = strlen(string);
|
||||
int bufferSize = stringLength + 1;
|
||||
int i, j;
|
||||
char *newString;
|
||||
static char *quoteArgument(const char *arg) {
|
||||
// Quote if it has spaces, tabs, or is empty
|
||||
if(!*arg || strpbrk(arg, " \t\"")) {
|
||||
size_t length = strlen(arg);
|
||||
size_t bufferSize = length * 2 + 3; // maximum escapes + quotes + terminator
|
||||
char *buffer = (char *)malloc(bufferSize);
|
||||
char *p = buffer;
|
||||
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
*p++ = '"'; // Open quote
|
||||
|
||||
for (i = 0; i < stringLength; i++) {
|
||||
if (string[i] == '"')
|
||||
bufferSize++;
|
||||
for(size_t i = 0; i < length; i++) {
|
||||
if(arg[i] == '"') {
|
||||
// Escape quotes
|
||||
*p++ = '\\';
|
||||
*p++ = '"';
|
||||
} else {
|
||||
// Everything else
|
||||
*p++ = arg[i];
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = '"'; // Close quote
|
||||
*p = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
newString = (char*)malloc(bufferSize);
|
||||
|
||||
if (newString == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0, j = 0; i < stringLength; i++) {
|
||||
if (string[i] == '"')
|
||||
newString[j++] = '\\';
|
||||
|
||||
newString[j++] = string[i];
|
||||
}
|
||||
|
||||
newString[j] = '\0';
|
||||
|
||||
return newString;
|
||||
// Duping to make memory management easier
|
||||
return _strdup(arg);
|
||||
}
|
||||
|
||||
static int spawn(const char *cmdname, char **argv) {
|
||||
int argc = 0;
|
||||
char **newArgv = argv;
|
||||
int i;
|
||||
intptr_t exitStatus;
|
||||
size_t totalLength = 0;
|
||||
for(int i = 0; argv[i] != NULL; i++) {
|
||||
char *quotedArg = quoteArgument(argv[i]);
|
||||
totalLength += strlen(quotedArg) + 1;
|
||||
free(quotedArg);
|
||||
}
|
||||
|
||||
// _spawnvp removes double quotes from arguments, so we
|
||||
// have to escape them manually
|
||||
while (*newArgv++ != NULL)
|
||||
argc++;
|
||||
char *cmdline = (char *)malloc(totalLength + 1);
|
||||
cmdline[0] = '\0';
|
||||
|
||||
newArgv = (char **)malloc(sizeof(char*) * (argc + 1));
|
||||
for(int i = 0; argv[i] != NULL; i++) {
|
||||
char *quotedArg = quoteArgument(argv[i]);
|
||||
strcat(cmdline, quotedArg);
|
||||
if(argv[i+1]) strcat(cmdline, " ");
|
||||
free(quotedArg);
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
newArgv[i] = escapeDoubleQuotes(argv[i]);
|
||||
STARTUPINFOA si = { sizeof(si) };
|
||||
PROCESS_INFORMATION pi;
|
||||
BOOL result = CreateProcessA(
|
||||
cmdname, cmdline,
|
||||
NULL, NULL, FALSE,
|
||||
0, NULL, NULL,
|
||||
&si, &pi);
|
||||
|
||||
newArgv[argc] = NULL;
|
||||
if(!result) {
|
||||
fprintf(stderr, "CreateProcess failed (%lu)\n", GetLastError());
|
||||
free(cmdline);
|
||||
return -1;
|
||||
}
|
||||
|
||||
exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv);
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
free(newArgv[i]);
|
||||
DWORD exit_code;
|
||||
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||
|
||||
free(newArgv);
|
||||
return exitStatus;
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
free(cmdline);
|
||||
|
||||
return (int)exit_code;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user