summaryrefslogtreecommitdiff
path: root/src/lib9/run_windows.c
blob: 87875b42dbdefd26a977cbc60636a65f3b4f521a (plain)
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
// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <u.h>
#include <windows.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include "win.h"

int
runcmd(char **argv)
{
	// Mostly copied from ../cmd/dist/windows.c.
	// If there's a bug here, fix the logic there too.
	int i, j, nslash;
	Fmt fmt;
	char *q;
	WinRune *r;
	STARTUPINFOW si;
	PROCESS_INFORMATION pi;
	DWORD code;

	fmtstrinit(&fmt);
	for(i=0; argv[i]; i++) {
		if(i > 0)
			fmtprint(&fmt, " ");
		q = argv[i];
		if(strstr(q, " ") || strstr(q, "\t") || strstr(q, "\"") || strstr(q, "\\\\") || (strlen(q) > 0 && q[strlen(q)-1] == '\\')) {
			fmtprint(&fmt, "\"");
			nslash = 0;
			for(; *q; q++) {
				if(*q == '\\') {
					nslash++;
					continue;
				}
				if(*q == '"') {
					for(j=0; j<2*nslash+1; j++)
						fmtprint(&fmt, "\\");
					nslash = 0;
				}
				for(j=0; j<nslash; j++)
					fmtprint(&fmt, "\\");
				nslash = 0;
				fmtprint(&fmt, "\"");
			}
			for(j=0; j<2*nslash; j++)
				fmtprint(&fmt, "\\");
			fmtprint(&fmt, "\"");
		} else {
			fmtprint(&fmt, "%s", q);
		}
	}
	
	q = fmtstrflush(&fmt);
	r = torune(q);
	free(q);

	memset(&si, 0, sizeof si);
	si.cb = sizeof si;
	si.dwFlags = STARTF_USESTDHANDLES;
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

	if(!CreateProcessW(nil, r, nil, nil, TRUE, 0, nil, nil, &si, &pi)) {
		free(r);
		return -1;
	}

	free(r);
	if(WaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE) != 0)
		return -1;
	i = GetExitCodeProcess(pi.hProcess, &code);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	if(!i)
		return -1;
	if(code != 0) {
		werrstr("unsuccessful exit status: %d", (int)code);
		return -1;
	}
	return 0;
}