2 Copyright (C) 2000 Kirill M. Katsnelson
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; 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. */
21 /* When run with an argument, i treats it as a command line, and pipes
22 command stdin, stdout and stderr to its own respective streams. How
23 silly it should sound, but windowed program in Win32 cannot do output
24 to the console from which it has been started, and should be run using
27 This utility is for running [tx]emacs as part of make process so that
28 its output goes to the same console as the rest of the make output
29 does. It can be used also when xemacs should be run as a batch
30 command ina script, especially when its standart output should be
31 obtained programmatically. */
45 * Make new handle as that pointed to by PH but
46 * inheritable, substitute PH with it, and close the
50 make_inheritable (HANDLE* ph)
53 DuplicateHandle (GetCurrentProcess(), *ph, GetCurrentProcess(), &htmp,
54 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
59 * Worker thread proc. Reads source, pumps into drain,
65 I_connector* pi = (I_connector*) pv_i;
67 DWORD really_read, unused;
69 while (ReadFile (pi->source, buffer, sizeof (buffer), &really_read, NULL) &&
70 WriteFile (pi->drain, buffer, really_read, &unused, NULL))
77 * Launch a pump for the given I-connector
80 start_pump (I_connector* pi)
83 HANDLE h_thread = CreateThread (NULL, 0, pump, (void*)pi, 0, &unused);
84 CloseHandle (h_thread);
88 * Get command line, skip over the executable name, return the rest.
93 LPTSTR cl = GetCommandLine ();
98 ix = _tcscspn (cl, _T(" \t\""));
101 cl = _tcschr (cl + ix + 1, '\"');
103 return NULL; /* Unmatched quote */
109 cl += _tcsspn (cl, _T(" \t"));
110 return *cl ? cl : NULL;
116 * Brew coffee and bring snickers
124 "i executes the command and reroutes its standard handles to the calling\n"
125 "console. Good for seeing output of GUI programs that use standard output."
133 PROCESS_INFORMATION pi;
134 I_connector I_in, I_out, I_err;
137 LPTSTR command = get_command ();
144 ZeroMemory (&si, sizeof (si));
145 si.dwFlags = STARTF_USESTDHANDLES;
147 I_in.source = GetStdHandle (STD_INPUT_HANDLE);
148 CreatePipe (&si.hStdInput, &I_in.drain, NULL, 0);
149 make_inheritable (&si.hStdInput);
151 I_out.drain = GetStdHandle (STD_OUTPUT_HANDLE);
152 CreatePipe (&I_out.source, &si.hStdOutput, NULL, 0);
153 make_inheritable (&si.hStdOutput);
155 I_err.drain = GetStdHandle (STD_ERROR_HANDLE);
156 CreatePipe (&I_err.source, &si.hStdError, NULL, 0);
157 make_inheritable (&si.hStdError);
159 if (CreateProcess (NULL, command, NULL, NULL, TRUE, 0,
160 NULL, NULL, &si, &pi) == 0)
162 _ftprintf (stderr, _T("Error %d launching `%s'\n"),
163 GetLastError (), command);
167 CloseHandle (pi.hThread);
169 /* Start pump in each I-connector */
174 /* Wait for the process to complete */
175 WaitForSingleObject (pi.hProcess, INFINITE);
176 GetExitCodeProcess (pi.hProcess, &exit_code);
177 CloseHandle (pi.hProcess);
179 /* Make pump threads eventually die out. Looks rude, I agree */
180 CloseHandle (GetStdHandle (STD_INPUT_HANDLE));
181 CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE));
182 CloseHandle (GetStdHandle (STD_ERROR_HANDLE));