comparison lib-src/i.c @ 442:abe6d1db359e r21-2-36

Import from CVS: tag r21-2-36
author cvs
date Mon, 13 Aug 2007 11:35:02 +0200
parents
children 6728e641994e
comparison
equal deleted inserted replaced
441:72a7cfa4a488 442:abe6d1db359e
1 /* I-connector utility
2 Copyright (C) 2000 Kirill M. Katsnelson
3
4 This file is part of XEmacs.
5
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
9 later version.
10
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
14 for more details.
15
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. */
20
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
25 this utility.
26
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. */
32
33 #include <windows.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <tchar.h>
37
38 typedef struct
39 {
40 HANDLE source;
41 HANDLE drain;
42 } I_connector;
43
44 /*
45 * Make new handle as that pointed to by PH but
46 * inheritable, substitute PH with it, and close the
47 * original one
48 */
49 static void
50 make_inheritable (HANDLE* ph)
51 {
52 HANDLE htmp;
53 DuplicateHandle (GetCurrentProcess(), *ph, GetCurrentProcess(), &htmp,
54 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
55 *ph = htmp;
56 }
57
58 /*
59 * Worker thread proc. Reads source, pumps into drain,
60 * till either clogs.
61 */
62 static DWORD CALLBACK
63 pump (LPVOID pv_i)
64 {
65 I_connector* pi = (I_connector*) pv_i;
66 BYTE buffer [256];
67 DWORD really_read, unused;
68
69 while (ReadFile (pi->source, buffer, sizeof (buffer), &really_read, NULL) &&
70 WriteFile (pi->drain, buffer, really_read, &unused, NULL))
71 ;
72
73 return 0;
74 }
75
76 /*
77 * Launch a pump for the given I-connector
78 */
79 static void
80 start_pump (I_connector* pi)
81 {
82 DWORD unused;
83 HANDLE h_thread = CreateThread (NULL, 0, pump, (void*)pi, 0, &unused);
84 CloseHandle (h_thread);
85 }
86
87 /*
88 * Get command line, skip over the executable name, return the rest.
89 */
90 static LPTSTR
91 get_command (void)
92 {
93 LPTSTR cl = GetCommandLine ();
94 int ix;
95
96 while (1)
97 {
98 ix = _tcscspn (cl, _T(" \t\""));
99 if (cl[ix] == '\"')
100 {
101 cl = _tcschr (cl + ix + 1, '\"');
102 if (cl == NULL)
103 return NULL; /* Unmatched quote */
104 cl++;
105 }
106 else
107 {
108 cl += ix;
109 cl += _tcsspn (cl, _T(" \t"));
110 return *cl ? cl : NULL;
111 }
112 }
113 }
114
115 /*
116 * Brew coffee and bring snickers
117 */
118 void
119 usage (void)
120 {
121 fprintf (stderr,
122 "\n"
123 "usage: i command\n"
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."
126 "\n");
127 }
128
129 int
130 main (void)
131 {
132 STARTUPINFO si;
133 PROCESS_INFORMATION pi;
134 I_connector I_in, I_out, I_err;
135 DWORD exit_code;
136
137 LPTSTR command = get_command ();
138 if (command == NULL)
139 {
140 usage ();
141 return 1;
142 }
143
144 ZeroMemory (&si, sizeof (si));
145 si.dwFlags = STARTF_USESTDHANDLES;
146
147 I_in.source = GetStdHandle (STD_INPUT_HANDLE);
148 CreatePipe (&si.hStdInput, &I_in.drain, NULL, 0);
149 make_inheritable (&si.hStdInput);
150
151 I_out.drain = GetStdHandle (STD_OUTPUT_HANDLE);
152 CreatePipe (&I_out.source, &si.hStdOutput, NULL, 0);
153 make_inheritable (&si.hStdOutput);
154
155 I_err.drain = GetStdHandle (STD_ERROR_HANDLE);
156 CreatePipe (&I_err.source, &si.hStdError, NULL, 0);
157 make_inheritable (&si.hStdError);
158
159 if (CreateProcess (NULL, command, NULL, NULL, TRUE, 0,
160 NULL, NULL, &si, &pi) == 0)
161 {
162 _ftprintf (stderr, _T("Error %d launching `%s'\n"),
163 GetLastError (), command);
164 return 2;
165 }
166
167 CloseHandle (pi.hThread);
168
169 /* Start pump in each I-connector */
170 start_pump (&I_in);
171 start_pump (&I_out);
172 start_pump (&I_err);
173
174 /* Wait for the process to complete */
175 WaitForSingleObject (pi.hProcess, INFINITE);
176 GetExitCodeProcess (pi.hProcess, &exit_code);
177 CloseHandle (pi.hProcess);
178
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));
183
184 return exit_code;
185 }