Mercurial > hg > xemacs-beta
comparison lib-src/i.c @ 406:b8cc9ab3f761 r21-2-33
Import from CVS: tag r21-2-33
| author | cvs |
|---|---|
| date | Mon, 13 Aug 2007 11:17:09 +0200 |
| parents | |
| children | 501cfd01ee6d |
comparison
equal
deleted
inserted
replaced
| 405:0e08f63c74d2 | 406:b8cc9ab3f761 |
|---|---|
| 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 q, ws, 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 } |
