Mercurial > hg > xemacs-beta
annotate lib-src/i.c @ 5636:07256dcc0c8b
Add missing foreback specifier values to the GUI Element face.
They were missing for an unexplicable reason in my initial patch, leading to
nil color instances in the whole hierarchy of widget faces.
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2012-01-03 Didier Verna <didier@xemacs.org>
* faces.c (complex_vars_of_faces): Add missing foreback specifier
values to the GUI Element face.
author | Didier Verna <didier@lrde.epita.fr> |
---|---|
date | Tue, 03 Jan 2012 11:25:06 +0100 |
parents | 308d34e9f07d |
children | e2fae7783046 |
rev | line source |
---|---|
442 | 1 /* I-connector utility |
2 Copyright (C) 2000 Kirill M. Katsnelson | |
1346 | 3 Copyright (C) 2002, 2003 Ben Wing. |
442 | 4 |
5 This file is part of XEmacs. | |
6 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2993
diff
changeset
|
7 XEmacs is free software: you can redistribute it and/or modify it |
442 | 8 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2993
diff
changeset
|
9 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2993
diff
changeset
|
10 option) any later version. |
442 | 11 |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2993
diff
changeset
|
18 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
442 | 19 |
20 /* When run with an argument, i treats it as a command line, and pipes | |
21 command stdin, stdout and stderr to its own respective streams. How | |
22 silly it should sound, but windowed program in Win32 cannot do output | |
23 to the console from which it has been started, and should be run using | |
24 this utility. | |
25 | |
26 This utility is for running [tx]emacs as part of make process so that | |
27 its output goes to the same console as the rest of the make output | |
28 does. It can be used also when xemacs should be run as a batch | |
29 command ina script, especially when its standart output should be | |
30 obtained programmatically. */ | |
31 | |
2993 | 32 #ifdef HAVE_CONFIG_H |
33 # include <config.h> | |
34 #endif | |
35 | |
442 | 36 #include <windows.h> |
37 #include <stdio.h> | |
38 #include <string.h> | |
39 #include <tchar.h> | |
40 | |
41 typedef struct | |
42 { | |
43 HANDLE source; | |
44 HANDLE drain; | |
45 } I_connector; | |
46 | |
47 /* | |
48 * Make new handle as that pointed to by PH but | |
49 * inheritable, substitute PH with it, and close the | |
50 * original one | |
51 */ | |
52 static void | |
53 make_inheritable (HANDLE* ph) | |
54 { | |
55 HANDLE htmp; | |
56 DuplicateHandle (GetCurrentProcess(), *ph, GetCurrentProcess(), &htmp, | |
57 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
58 *ph = htmp; | |
59 } | |
60 | |
61 /* | |
62 * Worker thread proc. Reads source, pumps into drain, | |
63 * till either clogs. | |
64 */ | |
65 static DWORD CALLBACK | |
66 pump (LPVOID pv_i) | |
67 { | |
68 I_connector* pi = (I_connector*) pv_i; | |
69 BYTE buffer [256]; | |
70 DWORD really_read, unused; | |
71 | |
2426 | 72 /* I said: |
73 | |
74 [[ The docs for ReadFile claim: | |
1346 | 75 |
76 The ReadFile function returns when one of the following is true: a write | |
77 operation completes on the write end of the pipe, the number of bytes | |
78 requested has been read, or an error occurs. | |
79 | |
80 But this is just not true. ReadFile never seems to block, and unless we | |
2426 | 81 Sleep(), we will chew up all the CPU time. --ben ]] |
82 | |
83 But in fact | |
84 | |
85 [a] this does not appear to be the case any more [maybe a temporary | |
86 bug in some versions of Win2000?] | |
87 [b] it causes data lossage. [#### Why should this be? Seems extremely | |
88 fishy. I tried commenting out the calls to close the standard | |
89 handles at the bottom of the program, but it made no difference. | |
90 Would we need some kind of additional handshaking? If we get | |
91 data loss with the sleep, then we are a race condition waiting | |
92 to happen. */ | |
442 | 93 while (ReadFile (pi->source, buffer, sizeof (buffer), &really_read, NULL) && |
94 WriteFile (pi->drain, buffer, really_read, &unused, NULL)) | |
2426 | 95 /* Sleep (100) */ ; |
442 | 96 |
97 return 0; | |
98 } | |
99 | |
100 /* | |
101 * Launch a pump for the given I-connector | |
102 */ | |
103 static void | |
104 start_pump (I_connector* pi) | |
105 { | |
106 DWORD unused; | |
107 HANDLE h_thread = CreateThread (NULL, 0, pump, (void*)pi, 0, &unused); | |
108 CloseHandle (h_thread); | |
109 } | |
110 | |
826 | 111 static HANDLE external_event; |
112 | |
113 static BOOL | |
114 ctrl_c_handler (unsigned long type) | |
115 { | |
116 SetEvent (external_event); | |
117 return FALSE; | |
118 } | |
119 | |
120 /* Skip over the executable name in the given command line. Correctly | |
121 handles quotes in the name. Return NULL upon error. If | |
122 REQUIRE_FOLLOWING is non-zero, it's an error if no argument follows the | |
123 executable name. */ | |
124 | |
442 | 125 static LPTSTR |
826 | 126 skip_executable_name (LPTSTR cl, int require_following) |
442 | 127 { |
128 int ix; | |
129 | |
130 while (1) | |
131 { | |
132 ix = _tcscspn (cl, _T(" \t\"")); | |
133 if (cl[ix] == '\"') | |
134 { | |
135 cl = _tcschr (cl + ix + 1, '\"'); | |
136 if (cl == NULL) | |
137 return NULL; /* Unmatched quote */ | |
138 cl++; | |
139 } | |
140 else | |
141 { | |
142 cl += ix; | |
143 cl += _tcsspn (cl, _T(" \t")); | |
826 | 144 if (!require_following) |
145 return cl; | |
442 | 146 return *cl ? cl : NULL; |
147 } | |
148 } | |
149 } | |
150 | |
151 /* | |
152 * Brew coffee and bring snickers | |
153 */ | |
154 void | |
155 usage (void) | |
156 { | |
157 fprintf (stderr, | |
158 "\n" | |
159 "usage: i command\n" | |
160 "i executes the command and reroutes its standard handles to the calling\n" | |
161 "console. Good for seeing output of GUI programs that use standard output." | |
162 "\n"); | |
163 } | |
164 | |
165 int | |
166 main (void) | |
167 { | |
168 STARTUPINFO si; | |
169 PROCESS_INFORMATION pi; | |
170 I_connector I_in, I_out, I_err; | |
171 DWORD exit_code; | |
826 | 172 LPTSTR command = skip_executable_name (GetCommandLine (), 1); |
173 | |
442 | 174 if (command == NULL) |
175 { | |
176 usage (); | |
177 return 1; | |
178 } | |
179 | |
180 ZeroMemory (&si, sizeof (si)); | |
181 si.dwFlags = STARTF_USESTDHANDLES; | |
182 | |
183 I_in.source = GetStdHandle (STD_INPUT_HANDLE); | |
184 CreatePipe (&si.hStdInput, &I_in.drain, NULL, 0); | |
185 make_inheritable (&si.hStdInput); | |
186 | |
187 I_out.drain = GetStdHandle (STD_OUTPUT_HANDLE); | |
188 CreatePipe (&I_out.source, &si.hStdOutput, NULL, 0); | |
189 make_inheritable (&si.hStdOutput); | |
190 | |
191 I_err.drain = GetStdHandle (STD_ERROR_HANDLE); | |
192 CreatePipe (&I_err.source, &si.hStdError, NULL, 0); | |
193 make_inheritable (&si.hStdError); | |
194 | |
826 | 195 { |
196 SECURITY_ATTRIBUTES sa; | |
197 LPTSTR new_command = | |
198 (LPTSTR) malloc (666 + sizeof (TCHAR) * _tcslen (command)); | |
199 LPTSTR past_exe; | |
200 | |
201 if (!new_command) | |
202 { | |
203 _ftprintf (stderr, _T ("Out of memory when launching `%s'\n"), | |
204 command); | |
205 return 2; | |
206 } | |
207 | |
208 past_exe = skip_executable_name (command, 0); | |
209 if (!past_exe) | |
210 { | |
211 usage (); | |
212 return 1; | |
213 } | |
214 | |
215 /* Since XEmacs isn't a console application, it can't easily be | |
216 terminated using ^C. Therefore, we set up a communication path with | |
217 it so that when a ^C is sent to us (using GenerateConsoleCtrlEvent), | |
218 we in turn signals it to commit suicide. (This is cleaner than using | |
219 TerminateProcess()). This makes (e.g.) the "Stop Build" command | |
220 from VC++ correctly terminate XEmacs. | |
221 | |
222 #### This will cause problems if i.exe is used for commands other | |
223 than XEmacs. We need to make behavior this a command-line | |
224 option. */ | |
442 | 225 |
826 | 226 /* Create the event as inheritable so that we can use it to communicate |
227 with the child process */ | |
228 sa.nLength = sizeof (sa); | |
229 sa.bInheritHandle = TRUE; | |
230 sa.lpSecurityDescriptor = NULL; | |
231 external_event = CreateEvent (&sa, FALSE, FALSE, NULL); | |
232 if (!external_event) | |
233 { | |
234 _ftprintf (stderr, _T ("Error %d creating signal event for `%s'\n"), | |
235 GetLastError (), command); | |
236 return 2; | |
237 } | |
238 | |
239 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); | |
240 _tcsncpy (new_command, command, past_exe - command); | |
241 _stprintf (new_command + (past_exe - command), | |
242 /* start with space in case no args past command name */ | |
243 " -mswindows-termination-handle %d ", (long) external_event); | |
244 _tcscat (new_command, past_exe); | |
245 | |
246 if (CreateProcess (NULL, new_command, NULL, NULL, TRUE, 0, | |
247 NULL, NULL, &si, &pi) == 0) | |
248 { | |
249 _ftprintf (stderr, _T("Error %d launching `%s'\n"), | |
250 GetLastError (), command); | |
251 return 2; | |
252 } | |
253 | |
254 CloseHandle (pi.hThread); | |
255 } | |
256 | |
442 | 257 |
258 /* Start pump in each I-connector */ | |
259 start_pump (&I_in); | |
260 start_pump (&I_out); | |
261 start_pump (&I_err); | |
262 | |
263 /* Wait for the process to complete */ | |
264 WaitForSingleObject (pi.hProcess, INFINITE); | |
265 GetExitCodeProcess (pi.hProcess, &exit_code); | |
266 CloseHandle (pi.hProcess); | |
267 | |
268 /* Make pump threads eventually die out. Looks rude, I agree */ | |
269 CloseHandle (GetStdHandle (STD_INPUT_HANDLE)); | |
270 CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE)); | |
271 CloseHandle (GetStdHandle (STD_ERROR_HANDLE)); | |
272 | |
273 return exit_code; | |
274 } |