Mercurial > hg > xemacs-beta
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 } |