+static int env_compare(const void *a, const void *b)
+{
+ char *const *ea = a;
+ char *const *eb = b;
+ return strcasecmp(*ea, *eb);
+}
+
+static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
+ int prepend_cmd)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ struct strbuf envblk, args;
+ unsigned flags;
+ BOOL ret;
+
+ /* Determine whether or not we are associated to a console */
+ HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
+ FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (cons == INVALID_HANDLE_VALUE) {
+ /* There is no console associated with this process.
+ * Since the child is a console process, Windows
+ * would normally create a console window. But
+ * since we'll be redirecting std streams, we do
+ * not need the console.
+ */
+ flags = CREATE_NO_WINDOW;
+ } else {
+ /* There is already a console. If we specified
+ * CREATE_NO_WINDOW here, too, Windows would
+ * disassociate the child from the console.
+ * Go figure!
+ */
+ flags = 0;
+ CloseHandle(cons);
+ }
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = (HANDLE) _get_osfhandle(0);
+ si.hStdOutput = (HANDLE) _get_osfhandle(1);
+ si.hStdError = (HANDLE) _get_osfhandle(2);
+
+ /* concatenate argv, quoting args as we go */
+ strbuf_init(&args, 0);
+ if (prepend_cmd) {
+ char *quoted = (char *)quote_arg(cmd);
+ strbuf_addstr(&args, quoted);
+ if (quoted != cmd)
+ free(quoted);
+ }
+ for (; *argv; argv++) {
+ char *quoted = (char *)quote_arg(*argv);
+ if (*args.buf)
+ strbuf_addch(&args, ' ');
+ strbuf_addstr(&args, quoted);
+ if (quoted != *argv)
+ free(quoted);
+ }
+
+ if (env) {
+ int count = 0;
+ char **e, **sorted_env;
+
+ for (e = env; *e; e++)
+ count++;
+
+ /* environment must be sorted */
+ sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
+ memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
+ qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
+
+ strbuf_init(&envblk, 0);
+ for (e = sorted_env; *e; e++) {
+ strbuf_addstr(&envblk, *e);
+ strbuf_addch(&envblk, '\0');
+ }
+ free(sorted_env);
+ }
+
+ memset(&pi, 0, sizeof(pi));
+ ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
+ env ? envblk.buf : NULL, NULL, &si, &pi);
+
+ if (env)
+ strbuf_release(&envblk);
+ strbuf_release(&args);
+
+ if (!ret) {
+ errno = ENOENT;
+ return -1;
+ }
+ CloseHandle(pi.hThread);
+ return (pid_t)pi.hProcess;
+}
+
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
+{
+ pid_t pid;
+ char **path = get_path_split();
+ char *prog = path_lookup(cmd, path, 0);
+
+ if (!prog) {
+ errno = ENOENT;
+ pid = -1;
+ }
+ else {
+ const char *interpr = parse_interpreter(prog);
+
+ if (interpr) {
+ const char *argv0 = argv[0];
+ char *iprog = path_lookup(interpr, path, 1);
+ argv[0] = prog;
+ if (!iprog) {
+ errno = ENOENT;
+ pid = -1;
+ }
+ else {
+ pid = mingw_spawnve(iprog, argv, env, 1);
+ free(iprog);
+ }
+ argv[0] = argv0;
+ }
+ else
+ pid = mingw_spawnve(prog, argv, env, 0);
+ free(prog);
+ }
+ free_path_split(path);
+ return pid;
+}
+