runnerw fixed for cygwin
[idea/community.git] / native / runner / runnerw / runnerw.cpp
1 #include <windows.h>
2 #include <stdio.h>
3 #include <tlhelp32.h>
4 #include <iostream>
5 #include <string>
6
7 void PrintUsage() {
8         printf("Usage: runnerw.exe <app> <args>\n");
9         printf("where <app> is console application and <args> it's arguments.\n");
10         printf("\n");
11         printf(
12                         "Runner invokes console application as a process with inherited input and output streams.\n");
13         printf(
14                         "Input stream is scanned for presence of 2 char 255(IAC) and 243(BRK) sequence and generates Ctrl-Break event in that case.\n");
15         printf(
16                         "Also in case of all type of event(Ctrl-C, Close, Shutdown etc) Ctrl-Break event is generated.\n");
17
18         exit(0);
19 }
20
21 void ErrorMessage(char *str) {
22
23         LPVOID msg;
24
25         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
26                         NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
27                         (LPTSTR) &msg, 0, NULL);
28
29         printf("%s: %s\n", str, msg);
30         LocalFree(msg);
31 }
32
33 void CtrlBreak() {
34         if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
35                 ErrorMessage("GenerateConsoleCtrlEvent");
36         }
37 }
38
39 BOOL is_iac = FALSE;
40
41 char IAC = 5;
42 char BRK = 3;
43
44 BOOL Scan(char buf[], int count) {
45         for (int i = 0; i < count; i++) {
46                 if (is_iac) {
47                         if (buf[i] == BRK) {
48                                 CtrlBreak();
49                                 return TRUE;
50                         } else {
51                                 is_iac = FALSE;
52                         }
53                 }
54                 if (buf[i] == IAC) {
55                         is_iac = TRUE;
56                 }
57         }
58
59         return FALSE;
60 }
61
62 BOOL CtrlHandler(DWORD fdwCtrlType) {
63         switch (fdwCtrlType) {
64         case CTRL_C_EVENT:
65         case CTRL_CLOSE_EVENT:
66         case CTRL_LOGOFF_EVENT:
67         case CTRL_SHUTDOWN_EVENT:
68                 CtrlBreak();
69                 return (TRUE);
70         case CTRL_BREAK_EVENT:
71                 return FALSE;
72         default:
73                 return FALSE;
74         }
75 }
76
77 struct StdInThreadParams {
78         HANDLE hEvent;
79         HANDLE write_stdin;
80 };
81
82 DWORD WINAPI StdInThread(void *param) {
83         StdInThreadParams *threadParams = (StdInThreadParams *) param;
84         char buf[1];
85         memset(buf, 0, sizeof(buf));
86
87         HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
88         while (true) {
89                 DWORD cbRead = 0;
90                 DWORD cbWrite = 0;
91
92                 char c;
93                 ReadFile(hStdin, &c, 1, &cbRead, NULL);
94                 if (cbRead > 0) {
95                         buf[0] = c;
96                         bool ctrlBroken = Scan(buf, 1);
97                         WriteFile(threadParams->write_stdin, buf, 1, &cbWrite, NULL);
98                         if (ctrlBroken) {
99                                 SetEvent(threadParams->hEvent);
100                                 break;
101                         }
102                 }
103         }
104         return 0;
105 }
106
107 bool hasEnding(std::string const &fullString, std::string const &ending) {
108         if (fullString.length() > ending.length()) {
109                 return (0 == fullString.compare(fullString.length() - ending.length(),
110                                 ending.length(), ending));
111         } else {
112                 return false;
113         }
114 }
115
116 int main(int argc, char * argv[]) {
117         if (argc < 2) {
118                 PrintUsage();
119         }
120
121         std::string app(argv[1]);
122         std::string args("");
123
124         for (int i = 1; i < argc; i++) {
125                 if (i>1) {
126                         args += " ";
127                 }
128                 if (strchr(argv[i], ' ')) {
129                         args += "\"";
130                         args += argv[i];
131                         args += "\"";
132                 } else {
133                         args += argv[i];
134                 }
135         }
136
137 //      if (app.length() == 0) {
138 //              PrintUsage();
139 //      }
140
141         STARTUPINFO si;
142         SECURITY_ATTRIBUTES sa;
143         PROCESS_INFORMATION pi;
144
145         HANDLE newstdin, write_stdin;
146
147         sa.lpSecurityDescriptor = NULL;
148
149         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
150         sa.bInheritHandle = true;
151
152         if (!CreatePipe(&newstdin, &write_stdin, &sa, 0)) {
153                 ErrorMessage("CreatePipe");
154                 exit(0);
155         }
156
157         GetStartupInfo(&si);
158
159         si.dwFlags = STARTF_USESTDHANDLES;
160         si.wShowWindow = SW_HIDE;
161         si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
162         si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
163         si.hStdInput = newstdin;
164
165         if (hasEnding(app, std::string(".bat"))) {
166 //              in MSDN it is said to do so, but actually that doesn't work
167 //              args = "/c " + args;
168 //              app = "cmd.exe";
169         } else {
170                 app = "";
171         }
172
173
174         char* c_app = NULL;
175
176         if (app.size()>0) {
177                 c_app = new char[app.size() + 1];
178                 strcpy(c_app, app.c_str());
179         }
180
181
182         char* c_args = new char[args.size() + 1];
183         strcpy(c_args, args.c_str());
184
185         SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
186
187         if (!CreateProcess(c_app, // Application name
188                         c_args, // Application arguments
189                         NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) {
190                 ErrorMessage("CreateProcess");
191                 CloseHandle(newstdin);
192                 CloseHandle(write_stdin);
193                 exit(0);
194         }
195
196         unsigned long exit = 0;
197         unsigned long b_read;
198         unsigned long avail;
199
200         HANDLE threadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
201
202         StdInThreadParams params;
203         params.hEvent = threadEvent;
204         params.write_stdin = write_stdin;
205
206         CreateThread(NULL, 0, &StdInThread, &params, 0, NULL);
207
208         HANDLE objects_to_wait[2];
209         objects_to_wait[0] = threadEvent;
210         objects_to_wait[1] = pi.hProcess;
211
212         while (true) {
213                 int rc = WaitForMultipleObjects(2, objects_to_wait, FALSE, INFINITE);
214                 if (rc == WAIT_OBJECT_0 + 1) {
215                         break;
216                 }
217         }
218
219         GetExitCodeProcess(pi.hProcess, &exit);
220
221         CloseHandle(pi.hThread);
222         CloseHandle(pi.hProcess);
223         CloseHandle(newstdin);
224         CloseHandle(write_stdin);
225         return exit;
226 }