Remove the unneeded $Id$ blabla from the source code.
[reactos.git] / rosapps / applications / devutils / gdb2 / gdb2.cpp
1 /*
2 * gdb2 - gdb output splitter
3 *
4 * Copyright (C) 2000,2001 Nedko Arnaoudov <nedkohome@atia.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "ph.h"
23
24 #define GDB_INITIAL_COMMAND "gdb.exe"
25 #define PARAMS_SEPARATOR " "
26 #define PARAMS_SEPARATOR_LEN strlen(PARAMS_SEPARATOR);
27
28 void DisplayError(const char *pszAPI);
29 void ReadAndHandleOutput(HANDLE hPipeRead);
30 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
31 HANDLE hChildStdIn,
32 HANDLE hChildStdErr,
33 char *pchCommandLine);
34
35 DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
36 HANDLE hChildProcess = NULL;
37 HANDLE hStdIn = NULL; // Handle to parents std input.
38 BOOL bRunThread = TRUE;
39
40 int main(int argc, char* argv[])
41 {
42 HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
43 HANDLE hInputWriteTmp,hInputRead,hInputWrite;
44 HANDLE hErrorWrite;
45 HANDLE hThread;
46 DWORD ThreadId;
47 SECURITY_ATTRIBUTES sa;
48
49 // Set up the security attributes struct.
50 sa.nLength= sizeof(SECURITY_ATTRIBUTES);
51 sa.lpSecurityDescriptor = NULL;
52 sa.bInheritHandle = TRUE;
53
54
55 // Create the child output pipe.
56 if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
57 DisplayError("CreatePipe");
58
59
60 // Create a duplicate of the output write handle for the std error
61 // write handle. This is necessary in case the child application
62 // closes one of its std output handles.
63 if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
64 GetCurrentProcess(),&hErrorWrite,0,
65 TRUE,DUPLICATE_SAME_ACCESS))
66 DisplayError("DuplicateHandle");
67
68
69 // Create the child input pipe.
70 if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
71 DisplayError("CreatePipe");
72
73
74 // Create new output read handle and the input write handles. Set
75 // the Properties to FALSE. Otherwise, the child inherits the
76 // properties and, as a result, non-closeable handles to the pipes
77 // are created.
78 if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
79 GetCurrentProcess(),
80 &hOutputRead, // Address of new handle.
81 0,FALSE, // Make it uninheritable.
82 DUPLICATE_SAME_ACCESS))
83 DisplayError("DupliateHandle");
84
85 if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
86 GetCurrentProcess(),
87 &hInputWrite, // Address of new handle.
88 0,FALSE, // Make it uninheritable.
89 DUPLICATE_SAME_ACCESS))
90 DisplayError("DupliateHandle");
91
92
93 // Close inheritable copies of the handles you do not want to be
94 // inherited.
95 if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
96 if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
97
98
99 // Get std input handle so you can close it and force the ReadFile to
100 // fail when you want the input thread to exit.
101 if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
102 INVALID_HANDLE_VALUE )
103 DisplayError("GetStdHandle");
104
105 SetConsoleTitle("gdb control console");
106
107 size_t size = strlen(GDB_INITIAL_COMMAND)+PARAMS_SEPARATOR_LEN;
108
109 // get parameters length
110 for (int i = 1 ; i < argc ; i++)
111 size += strlen(argv[i])+PARAMS_SEPARATOR_LEN;
112
113 size++; // terminating null
114
115 char *pszCommandLine = new char [size];
116 if (!pszCommandLine)
117 {
118 printf("out of memory.\n");
119 return -1;
120 }
121
122 strcpy(pszCommandLine,GDB_INITIAL_COMMAND);
123 for (int i = 1 ; i < argc ; i++)
124 {
125 strcat(pszCommandLine,PARAMS_SEPARATOR);
126 strcat(pszCommandLine,argv[i]);
127 }
128
129 PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite,pszCommandLine);
130
131
132 // Close pipe handles (do not continue to modify the parent).
133 // You need to make sure that no handles to the write end of the
134 // output pipe are maintained in this process or else the pipe will
135 // not close when the child process exits and the ReadFile will hang.
136 if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
137 if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
138 if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
139
140
141 // Launch the thread that gets the input and sends it to the child.
142 hThread = CreateThread(NULL,0,GetAndSendInputThread,
143 (LPVOID)hInputWrite,0,&ThreadId);
144 if (hThread == NULL) DisplayError("CreateThread");
145
146
147 // Read the child's output.
148 ReadAndHandleOutput(hOutputRead);
149 // Redirection is complete
150
151
152 // Force the read on the input to return by closing the stdin handle.
153 if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
154
155
156 // Tell the thread to exit and wait for thread to die.
157 bRunThread = FALSE;
158
159 if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
160 DisplayError("WaitForSingleObject");
161
162 if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
163 if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
164
165 return 0;
166 }
167
168 ///////////////////////////////////////////////////////////////////////
169 // PrepAndLaunchRedirectedChild
170 // Sets up STARTUPINFO structure, and launches redirected child.
171 ///////////////////////////////////////////////////////////////////////
172 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
173 HANDLE hChildStdIn,
174 HANDLE hChildStdErr,
175 char *pchCommandLine)
176 {
177 PROCESS_INFORMATION pi;
178 STARTUPINFO si;
179 static CHAR Title[] = "debugged program console";
180
181 // Set up the start up info struct.
182 ZeroMemory(&si,sizeof(STARTUPINFO));
183 si.cb = sizeof(STARTUPINFO);
184 si.dwFlags = STARTF_USESTDHANDLES;
185 si.hStdOutput = hChildStdOut;
186 si.hStdInput = hChildStdIn;
187 si.hStdError = hChildStdErr;
188 si.lpTitle = Title;
189 // Use this if you want to hide the child:
190 // si.wShowWindow = SW_HIDE;
191 // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
192 // use the wShowWindow flags.
193
194
195 // Launch the process that you want to redirect (in this case,
196 // Child.exe). Make sure Child.exe is in the same directory as
197 // redirect.c launch redirect from a command line to prevent location
198 // confusion.
199 if (!CreateProcess(NULL,pchCommandLine,NULL,NULL,TRUE,
200 CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
201 DisplayError("CreateProcess");
202
203
204 // Set global child process handle to cause threads to exit.
205 hChildProcess = pi.hProcess;
206
207
208 // Close any unnecessary handles.
209 if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
210 }
211
212 ///////////////////////////////////////////////////////////////////////
213 // ReadAndHandleOutput
214 // Monitors handle for input. Exits when child exits or pipe breaks.
215 ///////////////////////////////////////////////////////////////////////
216 void ReadAndHandleOutput(HANDLE hPipeRead)
217 {
218 CHAR lpBuffer[256];
219 DWORD nBytesRead;
220 DWORD nCharsWritten;
221
222 while(TRUE)
223 {
224 if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
225 &nBytesRead,NULL) || !nBytesRead)
226 {
227 if (GetLastError() == ERROR_BROKEN_PIPE)
228 break; // pipe done - normal exit path.
229 else
230 DisplayError("ReadFile"); // Something bad happened.
231 }
232
233 // Display the character read on the screen.
234 if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
235 nBytesRead,&nCharsWritten,NULL))
236 DisplayError("WriteConsole");
237 }
238 }
239
240
241 ///////////////////////////////////////////////////////////////////////
242 // GetAndSendInputThread
243 // Thread procedure that monitors the console for input and sends input
244 // to the child process through the input pipe.
245 // This thread ends when the child application exits.
246 ///////////////////////////////////////////////////////////////////////
247 DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
248 {
249 CHAR read_buff[256];
250 DWORD nBytesRead,nBytesWrote;
251 HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
252
253 // Get input from our console and send it to child through the pipe.
254 while (bRunThread)
255 {
256 if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
257 DisplayError("ReadConsole");
258
259 read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
260
261 if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
262 {
263 if (GetLastError() == ERROR_NO_DATA)
264 break; // Pipe was closed (normal exit path).
265 else
266 DisplayError("WriteFile");
267 }
268 }
269
270 return 1;
271 }
272
273 ///////////////////////////////////////////////////////////////////////
274 // DisplayError
275 // Displays the error number and corresponding message.
276 ///////////////////////////////////////////////////////////////////////
277 void DisplayError(const char *pszAPI)
278 {
279 LPVOID lpvMessageBuffer;
280 CHAR szPrintBuffer[512];
281 DWORD nCharsWritten;
282
283 FormatMessage(
284 FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
285 NULL, GetLastError(),
286 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
287 (LPTSTR)&lpvMessageBuffer, 0, NULL);
288
289 wsprintf(szPrintBuffer,
290 "ERROR: API = %s.\n error code = %d.\n message = %s.\n",
291 pszAPI, GetLastError(), (char *)lpvMessageBuffer);
292
293 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
294 lstrlen(szPrintBuffer),&nCharsWritten,NULL);
295
296 LocalFree(lpvMessageBuffer);
297 ExitProcess(GetLastError());
298 }