1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/* gcc on mingw is hardcoded to use /mingw (which is c:/mingw) to
find various files. If this is a different version of mingw to the
one that we have in the GHC tree then things can go wrong. We
therefore need to add various -B flags to the gcc commandline,
so that it uses our in-tree mingw. Hence this wrapper. */
#include "cwrapper.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <windows.h>
void die(const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
exit(1);
}
char *mkString(const char *fmt, ...) {
char *p;
int i, j;
va_list argp;
va_start(argp, fmt);
i = vsnprintf(NULL, 0, fmt, argp);
va_end(argp);
if (i < 0) {
die("vsnprintf 0 failed: errno %d: %s\n", errno, strerror(errno));
}
p = malloc(i + 1);
if (p == NULL) {
die("malloc failed: errno %d: %s\n", errno, strerror(errno));
}
va_start(argp, fmt);
j = vsnprintf(p, i + 1, fmt, argp);
va_end(argp);
if (j < 0) {
die("vsnprintf with %d failed: errno %d: %s\n",
i + 1, errno, strerror(errno));
}
return p;
}
char *flattenAndQuoteArgs(char *ptr, int argc, char *argv[])
{
int i;
char *src;
for (i = 0; i < argc; i++) {
*ptr++ = '"';
src = argv[i];
while(*src) {
if (*src == '"' || *src == '\\') {
*ptr++ = '\\';
}
*ptr++ = *src++;
}
*ptr++ = '"';
*ptr++ = ' ';
}
return ptr;
}
/* This function takes a callback to be called after the creation of the child
process but before we block waiting for the child. Can be NULL. */
__attribute__((noreturn)) int run (char *exePath,
int numArgs1, char **args1,
int numArgs2, char **args2,
runCallback callback)
{
int i, cmdline_len;
char *new_cmdline, *ptr;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
/* Compute length of the flattened 'argv'. for each arg:
* + 1 for the space
* + chars * 2 (accounting for possible escaping)
* + 2 for quotes
*/
cmdline_len = 1 + strlen(exePath)*2 + 2;
for (i=0; i < numArgs1; i++) {
cmdline_len += 1 + strlen(args1[i])*2 + 2;
}
for (i=0; i < numArgs2; i++) {
cmdline_len += 1 + strlen(args2[i])*2 + 2;
}
new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
if (!new_cmdline) {
die("failed to start up %s; insufficient memory", exePath);
}
ptr = flattenAndQuoteArgs(new_cmdline, 1, &exePath);
ptr = flattenAndQuoteArgs(ptr, numArgs1, args1);
ptr = flattenAndQuoteArgs(ptr, numArgs2, args2);
*--ptr = '\0'; // replace the final space with \0
/* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
from the parent intercepting console events such as Ctrl-C,
which it shouldn't. Installing an ignore-all console handler
didn't do the trick either.
Irrespective of this issue, using CreateProcess() is preferable,
as it makes this wrapper work on both mingw and cygwin.
*/
#if 0
fprintf(stderr, "Invoking %s\n", new_cmdline); fflush(stderr);
#endif
if (!CreateProcess(exePath,
new_cmdline,
NULL,
NULL,
TRUE,
0, /* dwCreationFlags */
NULL, /* lpEnvironment */
NULL, /* lpCurrentDirectory */
&si, /* lpStartupInfo */
&pi) ) {
die("Unable to start %s (error code: %lu)\n", exePath, GetLastError());
}
/* Synchronize input and wait for target to be ready. */
WaitForInputIdle(pi.hProcess, INFINITE);
/* If we have a registered callback then call it before we block. */
if (callback)
callback();
switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
case WAIT_OBJECT_0:
{
DWORD pExitCode;
if (GetExitCodeProcess(pi.hProcess, &pExitCode) == 0) {
exit(1);
}
exit(pExitCode);
}
case WAIT_ABANDONED:
case WAIT_FAILED:
/* in the event we get any hard errors, bring the child to a halt. */
TerminateProcess(pi.hProcess,1);
exit(1);
default:
exit(1);
}
}
|