root/branches/bud/hcf/process.d

Revision 227, 7.0 kB (checked in by Gregor, 2 years ago)

RELEASE: 0.12

Line 
1 /**
2  * Helpful process functions
3  *
4  * Authors:
5  *  Gregor Richards
6  *
7  * License:
8  *  Copyright (c) 2006, 2007  Gregor Richards
9  * 
10  *  Permission is hereby granted, free of charge, to any person obtaining a
11  *  copy of this software and associated documentation files (the "Software"),
12  *  to deal in the Software without restriction, including without limitation
13  *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  *  and/or sell copies of the Software, and to permit persons to whom the
15  *  Software is furnished to do so, subject to the following conditions:
16  * 
17  *  The above copyright notice and this permission notice shall be included in
18  *  all copies or substantial portions of the Software.
19  * 
20  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  *  DEALINGS IN THE SOFTWARE.
27  */
28
29 module hcf.process;
30
31 public import std.process;
32 alias std.process.system system;
33
34 import std.stdio;
35 import std.string;
36 import std.stream;
37
38 import std.c.stdlib;
39
40 private {
41     version (Windows) {
42         import bcd.windows.windows;
43     } else {
44         extern (C) int dup2(int, int);
45         extern (C) int fork();
46         extern (C) int pipe(int[2]);
47         extern (C) int read(int, void*, size_t);
48         extern (C) int write(int, void*, size_t);
49         extern (C) int close(int);
50         extern (C) size_t waitpid(size_t, int*, int);
51     }
52 }
53
54 class PStream : Stream {
55     /** First init step: this, then start the process based on its result */
56     void init1()
57     {
58         readable = true;
59         writeable = true;
60         seekable = false;
61        
62         version (Posix) {
63             // get our pipes
64             pipe(ip);
65             pipe(op);
66        
67             // fork
68             pid = fork();
69             if (pid == 0) {
70                 // dup2 in our stdin/out
71                 dup2(ip[0], 0);
72                 hcf.process.close(ip[1]);
73                 dup2(op[1], 1);
74                 dup2(op[1], 2);
75                 hcf.process.close(op[0]);
76             } else if (pid == -1) {
77                 // boom!
78                 throw new StreamException("Failed to fork");
79             } else {
80                 hcf.process.close(ip[0]);
81                 hcf.process.close(op[1]);
82             }
83         } else version (Windows) {
84             // get our pipes
85             _SECURITY_ATTRIBUTES sa;
86             sa.nLength = _SECURITY_ATTRIBUTES.sizeof;
87             sa.bInheritHandle = 1;
88             CreatePipe(&ipr, &ipw, &sa, 0);
89             CreatePipe(&opr, &opw, &sa, 0);
90            
91             // don't fork yet - it'll have to be done by the next step
92         }
93     }
94    
95     /** Use system */
96     this(char[] command)
97     {
98         init1();
99        
100         version (Posix) {
101             if (pid == 0) {
102                 exit(std.process.system(command));
103             }
104         } else version (Windows) {
105             _STARTUPINFOA si;
106             si.cb = _STARTUPINFOA.sizeof;
107             si.hStdInput = ipr;
108             si.hStdOutput = opw;
109             si.hStdError = opw;
110             si.dwFlags = STARTF_USESTDHANDLES;
111            
112             _PROCESS_INFORMATION pi;
113            
114             CreateProcessA(null, toStringz(command), null, null,
115                            1, 0, null, null, &si, &pi);
116             CloseHandle(ipr);
117             CloseHandle(opw);
118             CloseHandle(pi.hThread);
119             phnd = pi.hProcess;
120         }
121        
122         init2();
123     }
124    
125     /** Use execvp */
126     this(char[] pathname, char[][] argv)
127     {
128         init1();
129        
130         version (Posix) {
131             if (pid == 0) {
132                 execvp(pathname, argv);
133                 exit(1);
134             }
135         } else version(Windows) {
136             assert(0);
137         }
138        
139         init2();
140     }
141    
142     /** The second init part */
143     void init2()
144     {
145         isopen = true;
146     }
147    
148     uint readBlock(void* buffer, uint size)
149     {
150         version (Posix) {
151             int rd = hcf.process.read(op[0], buffer, size);
152             if (rd == -1) {
153                 readEOF = true;
154                 return 0;
155             } else {
156                 readEOF = false;
157             }
158             return rd;
159         } else version (Windows) {
160             uint rd;
161             if (!ReadFile(opr, buffer, size, &rd, null)) {
162                 readEOF = true;
163                 return 0;
164             } else {
165                 readEOF = false;
166             }
167             return rd;
168         }
169     }
170    
171     uint writeBlock(void* buffer, uint size)
172     {
173         version (Posix) {
174             int wt = hcf.process.write(ip[1], buffer, size);
175             if (wt == -1) {
176                 throw new StreamException("Process closed");
177             }
178             return wt;
179         } else version (Windows) {
180             uint wt;
181             if (!WriteFile(opr, buffer, size, &wt, null)) {
182                 readEOF = true;
183                 return 0;
184             } else {
185                 readEOF = false;
186             }
187             return wt;
188         }
189     }
190    
191     ulong seek(long offset, SeekPos whence)
192     {
193         throw new StreamException("Cannot seek in PStreams");
194     }
195    
196     /** Close the process, return the result */
197     void close()
198     {
199         if (isopen) {
200             isopen = false;
201             version (Posix) {
202                 waitpid(pid, &eval, 0);
203                 hcf.process.close(ip[1]);
204                 hcf.process.close(op[0]);
205             } else version (Windows) {
206                 GetExitCodeProcess(phnd, &eval);
207                 CloseHandle(phnd);
208                 CloseHandle(ipw);
209                 CloseHandle(opr);
210             }
211         }
212     }
213    
214     version (Posix) {
215         /** Get the exit value */
216         int exitValue()
217         {
218             return eval;
219         }
220     } else version (Windows) {
221         /** Get the exit value */
222         uint exitValue()
223         {
224             return eval;
225         }
226     }
227    
228     private:
229    
230     version (Posix) {
231         /** The pid */
232         int pid;
233    
234         /** The exit value */
235         int eval;
236    
237         /** The input pipe */
238         int[2] ip;
239    
240         /** The output pipe */
241         int[2] op;
242     } else version (Windows) {
243         /** The process handle */
244         HANDLE phnd;
245        
246         /** The exit value */
247         uint eval;
248    
249         /** The input pipe */
250         HANDLE ipr, ipw;
251        
252         /** The output pipe */
253         HANDLE opr, opw;
254     }
255 }
256
257 /** system + guarantee success */
258 void systemOrDie(char[] cmd)
259 {
260     int res;
261     res = system(cmd);
262     if (res) exit(res);
263 }
264
265 /** system + output */
266 int sayAndSystem(char[] cmd)
267 {
268     writefln("+ %s", cmd);
269     return system(cmd);
270 }
271
272 /** systemOrDie + output */
273 void saySystemDie(char[] cmd)
274 {
275     writefln("+ %s", cmd);
276     systemOrDie(cmd);
277 }
Note: See TracBrowser for help on using the browser.